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 * 7e51060f0SSean Hefty * This Software is licensed under one of the following licenses: 8e51060f0SSean Hefty * 9e51060f0SSean Hefty * 1) under the terms of the "Common Public License 1.0" a copy of which is 10e51060f0SSean Hefty * available from the Open Source Initiative, see 11e51060f0SSean Hefty * http://www.opensource.org/licenses/cpl.php. 12e51060f0SSean Hefty * 13e51060f0SSean Hefty * 2) under the terms of the "The BSD License" a copy of which is 14e51060f0SSean Hefty * available from the Open Source Initiative, see 15e51060f0SSean Hefty * http://www.opensource.org/licenses/bsd-license.php. 16e51060f0SSean Hefty * 17e51060f0SSean Hefty * 3) under the terms of the "GNU General Public License (GPL) Version 2" a 18e51060f0SSean Hefty * copy of which is available from the Open Source Initiative, see 19e51060f0SSean Hefty * http://www.opensource.org/licenses/gpl-license.php. 20e51060f0SSean Hefty * 21e51060f0SSean Hefty * Licensee has the right to choose one of the above licenses. 22e51060f0SSean Hefty * 23e51060f0SSean Hefty * Redistributions of source code must retain the above copyright 24e51060f0SSean Hefty * notice and one of the license notices. 25e51060f0SSean Hefty * 26e51060f0SSean Hefty * Redistributions in binary form must reproduce both the above copyright 27e51060f0SSean Hefty * notice, one of the license notices in the documentation 28e51060f0SSean Hefty * and/or other materials provided with the distribution. 29e51060f0SSean Hefty * 30e51060f0SSean Hefty */ 31e51060f0SSean Hefty 32e51060f0SSean Hefty #include <linux/completion.h> 33e51060f0SSean Hefty #include <linux/in.h> 34e51060f0SSean Hefty #include <linux/in6.h> 35e51060f0SSean Hefty #include <linux/mutex.h> 36e51060f0SSean Hefty #include <linux/random.h> 37e51060f0SSean Hefty #include <linux/idr.h> 38e51060f0SSean Hefty 39e51060f0SSean Hefty #include <net/tcp.h> 40e51060f0SSean Hefty 41e51060f0SSean Hefty #include <rdma/rdma_cm.h> 42e51060f0SSean Hefty #include <rdma/rdma_cm_ib.h> 43e51060f0SSean Hefty #include <rdma/ib_cache.h> 44e51060f0SSean Hefty #include <rdma/ib_cm.h> 45e51060f0SSean Hefty #include <rdma/ib_sa.h> 46e51060f0SSean Hefty 47e51060f0SSean Hefty MODULE_AUTHOR("Sean Hefty"); 48e51060f0SSean Hefty MODULE_DESCRIPTION("Generic RDMA CM Agent"); 49e51060f0SSean Hefty MODULE_LICENSE("Dual BSD/GPL"); 50e51060f0SSean Hefty 51e51060f0SSean Hefty #define CMA_CM_RESPONSE_TIMEOUT 20 52e51060f0SSean Hefty #define CMA_MAX_CM_RETRIES 3 53e51060f0SSean Hefty 54e51060f0SSean Hefty static void cma_add_one(struct ib_device *device); 55e51060f0SSean Hefty static void cma_remove_one(struct ib_device *device); 56e51060f0SSean Hefty 57e51060f0SSean Hefty static struct ib_client cma_client = { 58e51060f0SSean Hefty .name = "cma", 59e51060f0SSean Hefty .add = cma_add_one, 60e51060f0SSean Hefty .remove = cma_remove_one 61e51060f0SSean Hefty }; 62e51060f0SSean Hefty 63e51060f0SSean Hefty static LIST_HEAD(dev_list); 64e51060f0SSean Hefty static LIST_HEAD(listen_any_list); 65e51060f0SSean Hefty static DEFINE_MUTEX(lock); 66e51060f0SSean Hefty static struct workqueue_struct *cma_wq; 67e51060f0SSean Hefty static DEFINE_IDR(sdp_ps); 68e51060f0SSean Hefty static DEFINE_IDR(tcp_ps); 69e51060f0SSean Hefty 70e51060f0SSean Hefty struct cma_device { 71e51060f0SSean Hefty struct list_head list; 72e51060f0SSean Hefty struct ib_device *device; 73e51060f0SSean Hefty __be64 node_guid; 74e51060f0SSean Hefty struct completion comp; 75e51060f0SSean Hefty atomic_t refcount; 76e51060f0SSean Hefty struct list_head id_list; 77e51060f0SSean Hefty }; 78e51060f0SSean Hefty 79e51060f0SSean Hefty enum cma_state { 80e51060f0SSean Hefty CMA_IDLE, 81e51060f0SSean Hefty CMA_ADDR_QUERY, 82e51060f0SSean Hefty CMA_ADDR_RESOLVED, 83e51060f0SSean Hefty CMA_ROUTE_QUERY, 84e51060f0SSean Hefty CMA_ROUTE_RESOLVED, 85e51060f0SSean Hefty CMA_CONNECT, 86e51060f0SSean Hefty CMA_DISCONNECT, 87e51060f0SSean Hefty CMA_ADDR_BOUND, 88e51060f0SSean Hefty CMA_LISTEN, 89e51060f0SSean Hefty CMA_DEVICE_REMOVAL, 90e51060f0SSean Hefty CMA_DESTROYING 91e51060f0SSean Hefty }; 92e51060f0SSean Hefty 93e51060f0SSean Hefty struct rdma_bind_list { 94e51060f0SSean Hefty struct idr *ps; 95e51060f0SSean Hefty struct hlist_head owners; 96e51060f0SSean Hefty unsigned short port; 97e51060f0SSean Hefty }; 98e51060f0SSean Hefty 99e51060f0SSean Hefty /* 100e51060f0SSean Hefty * Device removal can occur at anytime, so we need extra handling to 101e51060f0SSean Hefty * serialize notifying the user of device removal with other callbacks. 102e51060f0SSean Hefty * We do this by disabling removal notification while a callback is in process, 103e51060f0SSean Hefty * and reporting it after the callback completes. 104e51060f0SSean Hefty */ 105e51060f0SSean Hefty struct rdma_id_private { 106e51060f0SSean Hefty struct rdma_cm_id id; 107e51060f0SSean Hefty 108e51060f0SSean Hefty struct rdma_bind_list *bind_list; 109e51060f0SSean Hefty struct hlist_node node; 110e51060f0SSean Hefty struct list_head list; 111e51060f0SSean Hefty struct list_head listen_list; 112e51060f0SSean Hefty struct cma_device *cma_dev; 113e51060f0SSean Hefty 114e51060f0SSean Hefty enum cma_state state; 115e51060f0SSean Hefty spinlock_t lock; 116e51060f0SSean Hefty struct completion comp; 117e51060f0SSean Hefty atomic_t refcount; 118e51060f0SSean Hefty wait_queue_head_t wait_remove; 119e51060f0SSean Hefty atomic_t dev_remove; 120e51060f0SSean Hefty 121e51060f0SSean Hefty int backlog; 122e51060f0SSean Hefty int timeout_ms; 123e51060f0SSean Hefty struct ib_sa_query *query; 124e51060f0SSean Hefty int query_id; 125e51060f0SSean Hefty union { 126e51060f0SSean Hefty struct ib_cm_id *ib; 127e51060f0SSean Hefty } cm_id; 128e51060f0SSean Hefty 129e51060f0SSean Hefty u32 seq_num; 130e51060f0SSean Hefty u32 qp_num; 131e51060f0SSean Hefty enum ib_qp_type qp_type; 132e51060f0SSean Hefty u8 srq; 133e51060f0SSean Hefty }; 134e51060f0SSean Hefty 135e51060f0SSean Hefty struct cma_work { 136e51060f0SSean Hefty struct work_struct work; 137e51060f0SSean Hefty struct rdma_id_private *id; 138e51060f0SSean Hefty enum cma_state old_state; 139e51060f0SSean Hefty enum cma_state new_state; 140e51060f0SSean Hefty struct rdma_cm_event event; 141e51060f0SSean Hefty }; 142e51060f0SSean Hefty 143e51060f0SSean Hefty union cma_ip_addr { 144e51060f0SSean Hefty struct in6_addr ip6; 145e51060f0SSean Hefty struct { 146e51060f0SSean Hefty __u32 pad[3]; 147e51060f0SSean Hefty __u32 addr; 148e51060f0SSean Hefty } ip4; 149e51060f0SSean Hefty }; 150e51060f0SSean Hefty 151e51060f0SSean Hefty struct cma_hdr { 152e51060f0SSean Hefty u8 cma_version; 153e51060f0SSean Hefty u8 ip_version; /* IP version: 7:4 */ 154e51060f0SSean Hefty __u16 port; 155e51060f0SSean Hefty union cma_ip_addr src_addr; 156e51060f0SSean Hefty union cma_ip_addr dst_addr; 157e51060f0SSean Hefty }; 158e51060f0SSean Hefty 159e51060f0SSean Hefty struct sdp_hh { 160e51060f0SSean Hefty u8 bsdh[16]; 161e51060f0SSean Hefty u8 sdp_version; /* Major version: 7:4 */ 162e51060f0SSean Hefty u8 ip_version; /* IP version: 7:4 */ 163e51060f0SSean Hefty u8 sdp_specific1[10]; 164e51060f0SSean Hefty __u16 port; 165e51060f0SSean Hefty __u16 sdp_specific2; 166e51060f0SSean Hefty union cma_ip_addr src_addr; 167e51060f0SSean Hefty union cma_ip_addr dst_addr; 168e51060f0SSean Hefty }; 169e51060f0SSean Hefty 170e51060f0SSean Hefty struct sdp_hah { 171e51060f0SSean Hefty u8 bsdh[16]; 172e51060f0SSean Hefty u8 sdp_version; 173e51060f0SSean Hefty }; 174e51060f0SSean Hefty 175e51060f0SSean Hefty #define CMA_VERSION 0x00 176e51060f0SSean Hefty #define SDP_MAJ_VERSION 0x2 177e51060f0SSean Hefty 178e51060f0SSean Hefty static int cma_comp(struct rdma_id_private *id_priv, enum cma_state comp) 179e51060f0SSean Hefty { 180e51060f0SSean Hefty unsigned long flags; 181e51060f0SSean Hefty int ret; 182e51060f0SSean Hefty 183e51060f0SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 184e51060f0SSean Hefty ret = (id_priv->state == comp); 185e51060f0SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 186e51060f0SSean Hefty return ret; 187e51060f0SSean Hefty } 188e51060f0SSean Hefty 189e51060f0SSean Hefty static int cma_comp_exch(struct rdma_id_private *id_priv, 190e51060f0SSean Hefty enum cma_state comp, enum cma_state exch) 191e51060f0SSean Hefty { 192e51060f0SSean Hefty unsigned long flags; 193e51060f0SSean Hefty int ret; 194e51060f0SSean Hefty 195e51060f0SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 196e51060f0SSean Hefty if ((ret = (id_priv->state == comp))) 197e51060f0SSean Hefty id_priv->state = exch; 198e51060f0SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 199e51060f0SSean Hefty return ret; 200e51060f0SSean Hefty } 201e51060f0SSean Hefty 202e51060f0SSean Hefty static enum cma_state cma_exch(struct rdma_id_private *id_priv, 203e51060f0SSean Hefty enum cma_state exch) 204e51060f0SSean Hefty { 205e51060f0SSean Hefty unsigned long flags; 206e51060f0SSean Hefty enum cma_state old; 207e51060f0SSean Hefty 208e51060f0SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 209e51060f0SSean Hefty old = id_priv->state; 210e51060f0SSean Hefty id_priv->state = exch; 211e51060f0SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 212e51060f0SSean Hefty return old; 213e51060f0SSean Hefty } 214e51060f0SSean Hefty 215e51060f0SSean Hefty static inline u8 cma_get_ip_ver(struct cma_hdr *hdr) 216e51060f0SSean Hefty { 217e51060f0SSean Hefty return hdr->ip_version >> 4; 218e51060f0SSean Hefty } 219e51060f0SSean Hefty 220e51060f0SSean Hefty static inline void cma_set_ip_ver(struct cma_hdr *hdr, u8 ip_ver) 221e51060f0SSean Hefty { 222e51060f0SSean Hefty hdr->ip_version = (ip_ver << 4) | (hdr->ip_version & 0xF); 223e51060f0SSean Hefty } 224e51060f0SSean Hefty 225e51060f0SSean Hefty static inline u8 sdp_get_majv(u8 sdp_version) 226e51060f0SSean Hefty { 227e51060f0SSean Hefty return sdp_version >> 4; 228e51060f0SSean Hefty } 229e51060f0SSean Hefty 230e51060f0SSean Hefty static inline u8 sdp_get_ip_ver(struct sdp_hh *hh) 231e51060f0SSean Hefty { 232e51060f0SSean Hefty return hh->ip_version >> 4; 233e51060f0SSean Hefty } 234e51060f0SSean Hefty 235e51060f0SSean Hefty static inline void sdp_set_ip_ver(struct sdp_hh *hh, u8 ip_ver) 236e51060f0SSean Hefty { 237e51060f0SSean Hefty hh->ip_version = (ip_ver << 4) | (hh->ip_version & 0xF); 238e51060f0SSean Hefty } 239e51060f0SSean Hefty 240e51060f0SSean Hefty static void cma_attach_to_dev(struct rdma_id_private *id_priv, 241e51060f0SSean Hefty struct cma_device *cma_dev) 242e51060f0SSean Hefty { 243e51060f0SSean Hefty atomic_inc(&cma_dev->refcount); 244e51060f0SSean Hefty id_priv->cma_dev = cma_dev; 245e51060f0SSean Hefty id_priv->id.device = cma_dev->device; 246e51060f0SSean Hefty list_add_tail(&id_priv->list, &cma_dev->id_list); 247e51060f0SSean Hefty } 248e51060f0SSean Hefty 249e51060f0SSean Hefty static inline void cma_deref_dev(struct cma_device *cma_dev) 250e51060f0SSean Hefty { 251e51060f0SSean Hefty if (atomic_dec_and_test(&cma_dev->refcount)) 252e51060f0SSean Hefty complete(&cma_dev->comp); 253e51060f0SSean Hefty } 254e51060f0SSean Hefty 255e51060f0SSean Hefty static void cma_detach_from_dev(struct rdma_id_private *id_priv) 256e51060f0SSean Hefty { 257e51060f0SSean Hefty list_del(&id_priv->list); 258e51060f0SSean Hefty cma_deref_dev(id_priv->cma_dev); 259e51060f0SSean Hefty id_priv->cma_dev = NULL; 260e51060f0SSean Hefty } 261e51060f0SSean Hefty 262e51060f0SSean Hefty static int cma_acquire_ib_dev(struct rdma_id_private *id_priv) 263e51060f0SSean Hefty { 264e51060f0SSean Hefty struct cma_device *cma_dev; 265e51060f0SSean Hefty union ib_gid *gid; 266e51060f0SSean Hefty int ret = -ENODEV; 267e51060f0SSean Hefty 268e51060f0SSean Hefty gid = ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr); 269e51060f0SSean Hefty 270e51060f0SSean Hefty mutex_lock(&lock); 271e51060f0SSean Hefty list_for_each_entry(cma_dev, &dev_list, list) { 272e51060f0SSean Hefty ret = ib_find_cached_gid(cma_dev->device, gid, 273e51060f0SSean Hefty &id_priv->id.port_num, NULL); 274e51060f0SSean Hefty if (!ret) { 275e51060f0SSean Hefty cma_attach_to_dev(id_priv, cma_dev); 276e51060f0SSean Hefty break; 277e51060f0SSean Hefty } 278e51060f0SSean Hefty } 279e51060f0SSean Hefty mutex_unlock(&lock); 280e51060f0SSean Hefty return ret; 281e51060f0SSean Hefty } 282e51060f0SSean Hefty 283e51060f0SSean Hefty static int cma_acquire_dev(struct rdma_id_private *id_priv) 284e51060f0SSean Hefty { 285e51060f0SSean Hefty switch (id_priv->id.route.addr.dev_addr.dev_type) { 286e51060f0SSean Hefty case IB_NODE_CA: 287e51060f0SSean Hefty return cma_acquire_ib_dev(id_priv); 288e51060f0SSean Hefty default: 289e51060f0SSean Hefty return -ENODEV; 290e51060f0SSean Hefty } 291e51060f0SSean Hefty } 292e51060f0SSean Hefty 293e51060f0SSean Hefty static void cma_deref_id(struct rdma_id_private *id_priv) 294e51060f0SSean Hefty { 295e51060f0SSean Hefty if (atomic_dec_and_test(&id_priv->refcount)) 296e51060f0SSean Hefty complete(&id_priv->comp); 297e51060f0SSean Hefty } 298e51060f0SSean Hefty 299e51060f0SSean Hefty static void cma_release_remove(struct rdma_id_private *id_priv) 300e51060f0SSean Hefty { 301e51060f0SSean Hefty if (atomic_dec_and_test(&id_priv->dev_remove)) 302e51060f0SSean Hefty wake_up(&id_priv->wait_remove); 303e51060f0SSean Hefty } 304e51060f0SSean Hefty 305e51060f0SSean Hefty struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler, 306e51060f0SSean Hefty void *context, enum rdma_port_space ps) 307e51060f0SSean Hefty { 308e51060f0SSean Hefty struct rdma_id_private *id_priv; 309e51060f0SSean Hefty 310e51060f0SSean Hefty id_priv = kzalloc(sizeof *id_priv, GFP_KERNEL); 311e51060f0SSean Hefty if (!id_priv) 312e51060f0SSean Hefty return ERR_PTR(-ENOMEM); 313e51060f0SSean Hefty 314e51060f0SSean Hefty id_priv->state = CMA_IDLE; 315e51060f0SSean Hefty id_priv->id.context = context; 316e51060f0SSean Hefty id_priv->id.event_handler = event_handler; 317e51060f0SSean Hefty id_priv->id.ps = ps; 318e51060f0SSean Hefty spin_lock_init(&id_priv->lock); 319e51060f0SSean Hefty init_completion(&id_priv->comp); 320e51060f0SSean Hefty atomic_set(&id_priv->refcount, 1); 321e51060f0SSean Hefty init_waitqueue_head(&id_priv->wait_remove); 322e51060f0SSean Hefty atomic_set(&id_priv->dev_remove, 0); 323e51060f0SSean Hefty INIT_LIST_HEAD(&id_priv->listen_list); 324e51060f0SSean Hefty get_random_bytes(&id_priv->seq_num, sizeof id_priv->seq_num); 325e51060f0SSean Hefty 326e51060f0SSean Hefty return &id_priv->id; 327e51060f0SSean Hefty } 328e51060f0SSean Hefty EXPORT_SYMBOL(rdma_create_id); 329e51060f0SSean Hefty 330e51060f0SSean Hefty static int cma_init_ib_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) 331e51060f0SSean Hefty { 332e51060f0SSean Hefty struct ib_qp_attr qp_attr; 333e51060f0SSean Hefty struct rdma_dev_addr *dev_addr; 334e51060f0SSean Hefty int ret; 335e51060f0SSean Hefty 336e51060f0SSean Hefty dev_addr = &id_priv->id.route.addr.dev_addr; 337e51060f0SSean Hefty ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num, 338e51060f0SSean Hefty ib_addr_get_pkey(dev_addr), 339e51060f0SSean Hefty &qp_attr.pkey_index); 340e51060f0SSean Hefty if (ret) 341e51060f0SSean Hefty return ret; 342e51060f0SSean Hefty 343e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_INIT; 344e51060f0SSean Hefty qp_attr.qp_access_flags = IB_ACCESS_LOCAL_WRITE; 345e51060f0SSean Hefty qp_attr.port_num = id_priv->id.port_num; 346e51060f0SSean Hefty return ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_ACCESS_FLAGS | 347e51060f0SSean Hefty IB_QP_PKEY_INDEX | IB_QP_PORT); 348e51060f0SSean Hefty } 349e51060f0SSean Hefty 350e51060f0SSean Hefty int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd, 351e51060f0SSean Hefty struct ib_qp_init_attr *qp_init_attr) 352e51060f0SSean Hefty { 353e51060f0SSean Hefty struct rdma_id_private *id_priv; 354e51060f0SSean Hefty struct ib_qp *qp; 355e51060f0SSean Hefty int ret; 356e51060f0SSean Hefty 357e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 358e51060f0SSean Hefty if (id->device != pd->device) 359e51060f0SSean Hefty return -EINVAL; 360e51060f0SSean Hefty 361e51060f0SSean Hefty qp = ib_create_qp(pd, qp_init_attr); 362e51060f0SSean Hefty if (IS_ERR(qp)) 363e51060f0SSean Hefty return PTR_ERR(qp); 364e51060f0SSean Hefty 365e51060f0SSean Hefty switch (id->device->node_type) { 366e51060f0SSean Hefty case IB_NODE_CA: 367e51060f0SSean Hefty ret = cma_init_ib_qp(id_priv, qp); 368e51060f0SSean Hefty break; 369e51060f0SSean Hefty default: 370e51060f0SSean Hefty ret = -ENOSYS; 371e51060f0SSean Hefty break; 372e51060f0SSean Hefty } 373e51060f0SSean Hefty 374e51060f0SSean Hefty if (ret) 375e51060f0SSean Hefty goto err; 376e51060f0SSean Hefty 377e51060f0SSean Hefty id->qp = qp; 378e51060f0SSean Hefty id_priv->qp_num = qp->qp_num; 379e51060f0SSean Hefty id_priv->qp_type = qp->qp_type; 380e51060f0SSean Hefty id_priv->srq = (qp->srq != NULL); 381e51060f0SSean Hefty return 0; 382e51060f0SSean Hefty err: 383e51060f0SSean Hefty ib_destroy_qp(qp); 384e51060f0SSean Hefty return ret; 385e51060f0SSean Hefty } 386e51060f0SSean Hefty EXPORT_SYMBOL(rdma_create_qp); 387e51060f0SSean Hefty 388e51060f0SSean Hefty void rdma_destroy_qp(struct rdma_cm_id *id) 389e51060f0SSean Hefty { 390e51060f0SSean Hefty ib_destroy_qp(id->qp); 391e51060f0SSean Hefty } 392e51060f0SSean Hefty EXPORT_SYMBOL(rdma_destroy_qp); 393e51060f0SSean Hefty 394e51060f0SSean Hefty static int cma_modify_qp_rtr(struct rdma_cm_id *id) 395e51060f0SSean Hefty { 396e51060f0SSean Hefty struct ib_qp_attr qp_attr; 397e51060f0SSean Hefty int qp_attr_mask, ret; 398e51060f0SSean Hefty 399e51060f0SSean Hefty if (!id->qp) 400e51060f0SSean Hefty return 0; 401e51060f0SSean Hefty 402e51060f0SSean Hefty /* Need to update QP attributes from default values. */ 403e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_INIT; 404e51060f0SSean Hefty ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask); 405e51060f0SSean Hefty if (ret) 406e51060f0SSean Hefty return ret; 407e51060f0SSean Hefty 408e51060f0SSean Hefty ret = ib_modify_qp(id->qp, &qp_attr, qp_attr_mask); 409e51060f0SSean Hefty if (ret) 410e51060f0SSean Hefty return ret; 411e51060f0SSean Hefty 412e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_RTR; 413e51060f0SSean Hefty ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask); 414e51060f0SSean Hefty if (ret) 415e51060f0SSean Hefty return ret; 416e51060f0SSean Hefty 417e51060f0SSean Hefty return ib_modify_qp(id->qp, &qp_attr, qp_attr_mask); 418e51060f0SSean Hefty } 419e51060f0SSean Hefty 420e51060f0SSean Hefty static int cma_modify_qp_rts(struct rdma_cm_id *id) 421e51060f0SSean Hefty { 422e51060f0SSean Hefty struct ib_qp_attr qp_attr; 423e51060f0SSean Hefty int qp_attr_mask, ret; 424e51060f0SSean Hefty 425e51060f0SSean Hefty if (!id->qp) 426e51060f0SSean Hefty return 0; 427e51060f0SSean Hefty 428e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_RTS; 429e51060f0SSean Hefty ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask); 430e51060f0SSean Hefty if (ret) 431e51060f0SSean Hefty return ret; 432e51060f0SSean Hefty 433e51060f0SSean Hefty return ib_modify_qp(id->qp, &qp_attr, qp_attr_mask); 434e51060f0SSean Hefty } 435e51060f0SSean Hefty 436e51060f0SSean Hefty static int cma_modify_qp_err(struct rdma_cm_id *id) 437e51060f0SSean Hefty { 438e51060f0SSean Hefty struct ib_qp_attr qp_attr; 439e51060f0SSean Hefty 440e51060f0SSean Hefty if (!id->qp) 441e51060f0SSean Hefty return 0; 442e51060f0SSean Hefty 443e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_ERR; 444e51060f0SSean Hefty return ib_modify_qp(id->qp, &qp_attr, IB_QP_STATE); 445e51060f0SSean Hefty } 446e51060f0SSean Hefty 447e51060f0SSean Hefty int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr, 448e51060f0SSean Hefty int *qp_attr_mask) 449e51060f0SSean Hefty { 450e51060f0SSean Hefty struct rdma_id_private *id_priv; 451e51060f0SSean Hefty int ret; 452e51060f0SSean Hefty 453e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 454e51060f0SSean Hefty switch (id_priv->id.device->node_type) { 455e51060f0SSean Hefty case IB_NODE_CA: 456e51060f0SSean Hefty ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr, 457e51060f0SSean Hefty qp_attr_mask); 458e51060f0SSean Hefty if (qp_attr->qp_state == IB_QPS_RTR) 459e51060f0SSean Hefty qp_attr->rq_psn = id_priv->seq_num; 460e51060f0SSean Hefty break; 461e51060f0SSean Hefty default: 462e51060f0SSean Hefty ret = -ENOSYS; 463e51060f0SSean Hefty break; 464e51060f0SSean Hefty } 465e51060f0SSean Hefty 466e51060f0SSean Hefty return ret; 467e51060f0SSean Hefty } 468e51060f0SSean Hefty EXPORT_SYMBOL(rdma_init_qp_attr); 469e51060f0SSean Hefty 470e51060f0SSean Hefty static inline int cma_zero_addr(struct sockaddr *addr) 471e51060f0SSean Hefty { 472e51060f0SSean Hefty struct in6_addr *ip6; 473e51060f0SSean Hefty 474e51060f0SSean Hefty if (addr->sa_family == AF_INET) 475e51060f0SSean Hefty return ZERONET(((struct sockaddr_in *) addr)->sin_addr.s_addr); 476e51060f0SSean Hefty else { 477e51060f0SSean Hefty ip6 = &((struct sockaddr_in6 *) addr)->sin6_addr; 478e51060f0SSean Hefty return (ip6->s6_addr32[0] | ip6->s6_addr32[1] | 479*5fd571cbSEric Sesterhenn ip6->s6_addr32[2] | ip6->s6_addr32[3]) == 0; 480e51060f0SSean Hefty } 481e51060f0SSean Hefty } 482e51060f0SSean Hefty 483e51060f0SSean Hefty static inline int cma_loopback_addr(struct sockaddr *addr) 484e51060f0SSean Hefty { 485e51060f0SSean Hefty return LOOPBACK(((struct sockaddr_in *) addr)->sin_addr.s_addr); 486e51060f0SSean Hefty } 487e51060f0SSean Hefty 488e51060f0SSean Hefty static inline int cma_any_addr(struct sockaddr *addr) 489e51060f0SSean Hefty { 490e51060f0SSean Hefty return cma_zero_addr(addr) || cma_loopback_addr(addr); 491e51060f0SSean Hefty } 492e51060f0SSean Hefty 493e51060f0SSean Hefty static inline int cma_any_port(struct sockaddr *addr) 494e51060f0SSean Hefty { 495e51060f0SSean Hefty return !((struct sockaddr_in *) addr)->sin_port; 496e51060f0SSean Hefty } 497e51060f0SSean Hefty 498e51060f0SSean Hefty static int cma_get_net_info(void *hdr, enum rdma_port_space ps, 499e51060f0SSean Hefty u8 *ip_ver, __u16 *port, 500e51060f0SSean Hefty union cma_ip_addr **src, union cma_ip_addr **dst) 501e51060f0SSean Hefty { 502e51060f0SSean Hefty switch (ps) { 503e51060f0SSean Hefty case RDMA_PS_SDP: 504e51060f0SSean Hefty if (sdp_get_majv(((struct sdp_hh *) hdr)->sdp_version) != 505e51060f0SSean Hefty SDP_MAJ_VERSION) 506e51060f0SSean Hefty return -EINVAL; 507e51060f0SSean Hefty 508e51060f0SSean Hefty *ip_ver = sdp_get_ip_ver(hdr); 509e51060f0SSean Hefty *port = ((struct sdp_hh *) hdr)->port; 510e51060f0SSean Hefty *src = &((struct sdp_hh *) hdr)->src_addr; 511e51060f0SSean Hefty *dst = &((struct sdp_hh *) hdr)->dst_addr; 512e51060f0SSean Hefty break; 513e51060f0SSean Hefty default: 514e51060f0SSean Hefty if (((struct cma_hdr *) hdr)->cma_version != CMA_VERSION) 515e51060f0SSean Hefty return -EINVAL; 516e51060f0SSean Hefty 517e51060f0SSean Hefty *ip_ver = cma_get_ip_ver(hdr); 518e51060f0SSean Hefty *port = ((struct cma_hdr *) hdr)->port; 519e51060f0SSean Hefty *src = &((struct cma_hdr *) hdr)->src_addr; 520e51060f0SSean Hefty *dst = &((struct cma_hdr *) hdr)->dst_addr; 521e51060f0SSean Hefty break; 522e51060f0SSean Hefty } 523e51060f0SSean Hefty 524e51060f0SSean Hefty if (*ip_ver != 4 && *ip_ver != 6) 525e51060f0SSean Hefty return -EINVAL; 526e51060f0SSean Hefty return 0; 527e51060f0SSean Hefty } 528e51060f0SSean Hefty 529e51060f0SSean Hefty static void cma_save_net_info(struct rdma_addr *addr, 530e51060f0SSean Hefty struct rdma_addr *listen_addr, 531e51060f0SSean Hefty u8 ip_ver, __u16 port, 532e51060f0SSean Hefty union cma_ip_addr *src, union cma_ip_addr *dst) 533e51060f0SSean Hefty { 534e51060f0SSean Hefty struct sockaddr_in *listen4, *ip4; 535e51060f0SSean Hefty struct sockaddr_in6 *listen6, *ip6; 536e51060f0SSean Hefty 537e51060f0SSean Hefty switch (ip_ver) { 538e51060f0SSean Hefty case 4: 539e51060f0SSean Hefty listen4 = (struct sockaddr_in *) &listen_addr->src_addr; 540e51060f0SSean Hefty ip4 = (struct sockaddr_in *) &addr->src_addr; 541e51060f0SSean Hefty ip4->sin_family = listen4->sin_family; 542e51060f0SSean Hefty ip4->sin_addr.s_addr = dst->ip4.addr; 543e51060f0SSean Hefty ip4->sin_port = listen4->sin_port; 544e51060f0SSean Hefty 545e51060f0SSean Hefty ip4 = (struct sockaddr_in *) &addr->dst_addr; 546e51060f0SSean Hefty ip4->sin_family = listen4->sin_family; 547e51060f0SSean Hefty ip4->sin_addr.s_addr = src->ip4.addr; 548e51060f0SSean Hefty ip4->sin_port = port; 549e51060f0SSean Hefty break; 550e51060f0SSean Hefty case 6: 551e51060f0SSean Hefty listen6 = (struct sockaddr_in6 *) &listen_addr->src_addr; 552e51060f0SSean Hefty ip6 = (struct sockaddr_in6 *) &addr->src_addr; 553e51060f0SSean Hefty ip6->sin6_family = listen6->sin6_family; 554e51060f0SSean Hefty ip6->sin6_addr = dst->ip6; 555e51060f0SSean Hefty ip6->sin6_port = listen6->sin6_port; 556e51060f0SSean Hefty 557e51060f0SSean Hefty ip6 = (struct sockaddr_in6 *) &addr->dst_addr; 558e51060f0SSean Hefty ip6->sin6_family = listen6->sin6_family; 559e51060f0SSean Hefty ip6->sin6_addr = src->ip6; 560e51060f0SSean Hefty ip6->sin6_port = port; 561e51060f0SSean Hefty break; 562e51060f0SSean Hefty default: 563e51060f0SSean Hefty break; 564e51060f0SSean Hefty } 565e51060f0SSean Hefty } 566e51060f0SSean Hefty 567e51060f0SSean Hefty static inline int cma_user_data_offset(enum rdma_port_space ps) 568e51060f0SSean Hefty { 569e51060f0SSean Hefty switch (ps) { 570e51060f0SSean Hefty case RDMA_PS_SDP: 571e51060f0SSean Hefty return 0; 572e51060f0SSean Hefty default: 573e51060f0SSean Hefty return sizeof(struct cma_hdr); 574e51060f0SSean Hefty } 575e51060f0SSean Hefty } 576e51060f0SSean Hefty 577e51060f0SSean Hefty static int cma_notify_user(struct rdma_id_private *id_priv, 578e51060f0SSean Hefty enum rdma_cm_event_type type, int status, 579e51060f0SSean Hefty void *data, u8 data_len) 580e51060f0SSean Hefty { 581e51060f0SSean Hefty struct rdma_cm_event event; 582e51060f0SSean Hefty 583e51060f0SSean Hefty event.event = type; 584e51060f0SSean Hefty event.status = status; 585e51060f0SSean Hefty event.private_data = data; 586e51060f0SSean Hefty event.private_data_len = data_len; 587e51060f0SSean Hefty 588e51060f0SSean Hefty return id_priv->id.event_handler(&id_priv->id, &event); 589e51060f0SSean Hefty } 590e51060f0SSean Hefty 591e51060f0SSean Hefty static void cma_cancel_route(struct rdma_id_private *id_priv) 592e51060f0SSean Hefty { 593e51060f0SSean Hefty switch (id_priv->id.device->node_type) { 594e51060f0SSean Hefty case IB_NODE_CA: 595e51060f0SSean Hefty if (id_priv->query) 596e51060f0SSean Hefty ib_sa_cancel_query(id_priv->query_id, id_priv->query); 597e51060f0SSean Hefty break; 598e51060f0SSean Hefty default: 599e51060f0SSean Hefty break; 600e51060f0SSean Hefty } 601e51060f0SSean Hefty } 602e51060f0SSean Hefty 603e51060f0SSean Hefty static inline int cma_internal_listen(struct rdma_id_private *id_priv) 604e51060f0SSean Hefty { 605e51060f0SSean Hefty return (id_priv->state == CMA_LISTEN) && id_priv->cma_dev && 606e51060f0SSean Hefty cma_any_addr(&id_priv->id.route.addr.src_addr); 607e51060f0SSean Hefty } 608e51060f0SSean Hefty 609e51060f0SSean Hefty static void cma_destroy_listen(struct rdma_id_private *id_priv) 610e51060f0SSean Hefty { 611e51060f0SSean Hefty cma_exch(id_priv, CMA_DESTROYING); 612e51060f0SSean Hefty 613e51060f0SSean Hefty if (id_priv->cma_dev) { 614e51060f0SSean Hefty switch (id_priv->id.device->node_type) { 615e51060f0SSean Hefty case IB_NODE_CA: 616e51060f0SSean Hefty if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib)) 617e51060f0SSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 618e51060f0SSean Hefty break; 619e51060f0SSean Hefty default: 620e51060f0SSean Hefty break; 621e51060f0SSean Hefty } 622e51060f0SSean Hefty cma_detach_from_dev(id_priv); 623e51060f0SSean Hefty } 624e51060f0SSean Hefty list_del(&id_priv->listen_list); 625e51060f0SSean Hefty 626e51060f0SSean Hefty cma_deref_id(id_priv); 627e51060f0SSean Hefty wait_for_completion(&id_priv->comp); 628e51060f0SSean Hefty 629e51060f0SSean Hefty kfree(id_priv); 630e51060f0SSean Hefty } 631e51060f0SSean Hefty 632e51060f0SSean Hefty static void cma_cancel_listens(struct rdma_id_private *id_priv) 633e51060f0SSean Hefty { 634e51060f0SSean Hefty struct rdma_id_private *dev_id_priv; 635e51060f0SSean Hefty 636e51060f0SSean Hefty mutex_lock(&lock); 637e51060f0SSean Hefty list_del(&id_priv->list); 638e51060f0SSean Hefty 639e51060f0SSean Hefty while (!list_empty(&id_priv->listen_list)) { 640e51060f0SSean Hefty dev_id_priv = list_entry(id_priv->listen_list.next, 641e51060f0SSean Hefty struct rdma_id_private, listen_list); 642e51060f0SSean Hefty cma_destroy_listen(dev_id_priv); 643e51060f0SSean Hefty } 644e51060f0SSean Hefty mutex_unlock(&lock); 645e51060f0SSean Hefty } 646e51060f0SSean Hefty 647e51060f0SSean Hefty static void cma_cancel_operation(struct rdma_id_private *id_priv, 648e51060f0SSean Hefty enum cma_state state) 649e51060f0SSean Hefty { 650e51060f0SSean Hefty switch (state) { 651e51060f0SSean Hefty case CMA_ADDR_QUERY: 652e51060f0SSean Hefty rdma_addr_cancel(&id_priv->id.route.addr.dev_addr); 653e51060f0SSean Hefty break; 654e51060f0SSean Hefty case CMA_ROUTE_QUERY: 655e51060f0SSean Hefty cma_cancel_route(id_priv); 656e51060f0SSean Hefty break; 657e51060f0SSean Hefty case CMA_LISTEN: 658e51060f0SSean Hefty if (cma_any_addr(&id_priv->id.route.addr.src_addr) && 659e51060f0SSean Hefty !id_priv->cma_dev) 660e51060f0SSean Hefty cma_cancel_listens(id_priv); 661e51060f0SSean Hefty break; 662e51060f0SSean Hefty default: 663e51060f0SSean Hefty break; 664e51060f0SSean Hefty } 665e51060f0SSean Hefty } 666e51060f0SSean Hefty 667e51060f0SSean Hefty static void cma_release_port(struct rdma_id_private *id_priv) 668e51060f0SSean Hefty { 669e51060f0SSean Hefty struct rdma_bind_list *bind_list = id_priv->bind_list; 670e51060f0SSean Hefty 671e51060f0SSean Hefty if (!bind_list) 672e51060f0SSean Hefty return; 673e51060f0SSean Hefty 674e51060f0SSean Hefty mutex_lock(&lock); 675e51060f0SSean Hefty hlist_del(&id_priv->node); 676e51060f0SSean Hefty if (hlist_empty(&bind_list->owners)) { 677e51060f0SSean Hefty idr_remove(bind_list->ps, bind_list->port); 678e51060f0SSean Hefty kfree(bind_list); 679e51060f0SSean Hefty } 680e51060f0SSean Hefty mutex_unlock(&lock); 681e51060f0SSean Hefty } 682e51060f0SSean Hefty 683e51060f0SSean Hefty void rdma_destroy_id(struct rdma_cm_id *id) 684e51060f0SSean Hefty { 685e51060f0SSean Hefty struct rdma_id_private *id_priv; 686e51060f0SSean Hefty enum cma_state state; 687e51060f0SSean Hefty 688e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 689e51060f0SSean Hefty state = cma_exch(id_priv, CMA_DESTROYING); 690e51060f0SSean Hefty cma_cancel_operation(id_priv, state); 691e51060f0SSean Hefty 692e51060f0SSean Hefty if (id_priv->cma_dev) { 693e51060f0SSean Hefty switch (id->device->node_type) { 694e51060f0SSean Hefty case IB_NODE_CA: 695e51060f0SSean Hefty if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib)) 696e51060f0SSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 697e51060f0SSean Hefty break; 698e51060f0SSean Hefty default: 699e51060f0SSean Hefty break; 700e51060f0SSean Hefty } 701e51060f0SSean Hefty mutex_lock(&lock); 702e51060f0SSean Hefty cma_detach_from_dev(id_priv); 703e51060f0SSean Hefty mutex_unlock(&lock); 704e51060f0SSean Hefty } 705e51060f0SSean Hefty 706e51060f0SSean Hefty cma_release_port(id_priv); 707e51060f0SSean Hefty cma_deref_id(id_priv); 708e51060f0SSean Hefty wait_for_completion(&id_priv->comp); 709e51060f0SSean Hefty 710e51060f0SSean Hefty kfree(id_priv->id.route.path_rec); 711e51060f0SSean Hefty kfree(id_priv); 712e51060f0SSean Hefty } 713e51060f0SSean Hefty EXPORT_SYMBOL(rdma_destroy_id); 714e51060f0SSean Hefty 715e51060f0SSean Hefty static int cma_rep_recv(struct rdma_id_private *id_priv) 716e51060f0SSean Hefty { 717e51060f0SSean Hefty int ret; 718e51060f0SSean Hefty 719e51060f0SSean Hefty ret = cma_modify_qp_rtr(&id_priv->id); 720e51060f0SSean Hefty if (ret) 721e51060f0SSean Hefty goto reject; 722e51060f0SSean Hefty 723e51060f0SSean Hefty ret = cma_modify_qp_rts(&id_priv->id); 724e51060f0SSean Hefty if (ret) 725e51060f0SSean Hefty goto reject; 726e51060f0SSean Hefty 727e51060f0SSean Hefty ret = ib_send_cm_rtu(id_priv->cm_id.ib, NULL, 0); 728e51060f0SSean Hefty if (ret) 729e51060f0SSean Hefty goto reject; 730e51060f0SSean Hefty 731e51060f0SSean Hefty return 0; 732e51060f0SSean Hefty reject: 733e51060f0SSean Hefty cma_modify_qp_err(&id_priv->id); 734e51060f0SSean Hefty ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED, 735e51060f0SSean Hefty NULL, 0, NULL, 0); 736e51060f0SSean Hefty return ret; 737e51060f0SSean Hefty } 738e51060f0SSean Hefty 739e51060f0SSean Hefty static int cma_verify_rep(struct rdma_id_private *id_priv, void *data) 740e51060f0SSean Hefty { 741e51060f0SSean Hefty if (id_priv->id.ps == RDMA_PS_SDP && 742e51060f0SSean Hefty sdp_get_majv(((struct sdp_hah *) data)->sdp_version) != 743e51060f0SSean Hefty SDP_MAJ_VERSION) 744e51060f0SSean Hefty return -EINVAL; 745e51060f0SSean Hefty 746e51060f0SSean Hefty return 0; 747e51060f0SSean Hefty } 748e51060f0SSean Hefty 749e51060f0SSean Hefty static int cma_rtu_recv(struct rdma_id_private *id_priv) 750e51060f0SSean Hefty { 751e51060f0SSean Hefty int ret; 752e51060f0SSean Hefty 753e51060f0SSean Hefty ret = cma_modify_qp_rts(&id_priv->id); 754e51060f0SSean Hefty if (ret) 755e51060f0SSean Hefty goto reject; 756e51060f0SSean Hefty 757e51060f0SSean Hefty return 0; 758e51060f0SSean Hefty reject: 759e51060f0SSean Hefty cma_modify_qp_err(&id_priv->id); 760e51060f0SSean Hefty ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED, 761e51060f0SSean Hefty NULL, 0, NULL, 0); 762e51060f0SSean Hefty return ret; 763e51060f0SSean Hefty } 764e51060f0SSean Hefty 765e51060f0SSean Hefty static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) 766e51060f0SSean Hefty { 767e51060f0SSean Hefty struct rdma_id_private *id_priv = cm_id->context; 768e51060f0SSean Hefty enum rdma_cm_event_type event; 769e51060f0SSean Hefty u8 private_data_len = 0; 770e51060f0SSean Hefty int ret = 0, status = 0; 771e51060f0SSean Hefty 772e51060f0SSean Hefty atomic_inc(&id_priv->dev_remove); 773e51060f0SSean Hefty if (!cma_comp(id_priv, CMA_CONNECT)) 774e51060f0SSean Hefty goto out; 775e51060f0SSean Hefty 776e51060f0SSean Hefty switch (ib_event->event) { 777e51060f0SSean Hefty case IB_CM_REQ_ERROR: 778e51060f0SSean Hefty case IB_CM_REP_ERROR: 779e51060f0SSean Hefty event = RDMA_CM_EVENT_UNREACHABLE; 780e51060f0SSean Hefty status = -ETIMEDOUT; 781e51060f0SSean Hefty break; 782e51060f0SSean Hefty case IB_CM_REP_RECEIVED: 783e51060f0SSean Hefty status = cma_verify_rep(id_priv, ib_event->private_data); 784e51060f0SSean Hefty if (status) 785e51060f0SSean Hefty event = RDMA_CM_EVENT_CONNECT_ERROR; 786e51060f0SSean Hefty else if (id_priv->id.qp && id_priv->id.ps != RDMA_PS_SDP) { 787e51060f0SSean Hefty status = cma_rep_recv(id_priv); 788e51060f0SSean Hefty event = status ? RDMA_CM_EVENT_CONNECT_ERROR : 789e51060f0SSean Hefty RDMA_CM_EVENT_ESTABLISHED; 790e51060f0SSean Hefty } else 791e51060f0SSean Hefty event = RDMA_CM_EVENT_CONNECT_RESPONSE; 792e51060f0SSean Hefty private_data_len = IB_CM_REP_PRIVATE_DATA_SIZE; 793e51060f0SSean Hefty break; 794e51060f0SSean Hefty case IB_CM_RTU_RECEIVED: 795e51060f0SSean Hefty status = cma_rtu_recv(id_priv); 796e51060f0SSean Hefty event = status ? RDMA_CM_EVENT_CONNECT_ERROR : 797e51060f0SSean Hefty RDMA_CM_EVENT_ESTABLISHED; 798e51060f0SSean Hefty break; 799e51060f0SSean Hefty case IB_CM_DREQ_ERROR: 800e51060f0SSean Hefty status = -ETIMEDOUT; /* fall through */ 801e51060f0SSean Hefty case IB_CM_DREQ_RECEIVED: 802e51060f0SSean Hefty case IB_CM_DREP_RECEIVED: 803e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_CONNECT, CMA_DISCONNECT)) 804e51060f0SSean Hefty goto out; 805e51060f0SSean Hefty event = RDMA_CM_EVENT_DISCONNECTED; 806e51060f0SSean Hefty break; 807e51060f0SSean Hefty case IB_CM_TIMEWAIT_EXIT: 808e51060f0SSean Hefty case IB_CM_MRA_RECEIVED: 809e51060f0SSean Hefty /* ignore event */ 810e51060f0SSean Hefty goto out; 811e51060f0SSean Hefty case IB_CM_REJ_RECEIVED: 812e51060f0SSean Hefty cma_modify_qp_err(&id_priv->id); 813e51060f0SSean Hefty status = ib_event->param.rej_rcvd.reason; 814e51060f0SSean Hefty event = RDMA_CM_EVENT_REJECTED; 815e51060f0SSean Hefty break; 816e51060f0SSean Hefty default: 817e51060f0SSean Hefty printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d", 818e51060f0SSean Hefty ib_event->event); 819e51060f0SSean Hefty goto out; 820e51060f0SSean Hefty } 821e51060f0SSean Hefty 822e51060f0SSean Hefty ret = cma_notify_user(id_priv, event, status, ib_event->private_data, 823e51060f0SSean Hefty private_data_len); 824e51060f0SSean Hefty if (ret) { 825e51060f0SSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 826e51060f0SSean Hefty id_priv->cm_id.ib = NULL; 827e51060f0SSean Hefty cma_exch(id_priv, CMA_DESTROYING); 828e51060f0SSean Hefty cma_release_remove(id_priv); 829e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 830e51060f0SSean Hefty return ret; 831e51060f0SSean Hefty } 832e51060f0SSean Hefty out: 833e51060f0SSean Hefty cma_release_remove(id_priv); 834e51060f0SSean Hefty return ret; 835e51060f0SSean Hefty } 836e51060f0SSean Hefty 837e51060f0SSean Hefty static struct rdma_id_private *cma_new_id(struct rdma_cm_id *listen_id, 838e51060f0SSean Hefty struct ib_cm_event *ib_event) 839e51060f0SSean Hefty { 840e51060f0SSean Hefty struct rdma_id_private *id_priv; 841e51060f0SSean Hefty struct rdma_cm_id *id; 842e51060f0SSean Hefty struct rdma_route *rt; 843e51060f0SSean Hefty union cma_ip_addr *src, *dst; 844e51060f0SSean Hefty __u16 port; 845e51060f0SSean Hefty u8 ip_ver; 846e51060f0SSean Hefty 847e51060f0SSean Hefty id = rdma_create_id(listen_id->event_handler, listen_id->context, 848e51060f0SSean Hefty listen_id->ps); 849e51060f0SSean Hefty if (IS_ERR(id)) 850e51060f0SSean Hefty return NULL; 851e51060f0SSean Hefty 852e51060f0SSean Hefty rt = &id->route; 853e51060f0SSean Hefty rt->num_paths = ib_event->param.req_rcvd.alternate_path ? 2 : 1; 854e51060f0SSean Hefty rt->path_rec = kmalloc(sizeof *rt->path_rec * rt->num_paths, GFP_KERNEL); 855e51060f0SSean Hefty if (!rt->path_rec) 856e51060f0SSean Hefty goto err; 857e51060f0SSean Hefty 858e51060f0SSean Hefty if (cma_get_net_info(ib_event->private_data, listen_id->ps, 859e51060f0SSean Hefty &ip_ver, &port, &src, &dst)) 860e51060f0SSean Hefty goto err; 861e51060f0SSean Hefty 862e51060f0SSean Hefty cma_save_net_info(&id->route.addr, &listen_id->route.addr, 863e51060f0SSean Hefty ip_ver, port, src, dst); 864e51060f0SSean Hefty rt->path_rec[0] = *ib_event->param.req_rcvd.primary_path; 865e51060f0SSean Hefty if (rt->num_paths == 2) 866e51060f0SSean Hefty rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path; 867e51060f0SSean Hefty 868e51060f0SSean Hefty ib_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid); 869e51060f0SSean Hefty ib_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid); 870e51060f0SSean Hefty ib_addr_set_pkey(&rt->addr.dev_addr, be16_to_cpu(rt->path_rec[0].pkey)); 871e51060f0SSean Hefty rt->addr.dev_addr.dev_type = IB_NODE_CA; 872e51060f0SSean Hefty 873e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 874e51060f0SSean Hefty id_priv->state = CMA_CONNECT; 875e51060f0SSean Hefty return id_priv; 876e51060f0SSean Hefty err: 877e51060f0SSean Hefty rdma_destroy_id(id); 878e51060f0SSean Hefty return NULL; 879e51060f0SSean Hefty } 880e51060f0SSean Hefty 881e51060f0SSean Hefty static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) 882e51060f0SSean Hefty { 883e51060f0SSean Hefty struct rdma_id_private *listen_id, *conn_id; 884e51060f0SSean Hefty int offset, ret; 885e51060f0SSean Hefty 886e51060f0SSean Hefty listen_id = cm_id->context; 887e51060f0SSean Hefty atomic_inc(&listen_id->dev_remove); 888e51060f0SSean Hefty if (!cma_comp(listen_id, CMA_LISTEN)) { 889e51060f0SSean Hefty ret = -ECONNABORTED; 890e51060f0SSean Hefty goto out; 891e51060f0SSean Hefty } 892e51060f0SSean Hefty 893e51060f0SSean Hefty conn_id = cma_new_id(&listen_id->id, ib_event); 894e51060f0SSean Hefty if (!conn_id) { 895e51060f0SSean Hefty ret = -ENOMEM; 896e51060f0SSean Hefty goto out; 897e51060f0SSean Hefty } 898e51060f0SSean Hefty 899e51060f0SSean Hefty atomic_inc(&conn_id->dev_remove); 900e51060f0SSean Hefty ret = cma_acquire_ib_dev(conn_id); 901e51060f0SSean Hefty if (ret) { 902e51060f0SSean Hefty ret = -ENODEV; 903e51060f0SSean Hefty cma_release_remove(conn_id); 904e51060f0SSean Hefty rdma_destroy_id(&conn_id->id); 905e51060f0SSean Hefty goto out; 906e51060f0SSean Hefty } 907e51060f0SSean Hefty 908e51060f0SSean Hefty conn_id->cm_id.ib = cm_id; 909e51060f0SSean Hefty cm_id->context = conn_id; 910e51060f0SSean Hefty cm_id->cm_handler = cma_ib_handler; 911e51060f0SSean Hefty 912e51060f0SSean Hefty offset = cma_user_data_offset(listen_id->id.ps); 913e51060f0SSean Hefty ret = cma_notify_user(conn_id, RDMA_CM_EVENT_CONNECT_REQUEST, 0, 914e51060f0SSean Hefty ib_event->private_data + offset, 915e51060f0SSean Hefty IB_CM_REQ_PRIVATE_DATA_SIZE - offset); 916e51060f0SSean Hefty if (ret) { 917e51060f0SSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 918e51060f0SSean Hefty conn_id->cm_id.ib = NULL; 919e51060f0SSean Hefty cma_exch(conn_id, CMA_DESTROYING); 920e51060f0SSean Hefty cma_release_remove(conn_id); 921e51060f0SSean Hefty rdma_destroy_id(&conn_id->id); 922e51060f0SSean Hefty } 923e51060f0SSean Hefty out: 924e51060f0SSean Hefty cma_release_remove(listen_id); 925e51060f0SSean Hefty return ret; 926e51060f0SSean Hefty } 927e51060f0SSean Hefty 928e51060f0SSean Hefty static __be64 cma_get_service_id(enum rdma_port_space ps, struct sockaddr *addr) 929e51060f0SSean Hefty { 930e51060f0SSean Hefty return cpu_to_be64(((u64)ps << 16) + 931e51060f0SSean Hefty be16_to_cpu(((struct sockaddr_in *) addr)->sin_port)); 932e51060f0SSean Hefty } 933e51060f0SSean Hefty 934e51060f0SSean Hefty static void cma_set_compare_data(enum rdma_port_space ps, struct sockaddr *addr, 935e51060f0SSean Hefty struct ib_cm_compare_data *compare) 936e51060f0SSean Hefty { 937e51060f0SSean Hefty struct cma_hdr *cma_data, *cma_mask; 938e51060f0SSean Hefty struct sdp_hh *sdp_data, *sdp_mask; 939e51060f0SSean Hefty __u32 ip4_addr; 940e51060f0SSean Hefty struct in6_addr ip6_addr; 941e51060f0SSean Hefty 942e51060f0SSean Hefty memset(compare, 0, sizeof *compare); 943e51060f0SSean Hefty cma_data = (void *) compare->data; 944e51060f0SSean Hefty cma_mask = (void *) compare->mask; 945e51060f0SSean Hefty sdp_data = (void *) compare->data; 946e51060f0SSean Hefty sdp_mask = (void *) compare->mask; 947e51060f0SSean Hefty 948e51060f0SSean Hefty switch (addr->sa_family) { 949e51060f0SSean Hefty case AF_INET: 950e51060f0SSean Hefty ip4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; 951e51060f0SSean Hefty if (ps == RDMA_PS_SDP) { 952e51060f0SSean Hefty sdp_set_ip_ver(sdp_data, 4); 953e51060f0SSean Hefty sdp_set_ip_ver(sdp_mask, 0xF); 954e51060f0SSean Hefty sdp_data->dst_addr.ip4.addr = ip4_addr; 955e51060f0SSean Hefty sdp_mask->dst_addr.ip4.addr = ~0; 956e51060f0SSean Hefty } else { 957e51060f0SSean Hefty cma_set_ip_ver(cma_data, 4); 958e51060f0SSean Hefty cma_set_ip_ver(cma_mask, 0xF); 959e51060f0SSean Hefty cma_data->dst_addr.ip4.addr = ip4_addr; 960e51060f0SSean Hefty cma_mask->dst_addr.ip4.addr = ~0; 961e51060f0SSean Hefty } 962e51060f0SSean Hefty break; 963e51060f0SSean Hefty case AF_INET6: 964e51060f0SSean Hefty ip6_addr = ((struct sockaddr_in6 *) addr)->sin6_addr; 965e51060f0SSean Hefty if (ps == RDMA_PS_SDP) { 966e51060f0SSean Hefty sdp_set_ip_ver(sdp_data, 6); 967e51060f0SSean Hefty sdp_set_ip_ver(sdp_mask, 0xF); 968e51060f0SSean Hefty sdp_data->dst_addr.ip6 = ip6_addr; 969e51060f0SSean Hefty memset(&sdp_mask->dst_addr.ip6, 0xFF, 970e51060f0SSean Hefty sizeof sdp_mask->dst_addr.ip6); 971e51060f0SSean Hefty } else { 972e51060f0SSean Hefty cma_set_ip_ver(cma_data, 6); 973e51060f0SSean Hefty cma_set_ip_ver(cma_mask, 0xF); 974e51060f0SSean Hefty cma_data->dst_addr.ip6 = ip6_addr; 975e51060f0SSean Hefty memset(&cma_mask->dst_addr.ip6, 0xFF, 976e51060f0SSean Hefty sizeof cma_mask->dst_addr.ip6); 977e51060f0SSean Hefty } 978e51060f0SSean Hefty break; 979e51060f0SSean Hefty default: 980e51060f0SSean Hefty break; 981e51060f0SSean Hefty } 982e51060f0SSean Hefty } 983e51060f0SSean Hefty 984e51060f0SSean Hefty static int cma_ib_listen(struct rdma_id_private *id_priv) 985e51060f0SSean Hefty { 986e51060f0SSean Hefty struct ib_cm_compare_data compare_data; 987e51060f0SSean Hefty struct sockaddr *addr; 988e51060f0SSean Hefty __be64 svc_id; 989e51060f0SSean Hefty int ret; 990e51060f0SSean Hefty 991e51060f0SSean Hefty id_priv->cm_id.ib = ib_create_cm_id(id_priv->id.device, cma_req_handler, 992e51060f0SSean Hefty id_priv); 993e51060f0SSean Hefty if (IS_ERR(id_priv->cm_id.ib)) 994e51060f0SSean Hefty return PTR_ERR(id_priv->cm_id.ib); 995e51060f0SSean Hefty 996e51060f0SSean Hefty addr = &id_priv->id.route.addr.src_addr; 997e51060f0SSean Hefty svc_id = cma_get_service_id(id_priv->id.ps, addr); 998e51060f0SSean Hefty if (cma_any_addr(addr)) 999e51060f0SSean Hefty ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, NULL); 1000e51060f0SSean Hefty else { 1001e51060f0SSean Hefty cma_set_compare_data(id_priv->id.ps, addr, &compare_data); 1002e51060f0SSean Hefty ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, &compare_data); 1003e51060f0SSean Hefty } 1004e51060f0SSean Hefty 1005e51060f0SSean Hefty if (ret) { 1006e51060f0SSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 1007e51060f0SSean Hefty id_priv->cm_id.ib = NULL; 1008e51060f0SSean Hefty } 1009e51060f0SSean Hefty 1010e51060f0SSean Hefty return ret; 1011e51060f0SSean Hefty } 1012e51060f0SSean Hefty 1013e51060f0SSean Hefty static int cma_listen_handler(struct rdma_cm_id *id, 1014e51060f0SSean Hefty struct rdma_cm_event *event) 1015e51060f0SSean Hefty { 1016e51060f0SSean Hefty struct rdma_id_private *id_priv = id->context; 1017e51060f0SSean Hefty 1018e51060f0SSean Hefty id->context = id_priv->id.context; 1019e51060f0SSean Hefty id->event_handler = id_priv->id.event_handler; 1020e51060f0SSean Hefty return id_priv->id.event_handler(id, event); 1021e51060f0SSean Hefty } 1022e51060f0SSean Hefty 1023e51060f0SSean Hefty static void cma_listen_on_dev(struct rdma_id_private *id_priv, 1024e51060f0SSean Hefty struct cma_device *cma_dev) 1025e51060f0SSean Hefty { 1026e51060f0SSean Hefty struct rdma_id_private *dev_id_priv; 1027e51060f0SSean Hefty struct rdma_cm_id *id; 1028e51060f0SSean Hefty int ret; 1029e51060f0SSean Hefty 1030e51060f0SSean Hefty id = rdma_create_id(cma_listen_handler, id_priv, id_priv->id.ps); 1031e51060f0SSean Hefty if (IS_ERR(id)) 1032e51060f0SSean Hefty return; 1033e51060f0SSean Hefty 1034e51060f0SSean Hefty dev_id_priv = container_of(id, struct rdma_id_private, id); 1035e51060f0SSean Hefty 1036e51060f0SSean Hefty dev_id_priv->state = CMA_ADDR_BOUND; 1037e51060f0SSean Hefty memcpy(&id->route.addr.src_addr, &id_priv->id.route.addr.src_addr, 1038e51060f0SSean Hefty ip_addr_size(&id_priv->id.route.addr.src_addr)); 1039e51060f0SSean Hefty 1040e51060f0SSean Hefty cma_attach_to_dev(dev_id_priv, cma_dev); 1041e51060f0SSean Hefty list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list); 1042e51060f0SSean Hefty 1043e51060f0SSean Hefty ret = rdma_listen(id, id_priv->backlog); 1044e51060f0SSean Hefty if (ret) 1045e51060f0SSean Hefty goto err; 1046e51060f0SSean Hefty 1047e51060f0SSean Hefty return; 1048e51060f0SSean Hefty err: 1049e51060f0SSean Hefty cma_destroy_listen(dev_id_priv); 1050e51060f0SSean Hefty } 1051e51060f0SSean Hefty 1052e51060f0SSean Hefty static void cma_listen_on_all(struct rdma_id_private *id_priv) 1053e51060f0SSean Hefty { 1054e51060f0SSean Hefty struct cma_device *cma_dev; 1055e51060f0SSean Hefty 1056e51060f0SSean Hefty mutex_lock(&lock); 1057e51060f0SSean Hefty list_add_tail(&id_priv->list, &listen_any_list); 1058e51060f0SSean Hefty list_for_each_entry(cma_dev, &dev_list, list) 1059e51060f0SSean Hefty cma_listen_on_dev(id_priv, cma_dev); 1060e51060f0SSean Hefty mutex_unlock(&lock); 1061e51060f0SSean Hefty } 1062e51060f0SSean Hefty 1063e51060f0SSean Hefty static int cma_bind_any(struct rdma_cm_id *id, sa_family_t af) 1064e51060f0SSean Hefty { 1065e51060f0SSean Hefty struct sockaddr_in addr_in; 1066e51060f0SSean Hefty 1067e51060f0SSean Hefty memset(&addr_in, 0, sizeof addr_in); 1068e51060f0SSean Hefty addr_in.sin_family = af; 1069e51060f0SSean Hefty return rdma_bind_addr(id, (struct sockaddr *) &addr_in); 1070e51060f0SSean Hefty } 1071e51060f0SSean Hefty 1072e51060f0SSean Hefty int rdma_listen(struct rdma_cm_id *id, int backlog) 1073e51060f0SSean Hefty { 1074e51060f0SSean Hefty struct rdma_id_private *id_priv; 1075e51060f0SSean Hefty int ret; 1076e51060f0SSean Hefty 1077e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1078e51060f0SSean Hefty if (id_priv->state == CMA_IDLE) { 1079e51060f0SSean Hefty ret = cma_bind_any(id, AF_INET); 1080e51060f0SSean Hefty if (ret) 1081e51060f0SSean Hefty return ret; 1082e51060f0SSean Hefty } 1083e51060f0SSean Hefty 1084e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_LISTEN)) 1085e51060f0SSean Hefty return -EINVAL; 1086e51060f0SSean Hefty 1087e51060f0SSean Hefty id_priv->backlog = backlog; 1088e51060f0SSean Hefty if (id->device) { 1089e51060f0SSean Hefty switch (id->device->node_type) { 1090e51060f0SSean Hefty case IB_NODE_CA: 1091e51060f0SSean Hefty ret = cma_ib_listen(id_priv); 1092e51060f0SSean Hefty if (ret) 1093e51060f0SSean Hefty goto err; 1094e51060f0SSean Hefty break; 1095e51060f0SSean Hefty default: 1096e51060f0SSean Hefty ret = -ENOSYS; 1097e51060f0SSean Hefty goto err; 1098e51060f0SSean Hefty } 1099e51060f0SSean Hefty } else 1100e51060f0SSean Hefty cma_listen_on_all(id_priv); 1101e51060f0SSean Hefty 1102e51060f0SSean Hefty return 0; 1103e51060f0SSean Hefty err: 1104e51060f0SSean Hefty id_priv->backlog = 0; 1105e51060f0SSean Hefty cma_comp_exch(id_priv, CMA_LISTEN, CMA_ADDR_BOUND); 1106e51060f0SSean Hefty return ret; 1107e51060f0SSean Hefty } 1108e51060f0SSean Hefty EXPORT_SYMBOL(rdma_listen); 1109e51060f0SSean Hefty 1110e51060f0SSean Hefty static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec, 1111e51060f0SSean Hefty void *context) 1112e51060f0SSean Hefty { 1113e51060f0SSean Hefty struct cma_work *work = context; 1114e51060f0SSean Hefty struct rdma_route *route; 1115e51060f0SSean Hefty 1116e51060f0SSean Hefty route = &work->id->id.route; 1117e51060f0SSean Hefty 1118e51060f0SSean Hefty if (!status) { 1119e51060f0SSean Hefty route->num_paths = 1; 1120e51060f0SSean Hefty *route->path_rec = *path_rec; 1121e51060f0SSean Hefty } else { 1122e51060f0SSean Hefty work->old_state = CMA_ROUTE_QUERY; 1123e51060f0SSean Hefty work->new_state = CMA_ADDR_RESOLVED; 1124e51060f0SSean Hefty work->event.event = RDMA_CM_EVENT_ROUTE_ERROR; 1125e51060f0SSean Hefty } 1126e51060f0SSean Hefty 1127e51060f0SSean Hefty queue_work(cma_wq, &work->work); 1128e51060f0SSean Hefty } 1129e51060f0SSean Hefty 1130e51060f0SSean Hefty static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms, 1131e51060f0SSean Hefty struct cma_work *work) 1132e51060f0SSean Hefty { 1133e51060f0SSean Hefty struct rdma_dev_addr *addr = &id_priv->id.route.addr.dev_addr; 1134e51060f0SSean Hefty struct ib_sa_path_rec path_rec; 1135e51060f0SSean Hefty 1136e51060f0SSean Hefty memset(&path_rec, 0, sizeof path_rec); 1137e51060f0SSean Hefty path_rec.sgid = *ib_addr_get_sgid(addr); 1138e51060f0SSean Hefty path_rec.dgid = *ib_addr_get_dgid(addr); 1139e51060f0SSean Hefty path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(addr)); 1140e51060f0SSean Hefty path_rec.numb_path = 1; 1141e51060f0SSean Hefty 1142e51060f0SSean Hefty id_priv->query_id = ib_sa_path_rec_get(id_priv->id.device, 1143e51060f0SSean Hefty id_priv->id.port_num, &path_rec, 1144e51060f0SSean Hefty IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | 1145e51060f0SSean Hefty IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH, 1146e51060f0SSean Hefty timeout_ms, GFP_KERNEL, 1147e51060f0SSean Hefty cma_query_handler, work, &id_priv->query); 1148e51060f0SSean Hefty 1149e51060f0SSean Hefty return (id_priv->query_id < 0) ? id_priv->query_id : 0; 1150e51060f0SSean Hefty } 1151e51060f0SSean Hefty 1152e51060f0SSean Hefty static void cma_work_handler(void *data) 1153e51060f0SSean Hefty { 1154e51060f0SSean Hefty struct cma_work *work = data; 1155e51060f0SSean Hefty struct rdma_id_private *id_priv = work->id; 1156e51060f0SSean Hefty int destroy = 0; 1157e51060f0SSean Hefty 1158e51060f0SSean Hefty atomic_inc(&id_priv->dev_remove); 1159e51060f0SSean Hefty if (!cma_comp_exch(id_priv, work->old_state, work->new_state)) 1160e51060f0SSean Hefty goto out; 1161e51060f0SSean Hefty 1162e51060f0SSean Hefty if (id_priv->id.event_handler(&id_priv->id, &work->event)) { 1163e51060f0SSean Hefty cma_exch(id_priv, CMA_DESTROYING); 1164e51060f0SSean Hefty destroy = 1; 1165e51060f0SSean Hefty } 1166e51060f0SSean Hefty out: 1167e51060f0SSean Hefty cma_release_remove(id_priv); 1168e51060f0SSean Hefty cma_deref_id(id_priv); 1169e51060f0SSean Hefty if (destroy) 1170e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 1171e51060f0SSean Hefty kfree(work); 1172e51060f0SSean Hefty } 1173e51060f0SSean Hefty 1174e51060f0SSean Hefty static int cma_resolve_ib_route(struct rdma_id_private *id_priv, int timeout_ms) 1175e51060f0SSean Hefty { 1176e51060f0SSean Hefty struct rdma_route *route = &id_priv->id.route; 1177e51060f0SSean Hefty struct cma_work *work; 1178e51060f0SSean Hefty int ret; 1179e51060f0SSean Hefty 1180e51060f0SSean Hefty work = kzalloc(sizeof *work, GFP_KERNEL); 1181e51060f0SSean Hefty if (!work) 1182e51060f0SSean Hefty return -ENOMEM; 1183e51060f0SSean Hefty 1184e51060f0SSean Hefty work->id = id_priv; 1185e51060f0SSean Hefty INIT_WORK(&work->work, cma_work_handler, work); 1186e51060f0SSean Hefty work->old_state = CMA_ROUTE_QUERY; 1187e51060f0SSean Hefty work->new_state = CMA_ROUTE_RESOLVED; 1188e51060f0SSean Hefty work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; 1189e51060f0SSean Hefty 1190e51060f0SSean Hefty route->path_rec = kmalloc(sizeof *route->path_rec, GFP_KERNEL); 1191e51060f0SSean Hefty if (!route->path_rec) { 1192e51060f0SSean Hefty ret = -ENOMEM; 1193e51060f0SSean Hefty goto err1; 1194e51060f0SSean Hefty } 1195e51060f0SSean Hefty 1196e51060f0SSean Hefty ret = cma_query_ib_route(id_priv, timeout_ms, work); 1197e51060f0SSean Hefty if (ret) 1198e51060f0SSean Hefty goto err2; 1199e51060f0SSean Hefty 1200e51060f0SSean Hefty return 0; 1201e51060f0SSean Hefty err2: 1202e51060f0SSean Hefty kfree(route->path_rec); 1203e51060f0SSean Hefty route->path_rec = NULL; 1204e51060f0SSean Hefty err1: 1205e51060f0SSean Hefty kfree(work); 1206e51060f0SSean Hefty return ret; 1207e51060f0SSean Hefty } 1208e51060f0SSean Hefty 1209e51060f0SSean Hefty int rdma_set_ib_paths(struct rdma_cm_id *id, 1210e51060f0SSean Hefty struct ib_sa_path_rec *path_rec, int num_paths) 1211e51060f0SSean Hefty { 1212e51060f0SSean Hefty struct rdma_id_private *id_priv; 1213e51060f0SSean Hefty int ret; 1214e51060f0SSean Hefty 1215e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1216e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ROUTE_RESOLVED)) 1217e51060f0SSean Hefty return -EINVAL; 1218e51060f0SSean Hefty 1219e51060f0SSean Hefty id->route.path_rec = kmalloc(sizeof *path_rec * num_paths, GFP_KERNEL); 1220e51060f0SSean Hefty if (!id->route.path_rec) { 1221e51060f0SSean Hefty ret = -ENOMEM; 1222e51060f0SSean Hefty goto err; 1223e51060f0SSean Hefty } 1224e51060f0SSean Hefty 1225e51060f0SSean Hefty memcpy(id->route.path_rec, path_rec, sizeof *path_rec * num_paths); 1226e51060f0SSean Hefty return 0; 1227e51060f0SSean Hefty err: 1228e51060f0SSean Hefty cma_comp_exch(id_priv, CMA_ROUTE_RESOLVED, CMA_ADDR_RESOLVED); 1229e51060f0SSean Hefty return ret; 1230e51060f0SSean Hefty } 1231e51060f0SSean Hefty EXPORT_SYMBOL(rdma_set_ib_paths); 1232e51060f0SSean Hefty 1233e51060f0SSean Hefty int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms) 1234e51060f0SSean Hefty { 1235e51060f0SSean Hefty struct rdma_id_private *id_priv; 1236e51060f0SSean Hefty int ret; 1237e51060f0SSean Hefty 1238e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1239e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ROUTE_QUERY)) 1240e51060f0SSean Hefty return -EINVAL; 1241e51060f0SSean Hefty 1242e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 1243e51060f0SSean Hefty switch (id->device->node_type) { 1244e51060f0SSean Hefty case IB_NODE_CA: 1245e51060f0SSean Hefty ret = cma_resolve_ib_route(id_priv, timeout_ms); 1246e51060f0SSean Hefty break; 1247e51060f0SSean Hefty default: 1248e51060f0SSean Hefty ret = -ENOSYS; 1249e51060f0SSean Hefty break; 1250e51060f0SSean Hefty } 1251e51060f0SSean Hefty if (ret) 1252e51060f0SSean Hefty goto err; 1253e51060f0SSean Hefty 1254e51060f0SSean Hefty return 0; 1255e51060f0SSean Hefty err: 1256e51060f0SSean Hefty cma_comp_exch(id_priv, CMA_ROUTE_QUERY, CMA_ADDR_RESOLVED); 1257e51060f0SSean Hefty cma_deref_id(id_priv); 1258e51060f0SSean Hefty return ret; 1259e51060f0SSean Hefty } 1260e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_route); 1261e51060f0SSean Hefty 1262e51060f0SSean Hefty static int cma_bind_loopback(struct rdma_id_private *id_priv) 1263e51060f0SSean Hefty { 1264e51060f0SSean Hefty struct cma_device *cma_dev; 1265e51060f0SSean Hefty struct ib_port_attr port_attr; 1266e51060f0SSean Hefty union ib_gid *gid; 1267e51060f0SSean Hefty u16 pkey; 1268e51060f0SSean Hefty int ret; 1269e51060f0SSean Hefty u8 p; 1270e51060f0SSean Hefty 1271e51060f0SSean Hefty mutex_lock(&lock); 1272e51060f0SSean Hefty list_for_each_entry(cma_dev, &dev_list, list) 1273e51060f0SSean Hefty for (p = 1; p <= cma_dev->device->phys_port_cnt; ++p) 1274e51060f0SSean Hefty if (!ib_query_port (cma_dev->device, p, &port_attr) && 1275e51060f0SSean Hefty port_attr.state == IB_PORT_ACTIVE) 1276e51060f0SSean Hefty goto port_found; 1277e51060f0SSean Hefty 1278e51060f0SSean Hefty if (!list_empty(&dev_list)) { 1279e51060f0SSean Hefty p = 1; 1280e51060f0SSean Hefty cma_dev = list_entry(dev_list.next, struct cma_device, list); 1281e51060f0SSean Hefty } else { 1282e51060f0SSean Hefty ret = -ENODEV; 1283e51060f0SSean Hefty goto out; 1284e51060f0SSean Hefty } 1285e51060f0SSean Hefty 1286e51060f0SSean Hefty port_found: 1287e51060f0SSean Hefty gid = ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr); 1288e51060f0SSean Hefty ret = ib_get_cached_gid(cma_dev->device, p, 0, gid); 1289e51060f0SSean Hefty if (ret) 1290e51060f0SSean Hefty goto out; 1291e51060f0SSean Hefty 1292e51060f0SSean Hefty ret = ib_get_cached_pkey(cma_dev->device, p, 0, &pkey); 1293e51060f0SSean Hefty if (ret) 1294e51060f0SSean Hefty goto out; 1295e51060f0SSean Hefty 1296e51060f0SSean Hefty ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey); 1297e51060f0SSean Hefty id_priv->id.port_num = p; 1298e51060f0SSean Hefty cma_attach_to_dev(id_priv, cma_dev); 1299e51060f0SSean Hefty out: 1300e51060f0SSean Hefty mutex_unlock(&lock); 1301e51060f0SSean Hefty return ret; 1302e51060f0SSean Hefty } 1303e51060f0SSean Hefty 1304e51060f0SSean Hefty static void addr_handler(int status, struct sockaddr *src_addr, 1305e51060f0SSean Hefty struct rdma_dev_addr *dev_addr, void *context) 1306e51060f0SSean Hefty { 1307e51060f0SSean Hefty struct rdma_id_private *id_priv = context; 1308e51060f0SSean Hefty enum rdma_cm_event_type event; 1309e51060f0SSean Hefty 1310e51060f0SSean Hefty atomic_inc(&id_priv->dev_remove); 1311e51060f0SSean Hefty if (!id_priv->cma_dev && !status) 1312e51060f0SSean Hefty status = cma_acquire_dev(id_priv); 1313e51060f0SSean Hefty 1314e51060f0SSean Hefty if (status) { 1315e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_BOUND)) 1316e51060f0SSean Hefty goto out; 1317e51060f0SSean Hefty event = RDMA_CM_EVENT_ADDR_ERROR; 1318e51060f0SSean Hefty } else { 1319e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_RESOLVED)) 1320e51060f0SSean Hefty goto out; 1321e51060f0SSean Hefty memcpy(&id_priv->id.route.addr.src_addr, src_addr, 1322e51060f0SSean Hefty ip_addr_size(src_addr)); 1323e51060f0SSean Hefty event = RDMA_CM_EVENT_ADDR_RESOLVED; 1324e51060f0SSean Hefty } 1325e51060f0SSean Hefty 1326e51060f0SSean Hefty if (cma_notify_user(id_priv, event, status, NULL, 0)) { 1327e51060f0SSean Hefty cma_exch(id_priv, CMA_DESTROYING); 1328e51060f0SSean Hefty cma_release_remove(id_priv); 1329e51060f0SSean Hefty cma_deref_id(id_priv); 1330e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 1331e51060f0SSean Hefty return; 1332e51060f0SSean Hefty } 1333e51060f0SSean Hefty out: 1334e51060f0SSean Hefty cma_release_remove(id_priv); 1335e51060f0SSean Hefty cma_deref_id(id_priv); 1336e51060f0SSean Hefty } 1337e51060f0SSean Hefty 1338e51060f0SSean Hefty static int cma_resolve_loopback(struct rdma_id_private *id_priv) 1339e51060f0SSean Hefty { 1340e51060f0SSean Hefty struct cma_work *work; 1341e51060f0SSean Hefty struct sockaddr_in *src_in, *dst_in; 1342e51060f0SSean Hefty int ret; 1343e51060f0SSean Hefty 1344e51060f0SSean Hefty work = kzalloc(sizeof *work, GFP_KERNEL); 1345e51060f0SSean Hefty if (!work) 1346e51060f0SSean Hefty return -ENOMEM; 1347e51060f0SSean Hefty 1348e51060f0SSean Hefty if (!id_priv->cma_dev) { 1349e51060f0SSean Hefty ret = cma_bind_loopback(id_priv); 1350e51060f0SSean Hefty if (ret) 1351e51060f0SSean Hefty goto err; 1352e51060f0SSean Hefty } 1353e51060f0SSean Hefty 1354e51060f0SSean Hefty ib_addr_set_dgid(&id_priv->id.route.addr.dev_addr, 1355e51060f0SSean Hefty ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr)); 1356e51060f0SSean Hefty 1357e51060f0SSean Hefty if (cma_zero_addr(&id_priv->id.route.addr.src_addr)) { 1358e51060f0SSean Hefty src_in = (struct sockaddr_in *)&id_priv->id.route.addr.src_addr; 1359e51060f0SSean Hefty dst_in = (struct sockaddr_in *)&id_priv->id.route.addr.dst_addr; 1360e51060f0SSean Hefty src_in->sin_family = dst_in->sin_family; 1361e51060f0SSean Hefty src_in->sin_addr.s_addr = dst_in->sin_addr.s_addr; 1362e51060f0SSean Hefty } 1363e51060f0SSean Hefty 1364e51060f0SSean Hefty work->id = id_priv; 1365e51060f0SSean Hefty INIT_WORK(&work->work, cma_work_handler, work); 1366e51060f0SSean Hefty work->old_state = CMA_ADDR_QUERY; 1367e51060f0SSean Hefty work->new_state = CMA_ADDR_RESOLVED; 1368e51060f0SSean Hefty work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED; 1369e51060f0SSean Hefty queue_work(cma_wq, &work->work); 1370e51060f0SSean Hefty return 0; 1371e51060f0SSean Hefty err: 1372e51060f0SSean Hefty kfree(work); 1373e51060f0SSean Hefty return ret; 1374e51060f0SSean Hefty } 1375e51060f0SSean Hefty 1376e51060f0SSean Hefty static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, 1377e51060f0SSean Hefty struct sockaddr *dst_addr) 1378e51060f0SSean Hefty { 1379e51060f0SSean Hefty if (src_addr && src_addr->sa_family) 1380e51060f0SSean Hefty return rdma_bind_addr(id, src_addr); 1381e51060f0SSean Hefty else 1382e51060f0SSean Hefty return cma_bind_any(id, dst_addr->sa_family); 1383e51060f0SSean Hefty } 1384e51060f0SSean Hefty 1385e51060f0SSean Hefty int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, 1386e51060f0SSean Hefty struct sockaddr *dst_addr, int timeout_ms) 1387e51060f0SSean Hefty { 1388e51060f0SSean Hefty struct rdma_id_private *id_priv; 1389e51060f0SSean Hefty int ret; 1390e51060f0SSean Hefty 1391e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1392e51060f0SSean Hefty if (id_priv->state == CMA_IDLE) { 1393e51060f0SSean Hefty ret = cma_bind_addr(id, src_addr, dst_addr); 1394e51060f0SSean Hefty if (ret) 1395e51060f0SSean Hefty return ret; 1396e51060f0SSean Hefty } 1397e51060f0SSean Hefty 1398e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_ADDR_QUERY)) 1399e51060f0SSean Hefty return -EINVAL; 1400e51060f0SSean Hefty 1401e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 1402e51060f0SSean Hefty memcpy(&id->route.addr.dst_addr, dst_addr, ip_addr_size(dst_addr)); 1403e51060f0SSean Hefty if (cma_any_addr(dst_addr)) 1404e51060f0SSean Hefty ret = cma_resolve_loopback(id_priv); 1405e51060f0SSean Hefty else 1406e51060f0SSean Hefty ret = rdma_resolve_ip(&id->route.addr.src_addr, dst_addr, 1407e51060f0SSean Hefty &id->route.addr.dev_addr, 1408e51060f0SSean Hefty timeout_ms, addr_handler, id_priv); 1409e51060f0SSean Hefty if (ret) 1410e51060f0SSean Hefty goto err; 1411e51060f0SSean Hefty 1412e51060f0SSean Hefty return 0; 1413e51060f0SSean Hefty err: 1414e51060f0SSean Hefty cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_BOUND); 1415e51060f0SSean Hefty cma_deref_id(id_priv); 1416e51060f0SSean Hefty return ret; 1417e51060f0SSean Hefty } 1418e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_addr); 1419e51060f0SSean Hefty 1420e51060f0SSean Hefty static void cma_bind_port(struct rdma_bind_list *bind_list, 1421e51060f0SSean Hefty struct rdma_id_private *id_priv) 1422e51060f0SSean Hefty { 1423e51060f0SSean Hefty struct sockaddr_in *sin; 1424e51060f0SSean Hefty 1425e51060f0SSean Hefty sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; 1426e51060f0SSean Hefty sin->sin_port = htons(bind_list->port); 1427e51060f0SSean Hefty id_priv->bind_list = bind_list; 1428e51060f0SSean Hefty hlist_add_head(&id_priv->node, &bind_list->owners); 1429e51060f0SSean Hefty } 1430e51060f0SSean Hefty 1431e51060f0SSean Hefty static int cma_alloc_port(struct idr *ps, struct rdma_id_private *id_priv, 1432e51060f0SSean Hefty unsigned short snum) 1433e51060f0SSean Hefty { 1434e51060f0SSean Hefty struct rdma_bind_list *bind_list; 1435e51060f0SSean Hefty int port, start, ret; 1436e51060f0SSean Hefty 1437e51060f0SSean Hefty bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); 1438e51060f0SSean Hefty if (!bind_list) 1439e51060f0SSean Hefty return -ENOMEM; 1440e51060f0SSean Hefty 1441e51060f0SSean Hefty start = snum ? snum : sysctl_local_port_range[0]; 1442e51060f0SSean Hefty 1443e51060f0SSean Hefty do { 1444e51060f0SSean Hefty ret = idr_get_new_above(ps, bind_list, start, &port); 1445e51060f0SSean Hefty } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL)); 1446e51060f0SSean Hefty 1447e51060f0SSean Hefty if (ret) 1448e51060f0SSean Hefty goto err; 1449e51060f0SSean Hefty 1450e51060f0SSean Hefty if ((snum && port != snum) || 1451e51060f0SSean Hefty (!snum && port > sysctl_local_port_range[1])) { 1452e51060f0SSean Hefty idr_remove(ps, port); 1453e51060f0SSean Hefty ret = -EADDRNOTAVAIL; 1454e51060f0SSean Hefty goto err; 1455e51060f0SSean Hefty } 1456e51060f0SSean Hefty 1457e51060f0SSean Hefty bind_list->ps = ps; 1458e51060f0SSean Hefty bind_list->port = (unsigned short) port; 1459e51060f0SSean Hefty cma_bind_port(bind_list, id_priv); 1460e51060f0SSean Hefty return 0; 1461e51060f0SSean Hefty err: 1462e51060f0SSean Hefty kfree(bind_list); 1463e51060f0SSean Hefty return ret; 1464e51060f0SSean Hefty } 1465e51060f0SSean Hefty 1466e51060f0SSean Hefty static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv) 1467e51060f0SSean Hefty { 1468e51060f0SSean Hefty struct rdma_id_private *cur_id; 1469e51060f0SSean Hefty struct sockaddr_in *sin, *cur_sin; 1470e51060f0SSean Hefty struct rdma_bind_list *bind_list; 1471e51060f0SSean Hefty struct hlist_node *node; 1472e51060f0SSean Hefty unsigned short snum; 1473e51060f0SSean Hefty 1474e51060f0SSean Hefty sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; 1475e51060f0SSean Hefty snum = ntohs(sin->sin_port); 1476e51060f0SSean Hefty if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) 1477e51060f0SSean Hefty return -EACCES; 1478e51060f0SSean Hefty 1479e51060f0SSean Hefty bind_list = idr_find(ps, snum); 1480e51060f0SSean Hefty if (!bind_list) 1481e51060f0SSean Hefty return cma_alloc_port(ps, id_priv, snum); 1482e51060f0SSean Hefty 1483e51060f0SSean Hefty /* 1484e51060f0SSean Hefty * We don't support binding to any address if anyone is bound to 1485e51060f0SSean Hefty * a specific address on the same port. 1486e51060f0SSean Hefty */ 1487e51060f0SSean Hefty if (cma_any_addr(&id_priv->id.route.addr.src_addr)) 1488e51060f0SSean Hefty return -EADDRNOTAVAIL; 1489e51060f0SSean Hefty 1490e51060f0SSean Hefty hlist_for_each_entry(cur_id, node, &bind_list->owners, node) { 1491e51060f0SSean Hefty if (cma_any_addr(&cur_id->id.route.addr.src_addr)) 1492e51060f0SSean Hefty return -EADDRNOTAVAIL; 1493e51060f0SSean Hefty 1494e51060f0SSean Hefty cur_sin = (struct sockaddr_in *) &cur_id->id.route.addr.src_addr; 1495e51060f0SSean Hefty if (sin->sin_addr.s_addr == cur_sin->sin_addr.s_addr) 1496e51060f0SSean Hefty return -EADDRINUSE; 1497e51060f0SSean Hefty } 1498e51060f0SSean Hefty 1499e51060f0SSean Hefty cma_bind_port(bind_list, id_priv); 1500e51060f0SSean Hefty return 0; 1501e51060f0SSean Hefty } 1502e51060f0SSean Hefty 1503e51060f0SSean Hefty static int cma_get_port(struct rdma_id_private *id_priv) 1504e51060f0SSean Hefty { 1505e51060f0SSean Hefty struct idr *ps; 1506e51060f0SSean Hefty int ret; 1507e51060f0SSean Hefty 1508e51060f0SSean Hefty switch (id_priv->id.ps) { 1509e51060f0SSean Hefty case RDMA_PS_SDP: 1510e51060f0SSean Hefty ps = &sdp_ps; 1511e51060f0SSean Hefty break; 1512e51060f0SSean Hefty case RDMA_PS_TCP: 1513e51060f0SSean Hefty ps = &tcp_ps; 1514e51060f0SSean Hefty break; 1515e51060f0SSean Hefty default: 1516e51060f0SSean Hefty return -EPROTONOSUPPORT; 1517e51060f0SSean Hefty } 1518e51060f0SSean Hefty 1519e51060f0SSean Hefty mutex_lock(&lock); 1520e51060f0SSean Hefty if (cma_any_port(&id_priv->id.route.addr.src_addr)) 1521e51060f0SSean Hefty ret = cma_alloc_port(ps, id_priv, 0); 1522e51060f0SSean Hefty else 1523e51060f0SSean Hefty ret = cma_use_port(ps, id_priv); 1524e51060f0SSean Hefty mutex_unlock(&lock); 1525e51060f0SSean Hefty 1526e51060f0SSean Hefty return ret; 1527e51060f0SSean Hefty } 1528e51060f0SSean Hefty 1529e51060f0SSean Hefty int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) 1530e51060f0SSean Hefty { 1531e51060f0SSean Hefty struct rdma_id_private *id_priv; 1532e51060f0SSean Hefty int ret; 1533e51060f0SSean Hefty 1534e51060f0SSean Hefty if (addr->sa_family != AF_INET) 1535e51060f0SSean Hefty return -EAFNOSUPPORT; 1536e51060f0SSean Hefty 1537e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1538e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_IDLE, CMA_ADDR_BOUND)) 1539e51060f0SSean Hefty return -EINVAL; 1540e51060f0SSean Hefty 1541e51060f0SSean Hefty if (!cma_any_addr(addr)) { 1542e51060f0SSean Hefty ret = rdma_translate_ip(addr, &id->route.addr.dev_addr); 1543e51060f0SSean Hefty if (!ret) 1544e51060f0SSean Hefty ret = cma_acquire_dev(id_priv); 1545e51060f0SSean Hefty if (ret) 1546e51060f0SSean Hefty goto err; 1547e51060f0SSean Hefty } 1548e51060f0SSean Hefty 1549e51060f0SSean Hefty memcpy(&id->route.addr.src_addr, addr, ip_addr_size(addr)); 1550e51060f0SSean Hefty ret = cma_get_port(id_priv); 1551e51060f0SSean Hefty if (ret) 1552e51060f0SSean Hefty goto err; 1553e51060f0SSean Hefty 1554e51060f0SSean Hefty return 0; 1555e51060f0SSean Hefty err: 1556e51060f0SSean Hefty cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_IDLE); 1557e51060f0SSean Hefty return ret; 1558e51060f0SSean Hefty } 1559e51060f0SSean Hefty EXPORT_SYMBOL(rdma_bind_addr); 1560e51060f0SSean Hefty 1561e51060f0SSean Hefty static int cma_format_hdr(void *hdr, enum rdma_port_space ps, 1562e51060f0SSean Hefty struct rdma_route *route) 1563e51060f0SSean Hefty { 1564e51060f0SSean Hefty struct sockaddr_in *src4, *dst4; 1565e51060f0SSean Hefty struct cma_hdr *cma_hdr; 1566e51060f0SSean Hefty struct sdp_hh *sdp_hdr; 1567e51060f0SSean Hefty 1568e51060f0SSean Hefty src4 = (struct sockaddr_in *) &route->addr.src_addr; 1569e51060f0SSean Hefty dst4 = (struct sockaddr_in *) &route->addr.dst_addr; 1570e51060f0SSean Hefty 1571e51060f0SSean Hefty switch (ps) { 1572e51060f0SSean Hefty case RDMA_PS_SDP: 1573e51060f0SSean Hefty sdp_hdr = hdr; 1574e51060f0SSean Hefty if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION) 1575e51060f0SSean Hefty return -EINVAL; 1576e51060f0SSean Hefty sdp_set_ip_ver(sdp_hdr, 4); 1577e51060f0SSean Hefty sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; 1578e51060f0SSean Hefty sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; 1579e51060f0SSean Hefty sdp_hdr->port = src4->sin_port; 1580e51060f0SSean Hefty break; 1581e51060f0SSean Hefty default: 1582e51060f0SSean Hefty cma_hdr = hdr; 1583e51060f0SSean Hefty cma_hdr->cma_version = CMA_VERSION; 1584e51060f0SSean Hefty cma_set_ip_ver(cma_hdr, 4); 1585e51060f0SSean Hefty cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; 1586e51060f0SSean Hefty cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; 1587e51060f0SSean Hefty cma_hdr->port = src4->sin_port; 1588e51060f0SSean Hefty break; 1589e51060f0SSean Hefty } 1590e51060f0SSean Hefty return 0; 1591e51060f0SSean Hefty } 1592e51060f0SSean Hefty 1593e51060f0SSean Hefty static int cma_connect_ib(struct rdma_id_private *id_priv, 1594e51060f0SSean Hefty struct rdma_conn_param *conn_param) 1595e51060f0SSean Hefty { 1596e51060f0SSean Hefty struct ib_cm_req_param req; 1597e51060f0SSean Hefty struct rdma_route *route; 1598e51060f0SSean Hefty void *private_data; 1599e51060f0SSean Hefty int offset, ret; 1600e51060f0SSean Hefty 1601e51060f0SSean Hefty memset(&req, 0, sizeof req); 1602e51060f0SSean Hefty offset = cma_user_data_offset(id_priv->id.ps); 1603e51060f0SSean Hefty req.private_data_len = offset + conn_param->private_data_len; 1604e51060f0SSean Hefty private_data = kzalloc(req.private_data_len, GFP_ATOMIC); 1605e51060f0SSean Hefty if (!private_data) 1606e51060f0SSean Hefty return -ENOMEM; 1607e51060f0SSean Hefty 1608e51060f0SSean Hefty if (conn_param->private_data && conn_param->private_data_len) 1609e51060f0SSean Hefty memcpy(private_data + offset, conn_param->private_data, 1610e51060f0SSean Hefty conn_param->private_data_len); 1611e51060f0SSean Hefty 1612e51060f0SSean Hefty id_priv->cm_id.ib = ib_create_cm_id(id_priv->id.device, cma_ib_handler, 1613e51060f0SSean Hefty id_priv); 1614e51060f0SSean Hefty if (IS_ERR(id_priv->cm_id.ib)) { 1615e51060f0SSean Hefty ret = PTR_ERR(id_priv->cm_id.ib); 1616e51060f0SSean Hefty goto out; 1617e51060f0SSean Hefty } 1618e51060f0SSean Hefty 1619e51060f0SSean Hefty route = &id_priv->id.route; 1620e51060f0SSean Hefty ret = cma_format_hdr(private_data, id_priv->id.ps, route); 1621e51060f0SSean Hefty if (ret) 1622e51060f0SSean Hefty goto out; 1623e51060f0SSean Hefty req.private_data = private_data; 1624e51060f0SSean Hefty 1625e51060f0SSean Hefty req.primary_path = &route->path_rec[0]; 1626e51060f0SSean Hefty if (route->num_paths == 2) 1627e51060f0SSean Hefty req.alternate_path = &route->path_rec[1]; 1628e51060f0SSean Hefty 1629e51060f0SSean Hefty req.service_id = cma_get_service_id(id_priv->id.ps, 1630e51060f0SSean Hefty &route->addr.dst_addr); 1631e51060f0SSean Hefty req.qp_num = id_priv->qp_num; 1632e51060f0SSean Hefty req.qp_type = id_priv->qp_type; 1633e51060f0SSean Hefty req.starting_psn = id_priv->seq_num; 1634e51060f0SSean Hefty req.responder_resources = conn_param->responder_resources; 1635e51060f0SSean Hefty req.initiator_depth = conn_param->initiator_depth; 1636e51060f0SSean Hefty req.flow_control = conn_param->flow_control; 1637e51060f0SSean Hefty req.retry_count = conn_param->retry_count; 1638e51060f0SSean Hefty req.rnr_retry_count = conn_param->rnr_retry_count; 1639e51060f0SSean Hefty req.remote_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; 1640e51060f0SSean Hefty req.local_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; 1641e51060f0SSean Hefty req.max_cm_retries = CMA_MAX_CM_RETRIES; 1642e51060f0SSean Hefty req.srq = id_priv->srq ? 1 : 0; 1643e51060f0SSean Hefty 1644e51060f0SSean Hefty ret = ib_send_cm_req(id_priv->cm_id.ib, &req); 1645e51060f0SSean Hefty out: 1646e51060f0SSean Hefty kfree(private_data); 1647e51060f0SSean Hefty return ret; 1648e51060f0SSean Hefty } 1649e51060f0SSean Hefty 1650e51060f0SSean Hefty int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) 1651e51060f0SSean Hefty { 1652e51060f0SSean Hefty struct rdma_id_private *id_priv; 1653e51060f0SSean Hefty int ret; 1654e51060f0SSean Hefty 1655e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1656e51060f0SSean Hefty if (!cma_comp_exch(id_priv, CMA_ROUTE_RESOLVED, CMA_CONNECT)) 1657e51060f0SSean Hefty return -EINVAL; 1658e51060f0SSean Hefty 1659e51060f0SSean Hefty if (!id->qp) { 1660e51060f0SSean Hefty id_priv->qp_num = conn_param->qp_num; 1661e51060f0SSean Hefty id_priv->qp_type = conn_param->qp_type; 1662e51060f0SSean Hefty id_priv->srq = conn_param->srq; 1663e51060f0SSean Hefty } 1664e51060f0SSean Hefty 1665e51060f0SSean Hefty switch (id->device->node_type) { 1666e51060f0SSean Hefty case IB_NODE_CA: 1667e51060f0SSean Hefty ret = cma_connect_ib(id_priv, conn_param); 1668e51060f0SSean Hefty break; 1669e51060f0SSean Hefty default: 1670e51060f0SSean Hefty ret = -ENOSYS; 1671e51060f0SSean Hefty break; 1672e51060f0SSean Hefty } 1673e51060f0SSean Hefty if (ret) 1674e51060f0SSean Hefty goto err; 1675e51060f0SSean Hefty 1676e51060f0SSean Hefty return 0; 1677e51060f0SSean Hefty err: 1678e51060f0SSean Hefty cma_comp_exch(id_priv, CMA_CONNECT, CMA_ROUTE_RESOLVED); 1679e51060f0SSean Hefty return ret; 1680e51060f0SSean Hefty } 1681e51060f0SSean Hefty EXPORT_SYMBOL(rdma_connect); 1682e51060f0SSean Hefty 1683e51060f0SSean Hefty static int cma_accept_ib(struct rdma_id_private *id_priv, 1684e51060f0SSean Hefty struct rdma_conn_param *conn_param) 1685e51060f0SSean Hefty { 1686e51060f0SSean Hefty struct ib_cm_rep_param rep; 1687e51060f0SSean Hefty int ret; 1688e51060f0SSean Hefty 1689e51060f0SSean Hefty ret = cma_modify_qp_rtr(&id_priv->id); 1690e51060f0SSean Hefty if (ret) 1691e51060f0SSean Hefty return ret; 1692e51060f0SSean Hefty 1693e51060f0SSean Hefty memset(&rep, 0, sizeof rep); 1694e51060f0SSean Hefty rep.qp_num = id_priv->qp_num; 1695e51060f0SSean Hefty rep.starting_psn = id_priv->seq_num; 1696e51060f0SSean Hefty rep.private_data = conn_param->private_data; 1697e51060f0SSean Hefty rep.private_data_len = conn_param->private_data_len; 1698e51060f0SSean Hefty rep.responder_resources = conn_param->responder_resources; 1699e51060f0SSean Hefty rep.initiator_depth = conn_param->initiator_depth; 1700e51060f0SSean Hefty rep.target_ack_delay = CMA_CM_RESPONSE_TIMEOUT; 1701e51060f0SSean Hefty rep.failover_accepted = 0; 1702e51060f0SSean Hefty rep.flow_control = conn_param->flow_control; 1703e51060f0SSean Hefty rep.rnr_retry_count = conn_param->rnr_retry_count; 1704e51060f0SSean Hefty rep.srq = id_priv->srq ? 1 : 0; 1705e51060f0SSean Hefty 1706e51060f0SSean Hefty return ib_send_cm_rep(id_priv->cm_id.ib, &rep); 1707e51060f0SSean Hefty } 1708e51060f0SSean Hefty 1709e51060f0SSean Hefty int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) 1710e51060f0SSean Hefty { 1711e51060f0SSean Hefty struct rdma_id_private *id_priv; 1712e51060f0SSean Hefty int ret; 1713e51060f0SSean Hefty 1714e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1715e51060f0SSean Hefty if (!cma_comp(id_priv, CMA_CONNECT)) 1716e51060f0SSean Hefty return -EINVAL; 1717e51060f0SSean Hefty 1718e51060f0SSean Hefty if (!id->qp && conn_param) { 1719e51060f0SSean Hefty id_priv->qp_num = conn_param->qp_num; 1720e51060f0SSean Hefty id_priv->qp_type = conn_param->qp_type; 1721e51060f0SSean Hefty id_priv->srq = conn_param->srq; 1722e51060f0SSean Hefty } 1723e51060f0SSean Hefty 1724e51060f0SSean Hefty switch (id->device->node_type) { 1725e51060f0SSean Hefty case IB_NODE_CA: 1726e51060f0SSean Hefty if (conn_param) 1727e51060f0SSean Hefty ret = cma_accept_ib(id_priv, conn_param); 1728e51060f0SSean Hefty else 1729e51060f0SSean Hefty ret = cma_rep_recv(id_priv); 1730e51060f0SSean Hefty break; 1731e51060f0SSean Hefty default: 1732e51060f0SSean Hefty ret = -ENOSYS; 1733e51060f0SSean Hefty break; 1734e51060f0SSean Hefty } 1735e51060f0SSean Hefty 1736e51060f0SSean Hefty if (ret) 1737e51060f0SSean Hefty goto reject; 1738e51060f0SSean Hefty 1739e51060f0SSean Hefty return 0; 1740e51060f0SSean Hefty reject: 1741e51060f0SSean Hefty cma_modify_qp_err(id); 1742e51060f0SSean Hefty rdma_reject(id, NULL, 0); 1743e51060f0SSean Hefty return ret; 1744e51060f0SSean Hefty } 1745e51060f0SSean Hefty EXPORT_SYMBOL(rdma_accept); 1746e51060f0SSean Hefty 1747e51060f0SSean Hefty int rdma_reject(struct rdma_cm_id *id, const void *private_data, 1748e51060f0SSean Hefty u8 private_data_len) 1749e51060f0SSean Hefty { 1750e51060f0SSean Hefty struct rdma_id_private *id_priv; 1751e51060f0SSean Hefty int ret; 1752e51060f0SSean Hefty 1753e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1754e51060f0SSean Hefty if (!cma_comp(id_priv, CMA_CONNECT)) 1755e51060f0SSean Hefty return -EINVAL; 1756e51060f0SSean Hefty 1757e51060f0SSean Hefty switch (id->device->node_type) { 1758e51060f0SSean Hefty case IB_NODE_CA: 1759e51060f0SSean Hefty ret = ib_send_cm_rej(id_priv->cm_id.ib, 1760e51060f0SSean Hefty IB_CM_REJ_CONSUMER_DEFINED, NULL, 0, 1761e51060f0SSean Hefty private_data, private_data_len); 1762e51060f0SSean Hefty break; 1763e51060f0SSean Hefty default: 1764e51060f0SSean Hefty ret = -ENOSYS; 1765e51060f0SSean Hefty break; 1766e51060f0SSean Hefty } 1767e51060f0SSean Hefty return ret; 1768e51060f0SSean Hefty } 1769e51060f0SSean Hefty EXPORT_SYMBOL(rdma_reject); 1770e51060f0SSean Hefty 1771e51060f0SSean Hefty int rdma_disconnect(struct rdma_cm_id *id) 1772e51060f0SSean Hefty { 1773e51060f0SSean Hefty struct rdma_id_private *id_priv; 1774e51060f0SSean Hefty int ret; 1775e51060f0SSean Hefty 1776e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1777e51060f0SSean Hefty if (!cma_comp(id_priv, CMA_CONNECT) && 1778e51060f0SSean Hefty !cma_comp(id_priv, CMA_DISCONNECT)) 1779e51060f0SSean Hefty return -EINVAL; 1780e51060f0SSean Hefty 1781e51060f0SSean Hefty ret = cma_modify_qp_err(id); 1782e51060f0SSean Hefty if (ret) 1783e51060f0SSean Hefty goto out; 1784e51060f0SSean Hefty 1785e51060f0SSean Hefty switch (id->device->node_type) { 1786e51060f0SSean Hefty case IB_NODE_CA: 1787e51060f0SSean Hefty /* Initiate or respond to a disconnect. */ 1788e51060f0SSean Hefty if (ib_send_cm_dreq(id_priv->cm_id.ib, NULL, 0)) 1789e51060f0SSean Hefty ib_send_cm_drep(id_priv->cm_id.ib, NULL, 0); 1790e51060f0SSean Hefty break; 1791e51060f0SSean Hefty default: 1792e51060f0SSean Hefty break; 1793e51060f0SSean Hefty } 1794e51060f0SSean Hefty out: 1795e51060f0SSean Hefty return ret; 1796e51060f0SSean Hefty } 1797e51060f0SSean Hefty EXPORT_SYMBOL(rdma_disconnect); 1798e51060f0SSean Hefty 1799e51060f0SSean Hefty static void cma_add_one(struct ib_device *device) 1800e51060f0SSean Hefty { 1801e51060f0SSean Hefty struct cma_device *cma_dev; 1802e51060f0SSean Hefty struct rdma_id_private *id_priv; 1803e51060f0SSean Hefty 1804e51060f0SSean Hefty cma_dev = kmalloc(sizeof *cma_dev, GFP_KERNEL); 1805e51060f0SSean Hefty if (!cma_dev) 1806e51060f0SSean Hefty return; 1807e51060f0SSean Hefty 1808e51060f0SSean Hefty cma_dev->device = device; 1809e51060f0SSean Hefty cma_dev->node_guid = device->node_guid; 1810e51060f0SSean Hefty if (!cma_dev->node_guid) 1811e51060f0SSean Hefty goto err; 1812e51060f0SSean Hefty 1813e51060f0SSean Hefty init_completion(&cma_dev->comp); 1814e51060f0SSean Hefty atomic_set(&cma_dev->refcount, 1); 1815e51060f0SSean Hefty INIT_LIST_HEAD(&cma_dev->id_list); 1816e51060f0SSean Hefty ib_set_client_data(device, &cma_client, cma_dev); 1817e51060f0SSean Hefty 1818e51060f0SSean Hefty mutex_lock(&lock); 1819e51060f0SSean Hefty list_add_tail(&cma_dev->list, &dev_list); 1820e51060f0SSean Hefty list_for_each_entry(id_priv, &listen_any_list, list) 1821e51060f0SSean Hefty cma_listen_on_dev(id_priv, cma_dev); 1822e51060f0SSean Hefty mutex_unlock(&lock); 1823e51060f0SSean Hefty return; 1824e51060f0SSean Hefty err: 1825e51060f0SSean Hefty kfree(cma_dev); 1826e51060f0SSean Hefty } 1827e51060f0SSean Hefty 1828e51060f0SSean Hefty static int cma_remove_id_dev(struct rdma_id_private *id_priv) 1829e51060f0SSean Hefty { 1830e51060f0SSean Hefty enum cma_state state; 1831e51060f0SSean Hefty 1832e51060f0SSean Hefty /* Record that we want to remove the device */ 1833e51060f0SSean Hefty state = cma_exch(id_priv, CMA_DEVICE_REMOVAL); 1834e51060f0SSean Hefty if (state == CMA_DESTROYING) 1835e51060f0SSean Hefty return 0; 1836e51060f0SSean Hefty 1837e51060f0SSean Hefty cma_cancel_operation(id_priv, state); 1838e51060f0SSean Hefty wait_event(id_priv->wait_remove, !atomic_read(&id_priv->dev_remove)); 1839e51060f0SSean Hefty 1840e51060f0SSean Hefty /* Check for destruction from another callback. */ 1841e51060f0SSean Hefty if (!cma_comp(id_priv, CMA_DEVICE_REMOVAL)) 1842e51060f0SSean Hefty return 0; 1843e51060f0SSean Hefty 1844e51060f0SSean Hefty return cma_notify_user(id_priv, RDMA_CM_EVENT_DEVICE_REMOVAL, 1845e51060f0SSean Hefty 0, NULL, 0); 1846e51060f0SSean Hefty } 1847e51060f0SSean Hefty 1848e51060f0SSean Hefty static void cma_process_remove(struct cma_device *cma_dev) 1849e51060f0SSean Hefty { 1850e51060f0SSean Hefty struct list_head remove_list; 1851e51060f0SSean Hefty struct rdma_id_private *id_priv; 1852e51060f0SSean Hefty int ret; 1853e51060f0SSean Hefty 1854e51060f0SSean Hefty INIT_LIST_HEAD(&remove_list); 1855e51060f0SSean Hefty 1856e51060f0SSean Hefty mutex_lock(&lock); 1857e51060f0SSean Hefty while (!list_empty(&cma_dev->id_list)) { 1858e51060f0SSean Hefty id_priv = list_entry(cma_dev->id_list.next, 1859e51060f0SSean Hefty struct rdma_id_private, list); 1860e51060f0SSean Hefty 1861e51060f0SSean Hefty if (cma_internal_listen(id_priv)) { 1862e51060f0SSean Hefty cma_destroy_listen(id_priv); 1863e51060f0SSean Hefty continue; 1864e51060f0SSean Hefty } 1865e51060f0SSean Hefty 1866e51060f0SSean Hefty list_del(&id_priv->list); 1867e51060f0SSean Hefty list_add_tail(&id_priv->list, &remove_list); 1868e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 1869e51060f0SSean Hefty mutex_unlock(&lock); 1870e51060f0SSean Hefty 1871e51060f0SSean Hefty ret = cma_remove_id_dev(id_priv); 1872e51060f0SSean Hefty cma_deref_id(id_priv); 1873e51060f0SSean Hefty if (ret) 1874e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 1875e51060f0SSean Hefty 1876e51060f0SSean Hefty mutex_lock(&lock); 1877e51060f0SSean Hefty } 1878e51060f0SSean Hefty mutex_unlock(&lock); 1879e51060f0SSean Hefty 1880e51060f0SSean Hefty cma_deref_dev(cma_dev); 1881e51060f0SSean Hefty wait_for_completion(&cma_dev->comp); 1882e51060f0SSean Hefty } 1883e51060f0SSean Hefty 1884e51060f0SSean Hefty static void cma_remove_one(struct ib_device *device) 1885e51060f0SSean Hefty { 1886e51060f0SSean Hefty struct cma_device *cma_dev; 1887e51060f0SSean Hefty 1888e51060f0SSean Hefty cma_dev = ib_get_client_data(device, &cma_client); 1889e51060f0SSean Hefty if (!cma_dev) 1890e51060f0SSean Hefty return; 1891e51060f0SSean Hefty 1892e51060f0SSean Hefty mutex_lock(&lock); 1893e51060f0SSean Hefty list_del(&cma_dev->list); 1894e51060f0SSean Hefty mutex_unlock(&lock); 1895e51060f0SSean Hefty 1896e51060f0SSean Hefty cma_process_remove(cma_dev); 1897e51060f0SSean Hefty kfree(cma_dev); 1898e51060f0SSean Hefty } 1899e51060f0SSean Hefty 1900e51060f0SSean Hefty static int cma_init(void) 1901e51060f0SSean Hefty { 1902e51060f0SSean Hefty int ret; 1903e51060f0SSean Hefty 1904e51060f0SSean Hefty cma_wq = create_singlethread_workqueue("rdma_cm_wq"); 1905e51060f0SSean Hefty if (!cma_wq) 1906e51060f0SSean Hefty return -ENOMEM; 1907e51060f0SSean Hefty 1908e51060f0SSean Hefty ret = ib_register_client(&cma_client); 1909e51060f0SSean Hefty if (ret) 1910e51060f0SSean Hefty goto err; 1911e51060f0SSean Hefty return 0; 1912e51060f0SSean Hefty 1913e51060f0SSean Hefty err: 1914e51060f0SSean Hefty destroy_workqueue(cma_wq); 1915e51060f0SSean Hefty return ret; 1916e51060f0SSean Hefty } 1917e51060f0SSean Hefty 1918e51060f0SSean Hefty static void cma_cleanup(void) 1919e51060f0SSean Hefty { 1920e51060f0SSean Hefty ib_unregister_client(&cma_client); 1921e51060f0SSean Hefty destroy_workqueue(cma_wq); 1922e51060f0SSean Hefty idr_destroy(&sdp_ps); 1923e51060f0SSean Hefty idr_destroy(&tcp_ps); 1924e51060f0SSean Hefty } 1925e51060f0SSean Hefty 1926e51060f0SSean Hefty module_init(cma_init); 1927e51060f0SSean Hefty module_exit(cma_cleanup); 1928