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> 45e51060f0SSean Hefty 46e51060f0SSean Hefty #include <rdma/rdma_cm.h> 47e51060f0SSean Hefty #include <rdma/rdma_cm_ib.h> 48e51060f0SSean Hefty #include <rdma/ib_cache.h> 49e51060f0SSean Hefty #include <rdma/ib_cm.h> 50e51060f0SSean Hefty #include <rdma/ib_sa.h> 5107ebafbaSTom Tucker #include <rdma/iw_cm.h> 52e51060f0SSean Hefty 53e51060f0SSean Hefty MODULE_AUTHOR("Sean Hefty"); 54e51060f0SSean Hefty MODULE_DESCRIPTION("Generic RDMA CM Agent"); 55e51060f0SSean Hefty MODULE_LICENSE("Dual BSD/GPL"); 56e51060f0SSean Hefty 57e51060f0SSean Hefty #define CMA_CM_RESPONSE_TIMEOUT 20 58d5bb7599SMichael S. Tsirkin #define CMA_MAX_CM_RETRIES 15 59dcb3f974SSean Hefty #define CMA_CM_MRA_SETTING (IB_CM_MRA_FLAG_DELAY | 24) 60e51060f0SSean Hefty 61e51060f0SSean Hefty static void cma_add_one(struct ib_device *device); 62e51060f0SSean Hefty static void cma_remove_one(struct ib_device *device); 63e51060f0SSean Hefty 64e51060f0SSean Hefty static struct ib_client cma_client = { 65e51060f0SSean Hefty .name = "cma", 66e51060f0SSean Hefty .add = cma_add_one, 67e51060f0SSean Hefty .remove = cma_remove_one 68e51060f0SSean Hefty }; 69e51060f0SSean Hefty 70c1a0b23bSMichael S. Tsirkin static struct ib_sa_client sa_client; 717a118df3SSean Hefty static struct rdma_addr_client addr_client; 72e51060f0SSean Hefty static LIST_HEAD(dev_list); 73e51060f0SSean Hefty static LIST_HEAD(listen_any_list); 74e51060f0SSean Hefty static DEFINE_MUTEX(lock); 75e51060f0SSean Hefty static struct workqueue_struct *cma_wq; 76e51060f0SSean Hefty static DEFINE_IDR(sdp_ps); 77e51060f0SSean Hefty static DEFINE_IDR(tcp_ps); 78628e5f6dSSean Hefty static DEFINE_IDR(udp_ps); 79c8f6a362SSean Hefty static DEFINE_IDR(ipoib_ps); 80aedec080SSean Hefty static int next_port; 81e51060f0SSean Hefty 82e51060f0SSean Hefty struct cma_device { 83e51060f0SSean Hefty struct list_head list; 84e51060f0SSean Hefty struct ib_device *device; 85e51060f0SSean Hefty struct completion comp; 86e51060f0SSean Hefty atomic_t refcount; 87e51060f0SSean Hefty struct list_head id_list; 88e51060f0SSean Hefty }; 89e51060f0SSean Hefty 90e51060f0SSean Hefty enum cma_state { 91e51060f0SSean Hefty CMA_IDLE, 92e51060f0SSean Hefty CMA_ADDR_QUERY, 93e51060f0SSean Hefty CMA_ADDR_RESOLVED, 94e51060f0SSean Hefty CMA_ROUTE_QUERY, 95e51060f0SSean Hefty CMA_ROUTE_RESOLVED, 96e51060f0SSean Hefty CMA_CONNECT, 97e51060f0SSean Hefty CMA_DISCONNECT, 98e51060f0SSean Hefty CMA_ADDR_BOUND, 99e51060f0SSean Hefty CMA_LISTEN, 100e51060f0SSean Hefty CMA_DEVICE_REMOVAL, 101e51060f0SSean Hefty CMA_DESTROYING 102e51060f0SSean Hefty }; 103e51060f0SSean Hefty 104e51060f0SSean Hefty struct rdma_bind_list { 105e51060f0SSean Hefty struct idr *ps; 106e51060f0SSean Hefty struct hlist_head owners; 107e51060f0SSean Hefty unsigned short port; 108e51060f0SSean Hefty }; 109e51060f0SSean Hefty 110e51060f0SSean Hefty /* 111e51060f0SSean Hefty * Device removal can occur at anytime, so we need extra handling to 112e51060f0SSean Hefty * serialize notifying the user of device removal with other callbacks. 113e51060f0SSean Hefty * We do this by disabling removal notification while a callback is in process, 114e51060f0SSean Hefty * and reporting it after the callback completes. 115e51060f0SSean Hefty */ 116e51060f0SSean Hefty struct rdma_id_private { 117e51060f0SSean Hefty struct rdma_cm_id id; 118e51060f0SSean Hefty 119e51060f0SSean Hefty struct rdma_bind_list *bind_list; 120e51060f0SSean Hefty struct hlist_node node; 121d02d1f53SSean Hefty struct list_head list; /* listen_any_list or cma_device.list */ 122d02d1f53SSean Hefty struct list_head listen_list; /* per device listens */ 123e51060f0SSean Hefty struct cma_device *cma_dev; 124c8f6a362SSean Hefty struct list_head mc_list; 125e51060f0SSean Hefty 126d02d1f53SSean Hefty int internal_id; 127e51060f0SSean Hefty enum cma_state state; 128e51060f0SSean Hefty spinlock_t lock; 129c5483388SSean Hefty struct mutex qp_mutex; 130c5483388SSean Hefty 131e51060f0SSean Hefty struct completion comp; 132e51060f0SSean Hefty atomic_t refcount; 133de910bd9SOr Gerlitz struct mutex handler_mutex; 134e51060f0SSean Hefty 135e51060f0SSean Hefty int backlog; 136e51060f0SSean Hefty int timeout_ms; 137e51060f0SSean Hefty struct ib_sa_query *query; 138e51060f0SSean Hefty int query_id; 139e51060f0SSean Hefty union { 140e51060f0SSean Hefty struct ib_cm_id *ib; 14107ebafbaSTom Tucker struct iw_cm_id *iw; 142e51060f0SSean Hefty } cm_id; 143e51060f0SSean Hefty 144e51060f0SSean Hefty u32 seq_num; 145c8f6a362SSean Hefty u32 qkey; 146e51060f0SSean Hefty u32 qp_num; 147e51060f0SSean Hefty u8 srq; 148a81c994dSSean Hefty u8 tos; 149e51060f0SSean Hefty }; 150e51060f0SSean Hefty 151c8f6a362SSean Hefty struct cma_multicast { 152c8f6a362SSean Hefty struct rdma_id_private *id_priv; 153c8f6a362SSean Hefty union { 154c8f6a362SSean Hefty struct ib_sa_multicast *ib; 155c8f6a362SSean Hefty } multicast; 156c8f6a362SSean Hefty struct list_head list; 157c8f6a362SSean Hefty void *context; 158c8f6a362SSean Hefty struct sockaddr addr; 159c8f6a362SSean Hefty u8 pad[sizeof(struct sockaddr_in6) - 160c8f6a362SSean Hefty sizeof(struct sockaddr)]; 161c8f6a362SSean Hefty }; 162c8f6a362SSean Hefty 163e51060f0SSean Hefty struct cma_work { 164e51060f0SSean Hefty struct work_struct work; 165e51060f0SSean Hefty struct rdma_id_private *id; 166e51060f0SSean Hefty enum cma_state old_state; 167e51060f0SSean Hefty enum cma_state new_state; 168e51060f0SSean Hefty struct rdma_cm_event event; 169e51060f0SSean Hefty }; 170e51060f0SSean Hefty 171dd5bdff8SOr Gerlitz struct cma_ndev_work { 172dd5bdff8SOr Gerlitz struct work_struct work; 173dd5bdff8SOr Gerlitz struct rdma_id_private *id; 174dd5bdff8SOr Gerlitz struct rdma_cm_event event; 175dd5bdff8SOr Gerlitz }; 176dd5bdff8SOr Gerlitz 177e51060f0SSean Hefty union cma_ip_addr { 178e51060f0SSean Hefty struct in6_addr ip6; 179e51060f0SSean Hefty struct { 1801b90c137SAl Viro __be32 pad[3]; 1811b90c137SAl Viro __be32 addr; 182e51060f0SSean Hefty } ip4; 183e51060f0SSean Hefty }; 184e51060f0SSean Hefty 185e51060f0SSean Hefty struct cma_hdr { 186e51060f0SSean Hefty u8 cma_version; 187e51060f0SSean Hefty u8 ip_version; /* IP version: 7:4 */ 1881b90c137SAl Viro __be16 port; 189e51060f0SSean Hefty union cma_ip_addr src_addr; 190e51060f0SSean Hefty union cma_ip_addr dst_addr; 191e51060f0SSean Hefty }; 192e51060f0SSean Hefty 193e51060f0SSean Hefty struct sdp_hh { 194e51060f0SSean Hefty u8 bsdh[16]; 195e51060f0SSean Hefty u8 sdp_version; /* Major version: 7:4 */ 196e51060f0SSean Hefty u8 ip_version; /* IP version: 7:4 */ 197e51060f0SSean Hefty u8 sdp_specific1[10]; 1981b90c137SAl Viro __be16 port; 1991b90c137SAl Viro __be16 sdp_specific2; 200e51060f0SSean Hefty union cma_ip_addr src_addr; 201e51060f0SSean Hefty union cma_ip_addr dst_addr; 202e51060f0SSean Hefty }; 203e51060f0SSean Hefty 204e51060f0SSean Hefty struct sdp_hah { 205e51060f0SSean Hefty u8 bsdh[16]; 206e51060f0SSean Hefty u8 sdp_version; 207e51060f0SSean Hefty }; 208e51060f0SSean Hefty 209e51060f0SSean Hefty #define CMA_VERSION 0x00 210e51060f0SSean Hefty #define SDP_MAJ_VERSION 0x2 211e51060f0SSean Hefty 212e51060f0SSean Hefty static int cma_comp(struct rdma_id_private *id_priv, enum cma_state comp) 213e51060f0SSean Hefty { 214e51060f0SSean Hefty unsigned long flags; 215e51060f0SSean Hefty int ret; 216e51060f0SSean Hefty 217e51060f0SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 218e51060f0SSean Hefty ret = (id_priv->state == comp); 219e51060f0SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 220e51060f0SSean Hefty return ret; 221e51060f0SSean Hefty } 222e51060f0SSean Hefty 223e51060f0SSean Hefty static int cma_comp_exch(struct rdma_id_private *id_priv, 224e51060f0SSean Hefty enum cma_state comp, enum cma_state exch) 225e51060f0SSean Hefty { 226e51060f0SSean Hefty unsigned long flags; 227e51060f0SSean Hefty int ret; 228e51060f0SSean Hefty 229e51060f0SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 230e51060f0SSean Hefty if ((ret = (id_priv->state == comp))) 231e51060f0SSean Hefty id_priv->state = exch; 232e51060f0SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 233e51060f0SSean Hefty return ret; 234e51060f0SSean Hefty } 235e51060f0SSean Hefty 236e51060f0SSean Hefty static enum cma_state cma_exch(struct rdma_id_private *id_priv, 237e51060f0SSean Hefty enum cma_state exch) 238e51060f0SSean Hefty { 239e51060f0SSean Hefty unsigned long flags; 240e51060f0SSean Hefty enum cma_state old; 241e51060f0SSean Hefty 242e51060f0SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 243e51060f0SSean Hefty old = id_priv->state; 244e51060f0SSean Hefty id_priv->state = exch; 245e51060f0SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 246e51060f0SSean Hefty return old; 247e51060f0SSean Hefty } 248e51060f0SSean Hefty 249e51060f0SSean Hefty static inline u8 cma_get_ip_ver(struct cma_hdr *hdr) 250e51060f0SSean Hefty { 251e51060f0SSean Hefty return hdr->ip_version >> 4; 252e51060f0SSean Hefty } 253e51060f0SSean Hefty 254e51060f0SSean Hefty static inline void cma_set_ip_ver(struct cma_hdr *hdr, u8 ip_ver) 255e51060f0SSean Hefty { 256e51060f0SSean Hefty hdr->ip_version = (ip_ver << 4) | (hdr->ip_version & 0xF); 257e51060f0SSean Hefty } 258e51060f0SSean Hefty 259e51060f0SSean Hefty static inline u8 sdp_get_majv(u8 sdp_version) 260e51060f0SSean Hefty { 261e51060f0SSean Hefty return sdp_version >> 4; 262e51060f0SSean Hefty } 263e51060f0SSean Hefty 264e51060f0SSean Hefty static inline u8 sdp_get_ip_ver(struct sdp_hh *hh) 265e51060f0SSean Hefty { 266e51060f0SSean Hefty return hh->ip_version >> 4; 267e51060f0SSean Hefty } 268e51060f0SSean Hefty 269e51060f0SSean Hefty static inline void sdp_set_ip_ver(struct sdp_hh *hh, u8 ip_ver) 270e51060f0SSean Hefty { 271e51060f0SSean Hefty hh->ip_version = (ip_ver << 4) | (hh->ip_version & 0xF); 272e51060f0SSean Hefty } 273e51060f0SSean Hefty 274c8f6a362SSean Hefty static inline int cma_is_ud_ps(enum rdma_port_space ps) 275c8f6a362SSean Hefty { 276c8f6a362SSean Hefty return (ps == RDMA_PS_UDP || ps == RDMA_PS_IPOIB); 277c8f6a362SSean Hefty } 278c8f6a362SSean Hefty 279e51060f0SSean Hefty static void cma_attach_to_dev(struct rdma_id_private *id_priv, 280e51060f0SSean Hefty struct cma_device *cma_dev) 281e51060f0SSean Hefty { 282e51060f0SSean Hefty atomic_inc(&cma_dev->refcount); 283e51060f0SSean Hefty id_priv->cma_dev = cma_dev; 284e51060f0SSean Hefty id_priv->id.device = cma_dev->device; 285e51060f0SSean Hefty list_add_tail(&id_priv->list, &cma_dev->id_list); 286e51060f0SSean Hefty } 287e51060f0SSean Hefty 288e51060f0SSean Hefty static inline void cma_deref_dev(struct cma_device *cma_dev) 289e51060f0SSean Hefty { 290e51060f0SSean Hefty if (atomic_dec_and_test(&cma_dev->refcount)) 291e51060f0SSean Hefty complete(&cma_dev->comp); 292e51060f0SSean Hefty } 293e51060f0SSean Hefty 294e51060f0SSean Hefty static void cma_detach_from_dev(struct rdma_id_private *id_priv) 295e51060f0SSean Hefty { 296e51060f0SSean Hefty list_del(&id_priv->list); 297e51060f0SSean Hefty cma_deref_dev(id_priv->cma_dev); 298e51060f0SSean Hefty id_priv->cma_dev = NULL; 299e51060f0SSean Hefty } 300e51060f0SSean Hefty 301c8f6a362SSean Hefty static int cma_set_qkey(struct ib_device *device, u8 port_num, 302c8f6a362SSean Hefty enum rdma_port_space ps, 303c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr, u32 *qkey) 304c8f6a362SSean Hefty { 305c8f6a362SSean Hefty struct ib_sa_mcmember_rec rec; 306c8f6a362SSean Hefty int ret = 0; 307c8f6a362SSean Hefty 308c8f6a362SSean Hefty switch (ps) { 309c8f6a362SSean Hefty case RDMA_PS_UDP: 310c8f6a362SSean Hefty *qkey = RDMA_UDP_QKEY; 311c8f6a362SSean Hefty break; 312c8f6a362SSean Hefty case RDMA_PS_IPOIB: 313c8f6a362SSean Hefty ib_addr_get_mgid(dev_addr, &rec.mgid); 314c8f6a362SSean Hefty ret = ib_sa_get_mcmember_rec(device, port_num, &rec.mgid, &rec); 315c8f6a362SSean Hefty *qkey = be32_to_cpu(rec.qkey); 316c8f6a362SSean Hefty break; 317c8f6a362SSean Hefty default: 318c8f6a362SSean Hefty break; 319c8f6a362SSean Hefty } 320c8f6a362SSean Hefty return ret; 321c8f6a362SSean Hefty } 322c8f6a362SSean Hefty 32307ebafbaSTom Tucker static int cma_acquire_dev(struct rdma_id_private *id_priv) 324e51060f0SSean Hefty { 325c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 326e51060f0SSean Hefty struct cma_device *cma_dev; 327f0ee3404SMichael S. Tsirkin union ib_gid gid; 328e51060f0SSean Hefty int ret = -ENODEV; 329e51060f0SSean Hefty 330c8f6a362SSean Hefty switch (rdma_node_get_transport(dev_addr->dev_type)) { 33107ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 332c8f6a362SSean Hefty ib_addr_get_sgid(dev_addr, &gid); 33307ebafbaSTom Tucker break; 33407ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 335c8f6a362SSean Hefty iw_addr_get_sgid(dev_addr, &gid); 33607ebafbaSTom Tucker break; 33707ebafbaSTom Tucker default: 33807ebafbaSTom Tucker return -ENODEV; 33907ebafbaSTom Tucker } 34061a73c70SSean Hefty 341e51060f0SSean Hefty list_for_each_entry(cma_dev, &dev_list, list) { 342f0ee3404SMichael S. Tsirkin ret = ib_find_cached_gid(cma_dev->device, &gid, 343e51060f0SSean Hefty &id_priv->id.port_num, NULL); 344e51060f0SSean Hefty if (!ret) { 345c8f6a362SSean Hefty ret = cma_set_qkey(cma_dev->device, 346c8f6a362SSean Hefty id_priv->id.port_num, 347c8f6a362SSean Hefty id_priv->id.ps, dev_addr, 348c8f6a362SSean Hefty &id_priv->qkey); 349c8f6a362SSean Hefty if (!ret) 350e51060f0SSean Hefty cma_attach_to_dev(id_priv, cma_dev); 351e51060f0SSean Hefty break; 352e51060f0SSean Hefty } 353e51060f0SSean Hefty } 354e51060f0SSean Hefty return ret; 355e51060f0SSean Hefty } 356e51060f0SSean Hefty 357e51060f0SSean Hefty static void cma_deref_id(struct rdma_id_private *id_priv) 358e51060f0SSean Hefty { 359e51060f0SSean Hefty if (atomic_dec_and_test(&id_priv->refcount)) 360e51060f0SSean Hefty complete(&id_priv->comp); 361e51060f0SSean Hefty } 362e51060f0SSean Hefty 363de910bd9SOr Gerlitz static int cma_disable_callback(struct rdma_id_private *id_priv, 3648aa08602SSean Hefty enum cma_state state) 3658aa08602SSean Hefty { 366de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 367de910bd9SOr Gerlitz if (id_priv->state != state) { 368de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 369de910bd9SOr Gerlitz return -EINVAL; 3708aa08602SSean Hefty } 371de910bd9SOr Gerlitz return 0; 372e51060f0SSean Hefty } 373e51060f0SSean Hefty 3746c719f5cSSean Hefty static int cma_has_cm_dev(struct rdma_id_private *id_priv) 3756c719f5cSSean Hefty { 3766c719f5cSSean Hefty return (id_priv->id.device && id_priv->cm_id.ib); 3776c719f5cSSean Hefty } 3786c719f5cSSean Hefty 379e51060f0SSean Hefty struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler, 380e51060f0SSean Hefty void *context, enum rdma_port_space ps) 381e51060f0SSean Hefty { 382e51060f0SSean Hefty struct rdma_id_private *id_priv; 383e51060f0SSean Hefty 384e51060f0SSean Hefty id_priv = kzalloc(sizeof *id_priv, GFP_KERNEL); 385e51060f0SSean Hefty if (!id_priv) 386e51060f0SSean Hefty return ERR_PTR(-ENOMEM); 387e51060f0SSean Hefty 388e51060f0SSean Hefty id_priv->state = CMA_IDLE; 389e51060f0SSean Hefty id_priv->id.context = context; 390e51060f0SSean Hefty id_priv->id.event_handler = event_handler; 391e51060f0SSean Hefty id_priv->id.ps = ps; 392e51060f0SSean Hefty spin_lock_init(&id_priv->lock); 393c5483388SSean Hefty mutex_init(&id_priv->qp_mutex); 394e51060f0SSean Hefty init_completion(&id_priv->comp); 395e51060f0SSean Hefty atomic_set(&id_priv->refcount, 1); 396de910bd9SOr Gerlitz mutex_init(&id_priv->handler_mutex); 397e51060f0SSean Hefty INIT_LIST_HEAD(&id_priv->listen_list); 398c8f6a362SSean Hefty INIT_LIST_HEAD(&id_priv->mc_list); 399e51060f0SSean Hefty get_random_bytes(&id_priv->seq_num, sizeof id_priv->seq_num); 400e51060f0SSean Hefty 401e51060f0SSean Hefty return &id_priv->id; 402e51060f0SSean Hefty } 403e51060f0SSean Hefty EXPORT_SYMBOL(rdma_create_id); 404e51060f0SSean Hefty 405c8f6a362SSean Hefty static int cma_init_ud_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) 406e51060f0SSean Hefty { 407e51060f0SSean Hefty struct ib_qp_attr qp_attr; 408c8f6a362SSean Hefty int qp_attr_mask, ret; 409e51060f0SSean Hefty 410c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_INIT; 411c8f6a362SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 412e51060f0SSean Hefty if (ret) 413e51060f0SSean Hefty return ret; 414e51060f0SSean Hefty 415c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask); 416c8f6a362SSean Hefty if (ret) 417c8f6a362SSean Hefty return ret; 418c8f6a362SSean Hefty 419c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_RTR; 420c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE); 421c8f6a362SSean Hefty if (ret) 422c8f6a362SSean Hefty return ret; 423c8f6a362SSean Hefty 424c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_RTS; 425c8f6a362SSean Hefty qp_attr.sq_psn = 0; 426c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_SQ_PSN); 427c8f6a362SSean Hefty 428c8f6a362SSean Hefty return ret; 429e51060f0SSean Hefty } 430e51060f0SSean Hefty 431c8f6a362SSean Hefty static int cma_init_conn_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) 43207ebafbaSTom Tucker { 43307ebafbaSTom Tucker struct ib_qp_attr qp_attr; 434c8f6a362SSean Hefty int qp_attr_mask, ret; 43507ebafbaSTom Tucker 43607ebafbaSTom Tucker qp_attr.qp_state = IB_QPS_INIT; 437c8f6a362SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 438c8f6a362SSean Hefty if (ret) 439c8f6a362SSean Hefty return ret; 44007ebafbaSTom Tucker 441c8f6a362SSean Hefty return ib_modify_qp(qp, &qp_attr, qp_attr_mask); 44207ebafbaSTom Tucker } 44307ebafbaSTom Tucker 444e51060f0SSean Hefty int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd, 445e51060f0SSean Hefty struct ib_qp_init_attr *qp_init_attr) 446e51060f0SSean Hefty { 447e51060f0SSean Hefty struct rdma_id_private *id_priv; 448e51060f0SSean Hefty struct ib_qp *qp; 449e51060f0SSean Hefty int ret; 450e51060f0SSean Hefty 451e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 452e51060f0SSean Hefty if (id->device != pd->device) 453e51060f0SSean Hefty return -EINVAL; 454e51060f0SSean Hefty 455e51060f0SSean Hefty qp = ib_create_qp(pd, qp_init_attr); 456e51060f0SSean Hefty if (IS_ERR(qp)) 457e51060f0SSean Hefty return PTR_ERR(qp); 458e51060f0SSean Hefty 459c8f6a362SSean Hefty if (cma_is_ud_ps(id_priv->id.ps)) 460c8f6a362SSean Hefty ret = cma_init_ud_qp(id_priv, qp); 461c8f6a362SSean Hefty else 462c8f6a362SSean Hefty ret = cma_init_conn_qp(id_priv, qp); 463e51060f0SSean Hefty if (ret) 464e51060f0SSean Hefty goto err; 465e51060f0SSean Hefty 466e51060f0SSean Hefty id->qp = qp; 467e51060f0SSean Hefty id_priv->qp_num = qp->qp_num; 468e51060f0SSean Hefty id_priv->srq = (qp->srq != NULL); 469e51060f0SSean Hefty return 0; 470e51060f0SSean Hefty err: 471e51060f0SSean Hefty ib_destroy_qp(qp); 472e51060f0SSean Hefty return ret; 473e51060f0SSean Hefty } 474e51060f0SSean Hefty EXPORT_SYMBOL(rdma_create_qp); 475e51060f0SSean Hefty 476e51060f0SSean Hefty void rdma_destroy_qp(struct rdma_cm_id *id) 477e51060f0SSean Hefty { 478c5483388SSean Hefty struct rdma_id_private *id_priv; 479c5483388SSean Hefty 480c5483388SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 481c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 482c5483388SSean Hefty ib_destroy_qp(id_priv->id.qp); 483c5483388SSean Hefty id_priv->id.qp = NULL; 484c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 485e51060f0SSean Hefty } 486e51060f0SSean Hefty EXPORT_SYMBOL(rdma_destroy_qp); 487e51060f0SSean Hefty 4885851bb89SSean Hefty static int cma_modify_qp_rtr(struct rdma_id_private *id_priv, 4895851bb89SSean Hefty struct rdma_conn_param *conn_param) 490e51060f0SSean Hefty { 491e51060f0SSean Hefty struct ib_qp_attr qp_attr; 492e51060f0SSean Hefty int qp_attr_mask, ret; 493e51060f0SSean Hefty 494c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 495c5483388SSean Hefty if (!id_priv->id.qp) { 496c5483388SSean Hefty ret = 0; 497c5483388SSean Hefty goto out; 498c5483388SSean Hefty } 499e51060f0SSean Hefty 500e51060f0SSean Hefty /* Need to update QP attributes from default values. */ 501e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_INIT; 502c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 503e51060f0SSean Hefty if (ret) 504c5483388SSean Hefty goto out; 505e51060f0SSean Hefty 506c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 507e51060f0SSean Hefty if (ret) 508c5483388SSean Hefty goto out; 509e51060f0SSean Hefty 510e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_RTR; 511c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 512e51060f0SSean Hefty if (ret) 513c5483388SSean Hefty goto out; 514e51060f0SSean Hefty 5155851bb89SSean Hefty if (conn_param) 5165851bb89SSean Hefty qp_attr.max_dest_rd_atomic = conn_param->responder_resources; 517c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 518c5483388SSean Hefty out: 519c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 520c5483388SSean Hefty return ret; 521e51060f0SSean Hefty } 522e51060f0SSean Hefty 5235851bb89SSean Hefty static int cma_modify_qp_rts(struct rdma_id_private *id_priv, 5245851bb89SSean Hefty struct rdma_conn_param *conn_param) 525e51060f0SSean Hefty { 526e51060f0SSean Hefty struct ib_qp_attr qp_attr; 527e51060f0SSean Hefty int qp_attr_mask, ret; 528e51060f0SSean Hefty 529c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 530c5483388SSean Hefty if (!id_priv->id.qp) { 531c5483388SSean Hefty ret = 0; 532c5483388SSean Hefty goto out; 533e51060f0SSean Hefty } 534e51060f0SSean Hefty 535c5483388SSean Hefty qp_attr.qp_state = IB_QPS_RTS; 536c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 537c5483388SSean Hefty if (ret) 538c5483388SSean Hefty goto out; 539c5483388SSean Hefty 5405851bb89SSean Hefty if (conn_param) 5415851bb89SSean Hefty qp_attr.max_rd_atomic = conn_param->initiator_depth; 542c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 543c5483388SSean Hefty out: 544c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 545c5483388SSean Hefty return ret; 546c5483388SSean Hefty } 547c5483388SSean Hefty 548c5483388SSean Hefty static int cma_modify_qp_err(struct rdma_id_private *id_priv) 549e51060f0SSean Hefty { 550e51060f0SSean Hefty struct ib_qp_attr qp_attr; 551c5483388SSean Hefty int ret; 552e51060f0SSean Hefty 553c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 554c5483388SSean Hefty if (!id_priv->id.qp) { 555c5483388SSean Hefty ret = 0; 556c5483388SSean Hefty goto out; 557c5483388SSean Hefty } 558e51060f0SSean Hefty 559e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_ERR; 560c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, IB_QP_STATE); 561c5483388SSean Hefty out: 562c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 563c5483388SSean Hefty return ret; 564e51060f0SSean Hefty } 565e51060f0SSean Hefty 566c8f6a362SSean Hefty static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv, 567c8f6a362SSean Hefty struct ib_qp_attr *qp_attr, int *qp_attr_mask) 568c8f6a362SSean Hefty { 569c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 570c8f6a362SSean Hefty int ret; 571c8f6a362SSean Hefty 572c8f6a362SSean Hefty ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num, 573c8f6a362SSean Hefty ib_addr_get_pkey(dev_addr), 574c8f6a362SSean Hefty &qp_attr->pkey_index); 575c8f6a362SSean Hefty if (ret) 576c8f6a362SSean Hefty return ret; 577c8f6a362SSean Hefty 578c8f6a362SSean Hefty qp_attr->port_num = id_priv->id.port_num; 579c8f6a362SSean Hefty *qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT; 580c8f6a362SSean Hefty 581c8f6a362SSean Hefty if (cma_is_ud_ps(id_priv->id.ps)) { 582c8f6a362SSean Hefty qp_attr->qkey = id_priv->qkey; 583c8f6a362SSean Hefty *qp_attr_mask |= IB_QP_QKEY; 584c8f6a362SSean Hefty } else { 585c8f6a362SSean Hefty qp_attr->qp_access_flags = 0; 586c8f6a362SSean Hefty *qp_attr_mask |= IB_QP_ACCESS_FLAGS; 587c8f6a362SSean Hefty } 588c8f6a362SSean Hefty return 0; 589c8f6a362SSean Hefty } 590c8f6a362SSean Hefty 591e51060f0SSean Hefty int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr, 592e51060f0SSean Hefty int *qp_attr_mask) 593e51060f0SSean Hefty { 594e51060f0SSean Hefty struct rdma_id_private *id_priv; 595c8f6a362SSean Hefty int ret = 0; 596e51060f0SSean Hefty 597e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 59807ebafbaSTom Tucker switch (rdma_node_get_transport(id_priv->id.device->node_type)) { 59907ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 600c8f6a362SSean Hefty if (!id_priv->cm_id.ib || cma_is_ud_ps(id_priv->id.ps)) 601c8f6a362SSean Hefty ret = cma_ib_init_qp_attr(id_priv, qp_attr, qp_attr_mask); 602c8f6a362SSean Hefty else 603e51060f0SSean Hefty ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr, 604e51060f0SSean Hefty qp_attr_mask); 605e51060f0SSean Hefty if (qp_attr->qp_state == IB_QPS_RTR) 606e51060f0SSean Hefty qp_attr->rq_psn = id_priv->seq_num; 607e51060f0SSean Hefty break; 60807ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 609c8f6a362SSean Hefty if (!id_priv->cm_id.iw) { 6108f076531SDotan Barak qp_attr->qp_access_flags = 0; 611c8f6a362SSean Hefty *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS; 612c8f6a362SSean Hefty } else 61307ebafbaSTom Tucker ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr, 61407ebafbaSTom Tucker qp_attr_mask); 61507ebafbaSTom Tucker break; 616e51060f0SSean Hefty default: 617e51060f0SSean Hefty ret = -ENOSYS; 618e51060f0SSean Hefty break; 619e51060f0SSean Hefty } 620e51060f0SSean Hefty 621e51060f0SSean Hefty return ret; 622e51060f0SSean Hefty } 623e51060f0SSean Hefty EXPORT_SYMBOL(rdma_init_qp_attr); 624e51060f0SSean Hefty 625e51060f0SSean Hefty static inline int cma_zero_addr(struct sockaddr *addr) 626e51060f0SSean Hefty { 627e51060f0SSean Hefty struct in6_addr *ip6; 628e51060f0SSean Hefty 629e51060f0SSean Hefty if (addr->sa_family == AF_INET) 6306360a02aSJoe Perches return ipv4_is_zeronet( 6316360a02aSJoe Perches ((struct sockaddr_in *)addr)->sin_addr.s_addr); 632e51060f0SSean Hefty else { 633e51060f0SSean Hefty ip6 = &((struct sockaddr_in6 *) addr)->sin6_addr; 634e51060f0SSean Hefty return (ip6->s6_addr32[0] | ip6->s6_addr32[1] | 6355fd571cbSEric Sesterhenn ip6->s6_addr32[2] | ip6->s6_addr32[3]) == 0; 636e51060f0SSean Hefty } 637e51060f0SSean Hefty } 638e51060f0SSean Hefty 639e51060f0SSean Hefty static inline int cma_loopback_addr(struct sockaddr *addr) 640e51060f0SSean Hefty { 6416360a02aSJoe Perches return ipv4_is_loopback(((struct sockaddr_in *) addr)->sin_addr.s_addr); 642e51060f0SSean Hefty } 643e51060f0SSean Hefty 644e51060f0SSean Hefty static inline int cma_any_addr(struct sockaddr *addr) 645e51060f0SSean Hefty { 646e51060f0SSean Hefty return cma_zero_addr(addr) || cma_loopback_addr(addr); 647e51060f0SSean Hefty } 648e51060f0SSean Hefty 649628e5f6dSSean Hefty static inline __be16 cma_port(struct sockaddr *addr) 650628e5f6dSSean Hefty { 651628e5f6dSSean Hefty if (addr->sa_family == AF_INET) 652628e5f6dSSean Hefty return ((struct sockaddr_in *) addr)->sin_port; 653628e5f6dSSean Hefty else 654628e5f6dSSean Hefty return ((struct sockaddr_in6 *) addr)->sin6_port; 655628e5f6dSSean Hefty } 656628e5f6dSSean Hefty 657e51060f0SSean Hefty static inline int cma_any_port(struct sockaddr *addr) 658e51060f0SSean Hefty { 659628e5f6dSSean Hefty return !cma_port(addr); 660e51060f0SSean Hefty } 661e51060f0SSean Hefty 662e51060f0SSean Hefty static int cma_get_net_info(void *hdr, enum rdma_port_space ps, 6631b90c137SAl Viro u8 *ip_ver, __be16 *port, 664e51060f0SSean Hefty union cma_ip_addr **src, union cma_ip_addr **dst) 665e51060f0SSean Hefty { 666e51060f0SSean Hefty switch (ps) { 667e51060f0SSean Hefty case RDMA_PS_SDP: 668e51060f0SSean Hefty if (sdp_get_majv(((struct sdp_hh *) hdr)->sdp_version) != 669e51060f0SSean Hefty SDP_MAJ_VERSION) 670e51060f0SSean Hefty return -EINVAL; 671e51060f0SSean Hefty 672e51060f0SSean Hefty *ip_ver = sdp_get_ip_ver(hdr); 673e51060f0SSean Hefty *port = ((struct sdp_hh *) hdr)->port; 674e51060f0SSean Hefty *src = &((struct sdp_hh *) hdr)->src_addr; 675e51060f0SSean Hefty *dst = &((struct sdp_hh *) hdr)->dst_addr; 676e51060f0SSean Hefty break; 677e51060f0SSean Hefty default: 678e51060f0SSean Hefty if (((struct cma_hdr *) hdr)->cma_version != CMA_VERSION) 679e51060f0SSean Hefty return -EINVAL; 680e51060f0SSean Hefty 681e51060f0SSean Hefty *ip_ver = cma_get_ip_ver(hdr); 682e51060f0SSean Hefty *port = ((struct cma_hdr *) hdr)->port; 683e51060f0SSean Hefty *src = &((struct cma_hdr *) hdr)->src_addr; 684e51060f0SSean Hefty *dst = &((struct cma_hdr *) hdr)->dst_addr; 685e51060f0SSean Hefty break; 686e51060f0SSean Hefty } 687e51060f0SSean Hefty 688e51060f0SSean Hefty if (*ip_ver != 4 && *ip_ver != 6) 689e51060f0SSean Hefty return -EINVAL; 690e51060f0SSean Hefty return 0; 691e51060f0SSean Hefty } 692e51060f0SSean Hefty 693e51060f0SSean Hefty static void cma_save_net_info(struct rdma_addr *addr, 694e51060f0SSean Hefty struct rdma_addr *listen_addr, 6951b90c137SAl Viro u8 ip_ver, __be16 port, 696e51060f0SSean Hefty union cma_ip_addr *src, union cma_ip_addr *dst) 697e51060f0SSean Hefty { 698e51060f0SSean Hefty struct sockaddr_in *listen4, *ip4; 699e51060f0SSean Hefty struct sockaddr_in6 *listen6, *ip6; 700e51060f0SSean Hefty 701e51060f0SSean Hefty switch (ip_ver) { 702e51060f0SSean Hefty case 4: 703e51060f0SSean Hefty listen4 = (struct sockaddr_in *) &listen_addr->src_addr; 704e51060f0SSean Hefty ip4 = (struct sockaddr_in *) &addr->src_addr; 705e51060f0SSean Hefty ip4->sin_family = listen4->sin_family; 706e51060f0SSean Hefty ip4->sin_addr.s_addr = dst->ip4.addr; 707e51060f0SSean Hefty ip4->sin_port = listen4->sin_port; 708e51060f0SSean Hefty 709e51060f0SSean Hefty ip4 = (struct sockaddr_in *) &addr->dst_addr; 710e51060f0SSean Hefty ip4->sin_family = listen4->sin_family; 711e51060f0SSean Hefty ip4->sin_addr.s_addr = src->ip4.addr; 712e51060f0SSean Hefty ip4->sin_port = port; 713e51060f0SSean Hefty break; 714e51060f0SSean Hefty case 6: 715e51060f0SSean Hefty listen6 = (struct sockaddr_in6 *) &listen_addr->src_addr; 716e51060f0SSean Hefty ip6 = (struct sockaddr_in6 *) &addr->src_addr; 717e51060f0SSean Hefty ip6->sin6_family = listen6->sin6_family; 718e51060f0SSean Hefty ip6->sin6_addr = dst->ip6; 719e51060f0SSean Hefty ip6->sin6_port = listen6->sin6_port; 720e51060f0SSean Hefty 721e51060f0SSean Hefty ip6 = (struct sockaddr_in6 *) &addr->dst_addr; 722e51060f0SSean Hefty ip6->sin6_family = listen6->sin6_family; 723e51060f0SSean Hefty ip6->sin6_addr = src->ip6; 724e51060f0SSean Hefty ip6->sin6_port = port; 725e51060f0SSean Hefty break; 726e51060f0SSean Hefty default: 727e51060f0SSean Hefty break; 728e51060f0SSean Hefty } 729e51060f0SSean Hefty } 730e51060f0SSean Hefty 731e51060f0SSean Hefty static inline int cma_user_data_offset(enum rdma_port_space ps) 732e51060f0SSean Hefty { 733e51060f0SSean Hefty switch (ps) { 734e51060f0SSean Hefty case RDMA_PS_SDP: 735e51060f0SSean Hefty return 0; 736e51060f0SSean Hefty default: 737e51060f0SSean Hefty return sizeof(struct cma_hdr); 738e51060f0SSean Hefty } 739e51060f0SSean Hefty } 740e51060f0SSean Hefty 741e51060f0SSean Hefty static void cma_cancel_route(struct rdma_id_private *id_priv) 742e51060f0SSean Hefty { 74307ebafbaSTom Tucker switch (rdma_node_get_transport(id_priv->id.device->node_type)) { 74407ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 745e51060f0SSean Hefty if (id_priv->query) 746e51060f0SSean Hefty ib_sa_cancel_query(id_priv->query_id, id_priv->query); 747e51060f0SSean Hefty break; 748e51060f0SSean Hefty default: 749e51060f0SSean Hefty break; 750e51060f0SSean Hefty } 751e51060f0SSean Hefty } 752e51060f0SSean Hefty 753e51060f0SSean Hefty static void cma_cancel_listens(struct rdma_id_private *id_priv) 754e51060f0SSean Hefty { 755e51060f0SSean Hefty struct rdma_id_private *dev_id_priv; 756e51060f0SSean Hefty 757d02d1f53SSean Hefty /* 758d02d1f53SSean Hefty * Remove from listen_any_list to prevent added devices from spawning 759d02d1f53SSean Hefty * additional listen requests. 760d02d1f53SSean Hefty */ 761e51060f0SSean Hefty mutex_lock(&lock); 762e51060f0SSean Hefty list_del(&id_priv->list); 763e51060f0SSean Hefty 764e51060f0SSean Hefty while (!list_empty(&id_priv->listen_list)) { 765e51060f0SSean Hefty dev_id_priv = list_entry(id_priv->listen_list.next, 766e51060f0SSean Hefty struct rdma_id_private, listen_list); 767d02d1f53SSean Hefty /* sync with device removal to avoid duplicate destruction */ 768d02d1f53SSean Hefty list_del_init(&dev_id_priv->list); 769d02d1f53SSean Hefty list_del(&dev_id_priv->listen_list); 770d02d1f53SSean Hefty mutex_unlock(&lock); 771d02d1f53SSean Hefty 772d02d1f53SSean Hefty rdma_destroy_id(&dev_id_priv->id); 773d02d1f53SSean Hefty mutex_lock(&lock); 774e51060f0SSean Hefty } 775e51060f0SSean Hefty mutex_unlock(&lock); 776e51060f0SSean Hefty } 777e51060f0SSean Hefty 778e51060f0SSean Hefty static void cma_cancel_operation(struct rdma_id_private *id_priv, 779e51060f0SSean Hefty enum cma_state state) 780e51060f0SSean Hefty { 781e51060f0SSean Hefty switch (state) { 782e51060f0SSean Hefty case CMA_ADDR_QUERY: 783e51060f0SSean Hefty rdma_addr_cancel(&id_priv->id.route.addr.dev_addr); 784e51060f0SSean Hefty break; 785e51060f0SSean Hefty case CMA_ROUTE_QUERY: 786e51060f0SSean Hefty cma_cancel_route(id_priv); 787e51060f0SSean Hefty break; 788e51060f0SSean Hefty case CMA_LISTEN: 789e51060f0SSean Hefty if (cma_any_addr(&id_priv->id.route.addr.src_addr) && 790e51060f0SSean Hefty !id_priv->cma_dev) 791e51060f0SSean Hefty cma_cancel_listens(id_priv); 792e51060f0SSean Hefty break; 793e51060f0SSean Hefty default: 794e51060f0SSean Hefty break; 795e51060f0SSean Hefty } 796e51060f0SSean Hefty } 797e51060f0SSean Hefty 798e51060f0SSean Hefty static void cma_release_port(struct rdma_id_private *id_priv) 799e51060f0SSean Hefty { 800e51060f0SSean Hefty struct rdma_bind_list *bind_list = id_priv->bind_list; 801e51060f0SSean Hefty 802e51060f0SSean Hefty if (!bind_list) 803e51060f0SSean Hefty return; 804e51060f0SSean Hefty 805e51060f0SSean Hefty mutex_lock(&lock); 806e51060f0SSean Hefty hlist_del(&id_priv->node); 807e51060f0SSean Hefty if (hlist_empty(&bind_list->owners)) { 808e51060f0SSean Hefty idr_remove(bind_list->ps, bind_list->port); 809e51060f0SSean Hefty kfree(bind_list); 810e51060f0SSean Hefty } 811e51060f0SSean Hefty mutex_unlock(&lock); 812e51060f0SSean Hefty } 813e51060f0SSean Hefty 814c8f6a362SSean Hefty static void cma_leave_mc_groups(struct rdma_id_private *id_priv) 815c8f6a362SSean Hefty { 816c8f6a362SSean Hefty struct cma_multicast *mc; 817c8f6a362SSean Hefty 818c8f6a362SSean Hefty while (!list_empty(&id_priv->mc_list)) { 819c8f6a362SSean Hefty mc = container_of(id_priv->mc_list.next, 820c8f6a362SSean Hefty struct cma_multicast, list); 821c8f6a362SSean Hefty list_del(&mc->list); 822c8f6a362SSean Hefty ib_sa_free_multicast(mc->multicast.ib); 823c8f6a362SSean Hefty kfree(mc); 824c8f6a362SSean Hefty } 825c8f6a362SSean Hefty } 826c8f6a362SSean Hefty 827e51060f0SSean Hefty void rdma_destroy_id(struct rdma_cm_id *id) 828e51060f0SSean Hefty { 829e51060f0SSean Hefty struct rdma_id_private *id_priv; 830e51060f0SSean Hefty enum cma_state state; 831e51060f0SSean Hefty 832e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 833e51060f0SSean Hefty state = cma_exch(id_priv, CMA_DESTROYING); 834e51060f0SSean Hefty cma_cancel_operation(id_priv, state); 835e51060f0SSean Hefty 83661a73c70SSean Hefty mutex_lock(&lock); 837e51060f0SSean Hefty if (id_priv->cma_dev) { 83861a73c70SSean Hefty mutex_unlock(&lock); 83907ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 84007ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 841e51060f0SSean Hefty if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib)) 842e51060f0SSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 843e51060f0SSean Hefty break; 84407ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 84507ebafbaSTom Tucker if (id_priv->cm_id.iw && !IS_ERR(id_priv->cm_id.iw)) 84607ebafbaSTom Tucker iw_destroy_cm_id(id_priv->cm_id.iw); 84707ebafbaSTom Tucker break; 848e51060f0SSean Hefty default: 849e51060f0SSean Hefty break; 850e51060f0SSean Hefty } 851c8f6a362SSean Hefty cma_leave_mc_groups(id_priv); 852e51060f0SSean Hefty mutex_lock(&lock); 853e51060f0SSean Hefty cma_detach_from_dev(id_priv); 854e51060f0SSean Hefty } 85561a73c70SSean Hefty mutex_unlock(&lock); 856e51060f0SSean Hefty 857e51060f0SSean Hefty cma_release_port(id_priv); 858e51060f0SSean Hefty cma_deref_id(id_priv); 859e51060f0SSean Hefty wait_for_completion(&id_priv->comp); 860e51060f0SSean Hefty 861d02d1f53SSean Hefty if (id_priv->internal_id) 862d02d1f53SSean Hefty cma_deref_id(id_priv->id.context); 863d02d1f53SSean Hefty 864e51060f0SSean Hefty kfree(id_priv->id.route.path_rec); 865e51060f0SSean Hefty kfree(id_priv); 866e51060f0SSean Hefty } 867e51060f0SSean Hefty EXPORT_SYMBOL(rdma_destroy_id); 868e51060f0SSean Hefty 869e51060f0SSean Hefty static int cma_rep_recv(struct rdma_id_private *id_priv) 870e51060f0SSean Hefty { 871e51060f0SSean Hefty int ret; 872e51060f0SSean Hefty 8735851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, NULL); 874e51060f0SSean Hefty if (ret) 875e51060f0SSean Hefty goto reject; 876e51060f0SSean Hefty 8775851bb89SSean Hefty ret = cma_modify_qp_rts(id_priv, NULL); 878e51060f0SSean Hefty if (ret) 879e51060f0SSean Hefty goto reject; 880e51060f0SSean Hefty 881e51060f0SSean Hefty ret = ib_send_cm_rtu(id_priv->cm_id.ib, NULL, 0); 882e51060f0SSean Hefty if (ret) 883e51060f0SSean Hefty goto reject; 884e51060f0SSean Hefty 885e51060f0SSean Hefty return 0; 886e51060f0SSean Hefty reject: 887c5483388SSean Hefty cma_modify_qp_err(id_priv); 888e51060f0SSean Hefty ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED, 889e51060f0SSean Hefty NULL, 0, NULL, 0); 890e51060f0SSean Hefty return ret; 891e51060f0SSean Hefty } 892e51060f0SSean Hefty 893e51060f0SSean Hefty static int cma_verify_rep(struct rdma_id_private *id_priv, void *data) 894e51060f0SSean Hefty { 895e51060f0SSean Hefty if (id_priv->id.ps == RDMA_PS_SDP && 896e51060f0SSean Hefty sdp_get_majv(((struct sdp_hah *) data)->sdp_version) != 897e51060f0SSean Hefty SDP_MAJ_VERSION) 898e51060f0SSean Hefty return -EINVAL; 899e51060f0SSean Hefty 900e51060f0SSean Hefty return 0; 901e51060f0SSean Hefty } 902e51060f0SSean Hefty 903a1b1b61fSSean Hefty static void cma_set_rep_event_data(struct rdma_cm_event *event, 904a1b1b61fSSean Hefty struct ib_cm_rep_event_param *rep_data, 905a1b1b61fSSean Hefty void *private_data) 906a1b1b61fSSean Hefty { 907a1b1b61fSSean Hefty event->param.conn.private_data = private_data; 908a1b1b61fSSean Hefty event->param.conn.private_data_len = IB_CM_REP_PRIVATE_DATA_SIZE; 909a1b1b61fSSean Hefty event->param.conn.responder_resources = rep_data->responder_resources; 910a1b1b61fSSean Hefty event->param.conn.initiator_depth = rep_data->initiator_depth; 911a1b1b61fSSean Hefty event->param.conn.flow_control = rep_data->flow_control; 912a1b1b61fSSean Hefty event->param.conn.rnr_retry_count = rep_data->rnr_retry_count; 913a1b1b61fSSean Hefty event->param.conn.srq = rep_data->srq; 914a1b1b61fSSean Hefty event->param.conn.qp_num = rep_data->remote_qpn; 915a1b1b61fSSean Hefty } 916a1b1b61fSSean Hefty 917e51060f0SSean Hefty static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) 918e51060f0SSean Hefty { 919e51060f0SSean Hefty struct rdma_id_private *id_priv = cm_id->context; 920a1b1b61fSSean Hefty struct rdma_cm_event event; 921a1b1b61fSSean Hefty int ret = 0; 922e51060f0SSean Hefty 923*38ca83a5SAmir Vadai if ((ib_event->event != IB_CM_TIMEWAIT_EXIT && 924*38ca83a5SAmir Vadai cma_disable_callback(id_priv, CMA_CONNECT)) || 925*38ca83a5SAmir Vadai (ib_event->event == IB_CM_TIMEWAIT_EXIT && 926*38ca83a5SAmir Vadai cma_disable_callback(id_priv, CMA_DISCONNECT))) 9278aa08602SSean Hefty return 0; 928e51060f0SSean Hefty 929a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 930e51060f0SSean Hefty switch (ib_event->event) { 931e51060f0SSean Hefty case IB_CM_REQ_ERROR: 932e51060f0SSean Hefty case IB_CM_REP_ERROR: 933a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 934a1b1b61fSSean Hefty event.status = -ETIMEDOUT; 935e51060f0SSean Hefty break; 936e51060f0SSean Hefty case IB_CM_REP_RECEIVED: 937a1b1b61fSSean Hefty event.status = cma_verify_rep(id_priv, ib_event->private_data); 938a1b1b61fSSean Hefty if (event.status) 939a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_ERROR; 940e51060f0SSean Hefty else if (id_priv->id.qp && id_priv->id.ps != RDMA_PS_SDP) { 941a1b1b61fSSean Hefty event.status = cma_rep_recv(id_priv); 942a1b1b61fSSean Hefty event.event = event.status ? RDMA_CM_EVENT_CONNECT_ERROR : 943e51060f0SSean Hefty RDMA_CM_EVENT_ESTABLISHED; 944e51060f0SSean Hefty } else 945a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_RESPONSE; 946a1b1b61fSSean Hefty cma_set_rep_event_data(&event, &ib_event->param.rep_rcvd, 947a1b1b61fSSean Hefty ib_event->private_data); 948e51060f0SSean Hefty break; 949e51060f0SSean Hefty case IB_CM_RTU_RECEIVED: 9500fe313b0SSean Hefty case IB_CM_USER_ESTABLISHED: 9510fe313b0SSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 952e51060f0SSean Hefty break; 953e51060f0SSean Hefty case IB_CM_DREQ_ERROR: 954a1b1b61fSSean Hefty event.status = -ETIMEDOUT; /* fall through */ 955e51060f0SSean Hefty case IB_CM_DREQ_RECEIVED: 956e51060f0SSean Hefty case IB_CM_DREP_RECEIVED: 957e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_CONNECT, CMA_DISCONNECT)) 958e51060f0SSean Hefty goto out; 959a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DISCONNECTED; 960e51060f0SSean Hefty break; 961e51060f0SSean Hefty case IB_CM_TIMEWAIT_EXIT: 962*38ca83a5SAmir Vadai event.event = RDMA_CM_EVENT_TIMEWAIT_EXIT; 963*38ca83a5SAmir Vadai break; 964e51060f0SSean Hefty case IB_CM_MRA_RECEIVED: 965e51060f0SSean Hefty /* ignore event */ 966e51060f0SSean Hefty goto out; 967e51060f0SSean Hefty case IB_CM_REJ_RECEIVED: 968c5483388SSean Hefty cma_modify_qp_err(id_priv); 969a1b1b61fSSean Hefty event.status = ib_event->param.rej_rcvd.reason; 970a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_REJECTED; 971a1b1b61fSSean Hefty event.param.conn.private_data = ib_event->private_data; 972a1b1b61fSSean Hefty event.param.conn.private_data_len = IB_CM_REJ_PRIVATE_DATA_SIZE; 973e51060f0SSean Hefty break; 974e51060f0SSean Hefty default: 975468f2239SRoland Dreier printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d\n", 976e51060f0SSean Hefty ib_event->event); 977e51060f0SSean Hefty goto out; 978e51060f0SSean Hefty } 979e51060f0SSean Hefty 980a1b1b61fSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 981e51060f0SSean Hefty if (ret) { 982e51060f0SSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 983e51060f0SSean Hefty id_priv->cm_id.ib = NULL; 984e51060f0SSean Hefty cma_exch(id_priv, CMA_DESTROYING); 985de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 986e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 987e51060f0SSean Hefty return ret; 988e51060f0SSean Hefty } 989e51060f0SSean Hefty out: 990de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 991e51060f0SSean Hefty return ret; 992e51060f0SSean Hefty } 993e51060f0SSean Hefty 994628e5f6dSSean Hefty static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id, 995e51060f0SSean Hefty struct ib_cm_event *ib_event) 996e51060f0SSean Hefty { 997e51060f0SSean Hefty struct rdma_id_private *id_priv; 998e51060f0SSean Hefty struct rdma_cm_id *id; 999e51060f0SSean Hefty struct rdma_route *rt; 1000e51060f0SSean Hefty union cma_ip_addr *src, *dst; 10011b90c137SAl Viro __be16 port; 1002e51060f0SSean Hefty u8 ip_ver; 100364c5e613SOr Gerlitz int ret; 1004e51060f0SSean Hefty 1005e51060f0SSean Hefty if (cma_get_net_info(ib_event->private_data, listen_id->ps, 1006e51060f0SSean Hefty &ip_ver, &port, &src, &dst)) 1007e51060f0SSean Hefty goto err; 1008e51060f0SSean Hefty 10093f168d2bSKrishna Kumar id = rdma_create_id(listen_id->event_handler, listen_id->context, 10103f168d2bSKrishna Kumar listen_id->ps); 10113f168d2bSKrishna Kumar if (IS_ERR(id)) 10123f168d2bSKrishna Kumar goto err; 10133f168d2bSKrishna Kumar 1014e51060f0SSean Hefty cma_save_net_info(&id->route.addr, &listen_id->route.addr, 1015e51060f0SSean Hefty ip_ver, port, src, dst); 10163f168d2bSKrishna Kumar 10173f168d2bSKrishna Kumar rt = &id->route; 10183f168d2bSKrishna Kumar rt->num_paths = ib_event->param.req_rcvd.alternate_path ? 2 : 1; 10193f168d2bSKrishna Kumar rt->path_rec = kmalloc(sizeof *rt->path_rec * rt->num_paths, 10203f168d2bSKrishna Kumar GFP_KERNEL); 10213f168d2bSKrishna Kumar if (!rt->path_rec) 10223f168d2bSKrishna Kumar goto destroy_id; 10233f168d2bSKrishna Kumar 1024e51060f0SSean Hefty rt->path_rec[0] = *ib_event->param.req_rcvd.primary_path; 1025e51060f0SSean Hefty if (rt->num_paths == 2) 1026e51060f0SSean Hefty rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path; 1027e51060f0SSean Hefty 1028e51060f0SSean Hefty ib_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid); 102964c5e613SOr Gerlitz ret = rdma_translate_ip(&id->route.addr.src_addr, 103064c5e613SOr Gerlitz &id->route.addr.dev_addr); 103164c5e613SOr Gerlitz if (ret) 103264c5e613SOr Gerlitz goto destroy_id; 1033e51060f0SSean Hefty 1034e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1035e51060f0SSean Hefty id_priv->state = CMA_CONNECT; 1036e51060f0SSean Hefty return id_priv; 10373f168d2bSKrishna Kumar 10383f168d2bSKrishna Kumar destroy_id: 1039e51060f0SSean Hefty rdma_destroy_id(id); 10403f168d2bSKrishna Kumar err: 1041e51060f0SSean Hefty return NULL; 1042e51060f0SSean Hefty } 1043e51060f0SSean Hefty 1044628e5f6dSSean Hefty static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id, 1045628e5f6dSSean Hefty struct ib_cm_event *ib_event) 1046628e5f6dSSean Hefty { 1047628e5f6dSSean Hefty struct rdma_id_private *id_priv; 1048628e5f6dSSean Hefty struct rdma_cm_id *id; 1049628e5f6dSSean Hefty union cma_ip_addr *src, *dst; 10501b90c137SAl Viro __be16 port; 1051628e5f6dSSean Hefty u8 ip_ver; 1052628e5f6dSSean Hefty int ret; 1053628e5f6dSSean Hefty 1054628e5f6dSSean Hefty id = rdma_create_id(listen_id->event_handler, listen_id->context, 1055628e5f6dSSean Hefty listen_id->ps); 1056628e5f6dSSean Hefty if (IS_ERR(id)) 1057628e5f6dSSean Hefty return NULL; 1058628e5f6dSSean Hefty 1059628e5f6dSSean Hefty 1060628e5f6dSSean Hefty if (cma_get_net_info(ib_event->private_data, listen_id->ps, 1061628e5f6dSSean Hefty &ip_ver, &port, &src, &dst)) 1062628e5f6dSSean Hefty goto err; 1063628e5f6dSSean Hefty 1064628e5f6dSSean Hefty cma_save_net_info(&id->route.addr, &listen_id->route.addr, 1065628e5f6dSSean Hefty ip_ver, port, src, dst); 1066628e5f6dSSean Hefty 1067628e5f6dSSean Hefty ret = rdma_translate_ip(&id->route.addr.src_addr, 1068628e5f6dSSean Hefty &id->route.addr.dev_addr); 1069628e5f6dSSean Hefty if (ret) 1070628e5f6dSSean Hefty goto err; 1071628e5f6dSSean Hefty 1072628e5f6dSSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1073628e5f6dSSean Hefty id_priv->state = CMA_CONNECT; 1074628e5f6dSSean Hefty return id_priv; 1075628e5f6dSSean Hefty err: 1076628e5f6dSSean Hefty rdma_destroy_id(id); 1077628e5f6dSSean Hefty return NULL; 1078628e5f6dSSean Hefty } 1079628e5f6dSSean Hefty 1080a1b1b61fSSean Hefty static void cma_set_req_event_data(struct rdma_cm_event *event, 1081a1b1b61fSSean Hefty struct ib_cm_req_event_param *req_data, 1082a1b1b61fSSean Hefty void *private_data, int offset) 1083a1b1b61fSSean Hefty { 1084a1b1b61fSSean Hefty event->param.conn.private_data = private_data + offset; 1085a1b1b61fSSean Hefty event->param.conn.private_data_len = IB_CM_REQ_PRIVATE_DATA_SIZE - offset; 1086a1b1b61fSSean Hefty event->param.conn.responder_resources = req_data->responder_resources; 1087a1b1b61fSSean Hefty event->param.conn.initiator_depth = req_data->initiator_depth; 1088a1b1b61fSSean Hefty event->param.conn.flow_control = req_data->flow_control; 1089a1b1b61fSSean Hefty event->param.conn.retry_count = req_data->retry_count; 1090a1b1b61fSSean Hefty event->param.conn.rnr_retry_count = req_data->rnr_retry_count; 1091a1b1b61fSSean Hefty event->param.conn.srq = req_data->srq; 1092a1b1b61fSSean Hefty event->param.conn.qp_num = req_data->remote_qpn; 1093a1b1b61fSSean Hefty } 1094a1b1b61fSSean Hefty 1095e51060f0SSean Hefty static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) 1096e51060f0SSean Hefty { 1097e51060f0SSean Hefty struct rdma_id_private *listen_id, *conn_id; 1098a1b1b61fSSean Hefty struct rdma_cm_event event; 1099e51060f0SSean Hefty int offset, ret; 1100e51060f0SSean Hefty 1101e51060f0SSean Hefty listen_id = cm_id->context; 1102de910bd9SOr Gerlitz if (cma_disable_callback(listen_id, CMA_LISTEN)) 11038aa08602SSean Hefty return -ECONNABORTED; 1104e51060f0SSean Hefty 1105628e5f6dSSean Hefty memset(&event, 0, sizeof event); 1106628e5f6dSSean Hefty offset = cma_user_data_offset(listen_id->id.ps); 1107628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_REQUEST; 1108c8f6a362SSean Hefty if (cma_is_ud_ps(listen_id->id.ps)) { 1109628e5f6dSSean Hefty conn_id = cma_new_udp_id(&listen_id->id, ib_event); 1110628e5f6dSSean Hefty event.param.ud.private_data = ib_event->private_data + offset; 1111628e5f6dSSean Hefty event.param.ud.private_data_len = 1112628e5f6dSSean Hefty IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE - offset; 1113628e5f6dSSean Hefty } else { 1114628e5f6dSSean Hefty conn_id = cma_new_conn_id(&listen_id->id, ib_event); 1115628e5f6dSSean Hefty cma_set_req_event_data(&event, &ib_event->param.req_rcvd, 1116628e5f6dSSean Hefty ib_event->private_data, offset); 1117628e5f6dSSean Hefty } 1118e51060f0SSean Hefty if (!conn_id) { 1119e51060f0SSean Hefty ret = -ENOMEM; 1120e51060f0SSean Hefty goto out; 1121e51060f0SSean Hefty } 1122e51060f0SSean Hefty 1123de910bd9SOr Gerlitz mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING); 112461a73c70SSean Hefty mutex_lock(&lock); 112507ebafbaSTom Tucker ret = cma_acquire_dev(conn_id); 112661a73c70SSean Hefty mutex_unlock(&lock); 1127a1a733f6SKrishna Kumar if (ret) 1128a1a733f6SKrishna Kumar goto release_conn_id; 1129e51060f0SSean Hefty 1130e51060f0SSean Hefty conn_id->cm_id.ib = cm_id; 1131e51060f0SSean Hefty cm_id->context = conn_id; 1132e51060f0SSean Hefty cm_id->cm_handler = cma_ib_handler; 1133e51060f0SSean Hefty 1134a1b1b61fSSean Hefty ret = conn_id->id.event_handler(&conn_id->id, &event); 113545d9478dSVladimir Sokolovsky if (!ret) { 1136ead595aeSSean Hefty /* 1137ead595aeSSean Hefty * Acquire mutex to prevent user executing rdma_destroy_id() 1138ead595aeSSean Hefty * while we're accessing the cm_id. 1139ead595aeSSean Hefty */ 1140ead595aeSSean Hefty mutex_lock(&lock); 1141ead595aeSSean Hefty if (cma_comp(conn_id, CMA_CONNECT) && 1142ead595aeSSean Hefty !cma_is_ud_ps(conn_id->id.ps)) 1143ead595aeSSean Hefty ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0); 1144ead595aeSSean Hefty mutex_unlock(&lock); 1145de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 1146a1a733f6SKrishna Kumar goto out; 114745d9478dSVladimir Sokolovsky } 1148a1a733f6SKrishna Kumar 1149e51060f0SSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 1150e51060f0SSean Hefty conn_id->cm_id.ib = NULL; 1151a1a733f6SKrishna Kumar 1152a1a733f6SKrishna Kumar release_conn_id: 1153e51060f0SSean Hefty cma_exch(conn_id, CMA_DESTROYING); 1154de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 1155e51060f0SSean Hefty rdma_destroy_id(&conn_id->id); 1156a1a733f6SKrishna Kumar 1157e51060f0SSean Hefty out: 1158de910bd9SOr Gerlitz mutex_unlock(&listen_id->handler_mutex); 1159e51060f0SSean Hefty return ret; 1160e51060f0SSean Hefty } 1161e51060f0SSean Hefty 1162e51060f0SSean Hefty static __be64 cma_get_service_id(enum rdma_port_space ps, struct sockaddr *addr) 1163e51060f0SSean Hefty { 1164628e5f6dSSean Hefty return cpu_to_be64(((u64)ps << 16) + be16_to_cpu(cma_port(addr))); 1165e51060f0SSean Hefty } 1166e51060f0SSean Hefty 1167e51060f0SSean Hefty static void cma_set_compare_data(enum rdma_port_space ps, struct sockaddr *addr, 1168e51060f0SSean Hefty struct ib_cm_compare_data *compare) 1169e51060f0SSean Hefty { 1170e51060f0SSean Hefty struct cma_hdr *cma_data, *cma_mask; 1171e51060f0SSean Hefty struct sdp_hh *sdp_data, *sdp_mask; 11721b90c137SAl Viro __be32 ip4_addr; 1173e51060f0SSean Hefty struct in6_addr ip6_addr; 1174e51060f0SSean Hefty 1175e51060f0SSean Hefty memset(compare, 0, sizeof *compare); 1176e51060f0SSean Hefty cma_data = (void *) compare->data; 1177e51060f0SSean Hefty cma_mask = (void *) compare->mask; 1178e51060f0SSean Hefty sdp_data = (void *) compare->data; 1179e51060f0SSean Hefty sdp_mask = (void *) compare->mask; 1180e51060f0SSean Hefty 1181e51060f0SSean Hefty switch (addr->sa_family) { 1182e51060f0SSean Hefty case AF_INET: 1183e51060f0SSean Hefty ip4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; 1184e51060f0SSean Hefty if (ps == RDMA_PS_SDP) { 1185e51060f0SSean Hefty sdp_set_ip_ver(sdp_data, 4); 1186e51060f0SSean Hefty sdp_set_ip_ver(sdp_mask, 0xF); 1187e51060f0SSean Hefty sdp_data->dst_addr.ip4.addr = ip4_addr; 11881b90c137SAl Viro sdp_mask->dst_addr.ip4.addr = htonl(~0); 1189e51060f0SSean Hefty } else { 1190e51060f0SSean Hefty cma_set_ip_ver(cma_data, 4); 1191e51060f0SSean Hefty cma_set_ip_ver(cma_mask, 0xF); 1192e51060f0SSean Hefty cma_data->dst_addr.ip4.addr = ip4_addr; 11931b90c137SAl Viro cma_mask->dst_addr.ip4.addr = htonl(~0); 1194e51060f0SSean Hefty } 1195e51060f0SSean Hefty break; 1196e51060f0SSean Hefty case AF_INET6: 1197e51060f0SSean Hefty ip6_addr = ((struct sockaddr_in6 *) addr)->sin6_addr; 1198e51060f0SSean Hefty if (ps == RDMA_PS_SDP) { 1199e51060f0SSean Hefty sdp_set_ip_ver(sdp_data, 6); 1200e51060f0SSean Hefty sdp_set_ip_ver(sdp_mask, 0xF); 1201e51060f0SSean Hefty sdp_data->dst_addr.ip6 = ip6_addr; 1202e51060f0SSean Hefty memset(&sdp_mask->dst_addr.ip6, 0xFF, 1203e51060f0SSean Hefty sizeof sdp_mask->dst_addr.ip6); 1204e51060f0SSean Hefty } else { 1205e51060f0SSean Hefty cma_set_ip_ver(cma_data, 6); 1206e51060f0SSean Hefty cma_set_ip_ver(cma_mask, 0xF); 1207e51060f0SSean Hefty cma_data->dst_addr.ip6 = ip6_addr; 1208e51060f0SSean Hefty memset(&cma_mask->dst_addr.ip6, 0xFF, 1209e51060f0SSean Hefty sizeof cma_mask->dst_addr.ip6); 1210e51060f0SSean Hefty } 1211e51060f0SSean Hefty break; 1212e51060f0SSean Hefty default: 1213e51060f0SSean Hefty break; 1214e51060f0SSean Hefty } 1215e51060f0SSean Hefty } 1216e51060f0SSean Hefty 121707ebafbaSTom Tucker static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event) 121807ebafbaSTom Tucker { 121907ebafbaSTom Tucker struct rdma_id_private *id_priv = iw_id->context; 1220a1b1b61fSSean Hefty struct rdma_cm_event event; 122107ebafbaSTom Tucker struct sockaddr_in *sin; 122207ebafbaSTom Tucker int ret = 0; 122307ebafbaSTom Tucker 1224de910bd9SOr Gerlitz if (cma_disable_callback(id_priv, CMA_CONNECT)) 1225be65f086SSean Hefty return 0; 122607ebafbaSTom Tucker 1227be65f086SSean Hefty memset(&event, 0, sizeof event); 122807ebafbaSTom Tucker switch (iw_event->event) { 122907ebafbaSTom Tucker case IW_CM_EVENT_CLOSE: 1230a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DISCONNECTED; 123107ebafbaSTom Tucker break; 123207ebafbaSTom Tucker case IW_CM_EVENT_CONNECT_REPLY: 123307ebafbaSTom Tucker sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; 123407ebafbaSTom Tucker *sin = iw_event->local_addr; 123507ebafbaSTom Tucker sin = (struct sockaddr_in *) &id_priv->id.route.addr.dst_addr; 123607ebafbaSTom Tucker *sin = iw_event->remote_addr; 1237881a045fSSteve Wise switch (iw_event->status) { 1238881a045fSSteve Wise case 0: 1239a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 124007ebafbaSTom Tucker break; 1241881a045fSSteve Wise case -ECONNRESET: 1242881a045fSSteve Wise case -ECONNREFUSED: 1243881a045fSSteve Wise event.event = RDMA_CM_EVENT_REJECTED; 1244881a045fSSteve Wise break; 1245881a045fSSteve Wise case -ETIMEDOUT: 1246881a045fSSteve Wise event.event = RDMA_CM_EVENT_UNREACHABLE; 1247881a045fSSteve Wise break; 1248881a045fSSteve Wise default: 1249881a045fSSteve Wise event.event = RDMA_CM_EVENT_CONNECT_ERROR; 1250881a045fSSteve Wise break; 1251881a045fSSteve Wise } 1252881a045fSSteve Wise break; 125307ebafbaSTom Tucker case IW_CM_EVENT_ESTABLISHED: 1254a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 125507ebafbaSTom Tucker break; 125607ebafbaSTom Tucker default: 125707ebafbaSTom Tucker BUG_ON(1); 125807ebafbaSTom Tucker } 125907ebafbaSTom Tucker 1260a1b1b61fSSean Hefty event.status = iw_event->status; 1261a1b1b61fSSean Hefty event.param.conn.private_data = iw_event->private_data; 1262a1b1b61fSSean Hefty event.param.conn.private_data_len = iw_event->private_data_len; 1263a1b1b61fSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 126407ebafbaSTom Tucker if (ret) { 126507ebafbaSTom Tucker /* Destroy the CM ID by returning a non-zero value. */ 126607ebafbaSTom Tucker id_priv->cm_id.iw = NULL; 126707ebafbaSTom Tucker cma_exch(id_priv, CMA_DESTROYING); 1268de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 126907ebafbaSTom Tucker rdma_destroy_id(&id_priv->id); 127007ebafbaSTom Tucker return ret; 127107ebafbaSTom Tucker } 127207ebafbaSTom Tucker 1273de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 127407ebafbaSTom Tucker return ret; 127507ebafbaSTom Tucker } 127607ebafbaSTom Tucker 127707ebafbaSTom Tucker static int iw_conn_req_handler(struct iw_cm_id *cm_id, 127807ebafbaSTom Tucker struct iw_cm_event *iw_event) 127907ebafbaSTom Tucker { 128007ebafbaSTom Tucker struct rdma_cm_id *new_cm_id; 128107ebafbaSTom Tucker struct rdma_id_private *listen_id, *conn_id; 128207ebafbaSTom Tucker struct sockaddr_in *sin; 128307ebafbaSTom Tucker struct net_device *dev = NULL; 1284a1b1b61fSSean Hefty struct rdma_cm_event event; 128507ebafbaSTom Tucker int ret; 12868d8293cfSSteve Wise struct ib_device_attr attr; 128707ebafbaSTom Tucker 128807ebafbaSTom Tucker listen_id = cm_id->context; 1289de910bd9SOr Gerlitz if (cma_disable_callback(listen_id, CMA_LISTEN)) 12908aa08602SSean Hefty return -ECONNABORTED; 129107ebafbaSTom Tucker 129207ebafbaSTom Tucker /* Create a new RDMA id for the new IW CM ID */ 129307ebafbaSTom Tucker new_cm_id = rdma_create_id(listen_id->id.event_handler, 129407ebafbaSTom Tucker listen_id->id.context, 129507ebafbaSTom Tucker RDMA_PS_TCP); 129610f32065SJulia Lawall if (IS_ERR(new_cm_id)) { 129707ebafbaSTom Tucker ret = -ENOMEM; 129807ebafbaSTom Tucker goto out; 129907ebafbaSTom Tucker } 130007ebafbaSTom Tucker conn_id = container_of(new_cm_id, struct rdma_id_private, id); 1301de910bd9SOr Gerlitz mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING); 130207ebafbaSTom Tucker conn_id->state = CMA_CONNECT; 130307ebafbaSTom Tucker 13041ab35276SDenis V. Lunev dev = ip_dev_find(&init_net, iw_event->local_addr.sin_addr.s_addr); 130507ebafbaSTom Tucker if (!dev) { 130607ebafbaSTom Tucker ret = -EADDRNOTAVAIL; 1307de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 130807ebafbaSTom Tucker rdma_destroy_id(new_cm_id); 130907ebafbaSTom Tucker goto out; 131007ebafbaSTom Tucker } 131107ebafbaSTom Tucker ret = rdma_copy_addr(&conn_id->id.route.addr.dev_addr, dev, NULL); 131207ebafbaSTom Tucker if (ret) { 1313de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 131407ebafbaSTom Tucker rdma_destroy_id(new_cm_id); 131507ebafbaSTom Tucker goto out; 131607ebafbaSTom Tucker } 131707ebafbaSTom Tucker 131861a73c70SSean Hefty mutex_lock(&lock); 131907ebafbaSTom Tucker ret = cma_acquire_dev(conn_id); 132061a73c70SSean Hefty mutex_unlock(&lock); 132107ebafbaSTom Tucker if (ret) { 1322de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 132307ebafbaSTom Tucker rdma_destroy_id(new_cm_id); 132407ebafbaSTom Tucker goto out; 132507ebafbaSTom Tucker } 132607ebafbaSTom Tucker 132707ebafbaSTom Tucker conn_id->cm_id.iw = cm_id; 132807ebafbaSTom Tucker cm_id->context = conn_id; 132907ebafbaSTom Tucker cm_id->cm_handler = cma_iw_handler; 133007ebafbaSTom Tucker 133107ebafbaSTom Tucker sin = (struct sockaddr_in *) &new_cm_id->route.addr.src_addr; 133207ebafbaSTom Tucker *sin = iw_event->local_addr; 133307ebafbaSTom Tucker sin = (struct sockaddr_in *) &new_cm_id->route.addr.dst_addr; 133407ebafbaSTom Tucker *sin = iw_event->remote_addr; 133507ebafbaSTom Tucker 13368d8293cfSSteve Wise ret = ib_query_device(conn_id->id.device, &attr); 13378d8293cfSSteve Wise if (ret) { 1338de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 13398d8293cfSSteve Wise rdma_destroy_id(new_cm_id); 13408d8293cfSSteve Wise goto out; 13418d8293cfSSteve Wise } 13428d8293cfSSteve Wise 1343a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 1344a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_REQUEST; 1345a1b1b61fSSean Hefty event.param.conn.private_data = iw_event->private_data; 1346a1b1b61fSSean Hefty event.param.conn.private_data_len = iw_event->private_data_len; 13478d8293cfSSteve Wise event.param.conn.initiator_depth = attr.max_qp_init_rd_atom; 13488d8293cfSSteve Wise event.param.conn.responder_resources = attr.max_qp_rd_atom; 1349a1b1b61fSSean Hefty ret = conn_id->id.event_handler(&conn_id->id, &event); 135007ebafbaSTom Tucker if (ret) { 135107ebafbaSTom Tucker /* User wants to destroy the CM ID */ 135207ebafbaSTom Tucker conn_id->cm_id.iw = NULL; 135307ebafbaSTom Tucker cma_exch(conn_id, CMA_DESTROYING); 1354de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 135507ebafbaSTom Tucker rdma_destroy_id(&conn_id->id); 1356de910bd9SOr Gerlitz goto out; 135707ebafbaSTom Tucker } 135807ebafbaSTom Tucker 1359de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 1360de910bd9SOr Gerlitz 136107ebafbaSTom Tucker out: 136207ebafbaSTom Tucker if (dev) 136307ebafbaSTom Tucker dev_put(dev); 1364de910bd9SOr Gerlitz mutex_unlock(&listen_id->handler_mutex); 136507ebafbaSTom Tucker return ret; 136607ebafbaSTom Tucker } 136707ebafbaSTom Tucker 1368e51060f0SSean Hefty static int cma_ib_listen(struct rdma_id_private *id_priv) 1369e51060f0SSean Hefty { 1370e51060f0SSean Hefty struct ib_cm_compare_data compare_data; 1371e51060f0SSean Hefty struct sockaddr *addr; 1372e51060f0SSean Hefty __be64 svc_id; 1373e51060f0SSean Hefty int ret; 1374e51060f0SSean Hefty 1375e51060f0SSean Hefty id_priv->cm_id.ib = ib_create_cm_id(id_priv->id.device, cma_req_handler, 1376e51060f0SSean Hefty id_priv); 1377e51060f0SSean Hefty if (IS_ERR(id_priv->cm_id.ib)) 1378e51060f0SSean Hefty return PTR_ERR(id_priv->cm_id.ib); 1379e51060f0SSean Hefty 1380e51060f0SSean Hefty addr = &id_priv->id.route.addr.src_addr; 1381e51060f0SSean Hefty svc_id = cma_get_service_id(id_priv->id.ps, addr); 1382e51060f0SSean Hefty if (cma_any_addr(addr)) 1383e51060f0SSean Hefty ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, NULL); 1384e51060f0SSean Hefty else { 1385e51060f0SSean Hefty cma_set_compare_data(id_priv->id.ps, addr, &compare_data); 1386e51060f0SSean Hefty ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, &compare_data); 1387e51060f0SSean Hefty } 1388e51060f0SSean Hefty 1389e51060f0SSean Hefty if (ret) { 1390e51060f0SSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 1391e51060f0SSean Hefty id_priv->cm_id.ib = NULL; 1392e51060f0SSean Hefty } 1393e51060f0SSean Hefty 1394e51060f0SSean Hefty return ret; 1395e51060f0SSean Hefty } 1396e51060f0SSean Hefty 139707ebafbaSTom Tucker static int cma_iw_listen(struct rdma_id_private *id_priv, int backlog) 139807ebafbaSTom Tucker { 139907ebafbaSTom Tucker int ret; 140007ebafbaSTom Tucker struct sockaddr_in *sin; 140107ebafbaSTom Tucker 140207ebafbaSTom Tucker id_priv->cm_id.iw = iw_create_cm_id(id_priv->id.device, 140307ebafbaSTom Tucker iw_conn_req_handler, 140407ebafbaSTom Tucker id_priv); 140507ebafbaSTom Tucker if (IS_ERR(id_priv->cm_id.iw)) 140607ebafbaSTom Tucker return PTR_ERR(id_priv->cm_id.iw); 140707ebafbaSTom Tucker 140807ebafbaSTom Tucker sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; 140907ebafbaSTom Tucker id_priv->cm_id.iw->local_addr = *sin; 141007ebafbaSTom Tucker 141107ebafbaSTom Tucker ret = iw_cm_listen(id_priv->cm_id.iw, backlog); 141207ebafbaSTom Tucker 141307ebafbaSTom Tucker if (ret) { 141407ebafbaSTom Tucker iw_destroy_cm_id(id_priv->cm_id.iw); 141507ebafbaSTom Tucker id_priv->cm_id.iw = NULL; 141607ebafbaSTom Tucker } 141707ebafbaSTom Tucker 141807ebafbaSTom Tucker return ret; 141907ebafbaSTom Tucker } 142007ebafbaSTom Tucker 1421e51060f0SSean Hefty static int cma_listen_handler(struct rdma_cm_id *id, 1422e51060f0SSean Hefty struct rdma_cm_event *event) 1423e51060f0SSean Hefty { 1424e51060f0SSean Hefty struct rdma_id_private *id_priv = id->context; 1425e51060f0SSean Hefty 1426e51060f0SSean Hefty id->context = id_priv->id.context; 1427e51060f0SSean Hefty id->event_handler = id_priv->id.event_handler; 1428e51060f0SSean Hefty return id_priv->id.event_handler(id, event); 1429e51060f0SSean Hefty } 1430e51060f0SSean Hefty 1431e51060f0SSean Hefty static void cma_listen_on_dev(struct rdma_id_private *id_priv, 1432e51060f0SSean Hefty struct cma_device *cma_dev) 1433e51060f0SSean Hefty { 1434e51060f0SSean Hefty struct rdma_id_private *dev_id_priv; 1435e51060f0SSean Hefty struct rdma_cm_id *id; 1436e51060f0SSean Hefty int ret; 1437e51060f0SSean Hefty 1438e51060f0SSean Hefty id = rdma_create_id(cma_listen_handler, id_priv, id_priv->id.ps); 1439e51060f0SSean Hefty if (IS_ERR(id)) 1440e51060f0SSean Hefty return; 1441e51060f0SSean Hefty 1442e51060f0SSean Hefty dev_id_priv = container_of(id, struct rdma_id_private, id); 1443e51060f0SSean Hefty 1444e51060f0SSean Hefty dev_id_priv->state = CMA_ADDR_BOUND; 1445e51060f0SSean Hefty memcpy(&id->route.addr.src_addr, &id_priv->id.route.addr.src_addr, 1446e51060f0SSean Hefty ip_addr_size(&id_priv->id.route.addr.src_addr)); 1447e51060f0SSean Hefty 1448e51060f0SSean Hefty cma_attach_to_dev(dev_id_priv, cma_dev); 1449e51060f0SSean Hefty list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list); 1450d02d1f53SSean Hefty atomic_inc(&id_priv->refcount); 1451d02d1f53SSean Hefty dev_id_priv->internal_id = 1; 1452e51060f0SSean Hefty 1453e51060f0SSean Hefty ret = rdma_listen(id, id_priv->backlog); 1454e51060f0SSean Hefty if (ret) 1455d02d1f53SSean Hefty printk(KERN_WARNING "RDMA CMA: cma_listen_on_dev, error %d, " 1456468f2239SRoland Dreier "listening on device %s\n", ret, cma_dev->device->name); 1457e51060f0SSean Hefty } 1458e51060f0SSean Hefty 1459e51060f0SSean Hefty static void cma_listen_on_all(struct rdma_id_private *id_priv) 1460e51060f0SSean Hefty { 1461e51060f0SSean Hefty struct cma_device *cma_dev; 1462e51060f0SSean Hefty 1463e51060f0SSean Hefty mutex_lock(&lock); 1464e51060f0SSean Hefty list_add_tail(&id_priv->list, &listen_any_list); 1465e51060f0SSean Hefty list_for_each_entry(cma_dev, &dev_list, list) 1466e51060f0SSean Hefty cma_listen_on_dev(id_priv, cma_dev); 1467e51060f0SSean Hefty mutex_unlock(&lock); 1468e51060f0SSean Hefty } 1469e51060f0SSean Hefty 1470e51060f0SSean Hefty static int cma_bind_any(struct rdma_cm_id *id, sa_family_t af) 1471e51060f0SSean Hefty { 1472e51060f0SSean Hefty struct sockaddr_in addr_in; 1473e51060f0SSean Hefty 1474e51060f0SSean Hefty memset(&addr_in, 0, sizeof addr_in); 1475e51060f0SSean Hefty addr_in.sin_family = af; 1476e51060f0SSean Hefty return rdma_bind_addr(id, (struct sockaddr *) &addr_in); 1477e51060f0SSean Hefty } 1478e51060f0SSean Hefty 1479e51060f0SSean Hefty int rdma_listen(struct rdma_cm_id *id, int backlog) 1480e51060f0SSean Hefty { 1481e51060f0SSean Hefty struct rdma_id_private *id_priv; 1482e51060f0SSean Hefty int ret; 1483e51060f0SSean Hefty 1484e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1485e51060f0SSean Hefty if (id_priv->state == CMA_IDLE) { 1486e51060f0SSean Hefty ret = cma_bind_any(id, AF_INET); 1487e51060f0SSean Hefty if (ret) 1488e51060f0SSean Hefty return ret; 1489e51060f0SSean Hefty } 1490e51060f0SSean Hefty 1491e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_LISTEN)) 1492e51060f0SSean Hefty return -EINVAL; 1493e51060f0SSean Hefty 1494e51060f0SSean Hefty id_priv->backlog = backlog; 1495e51060f0SSean Hefty if (id->device) { 149607ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 149707ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 1498e51060f0SSean Hefty ret = cma_ib_listen(id_priv); 1499e51060f0SSean Hefty if (ret) 1500e51060f0SSean Hefty goto err; 1501e51060f0SSean Hefty break; 150207ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 150307ebafbaSTom Tucker ret = cma_iw_listen(id_priv, backlog); 150407ebafbaSTom Tucker if (ret) 150507ebafbaSTom Tucker goto err; 150607ebafbaSTom Tucker break; 1507e51060f0SSean Hefty default: 1508e51060f0SSean Hefty ret = -ENOSYS; 1509e51060f0SSean Hefty goto err; 1510e51060f0SSean Hefty } 1511e51060f0SSean Hefty } else 1512e51060f0SSean Hefty cma_listen_on_all(id_priv); 1513e51060f0SSean Hefty 1514e51060f0SSean Hefty return 0; 1515e51060f0SSean Hefty err: 1516e51060f0SSean Hefty id_priv->backlog = 0; 1517e51060f0SSean Hefty cma_comp_exch(id_priv, CMA_LISTEN, CMA_ADDR_BOUND); 1518e51060f0SSean Hefty return ret; 1519e51060f0SSean Hefty } 1520e51060f0SSean Hefty EXPORT_SYMBOL(rdma_listen); 1521e51060f0SSean Hefty 1522a81c994dSSean Hefty void rdma_set_service_type(struct rdma_cm_id *id, int tos) 1523a81c994dSSean Hefty { 1524a81c994dSSean Hefty struct rdma_id_private *id_priv; 1525a81c994dSSean Hefty 1526a81c994dSSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1527a81c994dSSean Hefty id_priv->tos = (u8) tos; 1528a81c994dSSean Hefty } 1529a81c994dSSean Hefty EXPORT_SYMBOL(rdma_set_service_type); 1530a81c994dSSean Hefty 1531e51060f0SSean Hefty static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec, 1532e51060f0SSean Hefty void *context) 1533e51060f0SSean Hefty { 1534e51060f0SSean Hefty struct cma_work *work = context; 1535e51060f0SSean Hefty struct rdma_route *route; 1536e51060f0SSean Hefty 1537e51060f0SSean Hefty route = &work->id->id.route; 1538e51060f0SSean Hefty 1539e51060f0SSean Hefty if (!status) { 1540e51060f0SSean Hefty route->num_paths = 1; 1541e51060f0SSean Hefty *route->path_rec = *path_rec; 1542e51060f0SSean Hefty } else { 1543e51060f0SSean Hefty work->old_state = CMA_ROUTE_QUERY; 1544e51060f0SSean Hefty work->new_state = CMA_ADDR_RESOLVED; 1545e51060f0SSean Hefty work->event.event = RDMA_CM_EVENT_ROUTE_ERROR; 15468f0472d3SSean Hefty work->event.status = status; 1547e51060f0SSean Hefty } 1548e51060f0SSean Hefty 1549e51060f0SSean Hefty queue_work(cma_wq, &work->work); 1550e51060f0SSean Hefty } 1551e51060f0SSean Hefty 1552e51060f0SSean Hefty static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms, 1553e51060f0SSean Hefty struct cma_work *work) 1554e51060f0SSean Hefty { 1555a81c994dSSean Hefty struct rdma_addr *addr = &id_priv->id.route.addr; 1556e51060f0SSean Hefty struct ib_sa_path_rec path_rec; 1557a81c994dSSean Hefty ib_sa_comp_mask comp_mask; 1558a81c994dSSean Hefty struct sockaddr_in6 *sin6; 1559e51060f0SSean Hefty 1560e51060f0SSean Hefty memset(&path_rec, 0, sizeof path_rec); 1561a81c994dSSean Hefty ib_addr_get_sgid(&addr->dev_addr, &path_rec.sgid); 1562a81c994dSSean Hefty ib_addr_get_dgid(&addr->dev_addr, &path_rec.dgid); 1563a81c994dSSean Hefty path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(&addr->dev_addr)); 1564e51060f0SSean Hefty path_rec.numb_path = 1; 1565962063e6SSean Hefty path_rec.reversible = 1; 1566a81c994dSSean Hefty path_rec.service_id = cma_get_service_id(id_priv->id.ps, &addr->dst_addr); 1567a81c994dSSean Hefty 1568a81c994dSSean Hefty comp_mask = IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | 1569a81c994dSSean Hefty IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH | 1570a81c994dSSean Hefty IB_SA_PATH_REC_REVERSIBLE | IB_SA_PATH_REC_SERVICE_ID; 1571a81c994dSSean Hefty 1572a81c994dSSean Hefty if (addr->src_addr.sa_family == AF_INET) { 1573a81c994dSSean Hefty path_rec.qos_class = cpu_to_be16((u16) id_priv->tos); 1574a81c994dSSean Hefty comp_mask |= IB_SA_PATH_REC_QOS_CLASS; 1575a81c994dSSean Hefty } else { 1576a81c994dSSean Hefty sin6 = (struct sockaddr_in6 *) &addr->src_addr; 1577a81c994dSSean Hefty path_rec.traffic_class = (u8) (be32_to_cpu(sin6->sin6_flowinfo) >> 20); 1578a81c994dSSean Hefty comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS; 1579a81c994dSSean Hefty } 1580e51060f0SSean Hefty 1581c1a0b23bSMichael S. Tsirkin id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device, 1582e51060f0SSean Hefty id_priv->id.port_num, &path_rec, 1583a81c994dSSean Hefty comp_mask, timeout_ms, 1584a81c994dSSean Hefty GFP_KERNEL, cma_query_handler, 1585a81c994dSSean Hefty work, &id_priv->query); 1586e51060f0SSean Hefty 1587e51060f0SSean Hefty return (id_priv->query_id < 0) ? id_priv->query_id : 0; 1588e51060f0SSean Hefty } 1589e51060f0SSean Hefty 1590c4028958SDavid Howells static void cma_work_handler(struct work_struct *_work) 1591e51060f0SSean Hefty { 1592c4028958SDavid Howells struct cma_work *work = container_of(_work, struct cma_work, work); 1593e51060f0SSean Hefty struct rdma_id_private *id_priv = work->id; 1594e51060f0SSean Hefty int destroy = 0; 1595e51060f0SSean Hefty 1596de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 1597e51060f0SSean Hefty if (!cma_comp_exch(id_priv, work->old_state, work->new_state)) 1598e51060f0SSean Hefty goto out; 1599e51060f0SSean Hefty 1600e51060f0SSean Hefty if (id_priv->id.event_handler(&id_priv->id, &work->event)) { 1601e51060f0SSean Hefty cma_exch(id_priv, CMA_DESTROYING); 1602e51060f0SSean Hefty destroy = 1; 1603e51060f0SSean Hefty } 1604e51060f0SSean Hefty out: 1605de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1606e51060f0SSean Hefty cma_deref_id(id_priv); 1607e51060f0SSean Hefty if (destroy) 1608e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 1609e51060f0SSean Hefty kfree(work); 1610e51060f0SSean Hefty } 1611e51060f0SSean Hefty 1612dd5bdff8SOr Gerlitz static void cma_ndev_work_handler(struct work_struct *_work) 1613dd5bdff8SOr Gerlitz { 1614dd5bdff8SOr Gerlitz struct cma_ndev_work *work = container_of(_work, struct cma_ndev_work, work); 1615dd5bdff8SOr Gerlitz struct rdma_id_private *id_priv = work->id; 1616dd5bdff8SOr Gerlitz int destroy = 0; 1617dd5bdff8SOr Gerlitz 1618dd5bdff8SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 1619dd5bdff8SOr Gerlitz if (id_priv->state == CMA_DESTROYING || 1620dd5bdff8SOr Gerlitz id_priv->state == CMA_DEVICE_REMOVAL) 1621dd5bdff8SOr Gerlitz goto out; 1622dd5bdff8SOr Gerlitz 1623dd5bdff8SOr Gerlitz if (id_priv->id.event_handler(&id_priv->id, &work->event)) { 1624dd5bdff8SOr Gerlitz cma_exch(id_priv, CMA_DESTROYING); 1625dd5bdff8SOr Gerlitz destroy = 1; 1626dd5bdff8SOr Gerlitz } 1627dd5bdff8SOr Gerlitz 1628dd5bdff8SOr Gerlitz out: 1629dd5bdff8SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1630dd5bdff8SOr Gerlitz cma_deref_id(id_priv); 1631dd5bdff8SOr Gerlitz if (destroy) 1632dd5bdff8SOr Gerlitz rdma_destroy_id(&id_priv->id); 1633dd5bdff8SOr Gerlitz kfree(work); 1634dd5bdff8SOr Gerlitz } 1635dd5bdff8SOr Gerlitz 1636e51060f0SSean Hefty static int cma_resolve_ib_route(struct rdma_id_private *id_priv, int timeout_ms) 1637e51060f0SSean Hefty { 1638e51060f0SSean Hefty struct rdma_route *route = &id_priv->id.route; 1639e51060f0SSean Hefty struct cma_work *work; 1640e51060f0SSean Hefty int ret; 1641e51060f0SSean Hefty 1642e51060f0SSean Hefty work = kzalloc(sizeof *work, GFP_KERNEL); 1643e51060f0SSean Hefty if (!work) 1644e51060f0SSean Hefty return -ENOMEM; 1645e51060f0SSean Hefty 1646e51060f0SSean Hefty work->id = id_priv; 1647c4028958SDavid Howells INIT_WORK(&work->work, cma_work_handler); 1648e51060f0SSean Hefty work->old_state = CMA_ROUTE_QUERY; 1649e51060f0SSean Hefty work->new_state = CMA_ROUTE_RESOLVED; 1650e51060f0SSean Hefty work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; 1651e51060f0SSean Hefty 1652e51060f0SSean Hefty route->path_rec = kmalloc(sizeof *route->path_rec, GFP_KERNEL); 1653e51060f0SSean Hefty if (!route->path_rec) { 1654e51060f0SSean Hefty ret = -ENOMEM; 1655e51060f0SSean Hefty goto err1; 1656e51060f0SSean Hefty } 1657e51060f0SSean Hefty 1658e51060f0SSean Hefty ret = cma_query_ib_route(id_priv, timeout_ms, work); 1659e51060f0SSean Hefty if (ret) 1660e51060f0SSean Hefty goto err2; 1661e51060f0SSean Hefty 1662e51060f0SSean Hefty return 0; 1663e51060f0SSean Hefty err2: 1664e51060f0SSean Hefty kfree(route->path_rec); 1665e51060f0SSean Hefty route->path_rec = NULL; 1666e51060f0SSean Hefty err1: 1667e51060f0SSean Hefty kfree(work); 1668e51060f0SSean Hefty return ret; 1669e51060f0SSean Hefty } 1670e51060f0SSean Hefty 1671e51060f0SSean Hefty int rdma_set_ib_paths(struct rdma_cm_id *id, 1672e51060f0SSean Hefty struct ib_sa_path_rec *path_rec, int num_paths) 1673e51060f0SSean Hefty { 1674e51060f0SSean Hefty struct rdma_id_private *id_priv; 1675e51060f0SSean Hefty int ret; 1676e51060f0SSean Hefty 1677e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1678e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ROUTE_RESOLVED)) 1679e51060f0SSean Hefty return -EINVAL; 1680e51060f0SSean Hefty 1681e51060f0SSean Hefty id->route.path_rec = kmalloc(sizeof *path_rec * num_paths, GFP_KERNEL); 1682e51060f0SSean Hefty if (!id->route.path_rec) { 1683e51060f0SSean Hefty ret = -ENOMEM; 1684e51060f0SSean Hefty goto err; 1685e51060f0SSean Hefty } 1686e51060f0SSean Hefty 1687e51060f0SSean Hefty memcpy(id->route.path_rec, path_rec, sizeof *path_rec * num_paths); 1688e51060f0SSean Hefty return 0; 1689e51060f0SSean Hefty err: 1690e51060f0SSean Hefty cma_comp_exch(id_priv, CMA_ROUTE_RESOLVED, CMA_ADDR_RESOLVED); 1691e51060f0SSean Hefty return ret; 1692e51060f0SSean Hefty } 1693e51060f0SSean Hefty EXPORT_SYMBOL(rdma_set_ib_paths); 1694e51060f0SSean Hefty 169507ebafbaSTom Tucker static int cma_resolve_iw_route(struct rdma_id_private *id_priv, int timeout_ms) 169607ebafbaSTom Tucker { 169707ebafbaSTom Tucker struct cma_work *work; 169807ebafbaSTom Tucker 169907ebafbaSTom Tucker work = kzalloc(sizeof *work, GFP_KERNEL); 170007ebafbaSTom Tucker if (!work) 170107ebafbaSTom Tucker return -ENOMEM; 170207ebafbaSTom Tucker 170307ebafbaSTom Tucker work->id = id_priv; 1704c4028958SDavid Howells INIT_WORK(&work->work, cma_work_handler); 170507ebafbaSTom Tucker work->old_state = CMA_ROUTE_QUERY; 170607ebafbaSTom Tucker work->new_state = CMA_ROUTE_RESOLVED; 170707ebafbaSTom Tucker work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; 170807ebafbaSTom Tucker queue_work(cma_wq, &work->work); 170907ebafbaSTom Tucker return 0; 171007ebafbaSTom Tucker } 171107ebafbaSTom Tucker 1712e51060f0SSean Hefty int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms) 1713e51060f0SSean Hefty { 1714e51060f0SSean Hefty struct rdma_id_private *id_priv; 1715e51060f0SSean Hefty int ret; 1716e51060f0SSean Hefty 1717e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1718e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ROUTE_QUERY)) 1719e51060f0SSean Hefty return -EINVAL; 1720e51060f0SSean Hefty 1721e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 172207ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 172307ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 1724e51060f0SSean Hefty ret = cma_resolve_ib_route(id_priv, timeout_ms); 1725e51060f0SSean Hefty break; 172607ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 172707ebafbaSTom Tucker ret = cma_resolve_iw_route(id_priv, timeout_ms); 172807ebafbaSTom Tucker break; 1729e51060f0SSean Hefty default: 1730e51060f0SSean Hefty ret = -ENOSYS; 1731e51060f0SSean Hefty break; 1732e51060f0SSean Hefty } 1733e51060f0SSean Hefty if (ret) 1734e51060f0SSean Hefty goto err; 1735e51060f0SSean Hefty 1736e51060f0SSean Hefty return 0; 1737e51060f0SSean Hefty err: 1738e51060f0SSean Hefty cma_comp_exch(id_priv, CMA_ROUTE_QUERY, CMA_ADDR_RESOLVED); 1739e51060f0SSean Hefty cma_deref_id(id_priv); 1740e51060f0SSean Hefty return ret; 1741e51060f0SSean Hefty } 1742e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_route); 1743e51060f0SSean Hefty 1744e51060f0SSean Hefty static int cma_bind_loopback(struct rdma_id_private *id_priv) 1745e51060f0SSean Hefty { 1746e51060f0SSean Hefty struct cma_device *cma_dev; 1747e51060f0SSean Hefty struct ib_port_attr port_attr; 1748f0ee3404SMichael S. Tsirkin union ib_gid gid; 1749e51060f0SSean Hefty u16 pkey; 1750e51060f0SSean Hefty int ret; 1751e51060f0SSean Hefty u8 p; 1752e51060f0SSean Hefty 1753e51060f0SSean Hefty mutex_lock(&lock); 1754e82153b5SKrishna Kumar if (list_empty(&dev_list)) { 1755e82153b5SKrishna Kumar ret = -ENODEV; 1756e82153b5SKrishna Kumar goto out; 1757e82153b5SKrishna Kumar } 1758e51060f0SSean Hefty list_for_each_entry(cma_dev, &dev_list, list) 1759e51060f0SSean Hefty for (p = 1; p <= cma_dev->device->phys_port_cnt; ++p) 1760e51060f0SSean Hefty if (!ib_query_port(cma_dev->device, p, &port_attr) && 1761e51060f0SSean Hefty port_attr.state == IB_PORT_ACTIVE) 1762e51060f0SSean Hefty goto port_found; 1763e51060f0SSean Hefty 1764e51060f0SSean Hefty p = 1; 1765e51060f0SSean Hefty cma_dev = list_entry(dev_list.next, struct cma_device, list); 1766e51060f0SSean Hefty 1767e51060f0SSean Hefty port_found: 1768f0ee3404SMichael S. Tsirkin ret = ib_get_cached_gid(cma_dev->device, p, 0, &gid); 1769e51060f0SSean Hefty if (ret) 1770e51060f0SSean Hefty goto out; 1771e51060f0SSean Hefty 1772e51060f0SSean Hefty ret = ib_get_cached_pkey(cma_dev->device, p, 0, &pkey); 1773e51060f0SSean Hefty if (ret) 1774e51060f0SSean Hefty goto out; 1775e51060f0SSean Hefty 1776f0ee3404SMichael S. Tsirkin ib_addr_set_sgid(&id_priv->id.route.addr.dev_addr, &gid); 1777e51060f0SSean Hefty ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey); 1778e51060f0SSean Hefty id_priv->id.port_num = p; 1779e51060f0SSean Hefty cma_attach_to_dev(id_priv, cma_dev); 1780e51060f0SSean Hefty out: 1781e51060f0SSean Hefty mutex_unlock(&lock); 1782e51060f0SSean Hefty return ret; 1783e51060f0SSean Hefty } 1784e51060f0SSean Hefty 1785e51060f0SSean Hefty static void addr_handler(int status, struct sockaddr *src_addr, 1786e51060f0SSean Hefty struct rdma_dev_addr *dev_addr, void *context) 1787e51060f0SSean Hefty { 1788e51060f0SSean Hefty struct rdma_id_private *id_priv = context; 1789a1b1b61fSSean Hefty struct rdma_cm_event event; 1790e51060f0SSean Hefty 1791a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 1792de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 179361a73c70SSean Hefty 179461a73c70SSean Hefty /* 179561a73c70SSean Hefty * Grab mutex to block rdma_destroy_id() from removing the device while 179661a73c70SSean Hefty * we're trying to acquire it. 179761a73c70SSean Hefty */ 179861a73c70SSean Hefty mutex_lock(&lock); 179961a73c70SSean Hefty if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_RESOLVED)) { 180061a73c70SSean Hefty mutex_unlock(&lock); 180161a73c70SSean Hefty goto out; 180261a73c70SSean Hefty } 180361a73c70SSean Hefty 180461a73c70SSean Hefty if (!status && !id_priv->cma_dev) 1805e51060f0SSean Hefty status = cma_acquire_dev(id_priv); 180661a73c70SSean Hefty mutex_unlock(&lock); 1807e51060f0SSean Hefty 1808e51060f0SSean Hefty if (status) { 180961a73c70SSean Hefty if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ADDR_BOUND)) 1810e51060f0SSean Hefty goto out; 1811a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ADDR_ERROR; 1812a1b1b61fSSean Hefty event.status = status; 1813e51060f0SSean Hefty } else { 1814e51060f0SSean Hefty memcpy(&id_priv->id.route.addr.src_addr, src_addr, 1815e51060f0SSean Hefty ip_addr_size(src_addr)); 1816a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ADDR_RESOLVED; 1817e51060f0SSean Hefty } 1818e51060f0SSean Hefty 1819a1b1b61fSSean Hefty if (id_priv->id.event_handler(&id_priv->id, &event)) { 1820e51060f0SSean Hefty cma_exch(id_priv, CMA_DESTROYING); 1821de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1822e51060f0SSean Hefty cma_deref_id(id_priv); 1823e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 1824e51060f0SSean Hefty return; 1825e51060f0SSean Hefty } 1826e51060f0SSean Hefty out: 1827de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1828e51060f0SSean Hefty cma_deref_id(id_priv); 1829e51060f0SSean Hefty } 1830e51060f0SSean Hefty 1831e51060f0SSean Hefty static int cma_resolve_loopback(struct rdma_id_private *id_priv) 1832e51060f0SSean Hefty { 1833e51060f0SSean Hefty struct cma_work *work; 1834e51060f0SSean Hefty struct sockaddr_in *src_in, *dst_in; 1835f0ee3404SMichael S. Tsirkin union ib_gid gid; 1836e51060f0SSean Hefty int ret; 1837e51060f0SSean Hefty 1838e51060f0SSean Hefty work = kzalloc(sizeof *work, GFP_KERNEL); 1839e51060f0SSean Hefty if (!work) 1840e51060f0SSean Hefty return -ENOMEM; 1841e51060f0SSean Hefty 1842e51060f0SSean Hefty if (!id_priv->cma_dev) { 1843e51060f0SSean Hefty ret = cma_bind_loopback(id_priv); 1844e51060f0SSean Hefty if (ret) 1845e51060f0SSean Hefty goto err; 1846e51060f0SSean Hefty } 1847e51060f0SSean Hefty 1848f0ee3404SMichael S. Tsirkin ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid); 1849f0ee3404SMichael S. Tsirkin ib_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid); 1850e51060f0SSean Hefty 1851e51060f0SSean Hefty if (cma_zero_addr(&id_priv->id.route.addr.src_addr)) { 1852e51060f0SSean Hefty src_in = (struct sockaddr_in *)&id_priv->id.route.addr.src_addr; 1853e51060f0SSean Hefty dst_in = (struct sockaddr_in *)&id_priv->id.route.addr.dst_addr; 1854e51060f0SSean Hefty src_in->sin_family = dst_in->sin_family; 1855e51060f0SSean Hefty src_in->sin_addr.s_addr = dst_in->sin_addr.s_addr; 1856e51060f0SSean Hefty } 1857e51060f0SSean Hefty 1858e51060f0SSean Hefty work->id = id_priv; 1859c4028958SDavid Howells INIT_WORK(&work->work, cma_work_handler); 1860e51060f0SSean Hefty work->old_state = CMA_ADDR_QUERY; 1861e51060f0SSean Hefty work->new_state = CMA_ADDR_RESOLVED; 1862e51060f0SSean Hefty work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED; 1863e51060f0SSean Hefty queue_work(cma_wq, &work->work); 1864e51060f0SSean Hefty return 0; 1865e51060f0SSean Hefty err: 1866e51060f0SSean Hefty kfree(work); 1867e51060f0SSean Hefty return ret; 1868e51060f0SSean Hefty } 1869e51060f0SSean Hefty 1870e51060f0SSean Hefty static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, 1871e51060f0SSean Hefty struct sockaddr *dst_addr) 1872e51060f0SSean Hefty { 1873e51060f0SSean Hefty if (src_addr && src_addr->sa_family) 1874e51060f0SSean Hefty return rdma_bind_addr(id, src_addr); 1875e51060f0SSean Hefty else 1876e51060f0SSean Hefty return cma_bind_any(id, dst_addr->sa_family); 1877e51060f0SSean Hefty } 1878e51060f0SSean Hefty 1879e51060f0SSean Hefty int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, 1880e51060f0SSean Hefty struct sockaddr *dst_addr, int timeout_ms) 1881e51060f0SSean Hefty { 1882e51060f0SSean Hefty struct rdma_id_private *id_priv; 1883e51060f0SSean Hefty int ret; 1884e51060f0SSean Hefty 1885e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1886e51060f0SSean Hefty if (id_priv->state == CMA_IDLE) { 1887e51060f0SSean Hefty ret = cma_bind_addr(id, src_addr, dst_addr); 1888e51060f0SSean Hefty if (ret) 1889e51060f0SSean Hefty return ret; 1890e51060f0SSean Hefty } 1891e51060f0SSean Hefty 1892e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_ADDR_QUERY)) 1893e51060f0SSean Hefty return -EINVAL; 1894e51060f0SSean Hefty 1895e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 1896e51060f0SSean Hefty memcpy(&id->route.addr.dst_addr, dst_addr, ip_addr_size(dst_addr)); 1897e51060f0SSean Hefty if (cma_any_addr(dst_addr)) 1898e51060f0SSean Hefty ret = cma_resolve_loopback(id_priv); 1899e51060f0SSean Hefty else 19007a118df3SSean Hefty ret = rdma_resolve_ip(&addr_client, &id->route.addr.src_addr, 19017a118df3SSean Hefty dst_addr, &id->route.addr.dev_addr, 1902e51060f0SSean Hefty timeout_ms, addr_handler, id_priv); 1903e51060f0SSean Hefty if (ret) 1904e51060f0SSean Hefty goto err; 1905e51060f0SSean Hefty 1906e51060f0SSean Hefty return 0; 1907e51060f0SSean Hefty err: 1908e51060f0SSean Hefty cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_BOUND); 1909e51060f0SSean Hefty cma_deref_id(id_priv); 1910e51060f0SSean Hefty return ret; 1911e51060f0SSean Hefty } 1912e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_addr); 1913e51060f0SSean Hefty 1914e51060f0SSean Hefty static void cma_bind_port(struct rdma_bind_list *bind_list, 1915e51060f0SSean Hefty struct rdma_id_private *id_priv) 1916e51060f0SSean Hefty { 1917e51060f0SSean Hefty struct sockaddr_in *sin; 1918e51060f0SSean Hefty 1919e51060f0SSean Hefty sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; 1920e51060f0SSean Hefty sin->sin_port = htons(bind_list->port); 1921e51060f0SSean Hefty id_priv->bind_list = bind_list; 1922e51060f0SSean Hefty hlist_add_head(&id_priv->node, &bind_list->owners); 1923e51060f0SSean Hefty } 1924e51060f0SSean Hefty 1925e51060f0SSean Hefty static int cma_alloc_port(struct idr *ps, struct rdma_id_private *id_priv, 1926e51060f0SSean Hefty unsigned short snum) 1927e51060f0SSean Hefty { 1928e51060f0SSean Hefty struct rdma_bind_list *bind_list; 1929aedec080SSean Hefty int port, ret; 1930e51060f0SSean Hefty 1931cb164b8cSSean Hefty bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); 1932e51060f0SSean Hefty if (!bind_list) 1933e51060f0SSean Hefty return -ENOMEM; 1934e51060f0SSean Hefty 1935e51060f0SSean Hefty do { 1936aedec080SSean Hefty ret = idr_get_new_above(ps, bind_list, snum, &port); 1937e51060f0SSean Hefty } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL)); 1938e51060f0SSean Hefty 1939e51060f0SSean Hefty if (ret) 1940aedec080SSean Hefty goto err1; 1941e51060f0SSean Hefty 1942aedec080SSean Hefty if (port != snum) { 1943e51060f0SSean Hefty ret = -EADDRNOTAVAIL; 1944aedec080SSean Hefty goto err2; 1945e51060f0SSean Hefty } 1946e51060f0SSean Hefty 1947e51060f0SSean Hefty bind_list->ps = ps; 1948e51060f0SSean Hefty bind_list->port = (unsigned short) port; 1949e51060f0SSean Hefty cma_bind_port(bind_list, id_priv); 1950e51060f0SSean Hefty return 0; 1951aedec080SSean Hefty err2: 1952aedec080SSean Hefty idr_remove(ps, port); 1953aedec080SSean Hefty err1: 1954aedec080SSean Hefty kfree(bind_list); 1955aedec080SSean Hefty return ret; 1956aedec080SSean Hefty } 1957aedec080SSean Hefty 1958aedec080SSean Hefty static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv) 1959aedec080SSean Hefty { 1960aedec080SSean Hefty struct rdma_bind_list *bind_list; 1961227b60f5SStephen Hemminger int port, ret, low, high; 1962aedec080SSean Hefty 1963aedec080SSean Hefty bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); 1964aedec080SSean Hefty if (!bind_list) 1965aedec080SSean Hefty return -ENOMEM; 1966aedec080SSean Hefty 1967aedec080SSean Hefty retry: 1968227b60f5SStephen Hemminger /* FIXME: add proper port randomization per like inet_csk_get_port */ 1969aedec080SSean Hefty do { 1970aedec080SSean Hefty ret = idr_get_new_above(ps, bind_list, next_port, &port); 1971aedec080SSean Hefty } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL)); 1972aedec080SSean Hefty 1973aedec080SSean Hefty if (ret) 1974aedec080SSean Hefty goto err1; 1975aedec080SSean Hefty 1976227b60f5SStephen Hemminger inet_get_local_port_range(&low, &high); 1977227b60f5SStephen Hemminger if (port > high) { 1978227b60f5SStephen Hemminger if (next_port != low) { 1979aedec080SSean Hefty idr_remove(ps, port); 1980227b60f5SStephen Hemminger next_port = low; 1981aedec080SSean Hefty goto retry; 1982aedec080SSean Hefty } 1983aedec080SSean Hefty ret = -EADDRNOTAVAIL; 1984aedec080SSean Hefty goto err2; 1985aedec080SSean Hefty } 1986aedec080SSean Hefty 1987227b60f5SStephen Hemminger if (port == high) 1988227b60f5SStephen Hemminger next_port = low; 1989aedec080SSean Hefty else 1990aedec080SSean Hefty next_port = port + 1; 1991aedec080SSean Hefty 1992aedec080SSean Hefty bind_list->ps = ps; 1993aedec080SSean Hefty bind_list->port = (unsigned short) port; 1994aedec080SSean Hefty cma_bind_port(bind_list, id_priv); 1995aedec080SSean Hefty return 0; 1996aedec080SSean Hefty err2: 1997aedec080SSean Hefty idr_remove(ps, port); 1998aedec080SSean Hefty err1: 1999e51060f0SSean Hefty kfree(bind_list); 2000e51060f0SSean Hefty return ret; 2001e51060f0SSean Hefty } 2002e51060f0SSean Hefty 2003e51060f0SSean Hefty static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv) 2004e51060f0SSean Hefty { 2005e51060f0SSean Hefty struct rdma_id_private *cur_id; 2006e51060f0SSean Hefty struct sockaddr_in *sin, *cur_sin; 2007e51060f0SSean Hefty struct rdma_bind_list *bind_list; 2008e51060f0SSean Hefty struct hlist_node *node; 2009e51060f0SSean Hefty unsigned short snum; 2010e51060f0SSean Hefty 2011e51060f0SSean Hefty sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; 2012e51060f0SSean Hefty snum = ntohs(sin->sin_port); 2013e51060f0SSean Hefty if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) 2014e51060f0SSean Hefty return -EACCES; 2015e51060f0SSean Hefty 2016e51060f0SSean Hefty bind_list = idr_find(ps, snum); 2017e51060f0SSean Hefty if (!bind_list) 2018e51060f0SSean Hefty return cma_alloc_port(ps, id_priv, snum); 2019e51060f0SSean Hefty 2020e51060f0SSean Hefty /* 2021e51060f0SSean Hefty * We don't support binding to any address if anyone is bound to 2022e51060f0SSean Hefty * a specific address on the same port. 2023e51060f0SSean Hefty */ 2024e51060f0SSean Hefty if (cma_any_addr(&id_priv->id.route.addr.src_addr)) 2025e51060f0SSean Hefty return -EADDRNOTAVAIL; 2026e51060f0SSean Hefty 2027e51060f0SSean Hefty hlist_for_each_entry(cur_id, node, &bind_list->owners, node) { 2028e51060f0SSean Hefty if (cma_any_addr(&cur_id->id.route.addr.src_addr)) 2029e51060f0SSean Hefty return -EADDRNOTAVAIL; 2030e51060f0SSean Hefty 2031e51060f0SSean Hefty cur_sin = (struct sockaddr_in *) &cur_id->id.route.addr.src_addr; 2032e51060f0SSean Hefty if (sin->sin_addr.s_addr == cur_sin->sin_addr.s_addr) 2033e51060f0SSean Hefty return -EADDRINUSE; 2034e51060f0SSean Hefty } 2035e51060f0SSean Hefty 2036e51060f0SSean Hefty cma_bind_port(bind_list, id_priv); 2037e51060f0SSean Hefty return 0; 2038e51060f0SSean Hefty } 2039e51060f0SSean Hefty 2040e51060f0SSean Hefty static int cma_get_port(struct rdma_id_private *id_priv) 2041e51060f0SSean Hefty { 2042e51060f0SSean Hefty struct idr *ps; 2043e51060f0SSean Hefty int ret; 2044e51060f0SSean Hefty 2045e51060f0SSean Hefty switch (id_priv->id.ps) { 2046e51060f0SSean Hefty case RDMA_PS_SDP: 2047e51060f0SSean Hefty ps = &sdp_ps; 2048e51060f0SSean Hefty break; 2049e51060f0SSean Hefty case RDMA_PS_TCP: 2050e51060f0SSean Hefty ps = &tcp_ps; 2051e51060f0SSean Hefty break; 2052628e5f6dSSean Hefty case RDMA_PS_UDP: 2053628e5f6dSSean Hefty ps = &udp_ps; 2054628e5f6dSSean Hefty break; 2055c8f6a362SSean Hefty case RDMA_PS_IPOIB: 2056c8f6a362SSean Hefty ps = &ipoib_ps; 2057c8f6a362SSean Hefty break; 2058e51060f0SSean Hefty default: 2059e51060f0SSean Hefty return -EPROTONOSUPPORT; 2060e51060f0SSean Hefty } 2061e51060f0SSean Hefty 2062e51060f0SSean Hefty mutex_lock(&lock); 2063e51060f0SSean Hefty if (cma_any_port(&id_priv->id.route.addr.src_addr)) 2064aedec080SSean Hefty ret = cma_alloc_any_port(ps, id_priv); 2065e51060f0SSean Hefty else 2066e51060f0SSean Hefty ret = cma_use_port(ps, id_priv); 2067e51060f0SSean Hefty mutex_unlock(&lock); 2068e51060f0SSean Hefty 2069e51060f0SSean Hefty return ret; 2070e51060f0SSean Hefty } 2071e51060f0SSean Hefty 2072e51060f0SSean Hefty int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) 2073e51060f0SSean Hefty { 2074e51060f0SSean Hefty struct rdma_id_private *id_priv; 2075e51060f0SSean Hefty int ret; 2076e51060f0SSean Hefty 2077e51060f0SSean Hefty if (addr->sa_family != AF_INET) 2078e51060f0SSean Hefty return -EAFNOSUPPORT; 2079e51060f0SSean Hefty 2080e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2081e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_IDLE, CMA_ADDR_BOUND)) 2082e51060f0SSean Hefty return -EINVAL; 2083e51060f0SSean Hefty 2084e51060f0SSean Hefty if (!cma_any_addr(addr)) { 2085e51060f0SSean Hefty ret = rdma_translate_ip(addr, &id->route.addr.dev_addr); 2086255d0c14SKrishna Kumar if (ret) 2087255d0c14SKrishna Kumar goto err1; 2088255d0c14SKrishna Kumar 208961a73c70SSean Hefty mutex_lock(&lock); 2090e51060f0SSean Hefty ret = cma_acquire_dev(id_priv); 209161a73c70SSean Hefty mutex_unlock(&lock); 2092e51060f0SSean Hefty if (ret) 2093255d0c14SKrishna Kumar goto err1; 2094e51060f0SSean Hefty } 2095e51060f0SSean Hefty 2096e51060f0SSean Hefty memcpy(&id->route.addr.src_addr, addr, ip_addr_size(addr)); 2097e51060f0SSean Hefty ret = cma_get_port(id_priv); 2098e51060f0SSean Hefty if (ret) 2099255d0c14SKrishna Kumar goto err2; 2100e51060f0SSean Hefty 2101e51060f0SSean Hefty return 0; 2102255d0c14SKrishna Kumar err2: 2103255d0c14SKrishna Kumar if (!cma_any_addr(addr)) { 2104255d0c14SKrishna Kumar mutex_lock(&lock); 2105255d0c14SKrishna Kumar cma_detach_from_dev(id_priv); 2106255d0c14SKrishna Kumar mutex_unlock(&lock); 2107255d0c14SKrishna Kumar } 2108255d0c14SKrishna Kumar err1: 2109e51060f0SSean Hefty cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_IDLE); 2110e51060f0SSean Hefty return ret; 2111e51060f0SSean Hefty } 2112e51060f0SSean Hefty EXPORT_SYMBOL(rdma_bind_addr); 2113e51060f0SSean Hefty 2114e51060f0SSean Hefty static int cma_format_hdr(void *hdr, enum rdma_port_space ps, 2115e51060f0SSean Hefty struct rdma_route *route) 2116e51060f0SSean Hefty { 2117e51060f0SSean Hefty struct sockaddr_in *src4, *dst4; 2118e51060f0SSean Hefty struct cma_hdr *cma_hdr; 2119e51060f0SSean Hefty struct sdp_hh *sdp_hdr; 2120e51060f0SSean Hefty 2121e51060f0SSean Hefty src4 = (struct sockaddr_in *) &route->addr.src_addr; 2122e51060f0SSean Hefty dst4 = (struct sockaddr_in *) &route->addr.dst_addr; 2123e51060f0SSean Hefty 2124e51060f0SSean Hefty switch (ps) { 2125e51060f0SSean Hefty case RDMA_PS_SDP: 2126e51060f0SSean Hefty sdp_hdr = hdr; 2127e51060f0SSean Hefty if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION) 2128e51060f0SSean Hefty return -EINVAL; 2129e51060f0SSean Hefty sdp_set_ip_ver(sdp_hdr, 4); 2130e51060f0SSean Hefty sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; 2131e51060f0SSean Hefty sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; 2132e51060f0SSean Hefty sdp_hdr->port = src4->sin_port; 2133e51060f0SSean Hefty break; 2134e51060f0SSean Hefty default: 2135e51060f0SSean Hefty cma_hdr = hdr; 2136e51060f0SSean Hefty cma_hdr->cma_version = CMA_VERSION; 2137e51060f0SSean Hefty cma_set_ip_ver(cma_hdr, 4); 2138e51060f0SSean Hefty cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; 2139e51060f0SSean Hefty cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; 2140e51060f0SSean Hefty cma_hdr->port = src4->sin_port; 2141e51060f0SSean Hefty break; 2142e51060f0SSean Hefty } 2143e51060f0SSean Hefty return 0; 2144e51060f0SSean Hefty } 2145e51060f0SSean Hefty 2146628e5f6dSSean Hefty static int cma_sidr_rep_handler(struct ib_cm_id *cm_id, 2147628e5f6dSSean Hefty struct ib_cm_event *ib_event) 2148628e5f6dSSean Hefty { 2149628e5f6dSSean Hefty struct rdma_id_private *id_priv = cm_id->context; 2150628e5f6dSSean Hefty struct rdma_cm_event event; 2151628e5f6dSSean Hefty struct ib_cm_sidr_rep_event_param *rep = &ib_event->param.sidr_rep_rcvd; 2152628e5f6dSSean Hefty int ret = 0; 2153628e5f6dSSean Hefty 2154de910bd9SOr Gerlitz if (cma_disable_callback(id_priv, CMA_CONNECT)) 21558aa08602SSean Hefty return 0; 2156628e5f6dSSean Hefty 21578aa08602SSean Hefty memset(&event, 0, sizeof event); 2158628e5f6dSSean Hefty switch (ib_event->event) { 2159628e5f6dSSean Hefty case IB_CM_SIDR_REQ_ERROR: 2160628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 2161628e5f6dSSean Hefty event.status = -ETIMEDOUT; 2162628e5f6dSSean Hefty break; 2163628e5f6dSSean Hefty case IB_CM_SIDR_REP_RECEIVED: 2164628e5f6dSSean Hefty event.param.ud.private_data = ib_event->private_data; 2165628e5f6dSSean Hefty event.param.ud.private_data_len = IB_CM_SIDR_REP_PRIVATE_DATA_SIZE; 2166628e5f6dSSean Hefty if (rep->status != IB_SIDR_SUCCESS) { 2167628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 2168628e5f6dSSean Hefty event.status = ib_event->param.sidr_rep_rcvd.status; 2169628e5f6dSSean Hefty break; 2170628e5f6dSSean Hefty } 2171c8f6a362SSean Hefty if (id_priv->qkey != rep->qkey) { 2172628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 2173628e5f6dSSean Hefty event.status = -EINVAL; 2174628e5f6dSSean Hefty break; 2175628e5f6dSSean Hefty } 2176628e5f6dSSean Hefty ib_init_ah_from_path(id_priv->id.device, id_priv->id.port_num, 2177628e5f6dSSean Hefty id_priv->id.route.path_rec, 2178628e5f6dSSean Hefty &event.param.ud.ah_attr); 2179628e5f6dSSean Hefty event.param.ud.qp_num = rep->qpn; 2180628e5f6dSSean Hefty event.param.ud.qkey = rep->qkey; 2181628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 2182628e5f6dSSean Hefty event.status = 0; 2183628e5f6dSSean Hefty break; 2184628e5f6dSSean Hefty default: 2185468f2239SRoland Dreier printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d\n", 2186628e5f6dSSean Hefty ib_event->event); 2187628e5f6dSSean Hefty goto out; 2188628e5f6dSSean Hefty } 2189628e5f6dSSean Hefty 2190628e5f6dSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 2191628e5f6dSSean Hefty if (ret) { 2192628e5f6dSSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 2193628e5f6dSSean Hefty id_priv->cm_id.ib = NULL; 2194628e5f6dSSean Hefty cma_exch(id_priv, CMA_DESTROYING); 2195de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2196628e5f6dSSean Hefty rdma_destroy_id(&id_priv->id); 2197628e5f6dSSean Hefty return ret; 2198628e5f6dSSean Hefty } 2199628e5f6dSSean Hefty out: 2200de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2201628e5f6dSSean Hefty return ret; 2202628e5f6dSSean Hefty } 2203628e5f6dSSean Hefty 2204628e5f6dSSean Hefty static int cma_resolve_ib_udp(struct rdma_id_private *id_priv, 2205628e5f6dSSean Hefty struct rdma_conn_param *conn_param) 2206628e5f6dSSean Hefty { 2207628e5f6dSSean Hefty struct ib_cm_sidr_req_param req; 2208628e5f6dSSean Hefty struct rdma_route *route; 2209628e5f6dSSean Hefty int ret; 2210628e5f6dSSean Hefty 2211628e5f6dSSean Hefty req.private_data_len = sizeof(struct cma_hdr) + 2212628e5f6dSSean Hefty conn_param->private_data_len; 2213628e5f6dSSean Hefty req.private_data = kzalloc(req.private_data_len, GFP_ATOMIC); 2214628e5f6dSSean Hefty if (!req.private_data) 2215628e5f6dSSean Hefty return -ENOMEM; 2216628e5f6dSSean Hefty 2217628e5f6dSSean Hefty if (conn_param->private_data && conn_param->private_data_len) 2218628e5f6dSSean Hefty memcpy((void *) req.private_data + sizeof(struct cma_hdr), 2219628e5f6dSSean Hefty conn_param->private_data, conn_param->private_data_len); 2220628e5f6dSSean Hefty 2221628e5f6dSSean Hefty route = &id_priv->id.route; 2222628e5f6dSSean Hefty ret = cma_format_hdr((void *) req.private_data, id_priv->id.ps, route); 2223628e5f6dSSean Hefty if (ret) 2224628e5f6dSSean Hefty goto out; 2225628e5f6dSSean Hefty 2226628e5f6dSSean Hefty id_priv->cm_id.ib = ib_create_cm_id(id_priv->id.device, 2227628e5f6dSSean Hefty cma_sidr_rep_handler, id_priv); 2228628e5f6dSSean Hefty if (IS_ERR(id_priv->cm_id.ib)) { 2229628e5f6dSSean Hefty ret = PTR_ERR(id_priv->cm_id.ib); 2230628e5f6dSSean Hefty goto out; 2231628e5f6dSSean Hefty } 2232628e5f6dSSean Hefty 2233628e5f6dSSean Hefty req.path = route->path_rec; 2234628e5f6dSSean Hefty req.service_id = cma_get_service_id(id_priv->id.ps, 2235628e5f6dSSean Hefty &route->addr.dst_addr); 2236628e5f6dSSean Hefty req.timeout_ms = 1 << (CMA_CM_RESPONSE_TIMEOUT - 8); 2237628e5f6dSSean Hefty req.max_cm_retries = CMA_MAX_CM_RETRIES; 2238628e5f6dSSean Hefty 2239628e5f6dSSean Hefty ret = ib_send_cm_sidr_req(id_priv->cm_id.ib, &req); 2240628e5f6dSSean Hefty if (ret) { 2241628e5f6dSSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 2242628e5f6dSSean Hefty id_priv->cm_id.ib = NULL; 2243628e5f6dSSean Hefty } 2244628e5f6dSSean Hefty out: 2245628e5f6dSSean Hefty kfree(req.private_data); 2246628e5f6dSSean Hefty return ret; 2247628e5f6dSSean Hefty } 2248628e5f6dSSean Hefty 2249e51060f0SSean Hefty static int cma_connect_ib(struct rdma_id_private *id_priv, 2250e51060f0SSean Hefty struct rdma_conn_param *conn_param) 2251e51060f0SSean Hefty { 2252e51060f0SSean Hefty struct ib_cm_req_param req; 2253e51060f0SSean Hefty struct rdma_route *route; 2254e51060f0SSean Hefty void *private_data; 2255e51060f0SSean Hefty int offset, ret; 2256e51060f0SSean Hefty 2257e51060f0SSean Hefty memset(&req, 0, sizeof req); 2258e51060f0SSean Hefty offset = cma_user_data_offset(id_priv->id.ps); 2259e51060f0SSean Hefty req.private_data_len = offset + conn_param->private_data_len; 2260e51060f0SSean Hefty private_data = kzalloc(req.private_data_len, GFP_ATOMIC); 2261e51060f0SSean Hefty if (!private_data) 2262e51060f0SSean Hefty return -ENOMEM; 2263e51060f0SSean Hefty 2264e51060f0SSean Hefty if (conn_param->private_data && conn_param->private_data_len) 2265e51060f0SSean Hefty memcpy(private_data + offset, conn_param->private_data, 2266e51060f0SSean Hefty conn_param->private_data_len); 2267e51060f0SSean Hefty 2268e51060f0SSean Hefty id_priv->cm_id.ib = ib_create_cm_id(id_priv->id.device, cma_ib_handler, 2269e51060f0SSean Hefty id_priv); 2270e51060f0SSean Hefty if (IS_ERR(id_priv->cm_id.ib)) { 2271e51060f0SSean Hefty ret = PTR_ERR(id_priv->cm_id.ib); 2272e51060f0SSean Hefty goto out; 2273e51060f0SSean Hefty } 2274e51060f0SSean Hefty 2275e51060f0SSean Hefty route = &id_priv->id.route; 2276e51060f0SSean Hefty ret = cma_format_hdr(private_data, id_priv->id.ps, route); 2277e51060f0SSean Hefty if (ret) 2278e51060f0SSean Hefty goto out; 2279e51060f0SSean Hefty req.private_data = private_data; 2280e51060f0SSean Hefty 2281e51060f0SSean Hefty req.primary_path = &route->path_rec[0]; 2282e51060f0SSean Hefty if (route->num_paths == 2) 2283e51060f0SSean Hefty req.alternate_path = &route->path_rec[1]; 2284e51060f0SSean Hefty 2285e51060f0SSean Hefty req.service_id = cma_get_service_id(id_priv->id.ps, 2286e51060f0SSean Hefty &route->addr.dst_addr); 2287e51060f0SSean Hefty req.qp_num = id_priv->qp_num; 22889b2e9c0cSSean Hefty req.qp_type = IB_QPT_RC; 2289e51060f0SSean Hefty req.starting_psn = id_priv->seq_num; 2290e51060f0SSean Hefty req.responder_resources = conn_param->responder_resources; 2291e51060f0SSean Hefty req.initiator_depth = conn_param->initiator_depth; 2292e51060f0SSean Hefty req.flow_control = conn_param->flow_control; 2293e51060f0SSean Hefty req.retry_count = conn_param->retry_count; 2294e51060f0SSean Hefty req.rnr_retry_count = conn_param->rnr_retry_count; 2295e51060f0SSean Hefty req.remote_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; 2296e51060f0SSean Hefty req.local_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; 2297e51060f0SSean Hefty req.max_cm_retries = CMA_MAX_CM_RETRIES; 2298e51060f0SSean Hefty req.srq = id_priv->srq ? 1 : 0; 2299e51060f0SSean Hefty 2300e51060f0SSean Hefty ret = ib_send_cm_req(id_priv->cm_id.ib, &req); 2301e51060f0SSean Hefty out: 2302675a027cSKrishna Kumar if (ret && !IS_ERR(id_priv->cm_id.ib)) { 2303675a027cSKrishna Kumar ib_destroy_cm_id(id_priv->cm_id.ib); 2304675a027cSKrishna Kumar id_priv->cm_id.ib = NULL; 2305675a027cSKrishna Kumar } 2306675a027cSKrishna Kumar 2307e51060f0SSean Hefty kfree(private_data); 2308e51060f0SSean Hefty return ret; 2309e51060f0SSean Hefty } 2310e51060f0SSean Hefty 231107ebafbaSTom Tucker static int cma_connect_iw(struct rdma_id_private *id_priv, 231207ebafbaSTom Tucker struct rdma_conn_param *conn_param) 231307ebafbaSTom Tucker { 231407ebafbaSTom Tucker struct iw_cm_id *cm_id; 231507ebafbaSTom Tucker struct sockaddr_in* sin; 231607ebafbaSTom Tucker int ret; 231707ebafbaSTom Tucker struct iw_cm_conn_param iw_param; 231807ebafbaSTom Tucker 231907ebafbaSTom Tucker cm_id = iw_create_cm_id(id_priv->id.device, cma_iw_handler, id_priv); 232007ebafbaSTom Tucker if (IS_ERR(cm_id)) { 232107ebafbaSTom Tucker ret = PTR_ERR(cm_id); 232207ebafbaSTom Tucker goto out; 232307ebafbaSTom Tucker } 232407ebafbaSTom Tucker 232507ebafbaSTom Tucker id_priv->cm_id.iw = cm_id; 232607ebafbaSTom Tucker 232707ebafbaSTom Tucker sin = (struct sockaddr_in*) &id_priv->id.route.addr.src_addr; 232807ebafbaSTom Tucker cm_id->local_addr = *sin; 232907ebafbaSTom Tucker 233007ebafbaSTom Tucker sin = (struct sockaddr_in*) &id_priv->id.route.addr.dst_addr; 233107ebafbaSTom Tucker cm_id->remote_addr = *sin; 233207ebafbaSTom Tucker 23335851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 2334675a027cSKrishna Kumar if (ret) 2335675a027cSKrishna Kumar goto out; 233607ebafbaSTom Tucker 233707ebafbaSTom Tucker iw_param.ord = conn_param->initiator_depth; 233807ebafbaSTom Tucker iw_param.ird = conn_param->responder_resources; 233907ebafbaSTom Tucker iw_param.private_data = conn_param->private_data; 234007ebafbaSTom Tucker iw_param.private_data_len = conn_param->private_data_len; 234107ebafbaSTom Tucker if (id_priv->id.qp) 234207ebafbaSTom Tucker iw_param.qpn = id_priv->qp_num; 234307ebafbaSTom Tucker else 234407ebafbaSTom Tucker iw_param.qpn = conn_param->qp_num; 234507ebafbaSTom Tucker ret = iw_cm_connect(cm_id, &iw_param); 234607ebafbaSTom Tucker out: 2347675a027cSKrishna Kumar if (ret && !IS_ERR(cm_id)) { 2348675a027cSKrishna Kumar iw_destroy_cm_id(cm_id); 2349675a027cSKrishna Kumar id_priv->cm_id.iw = NULL; 2350675a027cSKrishna Kumar } 235107ebafbaSTom Tucker return ret; 235207ebafbaSTom Tucker } 235307ebafbaSTom Tucker 2354e51060f0SSean Hefty int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) 2355e51060f0SSean Hefty { 2356e51060f0SSean Hefty struct rdma_id_private *id_priv; 2357e51060f0SSean Hefty int ret; 2358e51060f0SSean Hefty 2359e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2360e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_ROUTE_RESOLVED, CMA_CONNECT)) 2361e51060f0SSean Hefty return -EINVAL; 2362e51060f0SSean Hefty 2363e51060f0SSean Hefty if (!id->qp) { 2364e51060f0SSean Hefty id_priv->qp_num = conn_param->qp_num; 2365e51060f0SSean Hefty id_priv->srq = conn_param->srq; 2366e51060f0SSean Hefty } 2367e51060f0SSean Hefty 236807ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 236907ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 2370c8f6a362SSean Hefty if (cma_is_ud_ps(id->ps)) 2371628e5f6dSSean Hefty ret = cma_resolve_ib_udp(id_priv, conn_param); 2372628e5f6dSSean Hefty else 2373e51060f0SSean Hefty ret = cma_connect_ib(id_priv, conn_param); 2374e51060f0SSean Hefty break; 237507ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 237607ebafbaSTom Tucker ret = cma_connect_iw(id_priv, conn_param); 237707ebafbaSTom Tucker break; 2378e51060f0SSean Hefty default: 2379e51060f0SSean Hefty ret = -ENOSYS; 2380e51060f0SSean Hefty break; 2381e51060f0SSean Hefty } 2382e51060f0SSean Hefty if (ret) 2383e51060f0SSean Hefty goto err; 2384e51060f0SSean Hefty 2385e51060f0SSean Hefty return 0; 2386e51060f0SSean Hefty err: 2387e51060f0SSean Hefty cma_comp_exch(id_priv, CMA_CONNECT, CMA_ROUTE_RESOLVED); 2388e51060f0SSean Hefty return ret; 2389e51060f0SSean Hefty } 2390e51060f0SSean Hefty EXPORT_SYMBOL(rdma_connect); 2391e51060f0SSean Hefty 2392e51060f0SSean Hefty static int cma_accept_ib(struct rdma_id_private *id_priv, 2393e51060f0SSean Hefty struct rdma_conn_param *conn_param) 2394e51060f0SSean Hefty { 2395e51060f0SSean Hefty struct ib_cm_rep_param rep; 23965851bb89SSean Hefty int ret; 2397e51060f0SSean Hefty 23985851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 2399e51060f0SSean Hefty if (ret) 24000fe313b0SSean Hefty goto out; 24010fe313b0SSean Hefty 24025851bb89SSean Hefty ret = cma_modify_qp_rts(id_priv, conn_param); 24030fe313b0SSean Hefty if (ret) 24040fe313b0SSean Hefty goto out; 24050fe313b0SSean Hefty 2406e51060f0SSean Hefty memset(&rep, 0, sizeof rep); 2407e51060f0SSean Hefty rep.qp_num = id_priv->qp_num; 2408e51060f0SSean Hefty rep.starting_psn = id_priv->seq_num; 2409e51060f0SSean Hefty rep.private_data = conn_param->private_data; 2410e51060f0SSean Hefty rep.private_data_len = conn_param->private_data_len; 2411e51060f0SSean Hefty rep.responder_resources = conn_param->responder_resources; 2412e51060f0SSean Hefty rep.initiator_depth = conn_param->initiator_depth; 2413e51060f0SSean Hefty rep.failover_accepted = 0; 2414e51060f0SSean Hefty rep.flow_control = conn_param->flow_control; 2415e51060f0SSean Hefty rep.rnr_retry_count = conn_param->rnr_retry_count; 2416e51060f0SSean Hefty rep.srq = id_priv->srq ? 1 : 0; 2417e51060f0SSean Hefty 24180fe313b0SSean Hefty ret = ib_send_cm_rep(id_priv->cm_id.ib, &rep); 24190fe313b0SSean Hefty out: 24200fe313b0SSean Hefty return ret; 2421e51060f0SSean Hefty } 2422e51060f0SSean Hefty 242307ebafbaSTom Tucker static int cma_accept_iw(struct rdma_id_private *id_priv, 242407ebafbaSTom Tucker struct rdma_conn_param *conn_param) 242507ebafbaSTom Tucker { 242607ebafbaSTom Tucker struct iw_cm_conn_param iw_param; 242707ebafbaSTom Tucker int ret; 242807ebafbaSTom Tucker 24295851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 243007ebafbaSTom Tucker if (ret) 243107ebafbaSTom Tucker return ret; 243207ebafbaSTom Tucker 243307ebafbaSTom Tucker iw_param.ord = conn_param->initiator_depth; 243407ebafbaSTom Tucker iw_param.ird = conn_param->responder_resources; 243507ebafbaSTom Tucker iw_param.private_data = conn_param->private_data; 243607ebafbaSTom Tucker iw_param.private_data_len = conn_param->private_data_len; 243707ebafbaSTom Tucker if (id_priv->id.qp) { 243807ebafbaSTom Tucker iw_param.qpn = id_priv->qp_num; 243907ebafbaSTom Tucker } else 244007ebafbaSTom Tucker iw_param.qpn = conn_param->qp_num; 244107ebafbaSTom Tucker 244207ebafbaSTom Tucker return iw_cm_accept(id_priv->cm_id.iw, &iw_param); 244307ebafbaSTom Tucker } 244407ebafbaSTom Tucker 2445628e5f6dSSean Hefty static int cma_send_sidr_rep(struct rdma_id_private *id_priv, 2446628e5f6dSSean Hefty enum ib_cm_sidr_status status, 2447628e5f6dSSean Hefty const void *private_data, int private_data_len) 2448628e5f6dSSean Hefty { 2449628e5f6dSSean Hefty struct ib_cm_sidr_rep_param rep; 2450628e5f6dSSean Hefty 2451628e5f6dSSean Hefty memset(&rep, 0, sizeof rep); 2452628e5f6dSSean Hefty rep.status = status; 2453628e5f6dSSean Hefty if (status == IB_SIDR_SUCCESS) { 2454628e5f6dSSean Hefty rep.qp_num = id_priv->qp_num; 2455c8f6a362SSean Hefty rep.qkey = id_priv->qkey; 2456628e5f6dSSean Hefty } 2457628e5f6dSSean Hefty rep.private_data = private_data; 2458628e5f6dSSean Hefty rep.private_data_len = private_data_len; 2459628e5f6dSSean Hefty 2460628e5f6dSSean Hefty return ib_send_cm_sidr_rep(id_priv->cm_id.ib, &rep); 2461628e5f6dSSean Hefty } 2462628e5f6dSSean Hefty 2463e51060f0SSean Hefty int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) 2464e51060f0SSean Hefty { 2465e51060f0SSean Hefty struct rdma_id_private *id_priv; 2466e51060f0SSean Hefty int ret; 2467e51060f0SSean Hefty 2468e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2469e51060f0SSean Hefty if (!cma_comp(id_priv, CMA_CONNECT)) 2470e51060f0SSean Hefty return -EINVAL; 2471e51060f0SSean Hefty 2472e51060f0SSean Hefty if (!id->qp && conn_param) { 2473e51060f0SSean Hefty id_priv->qp_num = conn_param->qp_num; 2474e51060f0SSean Hefty id_priv->srq = conn_param->srq; 2475e51060f0SSean Hefty } 2476e51060f0SSean Hefty 247707ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 247807ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 2479c8f6a362SSean Hefty if (cma_is_ud_ps(id->ps)) 2480628e5f6dSSean Hefty ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS, 2481628e5f6dSSean Hefty conn_param->private_data, 2482628e5f6dSSean Hefty conn_param->private_data_len); 2483628e5f6dSSean Hefty else if (conn_param) 2484e51060f0SSean Hefty ret = cma_accept_ib(id_priv, conn_param); 2485e51060f0SSean Hefty else 2486e51060f0SSean Hefty ret = cma_rep_recv(id_priv); 2487e51060f0SSean Hefty break; 248807ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 248907ebafbaSTom Tucker ret = cma_accept_iw(id_priv, conn_param); 249007ebafbaSTom Tucker break; 2491e51060f0SSean Hefty default: 2492e51060f0SSean Hefty ret = -ENOSYS; 2493e51060f0SSean Hefty break; 2494e51060f0SSean Hefty } 2495e51060f0SSean Hefty 2496e51060f0SSean Hefty if (ret) 2497e51060f0SSean Hefty goto reject; 2498e51060f0SSean Hefty 2499e51060f0SSean Hefty return 0; 2500e51060f0SSean Hefty reject: 2501c5483388SSean Hefty cma_modify_qp_err(id_priv); 2502e51060f0SSean Hefty rdma_reject(id, NULL, 0); 2503e51060f0SSean Hefty return ret; 2504e51060f0SSean Hefty } 2505e51060f0SSean Hefty EXPORT_SYMBOL(rdma_accept); 2506e51060f0SSean Hefty 25070fe313b0SSean Hefty int rdma_notify(struct rdma_cm_id *id, enum ib_event_type event) 25080fe313b0SSean Hefty { 25090fe313b0SSean Hefty struct rdma_id_private *id_priv; 25100fe313b0SSean Hefty int ret; 25110fe313b0SSean Hefty 25120fe313b0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 25136c719f5cSSean Hefty if (!cma_has_cm_dev(id_priv)) 25140fe313b0SSean Hefty return -EINVAL; 25150fe313b0SSean Hefty 25160fe313b0SSean Hefty switch (id->device->node_type) { 25170fe313b0SSean Hefty case RDMA_NODE_IB_CA: 25180fe313b0SSean Hefty ret = ib_cm_notify(id_priv->cm_id.ib, event); 25190fe313b0SSean Hefty break; 25200fe313b0SSean Hefty default: 25210fe313b0SSean Hefty ret = 0; 25220fe313b0SSean Hefty break; 25230fe313b0SSean Hefty } 25240fe313b0SSean Hefty return ret; 25250fe313b0SSean Hefty } 25260fe313b0SSean Hefty EXPORT_SYMBOL(rdma_notify); 25270fe313b0SSean Hefty 2528e51060f0SSean Hefty int rdma_reject(struct rdma_cm_id *id, const void *private_data, 2529e51060f0SSean Hefty u8 private_data_len) 2530e51060f0SSean Hefty { 2531e51060f0SSean Hefty struct rdma_id_private *id_priv; 2532e51060f0SSean Hefty int ret; 2533e51060f0SSean Hefty 2534e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 25356c719f5cSSean Hefty if (!cma_has_cm_dev(id_priv)) 2536e51060f0SSean Hefty return -EINVAL; 2537e51060f0SSean Hefty 253807ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 253907ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 2540c8f6a362SSean Hefty if (cma_is_ud_ps(id->ps)) 2541628e5f6dSSean Hefty ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT, 2542e51060f0SSean Hefty private_data, private_data_len); 2543628e5f6dSSean Hefty else 2544628e5f6dSSean Hefty ret = ib_send_cm_rej(id_priv->cm_id.ib, 2545628e5f6dSSean Hefty IB_CM_REJ_CONSUMER_DEFINED, NULL, 2546628e5f6dSSean Hefty 0, private_data, private_data_len); 2547e51060f0SSean Hefty break; 254807ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 254907ebafbaSTom Tucker ret = iw_cm_reject(id_priv->cm_id.iw, 255007ebafbaSTom Tucker private_data, private_data_len); 255107ebafbaSTom Tucker break; 2552e51060f0SSean Hefty default: 2553e51060f0SSean Hefty ret = -ENOSYS; 2554e51060f0SSean Hefty break; 2555e51060f0SSean Hefty } 2556e51060f0SSean Hefty return ret; 2557e51060f0SSean Hefty } 2558e51060f0SSean Hefty EXPORT_SYMBOL(rdma_reject); 2559e51060f0SSean Hefty 2560e51060f0SSean Hefty int rdma_disconnect(struct rdma_cm_id *id) 2561e51060f0SSean Hefty { 2562e51060f0SSean Hefty struct rdma_id_private *id_priv; 2563e51060f0SSean Hefty int ret; 2564e51060f0SSean Hefty 2565e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 25666c719f5cSSean Hefty if (!cma_has_cm_dev(id_priv)) 2567e51060f0SSean Hefty return -EINVAL; 2568e51060f0SSean Hefty 256907ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 257007ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 2571c5483388SSean Hefty ret = cma_modify_qp_err(id_priv); 2572e51060f0SSean Hefty if (ret) 2573e51060f0SSean Hefty goto out; 2574e51060f0SSean Hefty /* Initiate or respond to a disconnect. */ 2575e51060f0SSean Hefty if (ib_send_cm_dreq(id_priv->cm_id.ib, NULL, 0)) 2576e51060f0SSean Hefty ib_send_cm_drep(id_priv->cm_id.ib, NULL, 0); 2577e51060f0SSean Hefty break; 257807ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 257907ebafbaSTom Tucker ret = iw_cm_disconnect(id_priv->cm_id.iw, 0); 258007ebafbaSTom Tucker break; 2581e51060f0SSean Hefty default: 258207ebafbaSTom Tucker ret = -EINVAL; 2583e51060f0SSean Hefty break; 2584e51060f0SSean Hefty } 2585e51060f0SSean Hefty out: 2586e51060f0SSean Hefty return ret; 2587e51060f0SSean Hefty } 2588e51060f0SSean Hefty EXPORT_SYMBOL(rdma_disconnect); 2589e51060f0SSean Hefty 2590c8f6a362SSean Hefty static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast) 2591c8f6a362SSean Hefty { 2592c8f6a362SSean Hefty struct rdma_id_private *id_priv; 2593c8f6a362SSean Hefty struct cma_multicast *mc = multicast->context; 2594c8f6a362SSean Hefty struct rdma_cm_event event; 2595c8f6a362SSean Hefty int ret; 2596c8f6a362SSean Hefty 2597c8f6a362SSean Hefty id_priv = mc->id_priv; 2598de910bd9SOr Gerlitz if (cma_disable_callback(id_priv, CMA_ADDR_BOUND) && 2599de910bd9SOr Gerlitz cma_disable_callback(id_priv, CMA_ADDR_RESOLVED)) 26008aa08602SSean Hefty return 0; 2601c8f6a362SSean Hefty 2602c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 2603c8f6a362SSean Hefty if (!status && id_priv->id.qp) 2604c8f6a362SSean Hefty status = ib_attach_mcast(id_priv->id.qp, &multicast->rec.mgid, 2605c8f6a362SSean Hefty multicast->rec.mlid); 2606c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 2607c8f6a362SSean Hefty 2608c8f6a362SSean Hefty memset(&event, 0, sizeof event); 2609c8f6a362SSean Hefty event.status = status; 2610c8f6a362SSean Hefty event.param.ud.private_data = mc->context; 2611c8f6a362SSean Hefty if (!status) { 2612c8f6a362SSean Hefty event.event = RDMA_CM_EVENT_MULTICAST_JOIN; 2613c8f6a362SSean Hefty ib_init_ah_from_mcmember(id_priv->id.device, 2614c8f6a362SSean Hefty id_priv->id.port_num, &multicast->rec, 2615c8f6a362SSean Hefty &event.param.ud.ah_attr); 2616c8f6a362SSean Hefty event.param.ud.qp_num = 0xFFFFFF; 2617c8f6a362SSean Hefty event.param.ud.qkey = be32_to_cpu(multicast->rec.qkey); 2618c8f6a362SSean Hefty } else 2619c8f6a362SSean Hefty event.event = RDMA_CM_EVENT_MULTICAST_ERROR; 2620c8f6a362SSean Hefty 2621c8f6a362SSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 2622c8f6a362SSean Hefty if (ret) { 2623c8f6a362SSean Hefty cma_exch(id_priv, CMA_DESTROYING); 2624de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2625c8f6a362SSean Hefty rdma_destroy_id(&id_priv->id); 2626c8f6a362SSean Hefty return 0; 2627c8f6a362SSean Hefty } 26288aa08602SSean Hefty 2629de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2630c8f6a362SSean Hefty return 0; 2631c8f6a362SSean Hefty } 2632c8f6a362SSean Hefty 2633c8f6a362SSean Hefty static void cma_set_mgid(struct rdma_id_private *id_priv, 2634c8f6a362SSean Hefty struct sockaddr *addr, union ib_gid *mgid) 2635c8f6a362SSean Hefty { 2636c8f6a362SSean Hefty unsigned char mc_map[MAX_ADDR_LEN]; 2637c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 2638c8f6a362SSean Hefty struct sockaddr_in *sin = (struct sockaddr_in *) addr; 2639c8f6a362SSean Hefty struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr; 2640c8f6a362SSean Hefty 2641c8f6a362SSean Hefty if (cma_any_addr(addr)) { 2642c8f6a362SSean Hefty memset(mgid, 0, sizeof *mgid); 2643c8f6a362SSean Hefty } else if ((addr->sa_family == AF_INET6) && 2644c8f6a362SSean Hefty ((be32_to_cpu(sin6->sin6_addr.s6_addr32[0]) & 0xFF10A01B) == 2645c8f6a362SSean Hefty 0xFF10A01B)) { 2646c8f6a362SSean Hefty /* IPv6 address is an SA assigned MGID. */ 2647c8f6a362SSean Hefty memcpy(mgid, &sin6->sin6_addr, sizeof *mgid); 2648c8f6a362SSean Hefty } else { 2649a9e527e3SRolf Manderscheid ip_ib_mc_map(sin->sin_addr.s_addr, dev_addr->broadcast, mc_map); 2650c8f6a362SSean Hefty if (id_priv->id.ps == RDMA_PS_UDP) 2651c8f6a362SSean Hefty mc_map[7] = 0x01; /* Use RDMA CM signature */ 2652c8f6a362SSean Hefty *mgid = *(union ib_gid *) (mc_map + 4); 2653c8f6a362SSean Hefty } 2654c8f6a362SSean Hefty } 2655c8f6a362SSean Hefty 2656c8f6a362SSean Hefty static int cma_join_ib_multicast(struct rdma_id_private *id_priv, 2657c8f6a362SSean Hefty struct cma_multicast *mc) 2658c8f6a362SSean Hefty { 2659c8f6a362SSean Hefty struct ib_sa_mcmember_rec rec; 2660c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 2661c8f6a362SSean Hefty ib_sa_comp_mask comp_mask; 2662c8f6a362SSean Hefty int ret; 2663c8f6a362SSean Hefty 2664c8f6a362SSean Hefty ib_addr_get_mgid(dev_addr, &rec.mgid); 2665c8f6a362SSean Hefty ret = ib_sa_get_mcmember_rec(id_priv->id.device, id_priv->id.port_num, 2666c8f6a362SSean Hefty &rec.mgid, &rec); 2667c8f6a362SSean Hefty if (ret) 2668c8f6a362SSean Hefty return ret; 2669c8f6a362SSean Hefty 2670c8f6a362SSean Hefty cma_set_mgid(id_priv, &mc->addr, &rec.mgid); 2671c8f6a362SSean Hefty if (id_priv->id.ps == RDMA_PS_UDP) 2672c8f6a362SSean Hefty rec.qkey = cpu_to_be32(RDMA_UDP_QKEY); 2673c8f6a362SSean Hefty ib_addr_get_sgid(dev_addr, &rec.port_gid); 2674c8f6a362SSean Hefty rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr)); 2675c8f6a362SSean Hefty rec.join_state = 1; 2676c8f6a362SSean Hefty 2677c8f6a362SSean Hefty comp_mask = IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID | 2678c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_PKEY | IB_SA_MCMEMBER_REC_JOIN_STATE | 2679c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_QKEY | IB_SA_MCMEMBER_REC_SL | 2680c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_FLOW_LABEL | 2681c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_TRAFFIC_CLASS; 2682c8f6a362SSean Hefty 2683c8f6a362SSean Hefty mc->multicast.ib = ib_sa_join_multicast(&sa_client, id_priv->id.device, 2684c8f6a362SSean Hefty id_priv->id.port_num, &rec, 2685c8f6a362SSean Hefty comp_mask, GFP_KERNEL, 2686c8f6a362SSean Hefty cma_ib_mc_handler, mc); 2687c8f6a362SSean Hefty if (IS_ERR(mc->multicast.ib)) 2688c8f6a362SSean Hefty return PTR_ERR(mc->multicast.ib); 2689c8f6a362SSean Hefty 2690c8f6a362SSean Hefty return 0; 2691c8f6a362SSean Hefty } 2692c8f6a362SSean Hefty 2693c8f6a362SSean Hefty int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, 2694c8f6a362SSean Hefty void *context) 2695c8f6a362SSean Hefty { 2696c8f6a362SSean Hefty struct rdma_id_private *id_priv; 2697c8f6a362SSean Hefty struct cma_multicast *mc; 2698c8f6a362SSean Hefty int ret; 2699c8f6a362SSean Hefty 2700c8f6a362SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2701c8f6a362SSean Hefty if (!cma_comp(id_priv, CMA_ADDR_BOUND) && 2702c8f6a362SSean Hefty !cma_comp(id_priv, CMA_ADDR_RESOLVED)) 2703c8f6a362SSean Hefty return -EINVAL; 2704c8f6a362SSean Hefty 2705c8f6a362SSean Hefty mc = kmalloc(sizeof *mc, GFP_KERNEL); 2706c8f6a362SSean Hefty if (!mc) 2707c8f6a362SSean Hefty return -ENOMEM; 2708c8f6a362SSean Hefty 2709c8f6a362SSean Hefty memcpy(&mc->addr, addr, ip_addr_size(addr)); 2710c8f6a362SSean Hefty mc->context = context; 2711c8f6a362SSean Hefty mc->id_priv = id_priv; 2712c8f6a362SSean Hefty 2713c8f6a362SSean Hefty spin_lock(&id_priv->lock); 2714c8f6a362SSean Hefty list_add(&mc->list, &id_priv->mc_list); 2715c8f6a362SSean Hefty spin_unlock(&id_priv->lock); 2716c8f6a362SSean Hefty 2717c8f6a362SSean Hefty switch (rdma_node_get_transport(id->device->node_type)) { 2718c8f6a362SSean Hefty case RDMA_TRANSPORT_IB: 2719c8f6a362SSean Hefty ret = cma_join_ib_multicast(id_priv, mc); 2720c8f6a362SSean Hefty break; 2721c8f6a362SSean Hefty default: 2722c8f6a362SSean Hefty ret = -ENOSYS; 2723c8f6a362SSean Hefty break; 2724c8f6a362SSean Hefty } 2725c8f6a362SSean Hefty 2726c8f6a362SSean Hefty if (ret) { 2727c8f6a362SSean Hefty spin_lock_irq(&id_priv->lock); 2728c8f6a362SSean Hefty list_del(&mc->list); 2729c8f6a362SSean Hefty spin_unlock_irq(&id_priv->lock); 2730c8f6a362SSean Hefty kfree(mc); 2731c8f6a362SSean Hefty } 2732c8f6a362SSean Hefty return ret; 2733c8f6a362SSean Hefty } 2734c8f6a362SSean Hefty EXPORT_SYMBOL(rdma_join_multicast); 2735c8f6a362SSean Hefty 2736c8f6a362SSean Hefty void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr) 2737c8f6a362SSean Hefty { 2738c8f6a362SSean Hefty struct rdma_id_private *id_priv; 2739c8f6a362SSean Hefty struct cma_multicast *mc; 2740c8f6a362SSean Hefty 2741c8f6a362SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2742c8f6a362SSean Hefty spin_lock_irq(&id_priv->lock); 2743c8f6a362SSean Hefty list_for_each_entry(mc, &id_priv->mc_list, list) { 2744c8f6a362SSean Hefty if (!memcmp(&mc->addr, addr, ip_addr_size(addr))) { 2745c8f6a362SSean Hefty list_del(&mc->list); 2746c8f6a362SSean Hefty spin_unlock_irq(&id_priv->lock); 2747c8f6a362SSean Hefty 2748c8f6a362SSean Hefty if (id->qp) 2749c8f6a362SSean Hefty ib_detach_mcast(id->qp, 2750c8f6a362SSean Hefty &mc->multicast.ib->rec.mgid, 2751c8f6a362SSean Hefty mc->multicast.ib->rec.mlid); 2752c8f6a362SSean Hefty ib_sa_free_multicast(mc->multicast.ib); 2753c8f6a362SSean Hefty kfree(mc); 2754c8f6a362SSean Hefty return; 2755c8f6a362SSean Hefty } 2756c8f6a362SSean Hefty } 2757c8f6a362SSean Hefty spin_unlock_irq(&id_priv->lock); 2758c8f6a362SSean Hefty } 2759c8f6a362SSean Hefty EXPORT_SYMBOL(rdma_leave_multicast); 2760c8f6a362SSean Hefty 2761dd5bdff8SOr Gerlitz static int cma_netdev_change(struct net_device *ndev, struct rdma_id_private *id_priv) 2762dd5bdff8SOr Gerlitz { 2763dd5bdff8SOr Gerlitz struct rdma_dev_addr *dev_addr; 2764dd5bdff8SOr Gerlitz struct cma_ndev_work *work; 2765dd5bdff8SOr Gerlitz 2766dd5bdff8SOr Gerlitz dev_addr = &id_priv->id.route.addr.dev_addr; 2767dd5bdff8SOr Gerlitz 2768dd5bdff8SOr Gerlitz if ((dev_addr->src_dev == ndev) && 2769dd5bdff8SOr Gerlitz memcmp(dev_addr->src_dev_addr, ndev->dev_addr, ndev->addr_len)) { 2770dd5bdff8SOr Gerlitz printk(KERN_INFO "RDMA CM addr change for ndev %s used by id %p\n", 2771dd5bdff8SOr Gerlitz ndev->name, &id_priv->id); 2772dd5bdff8SOr Gerlitz work = kzalloc(sizeof *work, GFP_KERNEL); 2773dd5bdff8SOr Gerlitz if (!work) 2774dd5bdff8SOr Gerlitz return -ENOMEM; 2775dd5bdff8SOr Gerlitz 2776dd5bdff8SOr Gerlitz INIT_WORK(&work->work, cma_ndev_work_handler); 2777dd5bdff8SOr Gerlitz work->id = id_priv; 2778dd5bdff8SOr Gerlitz work->event.event = RDMA_CM_EVENT_ADDR_CHANGE; 2779dd5bdff8SOr Gerlitz atomic_inc(&id_priv->refcount); 2780dd5bdff8SOr Gerlitz queue_work(cma_wq, &work->work); 2781dd5bdff8SOr Gerlitz } 2782dd5bdff8SOr Gerlitz 2783dd5bdff8SOr Gerlitz return 0; 2784dd5bdff8SOr Gerlitz } 2785dd5bdff8SOr Gerlitz 2786dd5bdff8SOr Gerlitz static int cma_netdev_callback(struct notifier_block *self, unsigned long event, 2787dd5bdff8SOr Gerlitz void *ctx) 2788dd5bdff8SOr Gerlitz { 2789dd5bdff8SOr Gerlitz struct net_device *ndev = (struct net_device *)ctx; 2790dd5bdff8SOr Gerlitz struct cma_device *cma_dev; 2791dd5bdff8SOr Gerlitz struct rdma_id_private *id_priv; 2792dd5bdff8SOr Gerlitz int ret = NOTIFY_DONE; 2793dd5bdff8SOr Gerlitz 2794dd5bdff8SOr Gerlitz if (dev_net(ndev) != &init_net) 2795dd5bdff8SOr Gerlitz return NOTIFY_DONE; 2796dd5bdff8SOr Gerlitz 2797dd5bdff8SOr Gerlitz if (event != NETDEV_BONDING_FAILOVER) 2798dd5bdff8SOr Gerlitz return NOTIFY_DONE; 2799dd5bdff8SOr Gerlitz 2800dd5bdff8SOr Gerlitz if (!(ndev->flags & IFF_MASTER) || !(ndev->priv_flags & IFF_BONDING)) 2801dd5bdff8SOr Gerlitz return NOTIFY_DONE; 2802dd5bdff8SOr Gerlitz 2803dd5bdff8SOr Gerlitz mutex_lock(&lock); 2804dd5bdff8SOr Gerlitz list_for_each_entry(cma_dev, &dev_list, list) 2805dd5bdff8SOr Gerlitz list_for_each_entry(id_priv, &cma_dev->id_list, list) { 2806dd5bdff8SOr Gerlitz ret = cma_netdev_change(ndev, id_priv); 2807dd5bdff8SOr Gerlitz if (ret) 2808dd5bdff8SOr Gerlitz goto out; 2809dd5bdff8SOr Gerlitz } 2810dd5bdff8SOr Gerlitz 2811dd5bdff8SOr Gerlitz out: 2812dd5bdff8SOr Gerlitz mutex_unlock(&lock); 2813dd5bdff8SOr Gerlitz return ret; 2814dd5bdff8SOr Gerlitz } 2815dd5bdff8SOr Gerlitz 2816dd5bdff8SOr Gerlitz static struct notifier_block cma_nb = { 2817dd5bdff8SOr Gerlitz .notifier_call = cma_netdev_callback 2818dd5bdff8SOr Gerlitz }; 2819dd5bdff8SOr Gerlitz 2820e51060f0SSean Hefty static void cma_add_one(struct ib_device *device) 2821e51060f0SSean Hefty { 2822e51060f0SSean Hefty struct cma_device *cma_dev; 2823e51060f0SSean Hefty struct rdma_id_private *id_priv; 2824e51060f0SSean Hefty 2825e51060f0SSean Hefty cma_dev = kmalloc(sizeof *cma_dev, GFP_KERNEL); 2826e51060f0SSean Hefty if (!cma_dev) 2827e51060f0SSean Hefty return; 2828e51060f0SSean Hefty 2829e51060f0SSean Hefty cma_dev->device = device; 2830e51060f0SSean Hefty 2831e51060f0SSean Hefty init_completion(&cma_dev->comp); 2832e51060f0SSean Hefty atomic_set(&cma_dev->refcount, 1); 2833e51060f0SSean Hefty INIT_LIST_HEAD(&cma_dev->id_list); 2834e51060f0SSean Hefty ib_set_client_data(device, &cma_client, cma_dev); 2835e51060f0SSean Hefty 2836e51060f0SSean Hefty mutex_lock(&lock); 2837e51060f0SSean Hefty list_add_tail(&cma_dev->list, &dev_list); 2838e51060f0SSean Hefty list_for_each_entry(id_priv, &listen_any_list, list) 2839e51060f0SSean Hefty cma_listen_on_dev(id_priv, cma_dev); 2840e51060f0SSean Hefty mutex_unlock(&lock); 2841e51060f0SSean Hefty } 2842e51060f0SSean Hefty 2843e51060f0SSean Hefty static int cma_remove_id_dev(struct rdma_id_private *id_priv) 2844e51060f0SSean Hefty { 2845a1b1b61fSSean Hefty struct rdma_cm_event event; 2846e51060f0SSean Hefty enum cma_state state; 2847de910bd9SOr Gerlitz int ret = 0; 2848e51060f0SSean Hefty 2849e51060f0SSean Hefty /* Record that we want to remove the device */ 2850e51060f0SSean Hefty state = cma_exch(id_priv, CMA_DEVICE_REMOVAL); 2851e51060f0SSean Hefty if (state == CMA_DESTROYING) 2852e51060f0SSean Hefty return 0; 2853e51060f0SSean Hefty 2854e51060f0SSean Hefty cma_cancel_operation(id_priv, state); 2855de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 2856e51060f0SSean Hefty 2857e51060f0SSean Hefty /* Check for destruction from another callback. */ 2858e51060f0SSean Hefty if (!cma_comp(id_priv, CMA_DEVICE_REMOVAL)) 2859de910bd9SOr Gerlitz goto out; 2860e51060f0SSean Hefty 2861a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 2862a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DEVICE_REMOVAL; 2863de910bd9SOr Gerlitz ret = id_priv->id.event_handler(&id_priv->id, &event); 2864de910bd9SOr Gerlitz out: 2865de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2866de910bd9SOr Gerlitz return ret; 2867e51060f0SSean Hefty } 2868e51060f0SSean Hefty 2869e51060f0SSean Hefty static void cma_process_remove(struct cma_device *cma_dev) 2870e51060f0SSean Hefty { 2871e51060f0SSean Hefty struct rdma_id_private *id_priv; 2872e51060f0SSean Hefty int ret; 2873e51060f0SSean Hefty 2874e51060f0SSean Hefty mutex_lock(&lock); 2875e51060f0SSean Hefty while (!list_empty(&cma_dev->id_list)) { 2876e51060f0SSean Hefty id_priv = list_entry(cma_dev->id_list.next, 2877e51060f0SSean Hefty struct rdma_id_private, list); 2878e51060f0SSean Hefty 2879d02d1f53SSean Hefty list_del(&id_priv->listen_list); 288094de178aSKrishna Kumar list_del_init(&id_priv->list); 2881e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 2882e51060f0SSean Hefty mutex_unlock(&lock); 2883e51060f0SSean Hefty 2884d02d1f53SSean Hefty ret = id_priv->internal_id ? 1 : cma_remove_id_dev(id_priv); 2885e51060f0SSean Hefty cma_deref_id(id_priv); 2886e51060f0SSean Hefty if (ret) 2887e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 2888e51060f0SSean Hefty 2889e51060f0SSean Hefty mutex_lock(&lock); 2890e51060f0SSean Hefty } 2891e51060f0SSean Hefty mutex_unlock(&lock); 2892e51060f0SSean Hefty 2893e51060f0SSean Hefty cma_deref_dev(cma_dev); 2894e51060f0SSean Hefty wait_for_completion(&cma_dev->comp); 2895e51060f0SSean Hefty } 2896e51060f0SSean Hefty 2897e51060f0SSean Hefty static void cma_remove_one(struct ib_device *device) 2898e51060f0SSean Hefty { 2899e51060f0SSean Hefty struct cma_device *cma_dev; 2900e51060f0SSean Hefty 2901e51060f0SSean Hefty cma_dev = ib_get_client_data(device, &cma_client); 2902e51060f0SSean Hefty if (!cma_dev) 2903e51060f0SSean Hefty return; 2904e51060f0SSean Hefty 2905e51060f0SSean Hefty mutex_lock(&lock); 2906e51060f0SSean Hefty list_del(&cma_dev->list); 2907e51060f0SSean Hefty mutex_unlock(&lock); 2908e51060f0SSean Hefty 2909e51060f0SSean Hefty cma_process_remove(cma_dev); 2910e51060f0SSean Hefty kfree(cma_dev); 2911e51060f0SSean Hefty } 2912e51060f0SSean Hefty 2913e51060f0SSean Hefty static int cma_init(void) 2914e51060f0SSean Hefty { 2915a25de534SAnton Arapov int ret, low, high, remaining; 2916e51060f0SSean Hefty 2917aedec080SSean Hefty get_random_bytes(&next_port, sizeof next_port); 2918227b60f5SStephen Hemminger inet_get_local_port_range(&low, &high); 2919a25de534SAnton Arapov remaining = (high - low) + 1; 2920a25de534SAnton Arapov next_port = ((unsigned int) next_port % remaining) + low; 2921227b60f5SStephen Hemminger 2922c7f743a6SSean Hefty cma_wq = create_singlethread_workqueue("rdma_cm"); 2923e51060f0SSean Hefty if (!cma_wq) 2924e51060f0SSean Hefty return -ENOMEM; 2925e51060f0SSean Hefty 2926c1a0b23bSMichael S. Tsirkin ib_sa_register_client(&sa_client); 29277a118df3SSean Hefty rdma_addr_register_client(&addr_client); 2928dd5bdff8SOr Gerlitz register_netdevice_notifier(&cma_nb); 2929c1a0b23bSMichael S. Tsirkin 2930e51060f0SSean Hefty ret = ib_register_client(&cma_client); 2931e51060f0SSean Hefty if (ret) 2932e51060f0SSean Hefty goto err; 2933e51060f0SSean Hefty return 0; 2934e51060f0SSean Hefty 2935e51060f0SSean Hefty err: 2936dd5bdff8SOr Gerlitz unregister_netdevice_notifier(&cma_nb); 29377a118df3SSean Hefty rdma_addr_unregister_client(&addr_client); 2938c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&sa_client); 2939e51060f0SSean Hefty destroy_workqueue(cma_wq); 2940e51060f0SSean Hefty return ret; 2941e51060f0SSean Hefty } 2942e51060f0SSean Hefty 2943e51060f0SSean Hefty static void cma_cleanup(void) 2944e51060f0SSean Hefty { 2945e51060f0SSean Hefty ib_unregister_client(&cma_client); 2946dd5bdff8SOr Gerlitz unregister_netdevice_notifier(&cma_nb); 29477a118df3SSean Hefty rdma_addr_unregister_client(&addr_client); 2948c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&sa_client); 2949e51060f0SSean Hefty destroy_workqueue(cma_wq); 2950e51060f0SSean Hefty idr_destroy(&sdp_ps); 2951e51060f0SSean Hefty idr_destroy(&tcp_ps); 2952628e5f6dSSean Hefty idr_destroy(&udp_ps); 2953c8f6a362SSean Hefty idr_destroy(&ipoib_ps); 2954e51060f0SSean Hefty } 2955e51060f0SSean Hefty 2956e51060f0SSean Hefty module_init(cma_init); 2957e51060f0SSean Hefty module_exit(cma_cleanup); 2958