1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004-2007 Intel Corporation. All rights reserved. 3219820Sjeff * Copyright (c) 2004 Topspin Corporation. All rights reserved. 4219820Sjeff * Copyright (c) 2004, 2005 Voltaire Corporation. All rights reserved. 5219820Sjeff * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 6219820Sjeff * 7219820Sjeff * This software is available to you under a choice of one of two 8219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 9219820Sjeff * General Public License (GPL) Version 2, available from the file 10219820Sjeff * COPYING in the main directory of this source tree, or the 11219820Sjeff * OpenIB.org BSD license below: 12219820Sjeff * 13219820Sjeff * Redistribution and use in source and binary forms, with or 14219820Sjeff * without modification, are permitted provided that the following 15219820Sjeff * conditions are met: 16219820Sjeff * 17219820Sjeff * - Redistributions of source code must retain the above 18219820Sjeff * copyright notice, this list of conditions and the following 19219820Sjeff * disclaimer. 20219820Sjeff * 21219820Sjeff * - Redistributions in binary form must reproduce the above 22219820Sjeff * copyright notice, this list of conditions and the following 23219820Sjeff * disclaimer in the documentation and/or other materials 24219820Sjeff * provided with the distribution. 25219820Sjeff * 26219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 27219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 28219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 29219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 30219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 31219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 32219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 33219820Sjeff * SOFTWARE. 34219820Sjeff */ 35219820Sjeff 36219820Sjeff#include <linux/completion.h> 37219820Sjeff#include <linux/dma-mapping.h> 38219820Sjeff#include <linux/device.h> 39219820Sjeff#include <linux/err.h> 40219820Sjeff#include <linux/idr.h> 41219820Sjeff#include <linux/interrupt.h> 42219820Sjeff#include <linux/random.h> 43219820Sjeff#include <linux/rbtree.h> 44219820Sjeff#include <linux/spinlock.h> 45219820Sjeff#include <linux/sysfs.h> 46219820Sjeff#include <linux/workqueue.h> 47219820Sjeff#include <linux/kdev_t.h> 48271127Shselasky#include <linux/string.h> 49219820Sjeff 50271127Shselasky#include <asm/atomic-long.h> 51271127Shselasky 52219820Sjeff#include <rdma/ib_cache.h> 53219820Sjeff#include <rdma/ib_cm.h> 54219820Sjeff#include "cm_msgs.h" 55219820Sjeff 56219820SjeffMODULE_AUTHOR("Sean Hefty"); 57219820SjeffMODULE_DESCRIPTION("InfiniBand CM"); 58219820SjeffMODULE_LICENSE("Dual BSD/GPL"); 59219820Sjeff 60219820Sjeff#define PFX "ib_cm: " 61219820Sjeff 62219820Sjeff/* 63219820Sjeff * Limit CM message timeouts to something reasonable: 64219820Sjeff * 8 seconds per message, with up to 15 retries 65219820Sjeff */ 66219820Sjeffstatic int max_timeout = 21; 67219820Sjeffmodule_param(max_timeout, int, 0644); 68219820SjeffMODULE_PARM_DESC(max_timeout, "Maximum IB CM per message timeout " 69219820Sjeff "(default=21, or ~8 seconds)"); 70219820Sjeff 71219820Sjeffstatic void cm_add_one(struct ib_device *device); 72219820Sjeffstatic void cm_remove_one(struct ib_device *device); 73219820Sjeff 74219820Sjeffstatic struct ib_client cm_client = { 75219820Sjeff .name = "cm", 76219820Sjeff .add = cm_add_one, 77219820Sjeff .remove = cm_remove_one 78219820Sjeff}; 79219820Sjeff 80219820Sjeffstatic struct ib_cm { 81219820Sjeff spinlock_t lock; 82219820Sjeff struct list_head device_list; 83219820Sjeff rwlock_t device_lock; 84219820Sjeff struct rb_root listen_service_table; 85219820Sjeff u64 listen_service_id; 86219820Sjeff /* struct rb_root peer_service_table; todo: fix peer to peer */ 87219820Sjeff struct rb_root remote_qp_table; 88219820Sjeff struct rb_root remote_id_table; 89219820Sjeff struct rb_root remote_sidr_table; 90219820Sjeff struct idr local_id_table; 91219820Sjeff __be32 random_id_operand; 92219820Sjeff struct list_head timewait_list; 93219820Sjeff struct workqueue_struct *wq; 94219820Sjeff} cm; 95219820Sjeff 96219820Sjeff/* Counter indexes ordered by attribute ID */ 97219820Sjeffenum { 98219820Sjeff CM_REQ_COUNTER, 99219820Sjeff CM_MRA_COUNTER, 100219820Sjeff CM_REJ_COUNTER, 101219820Sjeff CM_REP_COUNTER, 102219820Sjeff CM_RTU_COUNTER, 103219820Sjeff CM_DREQ_COUNTER, 104219820Sjeff CM_DREP_COUNTER, 105219820Sjeff CM_SIDR_REQ_COUNTER, 106219820Sjeff CM_SIDR_REP_COUNTER, 107219820Sjeff CM_LAP_COUNTER, 108219820Sjeff CM_APR_COUNTER, 109219820Sjeff CM_ATTR_COUNT, 110219820Sjeff CM_ATTR_ID_OFFSET = 0x0010, 111219820Sjeff}; 112219820Sjeff 113219820Sjeffenum { 114219820Sjeff CM_XMIT, 115219820Sjeff CM_XMIT_RETRIES, 116219820Sjeff CM_RECV, 117219820Sjeff CM_RECV_DUPLICATES, 118219820Sjeff CM_COUNTER_GROUPS 119219820Sjeff}; 120219820Sjeff 121219820Sjeffstatic char const counter_group_names[CM_COUNTER_GROUPS] 122219820Sjeff [sizeof("cm_rx_duplicates")] = { 123219820Sjeff "cm_tx_msgs", "cm_tx_retries", 124219820Sjeff "cm_rx_msgs", "cm_rx_duplicates" 125219820Sjeff}; 126219820Sjeff 127219820Sjeffstruct cm_counter_group { 128219820Sjeff struct kobject obj; 129219820Sjeff atomic_long_t counter[CM_ATTR_COUNT]; 130219820Sjeff}; 131219820Sjeff 132219820Sjeffstruct cm_counter_attribute { 133219820Sjeff struct attribute attr; 134219820Sjeff int index; 135219820Sjeff}; 136219820Sjeff 137219820Sjeff#define CM_COUNTER_ATTR(_name, _index) \ 138219820Sjeffstruct cm_counter_attribute cm_##_name##_counter_attr = { \ 139219820Sjeff .attr = { .name = __stringify(_name), .mode = 0444 }, \ 140219820Sjeff .index = _index \ 141219820Sjeff} 142219820Sjeff 143219820Sjeffstatic CM_COUNTER_ATTR(req, CM_REQ_COUNTER); 144219820Sjeffstatic CM_COUNTER_ATTR(mra, CM_MRA_COUNTER); 145219820Sjeffstatic CM_COUNTER_ATTR(rej, CM_REJ_COUNTER); 146219820Sjeffstatic CM_COUNTER_ATTR(rep, CM_REP_COUNTER); 147219820Sjeffstatic CM_COUNTER_ATTR(rtu, CM_RTU_COUNTER); 148219820Sjeffstatic CM_COUNTER_ATTR(dreq, CM_DREQ_COUNTER); 149219820Sjeffstatic CM_COUNTER_ATTR(drep, CM_DREP_COUNTER); 150219820Sjeffstatic CM_COUNTER_ATTR(sidr_req, CM_SIDR_REQ_COUNTER); 151219820Sjeffstatic CM_COUNTER_ATTR(sidr_rep, CM_SIDR_REP_COUNTER); 152219820Sjeffstatic CM_COUNTER_ATTR(lap, CM_LAP_COUNTER); 153219820Sjeffstatic CM_COUNTER_ATTR(apr, CM_APR_COUNTER); 154219820Sjeff 155219820Sjeffstatic struct attribute *cm_counter_default_attrs[] = { 156219820Sjeff &cm_req_counter_attr.attr, 157219820Sjeff &cm_mra_counter_attr.attr, 158219820Sjeff &cm_rej_counter_attr.attr, 159219820Sjeff &cm_rep_counter_attr.attr, 160219820Sjeff &cm_rtu_counter_attr.attr, 161219820Sjeff &cm_dreq_counter_attr.attr, 162219820Sjeff &cm_drep_counter_attr.attr, 163219820Sjeff &cm_sidr_req_counter_attr.attr, 164219820Sjeff &cm_sidr_rep_counter_attr.attr, 165219820Sjeff &cm_lap_counter_attr.attr, 166219820Sjeff &cm_apr_counter_attr.attr, 167219820Sjeff NULL 168219820Sjeff}; 169219820Sjeff 170219820Sjeffstruct cm_port { 171219820Sjeff struct cm_device *cm_dev; 172219820Sjeff struct ib_mad_agent *mad_agent; 173219820Sjeff struct kobject port_obj; 174219820Sjeff u8 port_num; 175219820Sjeff struct cm_counter_group counter_group[CM_COUNTER_GROUPS]; 176219820Sjeff}; 177219820Sjeff 178219820Sjeffstruct cm_device { 179219820Sjeff struct list_head list; 180219820Sjeff struct ib_device *ib_device; 181219820Sjeff struct device *device; 182219820Sjeff u8 ack_delay; 183219820Sjeff struct cm_port *port[0]; 184219820Sjeff}; 185219820Sjeff 186219820Sjeffstruct cm_av { 187219820Sjeff struct cm_port *port; 188219820Sjeff union ib_gid dgid; 189219820Sjeff struct ib_ah_attr ah_attr; 190219820Sjeff u16 pkey_index; 191219820Sjeff u8 timeout; 192219820Sjeff}; 193219820Sjeff 194219820Sjeffstruct cm_work { 195219820Sjeff struct delayed_work work; 196219820Sjeff struct list_head list; 197219820Sjeff struct cm_port *port; 198219820Sjeff struct ib_mad_recv_wc *mad_recv_wc; /* Received MADs */ 199219820Sjeff __be32 local_id; /* Established / timewait */ 200219820Sjeff __be32 remote_id; 201219820Sjeff struct ib_cm_event cm_event; 202219820Sjeff struct ib_sa_path_rec path[0]; 203219820Sjeff}; 204219820Sjeff 205219820Sjeffstruct cm_timewait_info { 206219820Sjeff struct cm_work work; /* Must be first. */ 207219820Sjeff struct list_head list; 208219820Sjeff struct rb_node remote_qp_node; 209219820Sjeff struct rb_node remote_id_node; 210219820Sjeff __be64 remote_ca_guid; 211219820Sjeff __be32 remote_qpn; 212219820Sjeff u8 inserted_remote_qp; 213219820Sjeff u8 inserted_remote_id; 214219820Sjeff}; 215219820Sjeff 216219820Sjeffstruct cm_id_private { 217219820Sjeff struct ib_cm_id id; 218219820Sjeff 219219820Sjeff struct rb_node service_node; 220219820Sjeff struct rb_node sidr_id_node; 221219820Sjeff spinlock_t lock; /* Do not acquire inside cm.lock */ 222219820Sjeff struct completion comp; 223219820Sjeff atomic_t refcount; 224219820Sjeff 225219820Sjeff struct ib_mad_send_buf *msg; 226219820Sjeff struct cm_timewait_info *timewait_info; 227219820Sjeff /* todo: use alternate port on send failure */ 228219820Sjeff struct cm_av av; 229219820Sjeff struct cm_av alt_av; 230219820Sjeff struct ib_cm_compare_data *compare_data; 231219820Sjeff 232219820Sjeff void *private_data; 233219820Sjeff __be64 tid; 234219820Sjeff __be32 local_qpn; 235219820Sjeff __be32 remote_qpn; 236219820Sjeff enum ib_qp_type qp_type; 237219820Sjeff __be32 sq_psn; 238219820Sjeff __be32 rq_psn; 239219820Sjeff int timeout_ms; 240219820Sjeff enum ib_mtu path_mtu; 241219820Sjeff __be16 pkey; 242219820Sjeff u8 private_data_len; 243219820Sjeff u8 max_cm_retries; 244219820Sjeff u8 peer_to_peer; 245219820Sjeff u8 responder_resources; 246219820Sjeff u8 initiator_depth; 247219820Sjeff u8 retry_count; 248219820Sjeff u8 rnr_retry_count; 249219820Sjeff u8 service_timeout; 250219820Sjeff u8 target_ack_delay; 251219820Sjeff 252219820Sjeff struct list_head work_list; 253219820Sjeff atomic_t work_count; 254219820Sjeff}; 255219820Sjeff 256219820Sjeffstatic void cm_work_handler(struct work_struct *work); 257219820Sjeff 258219820Sjeffstatic inline void cm_deref_id(struct cm_id_private *cm_id_priv) 259219820Sjeff{ 260219820Sjeff if (atomic_dec_and_test(&cm_id_priv->refcount)) 261219820Sjeff complete(&cm_id_priv->comp); 262219820Sjeff} 263219820Sjeff 264219820Sjeffstatic int cm_alloc_msg(struct cm_id_private *cm_id_priv, 265219820Sjeff struct ib_mad_send_buf **msg) 266219820Sjeff{ 267219820Sjeff struct ib_mad_agent *mad_agent; 268219820Sjeff struct ib_mad_send_buf *m; 269219820Sjeff struct ib_ah *ah; 270219820Sjeff 271219820Sjeff mad_agent = cm_id_priv->av.port->mad_agent; 272219820Sjeff ah = ib_create_ah(mad_agent->qp->pd, &cm_id_priv->av.ah_attr); 273219820Sjeff if (IS_ERR(ah)) 274219820Sjeff return PTR_ERR(ah); 275219820Sjeff 276219820Sjeff m = ib_create_send_mad(mad_agent, cm_id_priv->id.remote_cm_qpn, 277219820Sjeff cm_id_priv->av.pkey_index, 278219820Sjeff 0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, 279219820Sjeff GFP_ATOMIC); 280219820Sjeff if (IS_ERR(m)) { 281219820Sjeff ib_destroy_ah(ah); 282219820Sjeff return PTR_ERR(m); 283219820Sjeff } 284219820Sjeff 285219820Sjeff /* Timeout set by caller if response is expected. */ 286219820Sjeff m->ah = ah; 287219820Sjeff m->retries = cm_id_priv->max_cm_retries; 288219820Sjeff 289219820Sjeff atomic_inc(&cm_id_priv->refcount); 290219820Sjeff m->context[0] = cm_id_priv; 291219820Sjeff *msg = m; 292219820Sjeff return 0; 293219820Sjeff} 294219820Sjeff 295219820Sjeffstatic int cm_alloc_response_msg(struct cm_port *port, 296219820Sjeff struct ib_mad_recv_wc *mad_recv_wc, 297219820Sjeff struct ib_mad_send_buf **msg) 298219820Sjeff{ 299219820Sjeff struct ib_mad_send_buf *m; 300219820Sjeff struct ib_ah *ah; 301219820Sjeff 302219820Sjeff ah = ib_create_ah_from_wc(port->mad_agent->qp->pd, mad_recv_wc->wc, 303219820Sjeff mad_recv_wc->recv_buf.grh, port->port_num); 304219820Sjeff if (IS_ERR(ah)) 305219820Sjeff return PTR_ERR(ah); 306219820Sjeff 307219820Sjeff m = ib_create_send_mad(port->mad_agent, 1, mad_recv_wc->wc->pkey_index, 308219820Sjeff 0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, 309219820Sjeff GFP_ATOMIC); 310219820Sjeff if (IS_ERR(m)) { 311219820Sjeff ib_destroy_ah(ah); 312219820Sjeff return PTR_ERR(m); 313219820Sjeff } 314219820Sjeff m->ah = ah; 315219820Sjeff *msg = m; 316219820Sjeff return 0; 317219820Sjeff} 318219820Sjeff 319219820Sjeffstatic void cm_free_msg(struct ib_mad_send_buf *msg) 320219820Sjeff{ 321219820Sjeff ib_destroy_ah(msg->ah); 322219820Sjeff if (msg->context[0]) 323219820Sjeff cm_deref_id(msg->context[0]); 324219820Sjeff ib_free_send_mad(msg); 325219820Sjeff} 326219820Sjeff 327219820Sjeffstatic void * cm_copy_private_data(const void *private_data, 328219820Sjeff u8 private_data_len) 329219820Sjeff{ 330219820Sjeff void *data; 331219820Sjeff 332219820Sjeff if (!private_data || !private_data_len) 333219820Sjeff return NULL; 334219820Sjeff 335219820Sjeff data = kmemdup(private_data, private_data_len, GFP_KERNEL); 336219820Sjeff if (!data) 337219820Sjeff return ERR_PTR(-ENOMEM); 338219820Sjeff 339219820Sjeff return data; 340219820Sjeff} 341219820Sjeff 342219820Sjeffstatic void cm_set_private_data(struct cm_id_private *cm_id_priv, 343219820Sjeff void *private_data, u8 private_data_len) 344219820Sjeff{ 345219820Sjeff if (cm_id_priv->private_data && cm_id_priv->private_data_len) 346219820Sjeff kfree(cm_id_priv->private_data); 347219820Sjeff 348219820Sjeff cm_id_priv->private_data = private_data; 349219820Sjeff cm_id_priv->private_data_len = private_data_len; 350219820Sjeff} 351219820Sjeff 352219820Sjeffstatic void cm_init_av_for_response(struct cm_port *port, struct ib_wc *wc, 353219820Sjeff struct ib_grh *grh, struct cm_av *av) 354219820Sjeff{ 355219820Sjeff av->port = port; 356219820Sjeff av->pkey_index = wc->pkey_index; 357219820Sjeff ib_init_ah_from_wc(port->cm_dev->ib_device, port->port_num, wc, 358219820Sjeff grh, &av->ah_attr); 359219820Sjeff} 360219820Sjeff 361219820Sjeffstatic int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av) 362219820Sjeff{ 363219820Sjeff struct cm_device *cm_dev; 364219820Sjeff struct cm_port *port = NULL; 365219820Sjeff unsigned long flags; 366219820Sjeff int ret; 367219820Sjeff u8 p; 368219820Sjeff 369219820Sjeff read_lock_irqsave(&cm.device_lock, flags); 370219820Sjeff list_for_each_entry(cm_dev, &cm.device_list, list) { 371219820Sjeff if (!ib_find_cached_gid(cm_dev->ib_device, &path->sgid, 372219820Sjeff &p, NULL)) { 373219820Sjeff port = cm_dev->port[p-1]; 374219820Sjeff break; 375219820Sjeff } 376219820Sjeff } 377219820Sjeff read_unlock_irqrestore(&cm.device_lock, flags); 378219820Sjeff 379219820Sjeff if (!port) 380219820Sjeff return -EINVAL; 381219820Sjeff 382219820Sjeff ret = ib_find_cached_pkey(cm_dev->ib_device, port->port_num, 383219820Sjeff be16_to_cpu(path->pkey), &av->pkey_index); 384219820Sjeff if (ret) 385219820Sjeff return ret; 386219820Sjeff 387219820Sjeff av->port = port; 388219820Sjeff ib_init_ah_from_path(cm_dev->ib_device, port->port_num, path, 389219820Sjeff &av->ah_attr); 390219820Sjeff av->timeout = path->packet_life_time + 1; 391219820Sjeff return 0; 392219820Sjeff} 393219820Sjeff 394219820Sjeffstatic int cm_alloc_id(struct cm_id_private *cm_id_priv) 395219820Sjeff{ 396219820Sjeff unsigned long flags; 397219820Sjeff int ret, id; 398219820Sjeff static int next_id; 399219820Sjeff 400219820Sjeff do { 401219820Sjeff spin_lock_irqsave(&cm.lock, flags); 402219820Sjeff ret = idr_get_new_above(&cm.local_id_table, cm_id_priv, 403219820Sjeff next_id, &id); 404219820Sjeff if (!ret) 405219820Sjeff next_id = ((unsigned) id + 1) & MAX_ID_MASK; 406219820Sjeff spin_unlock_irqrestore(&cm.lock, flags); 407219820Sjeff } while( (ret == -EAGAIN) && idr_pre_get(&cm.local_id_table, GFP_KERNEL) ); 408219820Sjeff 409219820Sjeff cm_id_priv->id.local_id = (__force __be32)id ^ cm.random_id_operand; 410219820Sjeff return ret; 411219820Sjeff} 412219820Sjeff 413219820Sjeffstatic void cm_free_id(__be32 local_id) 414219820Sjeff{ 415219820Sjeff spin_lock_irq(&cm.lock); 416219820Sjeff idr_remove(&cm.local_id_table, 417219820Sjeff (__force int) (local_id ^ cm.random_id_operand)); 418219820Sjeff spin_unlock_irq(&cm.lock); 419219820Sjeff} 420219820Sjeff 421219820Sjeffstatic struct cm_id_private * cm_get_id(__be32 local_id, __be32 remote_id) 422219820Sjeff{ 423219820Sjeff struct cm_id_private *cm_id_priv; 424219820Sjeff 425219820Sjeff cm_id_priv = idr_find(&cm.local_id_table, 426219820Sjeff (__force int) (local_id ^ cm.random_id_operand)); 427219820Sjeff if (cm_id_priv) { 428219820Sjeff if (cm_id_priv->id.remote_id == remote_id) 429219820Sjeff atomic_inc(&cm_id_priv->refcount); 430219820Sjeff else 431219820Sjeff cm_id_priv = NULL; 432219820Sjeff } 433219820Sjeff 434219820Sjeff return cm_id_priv; 435219820Sjeff} 436219820Sjeff 437219820Sjeffstatic struct cm_id_private * cm_acquire_id(__be32 local_id, __be32 remote_id) 438219820Sjeff{ 439219820Sjeff struct cm_id_private *cm_id_priv; 440219820Sjeff 441219820Sjeff spin_lock_irq(&cm.lock); 442219820Sjeff cm_id_priv = cm_get_id(local_id, remote_id); 443219820Sjeff spin_unlock_irq(&cm.lock); 444219820Sjeff 445219820Sjeff return cm_id_priv; 446219820Sjeff} 447219820Sjeff 448219820Sjeffstatic void cm_mask_copy(u8 *dst, u8 *src, u8 *mask) 449219820Sjeff{ 450219820Sjeff int i; 451219820Sjeff 452219820Sjeff for (i = 0; i < IB_CM_COMPARE_SIZE / sizeof(unsigned long); i++) 453219820Sjeff ((unsigned long *) dst)[i] = ((unsigned long *) src)[i] & 454219820Sjeff ((unsigned long *) mask)[i]; 455219820Sjeff} 456219820Sjeff 457219820Sjeffstatic int cm_compare_data(struct ib_cm_compare_data *src_data, 458219820Sjeff struct ib_cm_compare_data *dst_data) 459219820Sjeff{ 460219820Sjeff u8 src[IB_CM_COMPARE_SIZE]; 461219820Sjeff u8 dst[IB_CM_COMPARE_SIZE]; 462219820Sjeff 463219820Sjeff if (!src_data || !dst_data) 464219820Sjeff return 0; 465219820Sjeff 466219820Sjeff cm_mask_copy(src, src_data->data, dst_data->mask); 467219820Sjeff cm_mask_copy(dst, dst_data->data, src_data->mask); 468219820Sjeff return memcmp(src, dst, IB_CM_COMPARE_SIZE); 469219820Sjeff} 470219820Sjeff 471219820Sjeffstatic int cm_compare_private_data(u8 *private_data, 472219820Sjeff struct ib_cm_compare_data *dst_data) 473219820Sjeff{ 474219820Sjeff u8 src[IB_CM_COMPARE_SIZE]; 475219820Sjeff 476219820Sjeff if (!dst_data) 477219820Sjeff return 0; 478219820Sjeff 479219820Sjeff cm_mask_copy(src, private_data, dst_data->mask); 480219820Sjeff return memcmp(src, dst_data->data, IB_CM_COMPARE_SIZE); 481219820Sjeff} 482219820Sjeff 483219820Sjeff/* 484219820Sjeff * Trivial helpers to strip endian annotation and compare; the 485219820Sjeff * endianness doesn't actually matter since we just need a stable 486219820Sjeff * order for the RB tree. 487219820Sjeff */ 488219820Sjeffstatic int be32_lt(__be32 a, __be32 b) 489219820Sjeff{ 490219820Sjeff return (__force u32) a < (__force u32) b; 491219820Sjeff} 492219820Sjeff 493219820Sjeffstatic int be32_gt(__be32 a, __be32 b) 494219820Sjeff{ 495219820Sjeff return (__force u32) a > (__force u32) b; 496219820Sjeff} 497219820Sjeff 498219820Sjeffstatic int be64_lt(__be64 a, __be64 b) 499219820Sjeff{ 500219820Sjeff return (__force u64) a < (__force u64) b; 501219820Sjeff} 502219820Sjeff 503219820Sjeffstatic int be64_gt(__be64 a, __be64 b) 504219820Sjeff{ 505219820Sjeff return (__force u64) a > (__force u64) b; 506219820Sjeff} 507219820Sjeff 508219820Sjeffstatic struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) 509219820Sjeff{ 510219820Sjeff struct rb_node **link = &cm.listen_service_table.rb_node; 511219820Sjeff struct rb_node *parent = NULL; 512219820Sjeff struct cm_id_private *cur_cm_id_priv; 513219820Sjeff __be64 service_id = cm_id_priv->id.service_id; 514219820Sjeff __be64 service_mask = cm_id_priv->id.service_mask; 515219820Sjeff int data_cmp; 516219820Sjeff 517219820Sjeff while (*link) { 518219820Sjeff parent = *link; 519219820Sjeff cur_cm_id_priv = rb_entry(parent, struct cm_id_private, 520219820Sjeff service_node); 521219820Sjeff data_cmp = cm_compare_data(cm_id_priv->compare_data, 522219820Sjeff cur_cm_id_priv->compare_data); 523219820Sjeff if ((cur_cm_id_priv->id.service_mask & service_id) == 524219820Sjeff (service_mask & cur_cm_id_priv->id.service_id) && 525219820Sjeff (cm_id_priv->id.device == cur_cm_id_priv->id.device) && 526219820Sjeff !data_cmp) 527219820Sjeff return cur_cm_id_priv; 528219820Sjeff 529219820Sjeff if (cm_id_priv->id.device < cur_cm_id_priv->id.device) 530219820Sjeff link = &(*link)->rb_left; 531219820Sjeff else if (cm_id_priv->id.device > cur_cm_id_priv->id.device) 532219820Sjeff link = &(*link)->rb_right; 533219820Sjeff else if (be64_lt(service_id, cur_cm_id_priv->id.service_id)) 534219820Sjeff link = &(*link)->rb_left; 535219820Sjeff else if (be64_gt(service_id, cur_cm_id_priv->id.service_id)) 536219820Sjeff link = &(*link)->rb_right; 537219820Sjeff else if (data_cmp < 0) 538219820Sjeff link = &(*link)->rb_left; 539219820Sjeff else 540219820Sjeff link = &(*link)->rb_right; 541219820Sjeff } 542219820Sjeff rb_link_node(&cm_id_priv->service_node, parent, link); 543219820Sjeff rb_insert_color(&cm_id_priv->service_node, &cm.listen_service_table); 544219820Sjeff return NULL; 545219820Sjeff} 546219820Sjeff 547219820Sjeffstatic struct cm_id_private * cm_find_listen(struct ib_device *device, 548219820Sjeff __be64 service_id, 549219820Sjeff u8 *private_data) 550219820Sjeff{ 551219820Sjeff struct rb_node *node = cm.listen_service_table.rb_node; 552219820Sjeff struct cm_id_private *cm_id_priv; 553219820Sjeff int data_cmp; 554219820Sjeff 555219820Sjeff while (node) { 556219820Sjeff cm_id_priv = rb_entry(node, struct cm_id_private, service_node); 557219820Sjeff data_cmp = cm_compare_private_data(private_data, 558219820Sjeff cm_id_priv->compare_data); 559219820Sjeff if ((cm_id_priv->id.service_mask & service_id) == 560219820Sjeff cm_id_priv->id.service_id && 561219820Sjeff (cm_id_priv->id.device == device) && !data_cmp) 562219820Sjeff return cm_id_priv; 563219820Sjeff 564219820Sjeff if (device < cm_id_priv->id.device) 565219820Sjeff node = node->rb_left; 566219820Sjeff else if (device > cm_id_priv->id.device) 567219820Sjeff node = node->rb_right; 568219820Sjeff else if (be64_lt(service_id, cm_id_priv->id.service_id)) 569219820Sjeff node = node->rb_left; 570219820Sjeff else if (be64_gt(service_id, cm_id_priv->id.service_id)) 571219820Sjeff node = node->rb_right; 572219820Sjeff else if (data_cmp < 0) 573219820Sjeff node = node->rb_left; 574219820Sjeff else 575219820Sjeff node = node->rb_right; 576219820Sjeff } 577219820Sjeff return NULL; 578219820Sjeff} 579219820Sjeff 580219820Sjeffstatic struct cm_timewait_info * cm_insert_remote_id(struct cm_timewait_info 581219820Sjeff *timewait_info) 582219820Sjeff{ 583219820Sjeff struct rb_node **link = &cm.remote_id_table.rb_node; 584219820Sjeff struct rb_node *parent = NULL; 585219820Sjeff struct cm_timewait_info *cur_timewait_info; 586219820Sjeff __be64 remote_ca_guid = timewait_info->remote_ca_guid; 587219820Sjeff __be32 remote_id = timewait_info->work.remote_id; 588219820Sjeff 589219820Sjeff while (*link) { 590219820Sjeff parent = *link; 591219820Sjeff cur_timewait_info = rb_entry(parent, struct cm_timewait_info, 592219820Sjeff remote_id_node); 593219820Sjeff if (be32_lt(remote_id, cur_timewait_info->work.remote_id)) 594219820Sjeff link = &(*link)->rb_left; 595219820Sjeff else if (be32_gt(remote_id, cur_timewait_info->work.remote_id)) 596219820Sjeff link = &(*link)->rb_right; 597219820Sjeff else if (be64_lt(remote_ca_guid, cur_timewait_info->remote_ca_guid)) 598219820Sjeff link = &(*link)->rb_left; 599219820Sjeff else if (be64_gt(remote_ca_guid, cur_timewait_info->remote_ca_guid)) 600219820Sjeff link = &(*link)->rb_right; 601219820Sjeff else 602219820Sjeff return cur_timewait_info; 603219820Sjeff } 604219820Sjeff timewait_info->inserted_remote_id = 1; 605219820Sjeff rb_link_node(&timewait_info->remote_id_node, parent, link); 606219820Sjeff rb_insert_color(&timewait_info->remote_id_node, &cm.remote_id_table); 607219820Sjeff return NULL; 608219820Sjeff} 609219820Sjeff 610219820Sjeffstatic struct cm_timewait_info * cm_find_remote_id(__be64 remote_ca_guid, 611219820Sjeff __be32 remote_id) 612219820Sjeff{ 613219820Sjeff struct rb_node *node = cm.remote_id_table.rb_node; 614219820Sjeff struct cm_timewait_info *timewait_info; 615219820Sjeff 616219820Sjeff while (node) { 617219820Sjeff timewait_info = rb_entry(node, struct cm_timewait_info, 618219820Sjeff remote_id_node); 619219820Sjeff if (be32_lt(remote_id, timewait_info->work.remote_id)) 620219820Sjeff node = node->rb_left; 621219820Sjeff else if (be32_gt(remote_id, timewait_info->work.remote_id)) 622219820Sjeff node = node->rb_right; 623219820Sjeff else if (be64_lt(remote_ca_guid, timewait_info->remote_ca_guid)) 624219820Sjeff node = node->rb_left; 625219820Sjeff else if (be64_gt(remote_ca_guid, timewait_info->remote_ca_guid)) 626219820Sjeff node = node->rb_right; 627219820Sjeff else 628219820Sjeff return timewait_info; 629219820Sjeff } 630219820Sjeff return NULL; 631219820Sjeff} 632219820Sjeff 633219820Sjeffstatic struct cm_timewait_info * cm_insert_remote_qpn(struct cm_timewait_info 634219820Sjeff *timewait_info) 635219820Sjeff{ 636219820Sjeff struct rb_node **link = &cm.remote_qp_table.rb_node; 637219820Sjeff struct rb_node *parent = NULL; 638219820Sjeff struct cm_timewait_info *cur_timewait_info; 639219820Sjeff __be64 remote_ca_guid = timewait_info->remote_ca_guid; 640219820Sjeff __be32 remote_qpn = timewait_info->remote_qpn; 641219820Sjeff 642219820Sjeff while (*link) { 643219820Sjeff parent = *link; 644219820Sjeff cur_timewait_info = rb_entry(parent, struct cm_timewait_info, 645219820Sjeff remote_qp_node); 646219820Sjeff if (be32_lt(remote_qpn, cur_timewait_info->remote_qpn)) 647219820Sjeff link = &(*link)->rb_left; 648219820Sjeff else if (be32_gt(remote_qpn, cur_timewait_info->remote_qpn)) 649219820Sjeff link = &(*link)->rb_right; 650219820Sjeff else if (be64_lt(remote_ca_guid, cur_timewait_info->remote_ca_guid)) 651219820Sjeff link = &(*link)->rb_left; 652219820Sjeff else if (be64_gt(remote_ca_guid, cur_timewait_info->remote_ca_guid)) 653219820Sjeff link = &(*link)->rb_right; 654219820Sjeff else 655219820Sjeff return cur_timewait_info; 656219820Sjeff } 657219820Sjeff timewait_info->inserted_remote_qp = 1; 658219820Sjeff rb_link_node(&timewait_info->remote_qp_node, parent, link); 659219820Sjeff rb_insert_color(&timewait_info->remote_qp_node, &cm.remote_qp_table); 660219820Sjeff return NULL; 661219820Sjeff} 662219820Sjeff 663219820Sjeffstatic struct cm_id_private * cm_insert_remote_sidr(struct cm_id_private 664219820Sjeff *cm_id_priv) 665219820Sjeff{ 666219820Sjeff struct rb_node **link = &cm.remote_sidr_table.rb_node; 667219820Sjeff struct rb_node *parent = NULL; 668219820Sjeff struct cm_id_private *cur_cm_id_priv; 669219820Sjeff union ib_gid *port_gid = &cm_id_priv->av.dgid; 670219820Sjeff __be32 remote_id = cm_id_priv->id.remote_id; 671219820Sjeff 672219820Sjeff while (*link) { 673219820Sjeff parent = *link; 674219820Sjeff cur_cm_id_priv = rb_entry(parent, struct cm_id_private, 675219820Sjeff sidr_id_node); 676219820Sjeff if (be32_lt(remote_id, cur_cm_id_priv->id.remote_id)) 677219820Sjeff link = &(*link)->rb_left; 678219820Sjeff else if (be32_gt(remote_id, cur_cm_id_priv->id.remote_id)) 679219820Sjeff link = &(*link)->rb_right; 680219820Sjeff else { 681219820Sjeff int cmp; 682219820Sjeff cmp = memcmp(port_gid, &cur_cm_id_priv->av.dgid, 683219820Sjeff sizeof *port_gid); 684219820Sjeff if (cmp < 0) 685219820Sjeff link = &(*link)->rb_left; 686219820Sjeff else if (cmp > 0) 687219820Sjeff link = &(*link)->rb_right; 688219820Sjeff else 689219820Sjeff return cur_cm_id_priv; 690219820Sjeff } 691219820Sjeff } 692219820Sjeff rb_link_node(&cm_id_priv->sidr_id_node, parent, link); 693219820Sjeff rb_insert_color(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table); 694219820Sjeff return NULL; 695219820Sjeff} 696219820Sjeff 697219820Sjeffstatic void cm_reject_sidr_req(struct cm_id_private *cm_id_priv, 698219820Sjeff enum ib_cm_sidr_status status) 699219820Sjeff{ 700219820Sjeff struct ib_cm_sidr_rep_param param; 701219820Sjeff 702219820Sjeff memset(¶m, 0, sizeof param); 703219820Sjeff param.status = status; 704219820Sjeff ib_send_cm_sidr_rep(&cm_id_priv->id, ¶m); 705219820Sjeff} 706219820Sjeff 707219820Sjeffstruct ib_cm_id *ib_create_cm_id(struct ib_device *device, 708219820Sjeff ib_cm_handler cm_handler, 709219820Sjeff void *context) 710219820Sjeff{ 711219820Sjeff struct cm_id_private *cm_id_priv; 712219820Sjeff int ret; 713219820Sjeff 714219820Sjeff cm_id_priv = kzalloc(sizeof *cm_id_priv, GFP_KERNEL); 715219820Sjeff if (!cm_id_priv) 716219820Sjeff return ERR_PTR(-ENOMEM); 717219820Sjeff 718219820Sjeff cm_id_priv->id.state = IB_CM_IDLE; 719219820Sjeff cm_id_priv->id.device = device; 720219820Sjeff cm_id_priv->id.cm_handler = cm_handler; 721219820Sjeff cm_id_priv->id.context = context; 722219820Sjeff cm_id_priv->id.remote_cm_qpn = 1; 723219820Sjeff ret = cm_alloc_id(cm_id_priv); 724219820Sjeff if (ret) 725219820Sjeff goto error; 726219820Sjeff 727219820Sjeff spin_lock_init(&cm_id_priv->lock); 728219820Sjeff init_completion(&cm_id_priv->comp); 729219820Sjeff INIT_LIST_HEAD(&cm_id_priv->work_list); 730219820Sjeff atomic_set(&cm_id_priv->work_count, -1); 731219820Sjeff atomic_set(&cm_id_priv->refcount, 1); 732219820Sjeff return &cm_id_priv->id; 733219820Sjeff 734219820Sjefferror: 735219820Sjeff kfree(cm_id_priv); 736219820Sjeff return ERR_PTR(-ENOMEM); 737219820Sjeff} 738219820SjeffEXPORT_SYMBOL(ib_create_cm_id); 739219820Sjeff 740219820Sjeffstatic struct cm_work * cm_dequeue_work(struct cm_id_private *cm_id_priv) 741219820Sjeff{ 742219820Sjeff struct cm_work *work; 743219820Sjeff 744219820Sjeff if (list_empty(&cm_id_priv->work_list)) 745219820Sjeff return NULL; 746219820Sjeff 747219820Sjeff work = list_entry(cm_id_priv->work_list.next, struct cm_work, list); 748219820Sjeff list_del(&work->list); 749219820Sjeff return work; 750219820Sjeff} 751219820Sjeff 752219820Sjeffstatic void cm_free_work(struct cm_work *work) 753219820Sjeff{ 754219820Sjeff if (work->mad_recv_wc) 755219820Sjeff ib_free_recv_mad(work->mad_recv_wc); 756219820Sjeff kfree(work); 757219820Sjeff} 758219820Sjeff 759219820Sjeffstatic inline int cm_convert_to_ms(int iba_time) 760219820Sjeff{ 761219820Sjeff /* approximate conversion to ms from 4.096us x 2^iba_time */ 762219820Sjeff return 1 << max(iba_time - 8, 0); 763219820Sjeff} 764219820Sjeff 765219820Sjeff/* 766219820Sjeff * calculate: 4.096x2^ack_timeout = 4.096x2^ack_delay + 2x4.096x2^life_time 767219820Sjeff * Because of how ack_timeout is stored, adding one doubles the timeout. 768219820Sjeff * To avoid large timeouts, select the max(ack_delay, life_time + 1), and 769219820Sjeff * increment it (round up) only if the other is within 50%. 770219820Sjeff */ 771219820Sjeffstatic u8 cm_ack_timeout(u8 ca_ack_delay, u8 packet_life_time) 772219820Sjeff{ 773219820Sjeff int ack_timeout = packet_life_time + 1; 774219820Sjeff 775219820Sjeff if (ack_timeout >= ca_ack_delay) 776219820Sjeff ack_timeout += (ca_ack_delay >= (ack_timeout - 1)); 777219820Sjeff else 778219820Sjeff ack_timeout = ca_ack_delay + 779219820Sjeff (ack_timeout >= (ca_ack_delay - 1)); 780219820Sjeff 781219820Sjeff return min(31, ack_timeout); 782219820Sjeff} 783219820Sjeff 784219820Sjeffstatic void cm_cleanup_timewait(struct cm_timewait_info *timewait_info) 785219820Sjeff{ 786219820Sjeff if (timewait_info->inserted_remote_id) { 787219820Sjeff rb_erase(&timewait_info->remote_id_node, &cm.remote_id_table); 788219820Sjeff timewait_info->inserted_remote_id = 0; 789219820Sjeff } 790219820Sjeff 791219820Sjeff if (timewait_info->inserted_remote_qp) { 792219820Sjeff rb_erase(&timewait_info->remote_qp_node, &cm.remote_qp_table); 793219820Sjeff timewait_info->inserted_remote_qp = 0; 794219820Sjeff } 795219820Sjeff} 796219820Sjeff 797219820Sjeffstatic struct cm_timewait_info * cm_create_timewait_info(__be32 local_id) 798219820Sjeff{ 799219820Sjeff struct cm_timewait_info *timewait_info; 800219820Sjeff 801219820Sjeff timewait_info = kzalloc(sizeof *timewait_info, GFP_KERNEL); 802219820Sjeff if (!timewait_info) 803219820Sjeff return ERR_PTR(-ENOMEM); 804219820Sjeff 805219820Sjeff timewait_info->work.local_id = local_id; 806219820Sjeff INIT_DELAYED_WORK(&timewait_info->work.work, cm_work_handler); 807219820Sjeff timewait_info->work.cm_event.event = IB_CM_TIMEWAIT_EXIT; 808219820Sjeff return timewait_info; 809219820Sjeff} 810219820Sjeff 811219820Sjeffstatic void cm_enter_timewait(struct cm_id_private *cm_id_priv) 812219820Sjeff{ 813219820Sjeff int wait_time; 814219820Sjeff unsigned long flags; 815219820Sjeff 816219820Sjeff spin_lock_irqsave(&cm.lock, flags); 817219820Sjeff cm_cleanup_timewait(cm_id_priv->timewait_info); 818219820Sjeff list_add_tail(&cm_id_priv->timewait_info->list, &cm.timewait_list); 819219820Sjeff spin_unlock_irqrestore(&cm.lock, flags); 820219820Sjeff 821219820Sjeff /* 822219820Sjeff * The cm_id could be destroyed by the user before we exit timewait. 823219820Sjeff * To protect against this, we search for the cm_id after exiting 824219820Sjeff * timewait before notifying the user that we've exited timewait. 825219820Sjeff */ 826219820Sjeff cm_id_priv->id.state = IB_CM_TIMEWAIT; 827219820Sjeff wait_time = cm_convert_to_ms(cm_id_priv->av.timeout); 828219820Sjeff queue_delayed_work(cm.wq, &cm_id_priv->timewait_info->work.work, 829219820Sjeff msecs_to_jiffies(wait_time)); 830219820Sjeff cm_id_priv->timewait_info = NULL; 831219820Sjeff} 832219820Sjeff 833219820Sjeffstatic void cm_reset_to_idle(struct cm_id_private *cm_id_priv) 834219820Sjeff{ 835219820Sjeff unsigned long flags; 836219820Sjeff 837219820Sjeff cm_id_priv->id.state = IB_CM_IDLE; 838219820Sjeff if (cm_id_priv->timewait_info) { 839219820Sjeff spin_lock_irqsave(&cm.lock, flags); 840219820Sjeff cm_cleanup_timewait(cm_id_priv->timewait_info); 841219820Sjeff spin_unlock_irqrestore(&cm.lock, flags); 842219820Sjeff kfree(cm_id_priv->timewait_info); 843219820Sjeff cm_id_priv->timewait_info = NULL; 844219820Sjeff } 845219820Sjeff} 846219820Sjeff 847219820Sjeffstatic void cm_destroy_id(struct ib_cm_id *cm_id, int err) 848219820Sjeff{ 849219820Sjeff struct cm_id_private *cm_id_priv; 850219820Sjeff struct cm_work *work; 851219820Sjeff 852219820Sjeff cm_id_priv = container_of(cm_id, struct cm_id_private, id); 853219820Sjeffretest: 854219820Sjeff spin_lock_irq(&cm_id_priv->lock); 855219820Sjeff switch (cm_id->state) { 856219820Sjeff case IB_CM_LISTEN: 857219820Sjeff cm_id->state = IB_CM_IDLE; 858219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 859219820Sjeff spin_lock_irq(&cm.lock); 860219820Sjeff rb_erase(&cm_id_priv->service_node, &cm.listen_service_table); 861219820Sjeff spin_unlock_irq(&cm.lock); 862219820Sjeff break; 863219820Sjeff case IB_CM_SIDR_REQ_SENT: 864219820Sjeff cm_id->state = IB_CM_IDLE; 865219820Sjeff ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); 866219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 867219820Sjeff break; 868219820Sjeff case IB_CM_SIDR_REQ_RCVD: 869219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 870219820Sjeff cm_reject_sidr_req(cm_id_priv, IB_SIDR_REJECT); 871219820Sjeff break; 872219820Sjeff case IB_CM_REQ_SENT: 873219820Sjeff ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); 874219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 875219820Sjeff ib_send_cm_rej(cm_id, IB_CM_REJ_TIMEOUT, 876219820Sjeff &cm_id_priv->id.device->node_guid, 877219820Sjeff sizeof cm_id_priv->id.device->node_guid, 878219820Sjeff NULL, 0); 879219820Sjeff break; 880219820Sjeff case IB_CM_REQ_RCVD: 881219820Sjeff if (err == -ENOMEM) { 882219820Sjeff /* Do not reject to allow future retries. */ 883219820Sjeff cm_reset_to_idle(cm_id_priv); 884219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 885219820Sjeff } else { 886219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 887219820Sjeff ib_send_cm_rej(cm_id, IB_CM_REJ_CONSUMER_DEFINED, 888219820Sjeff NULL, 0, NULL, 0); 889219820Sjeff } 890219820Sjeff break; 891219820Sjeff case IB_CM_MRA_REQ_RCVD: 892219820Sjeff case IB_CM_REP_SENT: 893219820Sjeff case IB_CM_MRA_REP_RCVD: 894219820Sjeff ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); 895219820Sjeff /* Fall through */ 896219820Sjeff case IB_CM_MRA_REQ_SENT: 897219820Sjeff case IB_CM_REP_RCVD: 898219820Sjeff case IB_CM_MRA_REP_SENT: 899219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 900219820Sjeff ib_send_cm_rej(cm_id, IB_CM_REJ_CONSUMER_DEFINED, 901219820Sjeff NULL, 0, NULL, 0); 902219820Sjeff break; 903219820Sjeff case IB_CM_ESTABLISHED: 904219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 905219820Sjeff ib_send_cm_dreq(cm_id, NULL, 0); 906219820Sjeff goto retest; 907219820Sjeff case IB_CM_DREQ_SENT: 908219820Sjeff ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); 909219820Sjeff cm_enter_timewait(cm_id_priv); 910219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 911219820Sjeff break; 912219820Sjeff case IB_CM_DREQ_RCVD: 913219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 914219820Sjeff ib_send_cm_drep(cm_id, NULL, 0); 915219820Sjeff break; 916219820Sjeff default: 917219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 918219820Sjeff break; 919219820Sjeff } 920219820Sjeff 921219820Sjeff cm_free_id(cm_id->local_id); 922219820Sjeff cm_deref_id(cm_id_priv); 923219820Sjeff wait_for_completion(&cm_id_priv->comp); 924219820Sjeff while ((work = cm_dequeue_work(cm_id_priv)) != NULL) 925219820Sjeff cm_free_work(work); 926219820Sjeff kfree(cm_id_priv->compare_data); 927219820Sjeff kfree(cm_id_priv->private_data); 928219820Sjeff kfree(cm_id_priv); 929219820Sjeff} 930219820Sjeff 931219820Sjeffvoid ib_destroy_cm_id(struct ib_cm_id *cm_id) 932219820Sjeff{ 933219820Sjeff cm_destroy_id(cm_id, 0); 934219820Sjeff} 935219820SjeffEXPORT_SYMBOL(ib_destroy_cm_id); 936219820Sjeff 937219820Sjeffint ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask, 938219820Sjeff struct ib_cm_compare_data *compare_data) 939219820Sjeff{ 940219820Sjeff struct cm_id_private *cm_id_priv, *cur_cm_id_priv; 941219820Sjeff unsigned long flags; 942219820Sjeff int ret = 0; 943219820Sjeff 944219820Sjeff service_mask = service_mask ? service_mask : ~cpu_to_be64(0); 945219820Sjeff service_id &= service_mask; 946219820Sjeff if ((service_id & IB_SERVICE_ID_AGN_MASK) == IB_CM_ASSIGN_SERVICE_ID && 947219820Sjeff (service_id != IB_CM_ASSIGN_SERVICE_ID)) 948219820Sjeff return -EINVAL; 949219820Sjeff 950219820Sjeff cm_id_priv = container_of(cm_id, struct cm_id_private, id); 951219820Sjeff if (cm_id->state != IB_CM_IDLE) 952219820Sjeff return -EINVAL; 953219820Sjeff 954219820Sjeff if (compare_data) { 955219820Sjeff cm_id_priv->compare_data = kzalloc(sizeof *compare_data, 956219820Sjeff GFP_KERNEL); 957219820Sjeff if (!cm_id_priv->compare_data) 958219820Sjeff return -ENOMEM; 959219820Sjeff cm_mask_copy(cm_id_priv->compare_data->data, 960219820Sjeff compare_data->data, compare_data->mask); 961219820Sjeff memcpy(cm_id_priv->compare_data->mask, compare_data->mask, 962219820Sjeff IB_CM_COMPARE_SIZE); 963219820Sjeff } 964219820Sjeff 965219820Sjeff cm_id->state = IB_CM_LISTEN; 966219820Sjeff 967219820Sjeff spin_lock_irqsave(&cm.lock, flags); 968219820Sjeff if (service_id == IB_CM_ASSIGN_SERVICE_ID) { 969219820Sjeff cm_id->service_id = cpu_to_be64(cm.listen_service_id++); 970219820Sjeff cm_id->service_mask = ~cpu_to_be64(0); 971219820Sjeff } else { 972219820Sjeff cm_id->service_id = service_id; 973219820Sjeff cm_id->service_mask = service_mask; 974219820Sjeff } 975219820Sjeff cur_cm_id_priv = cm_insert_listen(cm_id_priv); 976219820Sjeff spin_unlock_irqrestore(&cm.lock, flags); 977219820Sjeff 978219820Sjeff if (cur_cm_id_priv) { 979219820Sjeff cm_id->state = IB_CM_IDLE; 980219820Sjeff kfree(cm_id_priv->compare_data); 981219820Sjeff cm_id_priv->compare_data = NULL; 982219820Sjeff ret = -EBUSY; 983219820Sjeff } 984219820Sjeff return ret; 985219820Sjeff} 986219820SjeffEXPORT_SYMBOL(ib_cm_listen); 987219820Sjeff 988219820Sjeffstatic __be64 cm_form_tid(struct cm_id_private *cm_id_priv, 989219820Sjeff enum cm_msg_sequence msg_seq) 990219820Sjeff{ 991219820Sjeff u64 hi_tid, low_tid; 992219820Sjeff 993219820Sjeff hi_tid = ((u64) cm_id_priv->av.port->mad_agent->hi_tid) << 32; 994219820Sjeff low_tid = (u64) ((__force u32)cm_id_priv->id.local_id | 995219820Sjeff (msg_seq << 30)); 996219820Sjeff return cpu_to_be64(hi_tid | low_tid); 997219820Sjeff} 998219820Sjeff 999219820Sjeffstatic void cm_format_mad_hdr(struct ib_mad_hdr *hdr, 1000219820Sjeff __be16 attr_id, __be64 tid) 1001219820Sjeff{ 1002219820Sjeff hdr->base_version = IB_MGMT_BASE_VERSION; 1003219820Sjeff hdr->mgmt_class = IB_MGMT_CLASS_CM; 1004219820Sjeff hdr->class_version = IB_CM_CLASS_VERSION; 1005219820Sjeff hdr->method = IB_MGMT_METHOD_SEND; 1006219820Sjeff hdr->attr_id = attr_id; 1007219820Sjeff hdr->tid = tid; 1008219820Sjeff} 1009219820Sjeff 1010219820Sjeffstatic void cm_format_req(struct cm_req_msg *req_msg, 1011219820Sjeff struct cm_id_private *cm_id_priv, 1012219820Sjeff struct ib_cm_req_param *param) 1013219820Sjeff{ 1014219820Sjeff struct ib_sa_path_rec *pri_path = param->primary_path; 1015219820Sjeff struct ib_sa_path_rec *alt_path = param->alternate_path; 1016219820Sjeff 1017219820Sjeff cm_format_mad_hdr(&req_msg->hdr, CM_REQ_ATTR_ID, 1018219820Sjeff cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_REQ)); 1019219820Sjeff 1020219820Sjeff req_msg->local_comm_id = cm_id_priv->id.local_id; 1021219820Sjeff req_msg->service_id = param->service_id; 1022219820Sjeff req_msg->local_ca_guid = cm_id_priv->id.device->node_guid; 1023219820Sjeff cm_req_set_local_qpn(req_msg, cpu_to_be32(param->qp_num)); 1024219820Sjeff cm_req_set_resp_res(req_msg, param->responder_resources); 1025219820Sjeff cm_req_set_init_depth(req_msg, param->initiator_depth); 1026219820Sjeff cm_req_set_remote_resp_timeout(req_msg, 1027219820Sjeff param->remote_cm_response_timeout); 1028219820Sjeff if (param->remote_cm_response_timeout > (u8) max_timeout) { 1029219820Sjeff printk(KERN_WARNING PFX "req remote_cm_response_timeout %d > " 1030219820Sjeff "%d, decreasing\n", param->remote_cm_response_timeout, 1031219820Sjeff max_timeout); 1032219820Sjeff cm_req_set_remote_resp_timeout(req_msg, (u8) max_timeout); 1033219820Sjeff } 1034219820Sjeff cm_req_set_qp_type(req_msg, param->qp_type); 1035219820Sjeff cm_req_set_flow_ctrl(req_msg, param->flow_control); 1036219820Sjeff cm_req_set_starting_psn(req_msg, cpu_to_be32(param->starting_psn)); 1037219820Sjeff cm_req_set_local_resp_timeout(req_msg, 1038219820Sjeff param->local_cm_response_timeout); 1039219820Sjeff if (param->local_cm_response_timeout > (u8) max_timeout) { 1040219820Sjeff printk(KERN_WARNING PFX "req local_cm_response_timeout %d > " 1041219820Sjeff "%d, decreasing\n", param->local_cm_response_timeout, 1042219820Sjeff max_timeout); 1043219820Sjeff cm_req_set_local_resp_timeout(req_msg, (u8) max_timeout); 1044219820Sjeff } 1045219820Sjeff cm_req_set_retry_count(req_msg, param->retry_count); 1046219820Sjeff req_msg->pkey = param->primary_path->pkey; 1047219820Sjeff cm_req_set_path_mtu(req_msg, param->primary_path->mtu); 1048219820Sjeff cm_req_set_rnr_retry_count(req_msg, param->rnr_retry_count); 1049219820Sjeff cm_req_set_max_cm_retries(req_msg, param->max_cm_retries); 1050219820Sjeff cm_req_set_srq(req_msg, param->srq); 1051219820Sjeff 1052219820Sjeff if (pri_path->hop_limit <= 1) { 1053219820Sjeff req_msg->primary_local_lid = pri_path->slid; 1054219820Sjeff req_msg->primary_remote_lid = pri_path->dlid; 1055219820Sjeff } else { 1056219820Sjeff /* Work-around until there's a way to obtain remote LID info */ 1057219820Sjeff req_msg->primary_local_lid = IB_LID_PERMISSIVE; 1058219820Sjeff req_msg->primary_remote_lid = IB_LID_PERMISSIVE; 1059219820Sjeff } 1060219820Sjeff req_msg->primary_local_gid = pri_path->sgid; 1061219820Sjeff req_msg->primary_remote_gid = pri_path->dgid; 1062219820Sjeff cm_req_set_primary_flow_label(req_msg, pri_path->flow_label); 1063219820Sjeff cm_req_set_primary_packet_rate(req_msg, pri_path->rate); 1064219820Sjeff req_msg->primary_traffic_class = pri_path->traffic_class; 1065219820Sjeff req_msg->primary_hop_limit = pri_path->hop_limit; 1066219820Sjeff cm_req_set_primary_sl(req_msg, pri_path->sl); 1067219820Sjeff cm_req_set_primary_subnet_local(req_msg, (pri_path->hop_limit <= 1)); 1068219820Sjeff cm_req_set_primary_local_ack_timeout(req_msg, 1069219820Sjeff cm_ack_timeout(cm_id_priv->av.port->cm_dev->ack_delay, 1070219820Sjeff pri_path->packet_life_time)); 1071219820Sjeff 1072219820Sjeff if (alt_path) { 1073219820Sjeff if (alt_path->hop_limit <= 1) { 1074219820Sjeff req_msg->alt_local_lid = alt_path->slid; 1075219820Sjeff req_msg->alt_remote_lid = alt_path->dlid; 1076219820Sjeff } else { 1077219820Sjeff req_msg->alt_local_lid = IB_LID_PERMISSIVE; 1078219820Sjeff req_msg->alt_remote_lid = IB_LID_PERMISSIVE; 1079219820Sjeff } 1080219820Sjeff req_msg->alt_local_gid = alt_path->sgid; 1081219820Sjeff req_msg->alt_remote_gid = alt_path->dgid; 1082219820Sjeff cm_req_set_alt_flow_label(req_msg, 1083219820Sjeff alt_path->flow_label); 1084219820Sjeff cm_req_set_alt_packet_rate(req_msg, alt_path->rate); 1085219820Sjeff req_msg->alt_traffic_class = alt_path->traffic_class; 1086219820Sjeff req_msg->alt_hop_limit = alt_path->hop_limit; 1087219820Sjeff cm_req_set_alt_sl(req_msg, alt_path->sl); 1088219820Sjeff cm_req_set_alt_subnet_local(req_msg, (alt_path->hop_limit <= 1)); 1089219820Sjeff cm_req_set_alt_local_ack_timeout(req_msg, 1090219820Sjeff cm_ack_timeout(cm_id_priv->av.port->cm_dev->ack_delay, 1091219820Sjeff alt_path->packet_life_time)); 1092219820Sjeff } 1093219820Sjeff 1094219820Sjeff if (param->private_data && param->private_data_len) 1095219820Sjeff memcpy(req_msg->private_data, param->private_data, 1096219820Sjeff param->private_data_len); 1097219820Sjeff} 1098219820Sjeff 1099219820Sjeffstatic int cm_validate_req_param(struct ib_cm_req_param *param) 1100219820Sjeff{ 1101219820Sjeff /* peer-to-peer not supported */ 1102219820Sjeff if (param->peer_to_peer) 1103219820Sjeff return -EINVAL; 1104219820Sjeff 1105219820Sjeff if (!param->primary_path) 1106219820Sjeff return -EINVAL; 1107219820Sjeff 1108219820Sjeff if (param->qp_type != IB_QPT_RC && param->qp_type != IB_QPT_UC) 1109219820Sjeff return -EINVAL; 1110219820Sjeff 1111219820Sjeff if (param->private_data && 1112219820Sjeff param->private_data_len > IB_CM_REQ_PRIVATE_DATA_SIZE) 1113219820Sjeff return -EINVAL; 1114219820Sjeff 1115219820Sjeff if (param->alternate_path && 1116219820Sjeff (param->alternate_path->pkey != param->primary_path->pkey || 1117219820Sjeff param->alternate_path->mtu != param->primary_path->mtu)) 1118219820Sjeff return -EINVAL; 1119219820Sjeff 1120219820Sjeff return 0; 1121219820Sjeff} 1122219820Sjeff 1123219820Sjeffint ib_send_cm_req(struct ib_cm_id *cm_id, 1124219820Sjeff struct ib_cm_req_param *param) 1125219820Sjeff{ 1126219820Sjeff struct cm_id_private *cm_id_priv; 1127219820Sjeff struct cm_req_msg *req_msg; 1128219820Sjeff unsigned long flags; 1129219820Sjeff int ret; 1130219820Sjeff 1131219820Sjeff ret = cm_validate_req_param(param); 1132219820Sjeff if (ret) 1133219820Sjeff return ret; 1134219820Sjeff 1135219820Sjeff /* Verify that we're not in timewait. */ 1136219820Sjeff cm_id_priv = container_of(cm_id, struct cm_id_private, id); 1137219820Sjeff spin_lock_irqsave(&cm_id_priv->lock, flags); 1138219820Sjeff if (cm_id->state != IB_CM_IDLE) { 1139219820Sjeff spin_unlock_irqrestore(&cm_id_priv->lock, flags); 1140219820Sjeff ret = -EINVAL; 1141219820Sjeff goto out; 1142219820Sjeff } 1143219820Sjeff spin_unlock_irqrestore(&cm_id_priv->lock, flags); 1144219820Sjeff 1145219820Sjeff cm_id_priv->timewait_info = cm_create_timewait_info(cm_id_priv-> 1146219820Sjeff id.local_id); 1147219820Sjeff if (IS_ERR(cm_id_priv->timewait_info)) { 1148219820Sjeff ret = PTR_ERR(cm_id_priv->timewait_info); 1149219820Sjeff goto out; 1150219820Sjeff } 1151219820Sjeff 1152219820Sjeff ret = cm_init_av_by_path(param->primary_path, &cm_id_priv->av); 1153219820Sjeff if (ret) 1154219820Sjeff goto error1; 1155219820Sjeff if (param->alternate_path) { 1156219820Sjeff ret = cm_init_av_by_path(param->alternate_path, 1157219820Sjeff &cm_id_priv->alt_av); 1158219820Sjeff if (ret) 1159219820Sjeff goto error1; 1160219820Sjeff } 1161219820Sjeff cm_id->service_id = param->service_id; 1162219820Sjeff cm_id->service_mask = ~cpu_to_be64(0); 1163219820Sjeff cm_id_priv->timeout_ms = cm_convert_to_ms( 1164219820Sjeff param->primary_path->packet_life_time) * 2 + 1165219820Sjeff cm_convert_to_ms( 1166219820Sjeff param->remote_cm_response_timeout); 1167219820Sjeff if (cm_id_priv->timeout_ms > cm_convert_to_ms(max_timeout)) { 1168219820Sjeff printk(KERN_WARNING PFX "req timeout_ms %d > %d, decreasing\n", 1169219820Sjeff cm_id_priv->timeout_ms, cm_convert_to_ms(max_timeout)); 1170219820Sjeff cm_id_priv->timeout_ms = cm_convert_to_ms(max_timeout); 1171219820Sjeff } 1172219820Sjeff cm_id_priv->max_cm_retries = param->max_cm_retries; 1173219820Sjeff cm_id_priv->initiator_depth = param->initiator_depth; 1174219820Sjeff cm_id_priv->responder_resources = param->responder_resources; 1175219820Sjeff cm_id_priv->retry_count = param->retry_count; 1176219820Sjeff cm_id_priv->path_mtu = param->primary_path->mtu; 1177219820Sjeff cm_id_priv->pkey = param->primary_path->pkey; 1178219820Sjeff cm_id_priv->qp_type = param->qp_type; 1179219820Sjeff 1180219820Sjeff ret = cm_alloc_msg(cm_id_priv, &cm_id_priv->msg); 1181219820Sjeff if (ret) 1182219820Sjeff goto error1; 1183219820Sjeff 1184219820Sjeff req_msg = (struct cm_req_msg *) cm_id_priv->msg->mad; 1185219820Sjeff cm_format_req(req_msg, cm_id_priv, param); 1186219820Sjeff cm_id_priv->tid = req_msg->hdr.tid; 1187219820Sjeff cm_id_priv->msg->timeout_ms = cm_id_priv->timeout_ms; 1188219820Sjeff cm_id_priv->msg->context[1] = (void *) (unsigned long) IB_CM_REQ_SENT; 1189219820Sjeff 1190219820Sjeff cm_id_priv->local_qpn = cm_req_get_local_qpn(req_msg); 1191219820Sjeff cm_id_priv->rq_psn = cm_req_get_starting_psn(req_msg); 1192219820Sjeff 1193219820Sjeff spin_lock_irqsave(&cm_id_priv->lock, flags); 1194219820Sjeff ret = ib_post_send_mad(cm_id_priv->msg, NULL); 1195219820Sjeff if (ret) { 1196219820Sjeff spin_unlock_irqrestore(&cm_id_priv->lock, flags); 1197219820Sjeff goto error2; 1198219820Sjeff } 1199219820Sjeff BUG_ON(cm_id->state != IB_CM_IDLE); 1200219820Sjeff cm_id->state = IB_CM_REQ_SENT; 1201219820Sjeff spin_unlock_irqrestore(&cm_id_priv->lock, flags); 1202219820Sjeff return 0; 1203219820Sjeff 1204219820Sjefferror2: cm_free_msg(cm_id_priv->msg); 1205219820Sjefferror1: kfree(cm_id_priv->timewait_info); 1206219820Sjeffout: return ret; 1207219820Sjeff} 1208219820SjeffEXPORT_SYMBOL(ib_send_cm_req); 1209219820Sjeff 1210219820Sjeffstatic int cm_issue_rej(struct cm_port *port, 1211219820Sjeff struct ib_mad_recv_wc *mad_recv_wc, 1212219820Sjeff enum ib_cm_rej_reason reason, 1213219820Sjeff enum cm_msg_response msg_rejected, 1214219820Sjeff void *ari, u8 ari_length) 1215219820Sjeff{ 1216219820Sjeff struct ib_mad_send_buf *msg = NULL; 1217219820Sjeff struct cm_rej_msg *rej_msg, *rcv_msg; 1218219820Sjeff int ret; 1219219820Sjeff 1220219820Sjeff ret = cm_alloc_response_msg(port, mad_recv_wc, &msg); 1221219820Sjeff if (ret) 1222219820Sjeff return ret; 1223219820Sjeff 1224219820Sjeff /* We just need common CM header information. Cast to any message. */ 1225219820Sjeff rcv_msg = (struct cm_rej_msg *) mad_recv_wc->recv_buf.mad; 1226219820Sjeff rej_msg = (struct cm_rej_msg *) msg->mad; 1227219820Sjeff 1228219820Sjeff cm_format_mad_hdr(&rej_msg->hdr, CM_REJ_ATTR_ID, rcv_msg->hdr.tid); 1229219820Sjeff rej_msg->remote_comm_id = rcv_msg->local_comm_id; 1230219820Sjeff rej_msg->local_comm_id = rcv_msg->remote_comm_id; 1231219820Sjeff cm_rej_set_msg_rejected(rej_msg, msg_rejected); 1232219820Sjeff rej_msg->reason = cpu_to_be16(reason); 1233219820Sjeff 1234219820Sjeff if (ari && ari_length) { 1235219820Sjeff cm_rej_set_reject_info_len(rej_msg, ari_length); 1236219820Sjeff memcpy(rej_msg->ari, ari, ari_length); 1237219820Sjeff } 1238219820Sjeff 1239219820Sjeff ret = ib_post_send_mad(msg, NULL); 1240219820Sjeff if (ret) 1241219820Sjeff cm_free_msg(msg); 1242219820Sjeff 1243219820Sjeff return ret; 1244219820Sjeff} 1245219820Sjeff 1246219820Sjeffstatic inline int cm_is_active_peer(__be64 local_ca_guid, __be64 remote_ca_guid, 1247219820Sjeff __be32 local_qpn, __be32 remote_qpn) 1248219820Sjeff{ 1249219820Sjeff return (be64_to_cpu(local_ca_guid) > be64_to_cpu(remote_ca_guid) || 1250219820Sjeff ((local_ca_guid == remote_ca_guid) && 1251219820Sjeff (be32_to_cpu(local_qpn) > be32_to_cpu(remote_qpn)))); 1252219820Sjeff} 1253219820Sjeff 1254219820Sjeffstatic void cm_format_paths_from_req(struct cm_req_msg *req_msg, 1255219820Sjeff struct ib_sa_path_rec *primary_path, 1256219820Sjeff struct ib_sa_path_rec *alt_path) 1257219820Sjeff{ 1258219820Sjeff memset(primary_path, 0, sizeof *primary_path); 1259219820Sjeff primary_path->dgid = req_msg->primary_local_gid; 1260219820Sjeff primary_path->sgid = req_msg->primary_remote_gid; 1261219820Sjeff primary_path->dlid = req_msg->primary_local_lid; 1262219820Sjeff primary_path->slid = req_msg->primary_remote_lid; 1263219820Sjeff primary_path->flow_label = cm_req_get_primary_flow_label(req_msg); 1264219820Sjeff primary_path->hop_limit = req_msg->primary_hop_limit; 1265219820Sjeff primary_path->traffic_class = req_msg->primary_traffic_class; 1266219820Sjeff primary_path->reversible = 1; 1267219820Sjeff primary_path->pkey = req_msg->pkey; 1268219820Sjeff primary_path->sl = cm_req_get_primary_sl(req_msg); 1269219820Sjeff primary_path->mtu_selector = IB_SA_EQ; 1270219820Sjeff primary_path->mtu = cm_req_get_path_mtu(req_msg); 1271219820Sjeff primary_path->rate_selector = IB_SA_EQ; 1272219820Sjeff primary_path->rate = cm_req_get_primary_packet_rate(req_msg); 1273219820Sjeff primary_path->packet_life_time_selector = IB_SA_EQ; 1274219820Sjeff primary_path->packet_life_time = 1275219820Sjeff cm_req_get_primary_local_ack_timeout(req_msg); 1276219820Sjeff primary_path->packet_life_time -= (primary_path->packet_life_time > 0); 1277219820Sjeff 1278219820Sjeff if (req_msg->alt_local_lid) { 1279219820Sjeff memset(alt_path, 0, sizeof *alt_path); 1280219820Sjeff alt_path->dgid = req_msg->alt_local_gid; 1281219820Sjeff alt_path->sgid = req_msg->alt_remote_gid; 1282219820Sjeff alt_path->dlid = req_msg->alt_local_lid; 1283219820Sjeff alt_path->slid = req_msg->alt_remote_lid; 1284219820Sjeff alt_path->flow_label = cm_req_get_alt_flow_label(req_msg); 1285219820Sjeff alt_path->hop_limit = req_msg->alt_hop_limit; 1286219820Sjeff alt_path->traffic_class = req_msg->alt_traffic_class; 1287219820Sjeff alt_path->reversible = 1; 1288219820Sjeff alt_path->pkey = req_msg->pkey; 1289219820Sjeff alt_path->sl = cm_req_get_alt_sl(req_msg); 1290219820Sjeff alt_path->mtu_selector = IB_SA_EQ; 1291219820Sjeff alt_path->mtu = cm_req_get_path_mtu(req_msg); 1292219820Sjeff alt_path->rate_selector = IB_SA_EQ; 1293219820Sjeff alt_path->rate = cm_req_get_alt_packet_rate(req_msg); 1294219820Sjeff alt_path->packet_life_time_selector = IB_SA_EQ; 1295219820Sjeff alt_path->packet_life_time = 1296219820Sjeff cm_req_get_alt_local_ack_timeout(req_msg); 1297219820Sjeff alt_path->packet_life_time -= (alt_path->packet_life_time > 0); 1298219820Sjeff } 1299219820Sjeff} 1300219820Sjeff 1301219820Sjeffstatic void cm_format_req_event(struct cm_work *work, 1302219820Sjeff struct cm_id_private *cm_id_priv, 1303219820Sjeff struct ib_cm_id *listen_id) 1304219820Sjeff{ 1305219820Sjeff struct cm_req_msg *req_msg; 1306219820Sjeff struct ib_cm_req_event_param *param; 1307219820Sjeff 1308219820Sjeff req_msg = (struct cm_req_msg *)work->mad_recv_wc->recv_buf.mad; 1309219820Sjeff param = &work->cm_event.param.req_rcvd; 1310219820Sjeff param->listen_id = listen_id; 1311219820Sjeff param->port = cm_id_priv->av.port->port_num; 1312219820Sjeff param->primary_path = &work->path[0]; 1313219820Sjeff if (req_msg->alt_local_lid) 1314219820Sjeff param->alternate_path = &work->path[1]; 1315219820Sjeff else 1316219820Sjeff param->alternate_path = NULL; 1317219820Sjeff param->remote_ca_guid = req_msg->local_ca_guid; 1318219820Sjeff param->remote_qkey = be32_to_cpu(req_msg->local_qkey); 1319219820Sjeff param->remote_qpn = be32_to_cpu(cm_req_get_local_qpn(req_msg)); 1320219820Sjeff param->qp_type = cm_req_get_qp_type(req_msg); 1321219820Sjeff param->starting_psn = be32_to_cpu(cm_req_get_starting_psn(req_msg)); 1322219820Sjeff param->responder_resources = cm_req_get_init_depth(req_msg); 1323219820Sjeff param->initiator_depth = cm_req_get_resp_res(req_msg); 1324219820Sjeff param->local_cm_response_timeout = 1325219820Sjeff cm_req_get_remote_resp_timeout(req_msg); 1326219820Sjeff param->flow_control = cm_req_get_flow_ctrl(req_msg); 1327219820Sjeff param->remote_cm_response_timeout = 1328219820Sjeff cm_req_get_local_resp_timeout(req_msg); 1329219820Sjeff param->retry_count = cm_req_get_retry_count(req_msg); 1330219820Sjeff param->rnr_retry_count = cm_req_get_rnr_retry_count(req_msg); 1331219820Sjeff param->srq = cm_req_get_srq(req_msg); 1332219820Sjeff work->cm_event.private_data = &req_msg->private_data; 1333219820Sjeff} 1334219820Sjeff 1335219820Sjeffstatic void cm_process_work(struct cm_id_private *cm_id_priv, 1336219820Sjeff struct cm_work *work) 1337219820Sjeff{ 1338219820Sjeff int ret; 1339219820Sjeff 1340219820Sjeff /* We will typically only have the current event to report. */ 1341219820Sjeff ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, &work->cm_event); 1342219820Sjeff cm_free_work(work); 1343219820Sjeff 1344219820Sjeff while (!ret && !atomic_add_negative(-1, &cm_id_priv->work_count)) { 1345219820Sjeff spin_lock_irq(&cm_id_priv->lock); 1346219820Sjeff work = cm_dequeue_work(cm_id_priv); 1347219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 1348219820Sjeff BUG_ON(!work); 1349219820Sjeff ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, 1350219820Sjeff &work->cm_event); 1351219820Sjeff cm_free_work(work); 1352219820Sjeff } 1353219820Sjeff cm_deref_id(cm_id_priv); 1354219820Sjeff if (ret) 1355219820Sjeff cm_destroy_id(&cm_id_priv->id, ret); 1356219820Sjeff} 1357219820Sjeff 1358219820Sjeffstatic void cm_format_mra(struct cm_mra_msg *mra_msg, 1359219820Sjeff struct cm_id_private *cm_id_priv, 1360219820Sjeff enum cm_msg_response msg_mraed, u8 service_timeout, 1361219820Sjeff const void *private_data, u8 private_data_len) 1362219820Sjeff{ 1363219820Sjeff cm_format_mad_hdr(&mra_msg->hdr, CM_MRA_ATTR_ID, cm_id_priv->tid); 1364219820Sjeff cm_mra_set_msg_mraed(mra_msg, msg_mraed); 1365219820Sjeff mra_msg->local_comm_id = cm_id_priv->id.local_id; 1366219820Sjeff mra_msg->remote_comm_id = cm_id_priv->id.remote_id; 1367219820Sjeff cm_mra_set_service_timeout(mra_msg, service_timeout); 1368219820Sjeff 1369219820Sjeff if (private_data && private_data_len) 1370219820Sjeff memcpy(mra_msg->private_data, private_data, private_data_len); 1371219820Sjeff} 1372219820Sjeff 1373219820Sjeffstatic void cm_format_rej(struct cm_rej_msg *rej_msg, 1374219820Sjeff struct cm_id_private *cm_id_priv, 1375219820Sjeff enum ib_cm_rej_reason reason, 1376219820Sjeff void *ari, 1377219820Sjeff u8 ari_length, 1378219820Sjeff const void *private_data, 1379219820Sjeff u8 private_data_len) 1380219820Sjeff{ 1381219820Sjeff cm_format_mad_hdr(&rej_msg->hdr, CM_REJ_ATTR_ID, cm_id_priv->tid); 1382219820Sjeff rej_msg->remote_comm_id = cm_id_priv->id.remote_id; 1383219820Sjeff 1384219820Sjeff switch(cm_id_priv->id.state) { 1385219820Sjeff case IB_CM_REQ_RCVD: 1386219820Sjeff rej_msg->local_comm_id = 0; 1387219820Sjeff cm_rej_set_msg_rejected(rej_msg, CM_MSG_RESPONSE_REQ); 1388219820Sjeff break; 1389219820Sjeff case IB_CM_MRA_REQ_SENT: 1390219820Sjeff rej_msg->local_comm_id = cm_id_priv->id.local_id; 1391219820Sjeff cm_rej_set_msg_rejected(rej_msg, CM_MSG_RESPONSE_REQ); 1392219820Sjeff break; 1393219820Sjeff case IB_CM_REP_RCVD: 1394219820Sjeff case IB_CM_MRA_REP_SENT: 1395219820Sjeff rej_msg->local_comm_id = cm_id_priv->id.local_id; 1396219820Sjeff cm_rej_set_msg_rejected(rej_msg, CM_MSG_RESPONSE_REP); 1397219820Sjeff break; 1398219820Sjeff default: 1399219820Sjeff rej_msg->local_comm_id = cm_id_priv->id.local_id; 1400219820Sjeff cm_rej_set_msg_rejected(rej_msg, CM_MSG_RESPONSE_OTHER); 1401219820Sjeff break; 1402219820Sjeff } 1403219820Sjeff 1404219820Sjeff rej_msg->reason = cpu_to_be16(reason); 1405219820Sjeff if (ari && ari_length) { 1406219820Sjeff cm_rej_set_reject_info_len(rej_msg, ari_length); 1407219820Sjeff memcpy(rej_msg->ari, ari, ari_length); 1408219820Sjeff } 1409219820Sjeff 1410219820Sjeff if (private_data && private_data_len) 1411219820Sjeff memcpy(rej_msg->private_data, private_data, private_data_len); 1412219820Sjeff} 1413219820Sjeff 1414219820Sjeffstatic void cm_dup_req_handler(struct cm_work *work, 1415219820Sjeff struct cm_id_private *cm_id_priv) 1416219820Sjeff{ 1417219820Sjeff struct ib_mad_send_buf *msg = NULL; 1418219820Sjeff int ret; 1419219820Sjeff 1420219820Sjeff atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. 1421219820Sjeff counter[CM_REQ_COUNTER]); 1422219820Sjeff 1423219820Sjeff /* Quick state check to discard duplicate REQs. */ 1424219820Sjeff if (cm_id_priv->id.state == IB_CM_REQ_RCVD) 1425219820Sjeff return; 1426219820Sjeff 1427219820Sjeff ret = cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg); 1428219820Sjeff if (ret) 1429219820Sjeff return; 1430219820Sjeff 1431219820Sjeff spin_lock_irq(&cm_id_priv->lock); 1432219820Sjeff switch (cm_id_priv->id.state) { 1433219820Sjeff case IB_CM_MRA_REQ_SENT: 1434219820Sjeff cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, 1435219820Sjeff CM_MSG_RESPONSE_REQ, cm_id_priv->service_timeout, 1436219820Sjeff cm_id_priv->private_data, 1437219820Sjeff cm_id_priv->private_data_len); 1438219820Sjeff break; 1439219820Sjeff case IB_CM_TIMEWAIT: 1440219820Sjeff cm_format_rej((struct cm_rej_msg *) msg->mad, cm_id_priv, 1441219820Sjeff IB_CM_REJ_STALE_CONN, NULL, 0, NULL, 0); 1442219820Sjeff break; 1443219820Sjeff default: 1444219820Sjeff goto unlock; 1445219820Sjeff } 1446219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 1447219820Sjeff 1448219820Sjeff ret = ib_post_send_mad(msg, NULL); 1449219820Sjeff if (ret) 1450219820Sjeff goto free; 1451219820Sjeff return; 1452219820Sjeff 1453219820Sjeffunlock: spin_unlock_irq(&cm_id_priv->lock); 1454219820Sjefffree: cm_free_msg(msg); 1455219820Sjeff} 1456219820Sjeff 1457219820Sjeffstatic struct cm_id_private * cm_match_req(struct cm_work *work, 1458219820Sjeff struct cm_id_private *cm_id_priv) 1459219820Sjeff{ 1460219820Sjeff struct cm_id_private *listen_cm_id_priv, *cur_cm_id_priv; 1461219820Sjeff struct cm_timewait_info *timewait_info; 1462219820Sjeff struct cm_req_msg *req_msg; 1463219820Sjeff 1464219820Sjeff req_msg = (struct cm_req_msg *)work->mad_recv_wc->recv_buf.mad; 1465219820Sjeff 1466219820Sjeff /* Check for possible duplicate REQ. */ 1467219820Sjeff spin_lock_irq(&cm.lock); 1468219820Sjeff timewait_info = cm_insert_remote_id(cm_id_priv->timewait_info); 1469219820Sjeff if (timewait_info) { 1470219820Sjeff cur_cm_id_priv = cm_get_id(timewait_info->work.local_id, 1471219820Sjeff timewait_info->work.remote_id); 1472219820Sjeff spin_unlock_irq(&cm.lock); 1473219820Sjeff if (cur_cm_id_priv) { 1474219820Sjeff cm_dup_req_handler(work, cur_cm_id_priv); 1475219820Sjeff cm_deref_id(cur_cm_id_priv); 1476219820Sjeff } 1477219820Sjeff return NULL; 1478219820Sjeff } 1479219820Sjeff 1480219820Sjeff /* Check for stale connections. */ 1481219820Sjeff timewait_info = cm_insert_remote_qpn(cm_id_priv->timewait_info); 1482219820Sjeff if (timewait_info) { 1483219820Sjeff cm_cleanup_timewait(cm_id_priv->timewait_info); 1484219820Sjeff spin_unlock_irq(&cm.lock); 1485219820Sjeff cm_issue_rej(work->port, work->mad_recv_wc, 1486219820Sjeff IB_CM_REJ_STALE_CONN, CM_MSG_RESPONSE_REQ, 1487219820Sjeff NULL, 0); 1488219820Sjeff return NULL; 1489219820Sjeff } 1490219820Sjeff 1491219820Sjeff /* Find matching listen request. */ 1492219820Sjeff listen_cm_id_priv = cm_find_listen(cm_id_priv->id.device, 1493219820Sjeff req_msg->service_id, 1494219820Sjeff req_msg->private_data); 1495219820Sjeff if (!listen_cm_id_priv) { 1496219820Sjeff cm_cleanup_timewait(cm_id_priv->timewait_info); 1497219820Sjeff spin_unlock_irq(&cm.lock); 1498219820Sjeff cm_issue_rej(work->port, work->mad_recv_wc, 1499219820Sjeff IB_CM_REJ_INVALID_SERVICE_ID, CM_MSG_RESPONSE_REQ, 1500219820Sjeff NULL, 0); 1501219820Sjeff goto out; 1502219820Sjeff } 1503219820Sjeff atomic_inc(&listen_cm_id_priv->refcount); 1504219820Sjeff atomic_inc(&cm_id_priv->refcount); 1505219820Sjeff cm_id_priv->id.state = IB_CM_REQ_RCVD; 1506219820Sjeff atomic_inc(&cm_id_priv->work_count); 1507219820Sjeff spin_unlock_irq(&cm.lock); 1508219820Sjeffout: 1509219820Sjeff return listen_cm_id_priv; 1510219820Sjeff} 1511219820Sjeff 1512219820Sjeff/* 1513219820Sjeff * Work-around for inter-subnet connections. If the LIDs are permissive, 1514219820Sjeff * we need to override the LID/SL data in the REQ with the LID information 1515219820Sjeff * in the work completion. 1516219820Sjeff */ 1517219820Sjeffstatic void cm_process_routed_req(struct cm_req_msg *req_msg, struct ib_wc *wc) 1518219820Sjeff{ 1519219820Sjeff if (!cm_req_get_primary_subnet_local(req_msg)) { 1520219820Sjeff if (req_msg->primary_local_lid == IB_LID_PERMISSIVE) { 1521219820Sjeff req_msg->primary_local_lid = cpu_to_be16(wc->slid); 1522219820Sjeff cm_req_set_primary_sl(req_msg, wc->sl); 1523219820Sjeff } 1524219820Sjeff 1525219820Sjeff if (req_msg->primary_remote_lid == IB_LID_PERMISSIVE) 1526219820Sjeff req_msg->primary_remote_lid = cpu_to_be16(wc->dlid_path_bits); 1527219820Sjeff } 1528219820Sjeff 1529219820Sjeff if (!cm_req_get_alt_subnet_local(req_msg)) { 1530219820Sjeff if (req_msg->alt_local_lid == IB_LID_PERMISSIVE) { 1531219820Sjeff req_msg->alt_local_lid = cpu_to_be16(wc->slid); 1532219820Sjeff cm_req_set_alt_sl(req_msg, wc->sl); 1533219820Sjeff } 1534219820Sjeff 1535219820Sjeff if (req_msg->alt_remote_lid == IB_LID_PERMISSIVE) 1536219820Sjeff req_msg->alt_remote_lid = cpu_to_be16(wc->dlid_path_bits); 1537219820Sjeff } 1538219820Sjeff} 1539219820Sjeff 1540219820Sjeffstatic int cm_req_handler(struct cm_work *work) 1541219820Sjeff{ 1542219820Sjeff struct ib_cm_id *cm_id; 1543219820Sjeff struct cm_id_private *cm_id_priv, *listen_cm_id_priv; 1544219820Sjeff struct cm_req_msg *req_msg; 1545219820Sjeff int ret; 1546219820Sjeff 1547219820Sjeff req_msg = (struct cm_req_msg *)work->mad_recv_wc->recv_buf.mad; 1548219820Sjeff 1549219820Sjeff cm_id = ib_create_cm_id(work->port->cm_dev->ib_device, NULL, NULL); 1550219820Sjeff if (IS_ERR(cm_id)) 1551219820Sjeff return PTR_ERR(cm_id); 1552219820Sjeff 1553219820Sjeff cm_id_priv = container_of(cm_id, struct cm_id_private, id); 1554219820Sjeff cm_id_priv->id.remote_id = req_msg->local_comm_id; 1555219820Sjeff cm_init_av_for_response(work->port, work->mad_recv_wc->wc, 1556219820Sjeff work->mad_recv_wc->recv_buf.grh, 1557219820Sjeff &cm_id_priv->av); 1558219820Sjeff cm_id_priv->timewait_info = cm_create_timewait_info(cm_id_priv-> 1559219820Sjeff id.local_id); 1560219820Sjeff if (IS_ERR(cm_id_priv->timewait_info)) { 1561219820Sjeff ret = PTR_ERR(cm_id_priv->timewait_info); 1562219820Sjeff goto destroy; 1563219820Sjeff } 1564219820Sjeff cm_id_priv->timewait_info->work.remote_id = req_msg->local_comm_id; 1565219820Sjeff cm_id_priv->timewait_info->remote_ca_guid = req_msg->local_ca_guid; 1566219820Sjeff cm_id_priv->timewait_info->remote_qpn = cm_req_get_local_qpn(req_msg); 1567219820Sjeff 1568219820Sjeff listen_cm_id_priv = cm_match_req(work, cm_id_priv); 1569219820Sjeff if (!listen_cm_id_priv) { 1570219820Sjeff ret = -EINVAL; 1571219820Sjeff kfree(cm_id_priv->timewait_info); 1572219820Sjeff goto destroy; 1573219820Sjeff } 1574219820Sjeff 1575219820Sjeff cm_id_priv->id.cm_handler = listen_cm_id_priv->id.cm_handler; 1576219820Sjeff cm_id_priv->id.context = listen_cm_id_priv->id.context; 1577219820Sjeff cm_id_priv->id.service_id = req_msg->service_id; 1578219820Sjeff cm_id_priv->id.service_mask = ~cpu_to_be64(0); 1579219820Sjeff 1580219820Sjeff cm_process_routed_req(req_msg, work->mad_recv_wc->wc); 1581219820Sjeff cm_format_paths_from_req(req_msg, &work->path[0], &work->path[1]); 1582219820Sjeff ret = cm_init_av_by_path(&work->path[0], &cm_id_priv->av); 1583219820Sjeff if (ret) { 1584219820Sjeff ib_get_cached_gid(work->port->cm_dev->ib_device, 1585219820Sjeff work->port->port_num, 0, &work->path[0].sgid); 1586219820Sjeff ib_send_cm_rej(cm_id, IB_CM_REJ_INVALID_GID, 1587219820Sjeff &work->path[0].sgid, sizeof work->path[0].sgid, 1588219820Sjeff NULL, 0); 1589219820Sjeff goto rejected; 1590219820Sjeff } 1591219820Sjeff if (req_msg->alt_local_lid) { 1592219820Sjeff ret = cm_init_av_by_path(&work->path[1], &cm_id_priv->alt_av); 1593219820Sjeff if (ret) { 1594219820Sjeff ib_send_cm_rej(cm_id, IB_CM_REJ_INVALID_ALT_GID, 1595219820Sjeff &work->path[0].sgid, 1596219820Sjeff sizeof work->path[0].sgid, NULL, 0); 1597219820Sjeff goto rejected; 1598219820Sjeff } 1599219820Sjeff } 1600219820Sjeff cm_id_priv->tid = req_msg->hdr.tid; 1601219820Sjeff cm_id_priv->timeout_ms = cm_convert_to_ms( 1602219820Sjeff cm_req_get_local_resp_timeout(req_msg)); 1603219820Sjeff if (cm_req_get_local_resp_timeout(req_msg) > (u8) max_timeout) { 1604219820Sjeff printk(KERN_WARNING PFX "rcvd cm_local_resp_timeout %d > %d, " 1605219820Sjeff "decreasing used timeout_ms\n", 1606219820Sjeff cm_req_get_local_resp_timeout(req_msg), max_timeout); 1607219820Sjeff cm_id_priv->timeout_ms = cm_convert_to_ms(max_timeout); 1608219820Sjeff } 1609219820Sjeff 1610219820Sjeff cm_id_priv->max_cm_retries = cm_req_get_max_cm_retries(req_msg); 1611219820Sjeff cm_id_priv->remote_qpn = cm_req_get_local_qpn(req_msg); 1612219820Sjeff cm_id_priv->initiator_depth = cm_req_get_resp_res(req_msg); 1613219820Sjeff cm_id_priv->responder_resources = cm_req_get_init_depth(req_msg); 1614219820Sjeff cm_id_priv->path_mtu = cm_req_get_path_mtu(req_msg); 1615219820Sjeff cm_id_priv->pkey = req_msg->pkey; 1616219820Sjeff cm_id_priv->sq_psn = cm_req_get_starting_psn(req_msg); 1617219820Sjeff cm_id_priv->retry_count = cm_req_get_retry_count(req_msg); 1618219820Sjeff cm_id_priv->rnr_retry_count = cm_req_get_rnr_retry_count(req_msg); 1619219820Sjeff cm_id_priv->qp_type = cm_req_get_qp_type(req_msg); 1620219820Sjeff 1621219820Sjeff cm_format_req_event(work, cm_id_priv, &listen_cm_id_priv->id); 1622219820Sjeff cm_process_work(cm_id_priv, work); 1623219820Sjeff cm_deref_id(listen_cm_id_priv); 1624219820Sjeff return 0; 1625219820Sjeff 1626219820Sjeffrejected: 1627219820Sjeff atomic_dec(&cm_id_priv->refcount); 1628219820Sjeff cm_deref_id(listen_cm_id_priv); 1629219820Sjeffdestroy: 1630219820Sjeff ib_destroy_cm_id(cm_id); 1631219820Sjeff return ret; 1632219820Sjeff} 1633219820Sjeff 1634219820Sjeffstatic void cm_format_rep(struct cm_rep_msg *rep_msg, 1635219820Sjeff struct cm_id_private *cm_id_priv, 1636219820Sjeff struct ib_cm_rep_param *param) 1637219820Sjeff{ 1638219820Sjeff cm_format_mad_hdr(&rep_msg->hdr, CM_REP_ATTR_ID, cm_id_priv->tid); 1639219820Sjeff rep_msg->local_comm_id = cm_id_priv->id.local_id; 1640219820Sjeff rep_msg->remote_comm_id = cm_id_priv->id.remote_id; 1641219820Sjeff cm_rep_set_local_qpn(rep_msg, cpu_to_be32(param->qp_num)); 1642219820Sjeff cm_rep_set_starting_psn(rep_msg, cpu_to_be32(param->starting_psn)); 1643219820Sjeff rep_msg->resp_resources = param->responder_resources; 1644219820Sjeff rep_msg->initiator_depth = param->initiator_depth; 1645219820Sjeff cm_rep_set_target_ack_delay(rep_msg, 1646219820Sjeff cm_id_priv->av.port->cm_dev->ack_delay); 1647219820Sjeff cm_rep_set_failover(rep_msg, param->failover_accepted); 1648219820Sjeff cm_rep_set_flow_ctrl(rep_msg, param->flow_control); 1649219820Sjeff cm_rep_set_rnr_retry_count(rep_msg, param->rnr_retry_count); 1650219820Sjeff cm_rep_set_srq(rep_msg, param->srq); 1651219820Sjeff rep_msg->local_ca_guid = cm_id_priv->id.device->node_guid; 1652219820Sjeff 1653219820Sjeff if (param->private_data && param->private_data_len) 1654219820Sjeff memcpy(rep_msg->private_data, param->private_data, 1655219820Sjeff param->private_data_len); 1656219820Sjeff} 1657219820Sjeff 1658219820Sjeffint ib_send_cm_rep(struct ib_cm_id *cm_id, 1659219820Sjeff struct ib_cm_rep_param *param) 1660219820Sjeff{ 1661219820Sjeff struct cm_id_private *cm_id_priv; 1662219820Sjeff struct ib_mad_send_buf *msg; 1663219820Sjeff struct cm_rep_msg *rep_msg; 1664219820Sjeff unsigned long flags; 1665219820Sjeff int ret; 1666219820Sjeff 1667219820Sjeff if (param->private_data && 1668219820Sjeff param->private_data_len > IB_CM_REP_PRIVATE_DATA_SIZE) 1669219820Sjeff return -EINVAL; 1670219820Sjeff 1671219820Sjeff cm_id_priv = container_of(cm_id, struct cm_id_private, id); 1672219820Sjeff spin_lock_irqsave(&cm_id_priv->lock, flags); 1673219820Sjeff if (cm_id->state != IB_CM_REQ_RCVD && 1674219820Sjeff cm_id->state != IB_CM_MRA_REQ_SENT) { 1675219820Sjeff ret = -EINVAL; 1676219820Sjeff goto out; 1677219820Sjeff } 1678219820Sjeff 1679219820Sjeff ret = cm_alloc_msg(cm_id_priv, &msg); 1680219820Sjeff if (ret) 1681219820Sjeff goto out; 1682219820Sjeff 1683219820Sjeff rep_msg = (struct cm_rep_msg *) msg->mad; 1684219820Sjeff cm_format_rep(rep_msg, cm_id_priv, param); 1685219820Sjeff msg->timeout_ms = cm_id_priv->timeout_ms; 1686219820Sjeff msg->context[1] = (void *) (unsigned long) IB_CM_REP_SENT; 1687219820Sjeff 1688219820Sjeff ret = ib_post_send_mad(msg, NULL); 1689219820Sjeff if (ret) { 1690219820Sjeff spin_unlock_irqrestore(&cm_id_priv->lock, flags); 1691219820Sjeff cm_free_msg(msg); 1692219820Sjeff return ret; 1693219820Sjeff } 1694219820Sjeff 1695219820Sjeff cm_id->state = IB_CM_REP_SENT; 1696219820Sjeff cm_id_priv->msg = msg; 1697219820Sjeff cm_id_priv->initiator_depth = param->initiator_depth; 1698219820Sjeff cm_id_priv->responder_resources = param->responder_resources; 1699219820Sjeff cm_id_priv->rq_psn = cm_rep_get_starting_psn(rep_msg); 1700219820Sjeff cm_id_priv->local_qpn = cm_rep_get_local_qpn(rep_msg); 1701219820Sjeff 1702219820Sjeffout: spin_unlock_irqrestore(&cm_id_priv->lock, flags); 1703219820Sjeff return ret; 1704219820Sjeff} 1705219820SjeffEXPORT_SYMBOL(ib_send_cm_rep); 1706219820Sjeff 1707219820Sjeffstatic void cm_format_rtu(struct cm_rtu_msg *rtu_msg, 1708219820Sjeff struct cm_id_private *cm_id_priv, 1709219820Sjeff const void *private_data, 1710219820Sjeff u8 private_data_len) 1711219820Sjeff{ 1712219820Sjeff cm_format_mad_hdr(&rtu_msg->hdr, CM_RTU_ATTR_ID, cm_id_priv->tid); 1713219820Sjeff rtu_msg->local_comm_id = cm_id_priv->id.local_id; 1714219820Sjeff rtu_msg->remote_comm_id = cm_id_priv->id.remote_id; 1715219820Sjeff 1716219820Sjeff if (private_data && private_data_len) 1717219820Sjeff memcpy(rtu_msg->private_data, private_data, private_data_len); 1718219820Sjeff} 1719219820Sjeff 1720219820Sjeffint ib_send_cm_rtu(struct ib_cm_id *cm_id, 1721219820Sjeff const void *private_data, 1722219820Sjeff u8 private_data_len) 1723219820Sjeff{ 1724219820Sjeff struct cm_id_private *cm_id_priv; 1725219820Sjeff struct ib_mad_send_buf *msg; 1726219820Sjeff unsigned long flags; 1727219820Sjeff void *data; 1728219820Sjeff int ret; 1729219820Sjeff 1730219820Sjeff if (private_data && private_data_len > IB_CM_RTU_PRIVATE_DATA_SIZE) 1731219820Sjeff return -EINVAL; 1732219820Sjeff 1733219820Sjeff data = cm_copy_private_data(private_data, private_data_len); 1734219820Sjeff if (IS_ERR(data)) 1735219820Sjeff return PTR_ERR(data); 1736219820Sjeff 1737219820Sjeff cm_id_priv = container_of(cm_id, struct cm_id_private, id); 1738219820Sjeff spin_lock_irqsave(&cm_id_priv->lock, flags); 1739219820Sjeff if (cm_id->state != IB_CM_REP_RCVD && 1740219820Sjeff cm_id->state != IB_CM_MRA_REP_SENT) { 1741219820Sjeff ret = -EINVAL; 1742219820Sjeff goto error; 1743219820Sjeff } 1744219820Sjeff 1745219820Sjeff ret = cm_alloc_msg(cm_id_priv, &msg); 1746219820Sjeff if (ret) 1747219820Sjeff goto error; 1748219820Sjeff 1749219820Sjeff cm_format_rtu((struct cm_rtu_msg *) msg->mad, cm_id_priv, 1750219820Sjeff private_data, private_data_len); 1751219820Sjeff 1752219820Sjeff ret = ib_post_send_mad(msg, NULL); 1753219820Sjeff if (ret) { 1754219820Sjeff spin_unlock_irqrestore(&cm_id_priv->lock, flags); 1755219820Sjeff cm_free_msg(msg); 1756219820Sjeff kfree(data); 1757219820Sjeff return ret; 1758219820Sjeff } 1759219820Sjeff 1760219820Sjeff cm_id->state = IB_CM_ESTABLISHED; 1761219820Sjeff cm_set_private_data(cm_id_priv, data, private_data_len); 1762219820Sjeff spin_unlock_irqrestore(&cm_id_priv->lock, flags); 1763219820Sjeff return 0; 1764219820Sjeff 1765219820Sjefferror: spin_unlock_irqrestore(&cm_id_priv->lock, flags); 1766219820Sjeff kfree(data); 1767219820Sjeff return ret; 1768219820Sjeff} 1769219820SjeffEXPORT_SYMBOL(ib_send_cm_rtu); 1770219820Sjeff 1771219820Sjeffstatic void cm_format_rep_event(struct cm_work *work) 1772219820Sjeff{ 1773219820Sjeff struct cm_rep_msg *rep_msg; 1774219820Sjeff struct ib_cm_rep_event_param *param; 1775219820Sjeff 1776219820Sjeff rep_msg = (struct cm_rep_msg *)work->mad_recv_wc->recv_buf.mad; 1777219820Sjeff param = &work->cm_event.param.rep_rcvd; 1778219820Sjeff param->remote_ca_guid = rep_msg->local_ca_guid; 1779219820Sjeff param->remote_qkey = be32_to_cpu(rep_msg->local_qkey); 1780219820Sjeff param->remote_qpn = be32_to_cpu(cm_rep_get_local_qpn(rep_msg)); 1781219820Sjeff param->starting_psn = be32_to_cpu(cm_rep_get_starting_psn(rep_msg)); 1782219820Sjeff param->responder_resources = rep_msg->initiator_depth; 1783219820Sjeff param->initiator_depth = rep_msg->resp_resources; 1784219820Sjeff param->target_ack_delay = cm_rep_get_target_ack_delay(rep_msg); 1785219820Sjeff param->failover_accepted = cm_rep_get_failover(rep_msg); 1786219820Sjeff param->flow_control = cm_rep_get_flow_ctrl(rep_msg); 1787219820Sjeff param->rnr_retry_count = cm_rep_get_rnr_retry_count(rep_msg); 1788219820Sjeff param->srq = cm_rep_get_srq(rep_msg); 1789219820Sjeff work->cm_event.private_data = &rep_msg->private_data; 1790219820Sjeff} 1791219820Sjeff 1792219820Sjeffstatic void cm_dup_rep_handler(struct cm_work *work) 1793219820Sjeff{ 1794219820Sjeff struct cm_id_private *cm_id_priv; 1795219820Sjeff struct cm_rep_msg *rep_msg; 1796219820Sjeff struct ib_mad_send_buf *msg = NULL; 1797219820Sjeff int ret; 1798219820Sjeff 1799219820Sjeff rep_msg = (struct cm_rep_msg *) work->mad_recv_wc->recv_buf.mad; 1800219820Sjeff cm_id_priv = cm_acquire_id(rep_msg->remote_comm_id, 1801219820Sjeff rep_msg->local_comm_id); 1802219820Sjeff if (!cm_id_priv) 1803219820Sjeff return; 1804219820Sjeff 1805219820Sjeff atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. 1806219820Sjeff counter[CM_REP_COUNTER]); 1807219820Sjeff ret = cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg); 1808219820Sjeff if (ret) 1809219820Sjeff goto deref; 1810219820Sjeff 1811219820Sjeff spin_lock_irq(&cm_id_priv->lock); 1812219820Sjeff if (cm_id_priv->id.state == IB_CM_ESTABLISHED) 1813219820Sjeff cm_format_rtu((struct cm_rtu_msg *) msg->mad, cm_id_priv, 1814219820Sjeff cm_id_priv->private_data, 1815219820Sjeff cm_id_priv->private_data_len); 1816219820Sjeff else if (cm_id_priv->id.state == IB_CM_MRA_REP_SENT) 1817219820Sjeff cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, 1818219820Sjeff CM_MSG_RESPONSE_REP, cm_id_priv->service_timeout, 1819219820Sjeff cm_id_priv->private_data, 1820219820Sjeff cm_id_priv->private_data_len); 1821219820Sjeff else 1822219820Sjeff goto unlock; 1823219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 1824219820Sjeff 1825219820Sjeff ret = ib_post_send_mad(msg, NULL); 1826219820Sjeff if (ret) 1827219820Sjeff goto free; 1828219820Sjeff goto deref; 1829219820Sjeff 1830219820Sjeffunlock: spin_unlock_irq(&cm_id_priv->lock); 1831219820Sjefffree: cm_free_msg(msg); 1832219820Sjeffderef: cm_deref_id(cm_id_priv); 1833219820Sjeff} 1834219820Sjeff 1835219820Sjeffstatic int cm_rep_handler(struct cm_work *work) 1836219820Sjeff{ 1837219820Sjeff struct cm_id_private *cm_id_priv; 1838219820Sjeff struct cm_rep_msg *rep_msg; 1839219820Sjeff int ret; 1840219820Sjeff 1841219820Sjeff rep_msg = (struct cm_rep_msg *)work->mad_recv_wc->recv_buf.mad; 1842219820Sjeff cm_id_priv = cm_acquire_id(rep_msg->remote_comm_id, 0); 1843219820Sjeff if (!cm_id_priv) { 1844219820Sjeff cm_dup_rep_handler(work); 1845219820Sjeff return -EINVAL; 1846219820Sjeff } 1847219820Sjeff 1848219820Sjeff cm_format_rep_event(work); 1849219820Sjeff 1850219820Sjeff spin_lock_irq(&cm_id_priv->lock); 1851219820Sjeff switch (cm_id_priv->id.state) { 1852219820Sjeff case IB_CM_REQ_SENT: 1853219820Sjeff case IB_CM_MRA_REQ_RCVD: 1854219820Sjeff break; 1855219820Sjeff default: 1856219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 1857219820Sjeff ret = -EINVAL; 1858219820Sjeff goto error; 1859219820Sjeff } 1860219820Sjeff 1861219820Sjeff cm_id_priv->timewait_info->work.remote_id = rep_msg->local_comm_id; 1862219820Sjeff cm_id_priv->timewait_info->remote_ca_guid = rep_msg->local_ca_guid; 1863219820Sjeff cm_id_priv->timewait_info->remote_qpn = cm_rep_get_local_qpn(rep_msg); 1864219820Sjeff 1865219820Sjeff spin_lock(&cm.lock); 1866219820Sjeff /* Check for duplicate REP. */ 1867219820Sjeff if (cm_insert_remote_id(cm_id_priv->timewait_info)) { 1868219820Sjeff spin_unlock(&cm.lock); 1869219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 1870219820Sjeff ret = -EINVAL; 1871219820Sjeff goto error; 1872219820Sjeff } 1873219820Sjeff /* Check for a stale connection. */ 1874219820Sjeff if (cm_insert_remote_qpn(cm_id_priv->timewait_info)) { 1875219820Sjeff rb_erase(&cm_id_priv->timewait_info->remote_id_node, 1876219820Sjeff &cm.remote_id_table); 1877219820Sjeff cm_id_priv->timewait_info->inserted_remote_id = 0; 1878219820Sjeff spin_unlock(&cm.lock); 1879219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 1880219820Sjeff cm_issue_rej(work->port, work->mad_recv_wc, 1881219820Sjeff IB_CM_REJ_STALE_CONN, CM_MSG_RESPONSE_REP, 1882219820Sjeff NULL, 0); 1883219820Sjeff ret = -EINVAL; 1884219820Sjeff goto error; 1885219820Sjeff } 1886219820Sjeff spin_unlock(&cm.lock); 1887219820Sjeff 1888219820Sjeff cm_id_priv->id.state = IB_CM_REP_RCVD; 1889219820Sjeff cm_id_priv->id.remote_id = rep_msg->local_comm_id; 1890219820Sjeff cm_id_priv->remote_qpn = cm_rep_get_local_qpn(rep_msg); 1891219820Sjeff cm_id_priv->initiator_depth = rep_msg->resp_resources; 1892219820Sjeff cm_id_priv->responder_resources = rep_msg->initiator_depth; 1893219820Sjeff cm_id_priv->sq_psn = cm_rep_get_starting_psn(rep_msg); 1894219820Sjeff cm_id_priv->rnr_retry_count = cm_rep_get_rnr_retry_count(rep_msg); 1895219820Sjeff cm_id_priv->target_ack_delay = cm_rep_get_target_ack_delay(rep_msg); 1896219820Sjeff cm_id_priv->av.timeout = 1897219820Sjeff cm_ack_timeout(cm_id_priv->target_ack_delay, 1898219820Sjeff cm_id_priv->av.timeout - 1); 1899219820Sjeff cm_id_priv->alt_av.timeout = 1900219820Sjeff cm_ack_timeout(cm_id_priv->target_ack_delay, 1901219820Sjeff cm_id_priv->alt_av.timeout - 1); 1902219820Sjeff 1903219820Sjeff /* todo: handle peer_to_peer */ 1904219820Sjeff 1905219820Sjeff ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); 1906219820Sjeff ret = atomic_inc_and_test(&cm_id_priv->work_count); 1907219820Sjeff if (!ret) 1908219820Sjeff list_add_tail(&work->list, &cm_id_priv->work_list); 1909219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 1910219820Sjeff 1911219820Sjeff if (ret) 1912219820Sjeff cm_process_work(cm_id_priv, work); 1913219820Sjeff else 1914219820Sjeff cm_deref_id(cm_id_priv); 1915219820Sjeff return 0; 1916219820Sjeff 1917219820Sjefferror: 1918219820Sjeff cm_deref_id(cm_id_priv); 1919219820Sjeff return ret; 1920219820Sjeff} 1921219820Sjeff 1922219820Sjeffstatic int cm_establish_handler(struct cm_work *work) 1923219820Sjeff{ 1924219820Sjeff struct cm_id_private *cm_id_priv; 1925219820Sjeff int ret; 1926219820Sjeff 1927219820Sjeff /* See comment in cm_establish about lookup. */ 1928219820Sjeff cm_id_priv = cm_acquire_id(work->local_id, work->remote_id); 1929219820Sjeff if (!cm_id_priv) 1930219820Sjeff return -EINVAL; 1931219820Sjeff 1932219820Sjeff spin_lock_irq(&cm_id_priv->lock); 1933219820Sjeff if (cm_id_priv->id.state != IB_CM_ESTABLISHED) { 1934219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 1935219820Sjeff goto out; 1936219820Sjeff } 1937219820Sjeff 1938219820Sjeff ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); 1939219820Sjeff ret = atomic_inc_and_test(&cm_id_priv->work_count); 1940219820Sjeff if (!ret) 1941219820Sjeff list_add_tail(&work->list, &cm_id_priv->work_list); 1942219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 1943219820Sjeff 1944219820Sjeff if (ret) 1945219820Sjeff cm_process_work(cm_id_priv, work); 1946219820Sjeff else 1947219820Sjeff cm_deref_id(cm_id_priv); 1948219820Sjeff return 0; 1949219820Sjeffout: 1950219820Sjeff cm_deref_id(cm_id_priv); 1951219820Sjeff return -EINVAL; 1952219820Sjeff} 1953219820Sjeff 1954219820Sjeffstatic int cm_rtu_handler(struct cm_work *work) 1955219820Sjeff{ 1956219820Sjeff struct cm_id_private *cm_id_priv; 1957219820Sjeff struct cm_rtu_msg *rtu_msg; 1958219820Sjeff int ret; 1959219820Sjeff 1960219820Sjeff rtu_msg = (struct cm_rtu_msg *)work->mad_recv_wc->recv_buf.mad; 1961219820Sjeff cm_id_priv = cm_acquire_id(rtu_msg->remote_comm_id, 1962219820Sjeff rtu_msg->local_comm_id); 1963219820Sjeff if (!cm_id_priv) 1964219820Sjeff return -EINVAL; 1965219820Sjeff 1966219820Sjeff work->cm_event.private_data = &rtu_msg->private_data; 1967219820Sjeff 1968219820Sjeff spin_lock_irq(&cm_id_priv->lock); 1969219820Sjeff if (cm_id_priv->id.state != IB_CM_REP_SENT && 1970219820Sjeff cm_id_priv->id.state != IB_CM_MRA_REP_RCVD) { 1971219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 1972219820Sjeff atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. 1973219820Sjeff counter[CM_RTU_COUNTER]); 1974219820Sjeff goto out; 1975219820Sjeff } 1976219820Sjeff cm_id_priv->id.state = IB_CM_ESTABLISHED; 1977219820Sjeff 1978219820Sjeff ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); 1979219820Sjeff ret = atomic_inc_and_test(&cm_id_priv->work_count); 1980219820Sjeff if (!ret) 1981219820Sjeff list_add_tail(&work->list, &cm_id_priv->work_list); 1982219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 1983219820Sjeff 1984219820Sjeff if (ret) 1985219820Sjeff cm_process_work(cm_id_priv, work); 1986219820Sjeff else 1987219820Sjeff cm_deref_id(cm_id_priv); 1988219820Sjeff return 0; 1989219820Sjeffout: 1990219820Sjeff cm_deref_id(cm_id_priv); 1991219820Sjeff return -EINVAL; 1992219820Sjeff} 1993219820Sjeff 1994219820Sjeffstatic void cm_format_dreq(struct cm_dreq_msg *dreq_msg, 1995219820Sjeff struct cm_id_private *cm_id_priv, 1996219820Sjeff const void *private_data, 1997219820Sjeff u8 private_data_len) 1998219820Sjeff{ 1999219820Sjeff cm_format_mad_hdr(&dreq_msg->hdr, CM_DREQ_ATTR_ID, 2000219820Sjeff cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_DREQ)); 2001219820Sjeff dreq_msg->local_comm_id = cm_id_priv->id.local_id; 2002219820Sjeff dreq_msg->remote_comm_id = cm_id_priv->id.remote_id; 2003219820Sjeff cm_dreq_set_remote_qpn(dreq_msg, cm_id_priv->remote_qpn); 2004219820Sjeff 2005219820Sjeff if (private_data && private_data_len) 2006219820Sjeff memcpy(dreq_msg->private_data, private_data, private_data_len); 2007219820Sjeff} 2008219820Sjeff 2009219820Sjeffint ib_send_cm_dreq(struct ib_cm_id *cm_id, 2010219820Sjeff const void *private_data, 2011219820Sjeff u8 private_data_len) 2012219820Sjeff{ 2013219820Sjeff struct cm_id_private *cm_id_priv; 2014219820Sjeff struct ib_mad_send_buf *msg; 2015219820Sjeff unsigned long flags; 2016219820Sjeff int ret; 2017219820Sjeff 2018219820Sjeff if (private_data && private_data_len > IB_CM_DREQ_PRIVATE_DATA_SIZE) 2019219820Sjeff return -EINVAL; 2020219820Sjeff 2021219820Sjeff cm_id_priv = container_of(cm_id, struct cm_id_private, id); 2022219820Sjeff spin_lock_irqsave(&cm_id_priv->lock, flags); 2023219820Sjeff if (cm_id->state != IB_CM_ESTABLISHED) { 2024219820Sjeff ret = -EINVAL; 2025219820Sjeff goto out; 2026219820Sjeff } 2027219820Sjeff 2028219820Sjeff ret = cm_alloc_msg(cm_id_priv, &msg); 2029219820Sjeff if (ret) { 2030219820Sjeff cm_enter_timewait(cm_id_priv); 2031219820Sjeff goto out; 2032219820Sjeff } 2033219820Sjeff 2034219820Sjeff cm_format_dreq((struct cm_dreq_msg *) msg->mad, cm_id_priv, 2035219820Sjeff private_data, private_data_len); 2036219820Sjeff msg->timeout_ms = cm_id_priv->timeout_ms; 2037219820Sjeff msg->context[1] = (void *) (unsigned long) IB_CM_DREQ_SENT; 2038219820Sjeff 2039219820Sjeff ret = ib_post_send_mad(msg, NULL); 2040219820Sjeff if (ret) { 2041219820Sjeff cm_enter_timewait(cm_id_priv); 2042219820Sjeff spin_unlock_irqrestore(&cm_id_priv->lock, flags); 2043219820Sjeff cm_free_msg(msg); 2044219820Sjeff return ret; 2045219820Sjeff } 2046219820Sjeff 2047219820Sjeff cm_id->state = IB_CM_DREQ_SENT; 2048219820Sjeff cm_id_priv->msg = msg; 2049219820Sjeffout: spin_unlock_irqrestore(&cm_id_priv->lock, flags); 2050219820Sjeff return ret; 2051219820Sjeff} 2052219820SjeffEXPORT_SYMBOL(ib_send_cm_dreq); 2053219820Sjeff 2054219820Sjeffstatic void cm_format_drep(struct cm_drep_msg *drep_msg, 2055219820Sjeff struct cm_id_private *cm_id_priv, 2056219820Sjeff const void *private_data, 2057219820Sjeff u8 private_data_len) 2058219820Sjeff{ 2059219820Sjeff cm_format_mad_hdr(&drep_msg->hdr, CM_DREP_ATTR_ID, cm_id_priv->tid); 2060219820Sjeff drep_msg->local_comm_id = cm_id_priv->id.local_id; 2061219820Sjeff drep_msg->remote_comm_id = cm_id_priv->id.remote_id; 2062219820Sjeff 2063219820Sjeff if (private_data && private_data_len) 2064219820Sjeff memcpy(drep_msg->private_data, private_data, private_data_len); 2065219820Sjeff} 2066219820Sjeff 2067219820Sjeffint ib_send_cm_drep(struct ib_cm_id *cm_id, 2068219820Sjeff const void *private_data, 2069219820Sjeff u8 private_data_len) 2070219820Sjeff{ 2071219820Sjeff struct cm_id_private *cm_id_priv; 2072219820Sjeff struct ib_mad_send_buf *msg; 2073219820Sjeff unsigned long flags; 2074219820Sjeff void *data; 2075219820Sjeff int ret; 2076219820Sjeff 2077219820Sjeff if (private_data && private_data_len > IB_CM_DREP_PRIVATE_DATA_SIZE) 2078219820Sjeff return -EINVAL; 2079219820Sjeff 2080219820Sjeff data = cm_copy_private_data(private_data, private_data_len); 2081219820Sjeff if (IS_ERR(data)) 2082219820Sjeff return PTR_ERR(data); 2083219820Sjeff 2084219820Sjeff cm_id_priv = container_of(cm_id, struct cm_id_private, id); 2085219820Sjeff spin_lock_irqsave(&cm_id_priv->lock, flags); 2086219820Sjeff if (cm_id->state != IB_CM_DREQ_RCVD) { 2087219820Sjeff spin_unlock_irqrestore(&cm_id_priv->lock, flags); 2088219820Sjeff kfree(data); 2089219820Sjeff return -EINVAL; 2090219820Sjeff } 2091219820Sjeff 2092219820Sjeff cm_set_private_data(cm_id_priv, data, private_data_len); 2093219820Sjeff cm_enter_timewait(cm_id_priv); 2094219820Sjeff 2095219820Sjeff ret = cm_alloc_msg(cm_id_priv, &msg); 2096219820Sjeff if (ret) 2097219820Sjeff goto out; 2098219820Sjeff 2099219820Sjeff cm_format_drep((struct cm_drep_msg *) msg->mad, cm_id_priv, 2100219820Sjeff private_data, private_data_len); 2101219820Sjeff 2102219820Sjeff ret = ib_post_send_mad(msg, NULL); 2103219820Sjeff if (ret) { 2104219820Sjeff spin_unlock_irqrestore(&cm_id_priv->lock, flags); 2105219820Sjeff cm_free_msg(msg); 2106219820Sjeff return ret; 2107219820Sjeff } 2108219820Sjeff 2109219820Sjeffout: spin_unlock_irqrestore(&cm_id_priv->lock, flags); 2110219820Sjeff return ret; 2111219820Sjeff} 2112219820SjeffEXPORT_SYMBOL(ib_send_cm_drep); 2113219820Sjeff 2114219820Sjeffstatic int cm_issue_drep(struct cm_port *port, 2115219820Sjeff struct ib_mad_recv_wc *mad_recv_wc) 2116219820Sjeff{ 2117219820Sjeff struct ib_mad_send_buf *msg = NULL; 2118219820Sjeff struct cm_dreq_msg *dreq_msg; 2119219820Sjeff struct cm_drep_msg *drep_msg; 2120219820Sjeff int ret; 2121219820Sjeff 2122219820Sjeff ret = cm_alloc_response_msg(port, mad_recv_wc, &msg); 2123219820Sjeff if (ret) 2124219820Sjeff return ret; 2125219820Sjeff 2126219820Sjeff dreq_msg = (struct cm_dreq_msg *) mad_recv_wc->recv_buf.mad; 2127219820Sjeff drep_msg = (struct cm_drep_msg *) msg->mad; 2128219820Sjeff 2129219820Sjeff cm_format_mad_hdr(&drep_msg->hdr, CM_DREP_ATTR_ID, dreq_msg->hdr.tid); 2130219820Sjeff drep_msg->remote_comm_id = dreq_msg->local_comm_id; 2131219820Sjeff drep_msg->local_comm_id = dreq_msg->remote_comm_id; 2132219820Sjeff 2133219820Sjeff ret = ib_post_send_mad(msg, NULL); 2134219820Sjeff if (ret) 2135219820Sjeff cm_free_msg(msg); 2136219820Sjeff 2137219820Sjeff return ret; 2138219820Sjeff} 2139219820Sjeff 2140219820Sjeffstatic int cm_dreq_handler(struct cm_work *work) 2141219820Sjeff{ 2142219820Sjeff struct cm_id_private *cm_id_priv; 2143219820Sjeff struct cm_dreq_msg *dreq_msg; 2144219820Sjeff struct ib_mad_send_buf *msg = NULL; 2145219820Sjeff int ret; 2146219820Sjeff 2147219820Sjeff dreq_msg = (struct cm_dreq_msg *)work->mad_recv_wc->recv_buf.mad; 2148219820Sjeff cm_id_priv = cm_acquire_id(dreq_msg->remote_comm_id, 2149219820Sjeff dreq_msg->local_comm_id); 2150219820Sjeff if (!cm_id_priv) { 2151219820Sjeff atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. 2152219820Sjeff counter[CM_DREQ_COUNTER]); 2153219820Sjeff cm_issue_drep(work->port, work->mad_recv_wc); 2154219820Sjeff return -EINVAL; 2155219820Sjeff } 2156219820Sjeff 2157219820Sjeff work->cm_event.private_data = &dreq_msg->private_data; 2158219820Sjeff 2159219820Sjeff spin_lock_irq(&cm_id_priv->lock); 2160219820Sjeff if (cm_id_priv->local_qpn != cm_dreq_get_remote_qpn(dreq_msg)) 2161219820Sjeff goto unlock; 2162219820Sjeff 2163219820Sjeff switch (cm_id_priv->id.state) { 2164219820Sjeff case IB_CM_REP_SENT: 2165219820Sjeff case IB_CM_DREQ_SENT: 2166219820Sjeff ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); 2167219820Sjeff break; 2168219820Sjeff case IB_CM_ESTABLISHED: 2169219820Sjeff case IB_CM_MRA_REP_RCVD: 2170219820Sjeff break; 2171219820Sjeff case IB_CM_TIMEWAIT: 2172219820Sjeff atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. 2173219820Sjeff counter[CM_DREQ_COUNTER]); 2174219820Sjeff if (cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg)) 2175219820Sjeff goto unlock; 2176219820Sjeff 2177219820Sjeff cm_format_drep((struct cm_drep_msg *) msg->mad, cm_id_priv, 2178219820Sjeff cm_id_priv->private_data, 2179219820Sjeff cm_id_priv->private_data_len); 2180219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 2181219820Sjeff 2182219820Sjeff if (ib_post_send_mad(msg, NULL)) 2183219820Sjeff cm_free_msg(msg); 2184219820Sjeff goto deref; 2185219820Sjeff case IB_CM_DREQ_RCVD: 2186219820Sjeff atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. 2187219820Sjeff counter[CM_DREQ_COUNTER]); 2188219820Sjeff goto unlock; 2189219820Sjeff default: 2190219820Sjeff goto unlock; 2191219820Sjeff } 2192219820Sjeff cm_id_priv->id.state = IB_CM_DREQ_RCVD; 2193219820Sjeff cm_id_priv->tid = dreq_msg->hdr.tid; 2194219820Sjeff ret = atomic_inc_and_test(&cm_id_priv->work_count); 2195219820Sjeff if (!ret) 2196219820Sjeff list_add_tail(&work->list, &cm_id_priv->work_list); 2197219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 2198219820Sjeff 2199219820Sjeff if (ret) 2200219820Sjeff cm_process_work(cm_id_priv, work); 2201219820Sjeff else 2202219820Sjeff cm_deref_id(cm_id_priv); 2203219820Sjeff return 0; 2204219820Sjeff 2205219820Sjeffunlock: spin_unlock_irq(&cm_id_priv->lock); 2206219820Sjeffderef: cm_deref_id(cm_id_priv); 2207219820Sjeff return -EINVAL; 2208219820Sjeff} 2209219820Sjeff 2210219820Sjeffstatic int cm_drep_handler(struct cm_work *work) 2211219820Sjeff{ 2212219820Sjeff struct cm_id_private *cm_id_priv; 2213219820Sjeff struct cm_drep_msg *drep_msg; 2214219820Sjeff int ret; 2215219820Sjeff 2216219820Sjeff drep_msg = (struct cm_drep_msg *)work->mad_recv_wc->recv_buf.mad; 2217219820Sjeff cm_id_priv = cm_acquire_id(drep_msg->remote_comm_id, 2218219820Sjeff drep_msg->local_comm_id); 2219219820Sjeff if (!cm_id_priv) 2220219820Sjeff return -EINVAL; 2221219820Sjeff 2222219820Sjeff work->cm_event.private_data = &drep_msg->private_data; 2223219820Sjeff 2224219820Sjeff spin_lock_irq(&cm_id_priv->lock); 2225219820Sjeff if (cm_id_priv->id.state != IB_CM_DREQ_SENT && 2226219820Sjeff cm_id_priv->id.state != IB_CM_DREQ_RCVD) { 2227219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 2228219820Sjeff goto out; 2229219820Sjeff } 2230219820Sjeff cm_enter_timewait(cm_id_priv); 2231219820Sjeff 2232219820Sjeff ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); 2233219820Sjeff ret = atomic_inc_and_test(&cm_id_priv->work_count); 2234219820Sjeff if (!ret) 2235219820Sjeff list_add_tail(&work->list, &cm_id_priv->work_list); 2236219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 2237219820Sjeff 2238219820Sjeff if (ret) 2239219820Sjeff cm_process_work(cm_id_priv, work); 2240219820Sjeff else 2241219820Sjeff cm_deref_id(cm_id_priv); 2242219820Sjeff return 0; 2243219820Sjeffout: 2244219820Sjeff cm_deref_id(cm_id_priv); 2245219820Sjeff return -EINVAL; 2246219820Sjeff} 2247219820Sjeff 2248219820Sjeffint ib_send_cm_rej(struct ib_cm_id *cm_id, 2249219820Sjeff enum ib_cm_rej_reason reason, 2250219820Sjeff void *ari, 2251219820Sjeff u8 ari_length, 2252219820Sjeff const void *private_data, 2253219820Sjeff u8 private_data_len) 2254219820Sjeff{ 2255219820Sjeff struct cm_id_private *cm_id_priv; 2256219820Sjeff struct ib_mad_send_buf *msg; 2257219820Sjeff unsigned long flags; 2258219820Sjeff int ret; 2259219820Sjeff 2260219820Sjeff if ((private_data && private_data_len > IB_CM_REJ_PRIVATE_DATA_SIZE) || 2261219820Sjeff (ari && ari_length > IB_CM_REJ_ARI_LENGTH)) 2262219820Sjeff return -EINVAL; 2263219820Sjeff 2264219820Sjeff cm_id_priv = container_of(cm_id, struct cm_id_private, id); 2265219820Sjeff 2266219820Sjeff spin_lock_irqsave(&cm_id_priv->lock, flags); 2267219820Sjeff switch (cm_id->state) { 2268219820Sjeff case IB_CM_REQ_SENT: 2269219820Sjeff case IB_CM_MRA_REQ_RCVD: 2270219820Sjeff case IB_CM_REQ_RCVD: 2271219820Sjeff case IB_CM_MRA_REQ_SENT: 2272219820Sjeff case IB_CM_REP_RCVD: 2273219820Sjeff case IB_CM_MRA_REP_SENT: 2274219820Sjeff ret = cm_alloc_msg(cm_id_priv, &msg); 2275219820Sjeff if (!ret) 2276219820Sjeff cm_format_rej((struct cm_rej_msg *) msg->mad, 2277219820Sjeff cm_id_priv, reason, ari, ari_length, 2278219820Sjeff private_data, private_data_len); 2279219820Sjeff 2280219820Sjeff cm_reset_to_idle(cm_id_priv); 2281219820Sjeff break; 2282219820Sjeff case IB_CM_REP_SENT: 2283219820Sjeff case IB_CM_MRA_REP_RCVD: 2284219820Sjeff ret = cm_alloc_msg(cm_id_priv, &msg); 2285219820Sjeff if (!ret) 2286219820Sjeff cm_format_rej((struct cm_rej_msg *) msg->mad, 2287219820Sjeff cm_id_priv, reason, ari, ari_length, 2288219820Sjeff private_data, private_data_len); 2289219820Sjeff 2290219820Sjeff cm_enter_timewait(cm_id_priv); 2291219820Sjeff break; 2292219820Sjeff default: 2293219820Sjeff ret = -EINVAL; 2294219820Sjeff goto out; 2295219820Sjeff } 2296219820Sjeff 2297219820Sjeff if (ret) 2298219820Sjeff goto out; 2299219820Sjeff 2300219820Sjeff ret = ib_post_send_mad(msg, NULL); 2301219820Sjeff if (ret) 2302219820Sjeff cm_free_msg(msg); 2303219820Sjeff 2304219820Sjeffout: spin_unlock_irqrestore(&cm_id_priv->lock, flags); 2305219820Sjeff return ret; 2306219820Sjeff} 2307219820SjeffEXPORT_SYMBOL(ib_send_cm_rej); 2308219820Sjeff 2309219820Sjeffstatic void cm_format_rej_event(struct cm_work *work) 2310219820Sjeff{ 2311219820Sjeff struct cm_rej_msg *rej_msg; 2312219820Sjeff struct ib_cm_rej_event_param *param; 2313219820Sjeff 2314219820Sjeff rej_msg = (struct cm_rej_msg *)work->mad_recv_wc->recv_buf.mad; 2315219820Sjeff param = &work->cm_event.param.rej_rcvd; 2316219820Sjeff param->ari = rej_msg->ari; 2317219820Sjeff param->ari_length = cm_rej_get_reject_info_len(rej_msg); 2318219820Sjeff param->reason = __be16_to_cpu(rej_msg->reason); 2319219820Sjeff work->cm_event.private_data = &rej_msg->private_data; 2320219820Sjeff} 2321219820Sjeff 2322219820Sjeffstatic struct cm_id_private * cm_acquire_rejected_id(struct cm_rej_msg *rej_msg) 2323219820Sjeff{ 2324219820Sjeff struct cm_timewait_info *timewait_info; 2325219820Sjeff struct cm_id_private *cm_id_priv; 2326219820Sjeff __be32 remote_id; 2327219820Sjeff 2328219820Sjeff remote_id = rej_msg->local_comm_id; 2329219820Sjeff 2330219820Sjeff if (__be16_to_cpu(rej_msg->reason) == IB_CM_REJ_TIMEOUT) { 2331219820Sjeff spin_lock_irq(&cm.lock); 2332219820Sjeff timewait_info = cm_find_remote_id( *((__be64 *) rej_msg->ari), 2333219820Sjeff remote_id); 2334219820Sjeff if (!timewait_info) { 2335219820Sjeff spin_unlock_irq(&cm.lock); 2336219820Sjeff return NULL; 2337219820Sjeff } 2338219820Sjeff cm_id_priv = idr_find(&cm.local_id_table, (__force int) 2339219820Sjeff (timewait_info->work.local_id ^ 2340219820Sjeff cm.random_id_operand)); 2341219820Sjeff if (cm_id_priv) { 2342219820Sjeff if (cm_id_priv->id.remote_id == remote_id) 2343219820Sjeff atomic_inc(&cm_id_priv->refcount); 2344219820Sjeff else 2345219820Sjeff cm_id_priv = NULL; 2346219820Sjeff } 2347219820Sjeff spin_unlock_irq(&cm.lock); 2348219820Sjeff } else if (cm_rej_get_msg_rejected(rej_msg) == CM_MSG_RESPONSE_REQ) 2349219820Sjeff cm_id_priv = cm_acquire_id(rej_msg->remote_comm_id, 0); 2350219820Sjeff else 2351219820Sjeff cm_id_priv = cm_acquire_id(rej_msg->remote_comm_id, remote_id); 2352219820Sjeff 2353219820Sjeff return cm_id_priv; 2354219820Sjeff} 2355219820Sjeff 2356219820Sjeffstatic int cm_rej_handler(struct cm_work *work) 2357219820Sjeff{ 2358219820Sjeff struct cm_id_private *cm_id_priv; 2359219820Sjeff struct cm_rej_msg *rej_msg; 2360219820Sjeff int ret; 2361219820Sjeff 2362219820Sjeff rej_msg = (struct cm_rej_msg *)work->mad_recv_wc->recv_buf.mad; 2363219820Sjeff cm_id_priv = cm_acquire_rejected_id(rej_msg); 2364219820Sjeff if (!cm_id_priv) 2365219820Sjeff return -EINVAL; 2366219820Sjeff 2367219820Sjeff cm_format_rej_event(work); 2368219820Sjeff 2369219820Sjeff spin_lock_irq(&cm_id_priv->lock); 2370219820Sjeff switch (cm_id_priv->id.state) { 2371219820Sjeff case IB_CM_REQ_SENT: 2372219820Sjeff case IB_CM_MRA_REQ_RCVD: 2373219820Sjeff case IB_CM_REP_SENT: 2374219820Sjeff case IB_CM_MRA_REP_RCVD: 2375219820Sjeff ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); 2376219820Sjeff /* fall through */ 2377219820Sjeff case IB_CM_REQ_RCVD: 2378219820Sjeff case IB_CM_MRA_REQ_SENT: 2379219820Sjeff if (__be16_to_cpu(rej_msg->reason) == IB_CM_REJ_STALE_CONN) 2380219820Sjeff cm_enter_timewait(cm_id_priv); 2381219820Sjeff else 2382219820Sjeff cm_reset_to_idle(cm_id_priv); 2383219820Sjeff break; 2384219820Sjeff case IB_CM_DREQ_SENT: 2385219820Sjeff ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); 2386219820Sjeff /* fall through */ 2387219820Sjeff case IB_CM_REP_RCVD: 2388219820Sjeff case IB_CM_MRA_REP_SENT: 2389219820Sjeff case IB_CM_ESTABLISHED: 2390219820Sjeff cm_enter_timewait(cm_id_priv); 2391219820Sjeff break; 2392219820Sjeff default: 2393219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 2394219820Sjeff ret = -EINVAL; 2395219820Sjeff goto out; 2396219820Sjeff } 2397219820Sjeff 2398219820Sjeff ret = atomic_inc_and_test(&cm_id_priv->work_count); 2399219820Sjeff if (!ret) 2400219820Sjeff list_add_tail(&work->list, &cm_id_priv->work_list); 2401219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 2402219820Sjeff 2403219820Sjeff if (ret) 2404219820Sjeff cm_process_work(cm_id_priv, work); 2405219820Sjeff else 2406219820Sjeff cm_deref_id(cm_id_priv); 2407219820Sjeff return 0; 2408219820Sjeffout: 2409219820Sjeff cm_deref_id(cm_id_priv); 2410219820Sjeff return -EINVAL; 2411219820Sjeff} 2412219820Sjeff 2413219820Sjeffint ib_send_cm_mra(struct ib_cm_id *cm_id, 2414219820Sjeff u8 service_timeout, 2415219820Sjeff const void *private_data, 2416219820Sjeff u8 private_data_len) 2417219820Sjeff{ 2418219820Sjeff struct cm_id_private *cm_id_priv; 2419219820Sjeff struct ib_mad_send_buf *msg; 2420219820Sjeff enum ib_cm_state cm_state; 2421219820Sjeff enum ib_cm_lap_state lap_state; 2422219820Sjeff enum cm_msg_response msg_response; 2423219820Sjeff void *data; 2424219820Sjeff unsigned long flags; 2425219820Sjeff int ret; 2426219820Sjeff 2427219820Sjeff if (private_data && private_data_len > IB_CM_MRA_PRIVATE_DATA_SIZE) 2428219820Sjeff return -EINVAL; 2429219820Sjeff 2430219820Sjeff data = cm_copy_private_data(private_data, private_data_len); 2431219820Sjeff if (IS_ERR(data)) 2432219820Sjeff return PTR_ERR(data); 2433219820Sjeff 2434219820Sjeff cm_id_priv = container_of(cm_id, struct cm_id_private, id); 2435219820Sjeff 2436219820Sjeff spin_lock_irqsave(&cm_id_priv->lock, flags); 2437219820Sjeff switch(cm_id_priv->id.state) { 2438219820Sjeff case IB_CM_REQ_RCVD: 2439219820Sjeff cm_state = IB_CM_MRA_REQ_SENT; 2440219820Sjeff lap_state = cm_id->lap_state; 2441219820Sjeff msg_response = CM_MSG_RESPONSE_REQ; 2442219820Sjeff break; 2443219820Sjeff case IB_CM_REP_RCVD: 2444219820Sjeff cm_state = IB_CM_MRA_REP_SENT; 2445219820Sjeff lap_state = cm_id->lap_state; 2446219820Sjeff msg_response = CM_MSG_RESPONSE_REP; 2447219820Sjeff break; 2448219820Sjeff case IB_CM_ESTABLISHED: 2449219820Sjeff if (cm_id->lap_state == IB_CM_LAP_RCVD) { 2450219820Sjeff cm_state = cm_id->state; 2451219820Sjeff lap_state = IB_CM_MRA_LAP_SENT; 2452219820Sjeff msg_response = CM_MSG_RESPONSE_OTHER; 2453219820Sjeff break; 2454219820Sjeff } 2455219820Sjeff default: 2456219820Sjeff ret = -EINVAL; 2457219820Sjeff goto error1; 2458219820Sjeff } 2459219820Sjeff 2460219820Sjeff if (!(service_timeout & IB_CM_MRA_FLAG_DELAY)) { 2461219820Sjeff ret = cm_alloc_msg(cm_id_priv, &msg); 2462219820Sjeff if (ret) 2463219820Sjeff goto error1; 2464219820Sjeff 2465219820Sjeff cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, 2466219820Sjeff msg_response, service_timeout, 2467219820Sjeff private_data, private_data_len); 2468219820Sjeff ret = ib_post_send_mad(msg, NULL); 2469219820Sjeff if (ret) 2470219820Sjeff goto error2; 2471219820Sjeff } 2472219820Sjeff 2473219820Sjeff cm_id->state = cm_state; 2474219820Sjeff cm_id->lap_state = lap_state; 2475219820Sjeff cm_id_priv->service_timeout = service_timeout; 2476219820Sjeff cm_set_private_data(cm_id_priv, data, private_data_len); 2477219820Sjeff spin_unlock_irqrestore(&cm_id_priv->lock, flags); 2478219820Sjeff return 0; 2479219820Sjeff 2480219820Sjefferror1: spin_unlock_irqrestore(&cm_id_priv->lock, flags); 2481219820Sjeff kfree(data); 2482219820Sjeff return ret; 2483219820Sjeff 2484219820Sjefferror2: spin_unlock_irqrestore(&cm_id_priv->lock, flags); 2485219820Sjeff kfree(data); 2486219820Sjeff cm_free_msg(msg); 2487219820Sjeff return ret; 2488219820Sjeff} 2489219820SjeffEXPORT_SYMBOL(ib_send_cm_mra); 2490219820Sjeff 2491219820Sjeffstatic struct cm_id_private * cm_acquire_mraed_id(struct cm_mra_msg *mra_msg) 2492219820Sjeff{ 2493219820Sjeff switch (cm_mra_get_msg_mraed(mra_msg)) { 2494219820Sjeff case CM_MSG_RESPONSE_REQ: 2495219820Sjeff return cm_acquire_id(mra_msg->remote_comm_id, 0); 2496219820Sjeff case CM_MSG_RESPONSE_REP: 2497219820Sjeff case CM_MSG_RESPONSE_OTHER: 2498219820Sjeff return cm_acquire_id(mra_msg->remote_comm_id, 2499219820Sjeff mra_msg->local_comm_id); 2500219820Sjeff default: 2501219820Sjeff return NULL; 2502219820Sjeff } 2503219820Sjeff} 2504219820Sjeff 2505219820Sjeffstatic int cm_mra_handler(struct cm_work *work) 2506219820Sjeff{ 2507219820Sjeff struct cm_id_private *cm_id_priv; 2508219820Sjeff struct cm_mra_msg *mra_msg; 2509219820Sjeff int timeout, ret; 2510219820Sjeff 2511219820Sjeff mra_msg = (struct cm_mra_msg *)work->mad_recv_wc->recv_buf.mad; 2512219820Sjeff cm_id_priv = cm_acquire_mraed_id(mra_msg); 2513219820Sjeff if (!cm_id_priv) 2514219820Sjeff return -EINVAL; 2515219820Sjeff 2516219820Sjeff work->cm_event.private_data = &mra_msg->private_data; 2517219820Sjeff work->cm_event.param.mra_rcvd.service_timeout = 2518219820Sjeff cm_mra_get_service_timeout(mra_msg); 2519219820Sjeff timeout = cm_convert_to_ms(cm_mra_get_service_timeout(mra_msg)) + 2520219820Sjeff cm_convert_to_ms(cm_id_priv->av.timeout); 2521219820Sjeff if (timeout > cm_convert_to_ms(max_timeout)) { 2522219820Sjeff printk(KERN_WARNING PFX "calculated mra timeout %d > %d, " 2523219820Sjeff "decreasing used timeout_ms\n", timeout, 2524219820Sjeff cm_convert_to_ms(max_timeout)); 2525219820Sjeff timeout = cm_convert_to_ms(max_timeout); 2526219820Sjeff } 2527219820Sjeff 2528219820Sjeff spin_lock_irq(&cm_id_priv->lock); 2529219820Sjeff switch (cm_id_priv->id.state) { 2530219820Sjeff case IB_CM_REQ_SENT: 2531219820Sjeff if (cm_mra_get_msg_mraed(mra_msg) != CM_MSG_RESPONSE_REQ || 2532219820Sjeff ib_modify_mad(cm_id_priv->av.port->mad_agent, 2533219820Sjeff cm_id_priv->msg, timeout)) 2534219820Sjeff goto out; 2535219820Sjeff cm_id_priv->id.state = IB_CM_MRA_REQ_RCVD; 2536219820Sjeff break; 2537219820Sjeff case IB_CM_REP_SENT: 2538219820Sjeff if (cm_mra_get_msg_mraed(mra_msg) != CM_MSG_RESPONSE_REP || 2539219820Sjeff ib_modify_mad(cm_id_priv->av.port->mad_agent, 2540219820Sjeff cm_id_priv->msg, timeout)) 2541219820Sjeff goto out; 2542219820Sjeff cm_id_priv->id.state = IB_CM_MRA_REP_RCVD; 2543219820Sjeff break; 2544219820Sjeff case IB_CM_ESTABLISHED: 2545219820Sjeff if (cm_mra_get_msg_mraed(mra_msg) != CM_MSG_RESPONSE_OTHER || 2546219820Sjeff cm_id_priv->id.lap_state != IB_CM_LAP_SENT || 2547219820Sjeff ib_modify_mad(cm_id_priv->av.port->mad_agent, 2548219820Sjeff cm_id_priv->msg, timeout)) { 2549219820Sjeff if (cm_id_priv->id.lap_state == IB_CM_MRA_LAP_RCVD) 2550219820Sjeff atomic_long_inc(&work->port-> 2551219820Sjeff counter_group[CM_RECV_DUPLICATES]. 2552219820Sjeff counter[CM_MRA_COUNTER]); 2553219820Sjeff goto out; 2554219820Sjeff } 2555219820Sjeff cm_id_priv->id.lap_state = IB_CM_MRA_LAP_RCVD; 2556219820Sjeff break; 2557219820Sjeff case IB_CM_MRA_REQ_RCVD: 2558219820Sjeff case IB_CM_MRA_REP_RCVD: 2559219820Sjeff atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. 2560219820Sjeff counter[CM_MRA_COUNTER]); 2561219820Sjeff /* fall through */ 2562219820Sjeff default: 2563219820Sjeff goto out; 2564219820Sjeff } 2565219820Sjeff 2566219820Sjeff cm_id_priv->msg->context[1] = (void *) (unsigned long) 2567219820Sjeff cm_id_priv->id.state; 2568219820Sjeff ret = atomic_inc_and_test(&cm_id_priv->work_count); 2569219820Sjeff if (!ret) 2570219820Sjeff list_add_tail(&work->list, &cm_id_priv->work_list); 2571219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 2572219820Sjeff 2573219820Sjeff if (ret) 2574219820Sjeff cm_process_work(cm_id_priv, work); 2575219820Sjeff else 2576219820Sjeff cm_deref_id(cm_id_priv); 2577219820Sjeff return 0; 2578219820Sjeffout: 2579219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 2580219820Sjeff cm_deref_id(cm_id_priv); 2581219820Sjeff return -EINVAL; 2582219820Sjeff} 2583219820Sjeff 2584219820Sjeffstatic void cm_format_lap(struct cm_lap_msg *lap_msg, 2585219820Sjeff struct cm_id_private *cm_id_priv, 2586219820Sjeff struct ib_sa_path_rec *alternate_path, 2587219820Sjeff const void *private_data, 2588219820Sjeff u8 private_data_len) 2589219820Sjeff{ 2590219820Sjeff cm_format_mad_hdr(&lap_msg->hdr, CM_LAP_ATTR_ID, 2591219820Sjeff cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_LAP)); 2592219820Sjeff lap_msg->local_comm_id = cm_id_priv->id.local_id; 2593219820Sjeff lap_msg->remote_comm_id = cm_id_priv->id.remote_id; 2594219820Sjeff cm_lap_set_remote_qpn(lap_msg, cm_id_priv->remote_qpn); 2595219820Sjeff /* todo: need remote CM response timeout */ 2596219820Sjeff cm_lap_set_remote_resp_timeout(lap_msg, 0x1F); 2597219820Sjeff lap_msg->alt_local_lid = alternate_path->slid; 2598219820Sjeff lap_msg->alt_remote_lid = alternate_path->dlid; 2599219820Sjeff lap_msg->alt_local_gid = alternate_path->sgid; 2600219820Sjeff lap_msg->alt_remote_gid = alternate_path->dgid; 2601219820Sjeff cm_lap_set_flow_label(lap_msg, alternate_path->flow_label); 2602219820Sjeff cm_lap_set_traffic_class(lap_msg, alternate_path->traffic_class); 2603219820Sjeff lap_msg->alt_hop_limit = alternate_path->hop_limit; 2604219820Sjeff cm_lap_set_packet_rate(lap_msg, alternate_path->rate); 2605219820Sjeff cm_lap_set_sl(lap_msg, alternate_path->sl); 2606219820Sjeff cm_lap_set_subnet_local(lap_msg, 1); /* local only... */ 2607219820Sjeff cm_lap_set_local_ack_timeout(lap_msg, 2608219820Sjeff cm_ack_timeout(cm_id_priv->av.port->cm_dev->ack_delay, 2609219820Sjeff alternate_path->packet_life_time)); 2610219820Sjeff 2611219820Sjeff if (private_data && private_data_len) 2612219820Sjeff memcpy(lap_msg->private_data, private_data, private_data_len); 2613219820Sjeff} 2614219820Sjeff 2615219820Sjeffint ib_send_cm_lap(struct ib_cm_id *cm_id, 2616219820Sjeff struct ib_sa_path_rec *alternate_path, 2617219820Sjeff const void *private_data, 2618219820Sjeff u8 private_data_len) 2619219820Sjeff{ 2620219820Sjeff struct cm_id_private *cm_id_priv; 2621219820Sjeff struct ib_mad_send_buf *msg; 2622219820Sjeff unsigned long flags; 2623219820Sjeff int ret; 2624219820Sjeff 2625219820Sjeff if (private_data && private_data_len > IB_CM_LAP_PRIVATE_DATA_SIZE) 2626219820Sjeff return -EINVAL; 2627219820Sjeff 2628219820Sjeff cm_id_priv = container_of(cm_id, struct cm_id_private, id); 2629219820Sjeff spin_lock_irqsave(&cm_id_priv->lock, flags); 2630219820Sjeff if (cm_id->state != IB_CM_ESTABLISHED || 2631219820Sjeff (cm_id->lap_state != IB_CM_LAP_UNINIT && 2632219820Sjeff cm_id->lap_state != IB_CM_LAP_IDLE)) { 2633219820Sjeff ret = -EINVAL; 2634219820Sjeff goto out; 2635219820Sjeff } 2636219820Sjeff 2637219820Sjeff ret = cm_init_av_by_path(alternate_path, &cm_id_priv->alt_av); 2638219820Sjeff if (ret) 2639219820Sjeff goto out; 2640219820Sjeff cm_id_priv->alt_av.timeout = 2641219820Sjeff cm_ack_timeout(cm_id_priv->target_ack_delay, 2642219820Sjeff cm_id_priv->alt_av.timeout - 1); 2643219820Sjeff 2644219820Sjeff ret = cm_alloc_msg(cm_id_priv, &msg); 2645219820Sjeff if (ret) 2646219820Sjeff goto out; 2647219820Sjeff 2648219820Sjeff cm_format_lap((struct cm_lap_msg *) msg->mad, cm_id_priv, 2649219820Sjeff alternate_path, private_data, private_data_len); 2650219820Sjeff msg->timeout_ms = cm_id_priv->timeout_ms; 2651219820Sjeff msg->context[1] = (void *) (unsigned long) IB_CM_ESTABLISHED; 2652219820Sjeff 2653219820Sjeff ret = ib_post_send_mad(msg, NULL); 2654219820Sjeff if (ret) { 2655219820Sjeff spin_unlock_irqrestore(&cm_id_priv->lock, flags); 2656219820Sjeff cm_free_msg(msg); 2657219820Sjeff return ret; 2658219820Sjeff } 2659219820Sjeff 2660219820Sjeff cm_id->lap_state = IB_CM_LAP_SENT; 2661219820Sjeff cm_id_priv->msg = msg; 2662219820Sjeff 2663219820Sjeffout: spin_unlock_irqrestore(&cm_id_priv->lock, flags); 2664219820Sjeff return ret; 2665219820Sjeff} 2666219820SjeffEXPORT_SYMBOL(ib_send_cm_lap); 2667219820Sjeff 2668219820Sjeffstatic void cm_format_path_from_lap(struct cm_id_private *cm_id_priv, 2669219820Sjeff struct ib_sa_path_rec *path, 2670219820Sjeff struct cm_lap_msg *lap_msg) 2671219820Sjeff{ 2672219820Sjeff memset(path, 0, sizeof *path); 2673219820Sjeff path->dgid = lap_msg->alt_local_gid; 2674219820Sjeff path->sgid = lap_msg->alt_remote_gid; 2675219820Sjeff path->dlid = lap_msg->alt_local_lid; 2676219820Sjeff path->slid = lap_msg->alt_remote_lid; 2677219820Sjeff path->flow_label = cm_lap_get_flow_label(lap_msg); 2678219820Sjeff path->hop_limit = lap_msg->alt_hop_limit; 2679219820Sjeff path->traffic_class = cm_lap_get_traffic_class(lap_msg); 2680219820Sjeff path->reversible = 1; 2681219820Sjeff path->pkey = cm_id_priv->pkey; 2682219820Sjeff path->sl = cm_lap_get_sl(lap_msg); 2683219820Sjeff path->mtu_selector = IB_SA_EQ; 2684219820Sjeff path->mtu = cm_id_priv->path_mtu; 2685219820Sjeff path->rate_selector = IB_SA_EQ; 2686219820Sjeff path->rate = cm_lap_get_packet_rate(lap_msg); 2687219820Sjeff path->packet_life_time_selector = IB_SA_EQ; 2688219820Sjeff path->packet_life_time = cm_lap_get_local_ack_timeout(lap_msg); 2689219820Sjeff path->packet_life_time -= (path->packet_life_time > 0); 2690219820Sjeff} 2691219820Sjeff 2692219820Sjeffstatic int cm_lap_handler(struct cm_work *work) 2693219820Sjeff{ 2694219820Sjeff struct cm_id_private *cm_id_priv; 2695219820Sjeff struct cm_lap_msg *lap_msg; 2696219820Sjeff struct ib_cm_lap_event_param *param; 2697219820Sjeff struct ib_mad_send_buf *msg = NULL; 2698219820Sjeff int ret; 2699219820Sjeff 2700219820Sjeff /* todo: verify LAP request and send reject APR if invalid. */ 2701219820Sjeff lap_msg = (struct cm_lap_msg *)work->mad_recv_wc->recv_buf.mad; 2702219820Sjeff cm_id_priv = cm_acquire_id(lap_msg->remote_comm_id, 2703219820Sjeff lap_msg->local_comm_id); 2704219820Sjeff if (!cm_id_priv) 2705219820Sjeff return -EINVAL; 2706219820Sjeff 2707219820Sjeff param = &work->cm_event.param.lap_rcvd; 2708219820Sjeff param->alternate_path = &work->path[0]; 2709219820Sjeff cm_format_path_from_lap(cm_id_priv, param->alternate_path, lap_msg); 2710219820Sjeff work->cm_event.private_data = &lap_msg->private_data; 2711219820Sjeff 2712219820Sjeff spin_lock_irq(&cm_id_priv->lock); 2713219820Sjeff if (cm_id_priv->id.state != IB_CM_ESTABLISHED) 2714219820Sjeff goto unlock; 2715219820Sjeff 2716219820Sjeff switch (cm_id_priv->id.lap_state) { 2717219820Sjeff case IB_CM_LAP_UNINIT: 2718219820Sjeff case IB_CM_LAP_IDLE: 2719219820Sjeff break; 2720219820Sjeff case IB_CM_MRA_LAP_SENT: 2721219820Sjeff atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. 2722219820Sjeff counter[CM_LAP_COUNTER]); 2723219820Sjeff if (cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg)) 2724219820Sjeff goto unlock; 2725219820Sjeff 2726219820Sjeff cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, 2727219820Sjeff CM_MSG_RESPONSE_OTHER, 2728219820Sjeff cm_id_priv->service_timeout, 2729219820Sjeff cm_id_priv->private_data, 2730219820Sjeff cm_id_priv->private_data_len); 2731219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 2732219820Sjeff 2733219820Sjeff if (ib_post_send_mad(msg, NULL)) 2734219820Sjeff cm_free_msg(msg); 2735219820Sjeff goto deref; 2736219820Sjeff case IB_CM_LAP_RCVD: 2737219820Sjeff atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. 2738219820Sjeff counter[CM_LAP_COUNTER]); 2739219820Sjeff goto unlock; 2740219820Sjeff default: 2741219820Sjeff goto unlock; 2742219820Sjeff } 2743219820Sjeff 2744219820Sjeff cm_id_priv->id.lap_state = IB_CM_LAP_RCVD; 2745219820Sjeff cm_id_priv->tid = lap_msg->hdr.tid; 2746219820Sjeff cm_init_av_for_response(work->port, work->mad_recv_wc->wc, 2747219820Sjeff work->mad_recv_wc->recv_buf.grh, 2748219820Sjeff &cm_id_priv->av); 2749219820Sjeff cm_init_av_by_path(param->alternate_path, &cm_id_priv->alt_av); 2750219820Sjeff ret = atomic_inc_and_test(&cm_id_priv->work_count); 2751219820Sjeff if (!ret) 2752219820Sjeff list_add_tail(&work->list, &cm_id_priv->work_list); 2753219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 2754219820Sjeff 2755219820Sjeff if (ret) 2756219820Sjeff cm_process_work(cm_id_priv, work); 2757219820Sjeff else 2758219820Sjeff cm_deref_id(cm_id_priv); 2759219820Sjeff return 0; 2760219820Sjeff 2761219820Sjeffunlock: spin_unlock_irq(&cm_id_priv->lock); 2762219820Sjeffderef: cm_deref_id(cm_id_priv); 2763219820Sjeff return -EINVAL; 2764219820Sjeff} 2765219820Sjeff 2766219820Sjeffstatic void cm_format_apr(struct cm_apr_msg *apr_msg, 2767219820Sjeff struct cm_id_private *cm_id_priv, 2768219820Sjeff enum ib_cm_apr_status status, 2769219820Sjeff void *info, 2770219820Sjeff u8 info_length, 2771219820Sjeff const void *private_data, 2772219820Sjeff u8 private_data_len) 2773219820Sjeff{ 2774219820Sjeff cm_format_mad_hdr(&apr_msg->hdr, CM_APR_ATTR_ID, cm_id_priv->tid); 2775219820Sjeff apr_msg->local_comm_id = cm_id_priv->id.local_id; 2776219820Sjeff apr_msg->remote_comm_id = cm_id_priv->id.remote_id; 2777219820Sjeff apr_msg->ap_status = (u8) status; 2778219820Sjeff 2779219820Sjeff if (info && info_length) { 2780219820Sjeff apr_msg->info_length = info_length; 2781219820Sjeff memcpy(apr_msg->info, info, info_length); 2782219820Sjeff } 2783219820Sjeff 2784219820Sjeff if (private_data && private_data_len) 2785219820Sjeff memcpy(apr_msg->private_data, private_data, private_data_len); 2786219820Sjeff} 2787219820Sjeff 2788219820Sjeffint ib_send_cm_apr(struct ib_cm_id *cm_id, 2789219820Sjeff enum ib_cm_apr_status status, 2790219820Sjeff void *info, 2791219820Sjeff u8 info_length, 2792219820Sjeff const void *private_data, 2793219820Sjeff u8 private_data_len) 2794219820Sjeff{ 2795219820Sjeff struct cm_id_private *cm_id_priv; 2796219820Sjeff struct ib_mad_send_buf *msg; 2797219820Sjeff unsigned long flags; 2798219820Sjeff int ret; 2799219820Sjeff 2800219820Sjeff if ((private_data && private_data_len > IB_CM_APR_PRIVATE_DATA_SIZE) || 2801219820Sjeff (info && info_length > IB_CM_APR_INFO_LENGTH)) 2802219820Sjeff return -EINVAL; 2803219820Sjeff 2804219820Sjeff cm_id_priv = container_of(cm_id, struct cm_id_private, id); 2805219820Sjeff spin_lock_irqsave(&cm_id_priv->lock, flags); 2806219820Sjeff if (cm_id->state != IB_CM_ESTABLISHED || 2807219820Sjeff (cm_id->lap_state != IB_CM_LAP_RCVD && 2808219820Sjeff cm_id->lap_state != IB_CM_MRA_LAP_SENT)) { 2809219820Sjeff ret = -EINVAL; 2810219820Sjeff goto out; 2811219820Sjeff } 2812219820Sjeff 2813219820Sjeff ret = cm_alloc_msg(cm_id_priv, &msg); 2814219820Sjeff if (ret) 2815219820Sjeff goto out; 2816219820Sjeff 2817219820Sjeff cm_format_apr((struct cm_apr_msg *) msg->mad, cm_id_priv, status, 2818219820Sjeff info, info_length, private_data, private_data_len); 2819219820Sjeff ret = ib_post_send_mad(msg, NULL); 2820219820Sjeff if (ret) { 2821219820Sjeff spin_unlock_irqrestore(&cm_id_priv->lock, flags); 2822219820Sjeff cm_free_msg(msg); 2823219820Sjeff return ret; 2824219820Sjeff } 2825219820Sjeff 2826219820Sjeff cm_id->lap_state = IB_CM_LAP_IDLE; 2827219820Sjeffout: spin_unlock_irqrestore(&cm_id_priv->lock, flags); 2828219820Sjeff return ret; 2829219820Sjeff} 2830219820SjeffEXPORT_SYMBOL(ib_send_cm_apr); 2831219820Sjeff 2832219820Sjeffstatic int cm_apr_handler(struct cm_work *work) 2833219820Sjeff{ 2834219820Sjeff struct cm_id_private *cm_id_priv; 2835219820Sjeff struct cm_apr_msg *apr_msg; 2836219820Sjeff int ret; 2837219820Sjeff 2838219820Sjeff apr_msg = (struct cm_apr_msg *)work->mad_recv_wc->recv_buf.mad; 2839219820Sjeff cm_id_priv = cm_acquire_id(apr_msg->remote_comm_id, 2840219820Sjeff apr_msg->local_comm_id); 2841219820Sjeff if (!cm_id_priv) 2842219820Sjeff return -EINVAL; /* Unmatched reply. */ 2843219820Sjeff 2844219820Sjeff work->cm_event.param.apr_rcvd.ap_status = apr_msg->ap_status; 2845219820Sjeff work->cm_event.param.apr_rcvd.apr_info = &apr_msg->info; 2846219820Sjeff work->cm_event.param.apr_rcvd.info_len = apr_msg->info_length; 2847219820Sjeff work->cm_event.private_data = &apr_msg->private_data; 2848219820Sjeff 2849219820Sjeff spin_lock_irq(&cm_id_priv->lock); 2850219820Sjeff if (cm_id_priv->id.state != IB_CM_ESTABLISHED || 2851219820Sjeff (cm_id_priv->id.lap_state != IB_CM_LAP_SENT && 2852219820Sjeff cm_id_priv->id.lap_state != IB_CM_MRA_LAP_RCVD)) { 2853219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 2854219820Sjeff goto out; 2855219820Sjeff } 2856219820Sjeff cm_id_priv->id.lap_state = IB_CM_LAP_IDLE; 2857219820Sjeff ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); 2858219820Sjeff cm_id_priv->msg = NULL; 2859219820Sjeff 2860219820Sjeff ret = atomic_inc_and_test(&cm_id_priv->work_count); 2861219820Sjeff if (!ret) 2862219820Sjeff list_add_tail(&work->list, &cm_id_priv->work_list); 2863219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 2864219820Sjeff 2865219820Sjeff if (ret) 2866219820Sjeff cm_process_work(cm_id_priv, work); 2867219820Sjeff else 2868219820Sjeff cm_deref_id(cm_id_priv); 2869219820Sjeff return 0; 2870219820Sjeffout: 2871219820Sjeff cm_deref_id(cm_id_priv); 2872219820Sjeff return -EINVAL; 2873219820Sjeff} 2874219820Sjeff 2875219820Sjeffstatic int cm_timewait_handler(struct cm_work *work) 2876219820Sjeff{ 2877219820Sjeff struct cm_timewait_info *timewait_info; 2878219820Sjeff struct cm_id_private *cm_id_priv; 2879219820Sjeff int ret; 2880219820Sjeff 2881219820Sjeff timewait_info = (struct cm_timewait_info *)work; 2882219820Sjeff spin_lock_irq(&cm.lock); 2883219820Sjeff list_del(&timewait_info->list); 2884219820Sjeff spin_unlock_irq(&cm.lock); 2885219820Sjeff 2886219820Sjeff cm_id_priv = cm_acquire_id(timewait_info->work.local_id, 2887219820Sjeff timewait_info->work.remote_id); 2888219820Sjeff if (!cm_id_priv) 2889219820Sjeff return -EINVAL; 2890219820Sjeff 2891219820Sjeff spin_lock_irq(&cm_id_priv->lock); 2892219820Sjeff if (cm_id_priv->id.state != IB_CM_TIMEWAIT || 2893219820Sjeff cm_id_priv->remote_qpn != timewait_info->remote_qpn) { 2894219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 2895219820Sjeff goto out; 2896219820Sjeff } 2897219820Sjeff cm_id_priv->id.state = IB_CM_IDLE; 2898219820Sjeff ret = atomic_inc_and_test(&cm_id_priv->work_count); 2899219820Sjeff if (!ret) 2900219820Sjeff list_add_tail(&work->list, &cm_id_priv->work_list); 2901219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 2902219820Sjeff 2903219820Sjeff if (ret) 2904219820Sjeff cm_process_work(cm_id_priv, work); 2905219820Sjeff else 2906219820Sjeff cm_deref_id(cm_id_priv); 2907219820Sjeff return 0; 2908219820Sjeffout: 2909219820Sjeff cm_deref_id(cm_id_priv); 2910219820Sjeff return -EINVAL; 2911219820Sjeff} 2912219820Sjeff 2913219820Sjeffstatic void cm_format_sidr_req(struct cm_sidr_req_msg *sidr_req_msg, 2914219820Sjeff struct cm_id_private *cm_id_priv, 2915219820Sjeff struct ib_cm_sidr_req_param *param) 2916219820Sjeff{ 2917219820Sjeff cm_format_mad_hdr(&sidr_req_msg->hdr, CM_SIDR_REQ_ATTR_ID, 2918219820Sjeff cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_SIDR)); 2919219820Sjeff sidr_req_msg->request_id = cm_id_priv->id.local_id; 2920219820Sjeff sidr_req_msg->pkey = param->path->pkey; 2921219820Sjeff sidr_req_msg->service_id = param->service_id; 2922219820Sjeff 2923219820Sjeff if (param->private_data && param->private_data_len) 2924219820Sjeff memcpy(sidr_req_msg->private_data, param->private_data, 2925219820Sjeff param->private_data_len); 2926219820Sjeff} 2927219820Sjeff 2928219820Sjeffint ib_send_cm_sidr_req(struct ib_cm_id *cm_id, 2929219820Sjeff struct ib_cm_sidr_req_param *param) 2930219820Sjeff{ 2931219820Sjeff struct cm_id_private *cm_id_priv; 2932219820Sjeff struct ib_mad_send_buf *msg; 2933219820Sjeff unsigned long flags; 2934219820Sjeff int ret; 2935219820Sjeff 2936219820Sjeff if (!param->path || (param->private_data && 2937219820Sjeff param->private_data_len > IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE)) 2938219820Sjeff return -EINVAL; 2939219820Sjeff 2940219820Sjeff cm_id_priv = container_of(cm_id, struct cm_id_private, id); 2941219820Sjeff ret = cm_init_av_by_path(param->path, &cm_id_priv->av); 2942219820Sjeff if (ret) 2943219820Sjeff goto out; 2944219820Sjeff 2945219820Sjeff cm_id->service_id = param->service_id; 2946219820Sjeff cm_id->service_mask = ~cpu_to_be64(0); 2947219820Sjeff cm_id_priv->timeout_ms = param->timeout_ms; 2948219820Sjeff if (cm_id_priv->timeout_ms > cm_convert_to_ms(max_timeout)) { 2949219820Sjeff printk(KERN_WARNING PFX "sidr req timeout_ms %d > %d, " 2950219820Sjeff "decreasing used timeout_ms\n", param->timeout_ms, 2951219820Sjeff cm_convert_to_ms(max_timeout)); 2952219820Sjeff cm_id_priv->timeout_ms = cm_convert_to_ms(max_timeout); 2953219820Sjeff } 2954219820Sjeff cm_id_priv->max_cm_retries = param->max_cm_retries; 2955219820Sjeff ret = cm_alloc_msg(cm_id_priv, &msg); 2956219820Sjeff if (ret) 2957219820Sjeff goto out; 2958219820Sjeff 2959219820Sjeff cm_format_sidr_req((struct cm_sidr_req_msg *) msg->mad, cm_id_priv, 2960219820Sjeff param); 2961219820Sjeff msg->timeout_ms = cm_id_priv->timeout_ms; 2962219820Sjeff msg->context[1] = (void *) (unsigned long) IB_CM_SIDR_REQ_SENT; 2963219820Sjeff 2964219820Sjeff spin_lock_irqsave(&cm_id_priv->lock, flags); 2965219820Sjeff if (cm_id->state == IB_CM_IDLE) 2966219820Sjeff ret = ib_post_send_mad(msg, NULL); 2967219820Sjeff else 2968219820Sjeff ret = -EINVAL; 2969219820Sjeff 2970219820Sjeff if (ret) { 2971219820Sjeff spin_unlock_irqrestore(&cm_id_priv->lock, flags); 2972219820Sjeff cm_free_msg(msg); 2973219820Sjeff goto out; 2974219820Sjeff } 2975219820Sjeff cm_id->state = IB_CM_SIDR_REQ_SENT; 2976219820Sjeff cm_id_priv->msg = msg; 2977219820Sjeff spin_unlock_irqrestore(&cm_id_priv->lock, flags); 2978219820Sjeffout: 2979219820Sjeff return ret; 2980219820Sjeff} 2981219820SjeffEXPORT_SYMBOL(ib_send_cm_sidr_req); 2982219820Sjeff 2983219820Sjeffstatic void cm_format_sidr_req_event(struct cm_work *work, 2984219820Sjeff struct ib_cm_id *listen_id) 2985219820Sjeff{ 2986219820Sjeff struct cm_sidr_req_msg *sidr_req_msg; 2987219820Sjeff struct ib_cm_sidr_req_event_param *param; 2988219820Sjeff 2989219820Sjeff sidr_req_msg = (struct cm_sidr_req_msg *) 2990219820Sjeff work->mad_recv_wc->recv_buf.mad; 2991219820Sjeff param = &work->cm_event.param.sidr_req_rcvd; 2992219820Sjeff param->pkey = __be16_to_cpu(sidr_req_msg->pkey); 2993219820Sjeff param->listen_id = listen_id; 2994219820Sjeff param->port = work->port->port_num; 2995219820Sjeff work->cm_event.private_data = &sidr_req_msg->private_data; 2996219820Sjeff} 2997219820Sjeff 2998219820Sjeffstatic int cm_sidr_req_handler(struct cm_work *work) 2999219820Sjeff{ 3000219820Sjeff struct ib_cm_id *cm_id; 3001219820Sjeff struct cm_id_private *cm_id_priv, *cur_cm_id_priv; 3002219820Sjeff struct cm_sidr_req_msg *sidr_req_msg; 3003219820Sjeff struct ib_wc *wc; 3004219820Sjeff 3005219820Sjeff cm_id = ib_create_cm_id(work->port->cm_dev->ib_device, NULL, NULL); 3006219820Sjeff if (IS_ERR(cm_id)) 3007219820Sjeff return PTR_ERR(cm_id); 3008219820Sjeff cm_id_priv = container_of(cm_id, struct cm_id_private, id); 3009219820Sjeff 3010219820Sjeff /* Record SGID/SLID and request ID for lookup. */ 3011219820Sjeff sidr_req_msg = (struct cm_sidr_req_msg *) 3012219820Sjeff work->mad_recv_wc->recv_buf.mad; 3013219820Sjeff wc = work->mad_recv_wc->wc; 3014219820Sjeff cm_id_priv->av.dgid.global.subnet_prefix = cpu_to_be64(wc->slid); 3015219820Sjeff cm_id_priv->av.dgid.global.interface_id = 0; 3016219820Sjeff cm_init_av_for_response(work->port, work->mad_recv_wc->wc, 3017219820Sjeff work->mad_recv_wc->recv_buf.grh, 3018219820Sjeff &cm_id_priv->av); 3019219820Sjeff cm_id_priv->id.remote_id = sidr_req_msg->request_id; 3020219820Sjeff cm_id_priv->tid = sidr_req_msg->hdr.tid; 3021219820Sjeff atomic_inc(&cm_id_priv->work_count); 3022219820Sjeff 3023219820Sjeff spin_lock_irq(&cm.lock); 3024219820Sjeff cur_cm_id_priv = cm_insert_remote_sidr(cm_id_priv); 3025219820Sjeff if (cur_cm_id_priv) { 3026219820Sjeff spin_unlock_irq(&cm.lock); 3027219820Sjeff atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. 3028219820Sjeff counter[CM_SIDR_REQ_COUNTER]); 3029219820Sjeff goto out; /* Duplicate message. */ 3030219820Sjeff } 3031219820Sjeff cm_id_priv->id.state = IB_CM_SIDR_REQ_RCVD; 3032219820Sjeff cur_cm_id_priv = cm_find_listen(cm_id->device, 3033219820Sjeff sidr_req_msg->service_id, 3034219820Sjeff sidr_req_msg->private_data); 3035219820Sjeff if (!cur_cm_id_priv) { 3036219820Sjeff spin_unlock_irq(&cm.lock); 3037219820Sjeff cm_reject_sidr_req(cm_id_priv, IB_SIDR_UNSUPPORTED); 3038219820Sjeff goto out; /* No match. */ 3039219820Sjeff } 3040219820Sjeff atomic_inc(&cur_cm_id_priv->refcount); 3041219820Sjeff spin_unlock_irq(&cm.lock); 3042219820Sjeff 3043219820Sjeff cm_id_priv->id.cm_handler = cur_cm_id_priv->id.cm_handler; 3044219820Sjeff cm_id_priv->id.context = cur_cm_id_priv->id.context; 3045219820Sjeff cm_id_priv->id.service_id = sidr_req_msg->service_id; 3046219820Sjeff cm_id_priv->id.service_mask = ~cpu_to_be64(0); 3047219820Sjeff 3048219820Sjeff cm_format_sidr_req_event(work, &cur_cm_id_priv->id); 3049219820Sjeff cm_process_work(cm_id_priv, work); 3050219820Sjeff cm_deref_id(cur_cm_id_priv); 3051219820Sjeff return 0; 3052219820Sjeffout: 3053219820Sjeff ib_destroy_cm_id(&cm_id_priv->id); 3054219820Sjeff return -EINVAL; 3055219820Sjeff} 3056219820Sjeff 3057219820Sjeffstatic void cm_format_sidr_rep(struct cm_sidr_rep_msg *sidr_rep_msg, 3058219820Sjeff struct cm_id_private *cm_id_priv, 3059219820Sjeff struct ib_cm_sidr_rep_param *param) 3060219820Sjeff{ 3061219820Sjeff cm_format_mad_hdr(&sidr_rep_msg->hdr, CM_SIDR_REP_ATTR_ID, 3062219820Sjeff cm_id_priv->tid); 3063219820Sjeff sidr_rep_msg->request_id = cm_id_priv->id.remote_id; 3064219820Sjeff sidr_rep_msg->status = param->status; 3065219820Sjeff cm_sidr_rep_set_qpn(sidr_rep_msg, cpu_to_be32(param->qp_num)); 3066219820Sjeff sidr_rep_msg->service_id = cm_id_priv->id.service_id; 3067219820Sjeff sidr_rep_msg->qkey = cpu_to_be32(param->qkey); 3068219820Sjeff 3069219820Sjeff if (param->info && param->info_length) 3070219820Sjeff memcpy(sidr_rep_msg->info, param->info, param->info_length); 3071219820Sjeff 3072219820Sjeff if (param->private_data && param->private_data_len) 3073219820Sjeff memcpy(sidr_rep_msg->private_data, param->private_data, 3074219820Sjeff param->private_data_len); 3075219820Sjeff} 3076219820Sjeff 3077219820Sjeffint ib_send_cm_sidr_rep(struct ib_cm_id *cm_id, 3078219820Sjeff struct ib_cm_sidr_rep_param *param) 3079219820Sjeff{ 3080219820Sjeff struct cm_id_private *cm_id_priv; 3081219820Sjeff struct ib_mad_send_buf *msg; 3082219820Sjeff unsigned long flags; 3083219820Sjeff int ret; 3084219820Sjeff 3085219820Sjeff if ((param->info && param->info_length > IB_CM_SIDR_REP_INFO_LENGTH) || 3086219820Sjeff (param->private_data && 3087219820Sjeff param->private_data_len > IB_CM_SIDR_REP_PRIVATE_DATA_SIZE)) 3088219820Sjeff return -EINVAL; 3089219820Sjeff 3090219820Sjeff cm_id_priv = container_of(cm_id, struct cm_id_private, id); 3091219820Sjeff spin_lock_irqsave(&cm_id_priv->lock, flags); 3092219820Sjeff if (cm_id->state != IB_CM_SIDR_REQ_RCVD) { 3093219820Sjeff ret = -EINVAL; 3094219820Sjeff goto error; 3095219820Sjeff } 3096219820Sjeff 3097219820Sjeff ret = cm_alloc_msg(cm_id_priv, &msg); 3098219820Sjeff if (ret) 3099219820Sjeff goto error; 3100219820Sjeff 3101219820Sjeff cm_format_sidr_rep((struct cm_sidr_rep_msg *) msg->mad, cm_id_priv, 3102219820Sjeff param); 3103219820Sjeff ret = ib_post_send_mad(msg, NULL); 3104219820Sjeff if (ret) { 3105219820Sjeff spin_unlock_irqrestore(&cm_id_priv->lock, flags); 3106219820Sjeff cm_free_msg(msg); 3107219820Sjeff return ret; 3108219820Sjeff } 3109219820Sjeff cm_id->state = IB_CM_IDLE; 3110219820Sjeff spin_unlock_irqrestore(&cm_id_priv->lock, flags); 3111219820Sjeff 3112219820Sjeff spin_lock_irqsave(&cm.lock, flags); 3113219820Sjeff rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table); 3114219820Sjeff spin_unlock_irqrestore(&cm.lock, flags); 3115219820Sjeff return 0; 3116219820Sjeff 3117219820Sjefferror: spin_unlock_irqrestore(&cm_id_priv->lock, flags); 3118219820Sjeff return ret; 3119219820Sjeff} 3120219820SjeffEXPORT_SYMBOL(ib_send_cm_sidr_rep); 3121219820Sjeff 3122219820Sjeffstatic void cm_format_sidr_rep_event(struct cm_work *work) 3123219820Sjeff{ 3124219820Sjeff struct cm_sidr_rep_msg *sidr_rep_msg; 3125219820Sjeff struct ib_cm_sidr_rep_event_param *param; 3126219820Sjeff 3127219820Sjeff sidr_rep_msg = (struct cm_sidr_rep_msg *) 3128219820Sjeff work->mad_recv_wc->recv_buf.mad; 3129219820Sjeff param = &work->cm_event.param.sidr_rep_rcvd; 3130219820Sjeff param->status = sidr_rep_msg->status; 3131219820Sjeff param->qkey = be32_to_cpu(sidr_rep_msg->qkey); 3132219820Sjeff param->qpn = be32_to_cpu(cm_sidr_rep_get_qpn(sidr_rep_msg)); 3133219820Sjeff param->info = &sidr_rep_msg->info; 3134219820Sjeff param->info_len = sidr_rep_msg->info_length; 3135219820Sjeff work->cm_event.private_data = &sidr_rep_msg->private_data; 3136219820Sjeff} 3137219820Sjeff 3138219820Sjeffstatic int cm_sidr_rep_handler(struct cm_work *work) 3139219820Sjeff{ 3140219820Sjeff struct cm_sidr_rep_msg *sidr_rep_msg; 3141219820Sjeff struct cm_id_private *cm_id_priv; 3142219820Sjeff 3143219820Sjeff sidr_rep_msg = (struct cm_sidr_rep_msg *) 3144219820Sjeff work->mad_recv_wc->recv_buf.mad; 3145219820Sjeff cm_id_priv = cm_acquire_id(sidr_rep_msg->request_id, 0); 3146219820Sjeff if (!cm_id_priv) 3147219820Sjeff return -EINVAL; /* Unmatched reply. */ 3148219820Sjeff 3149219820Sjeff spin_lock_irq(&cm_id_priv->lock); 3150219820Sjeff if (cm_id_priv->id.state != IB_CM_SIDR_REQ_SENT) { 3151219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 3152219820Sjeff goto out; 3153219820Sjeff } 3154219820Sjeff cm_id_priv->id.state = IB_CM_IDLE; 3155219820Sjeff ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); 3156219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 3157219820Sjeff 3158219820Sjeff cm_format_sidr_rep_event(work); 3159219820Sjeff cm_process_work(cm_id_priv, work); 3160219820Sjeff return 0; 3161219820Sjeffout: 3162219820Sjeff cm_deref_id(cm_id_priv); 3163219820Sjeff return -EINVAL; 3164219820Sjeff} 3165219820Sjeff 3166219820Sjeffstatic void cm_process_send_error(struct ib_mad_send_buf *msg, 3167219820Sjeff enum ib_wc_status wc_status) 3168219820Sjeff{ 3169219820Sjeff struct cm_id_private *cm_id_priv; 3170219820Sjeff struct ib_cm_event cm_event; 3171219820Sjeff enum ib_cm_state state; 3172219820Sjeff int ret; 3173219820Sjeff 3174219820Sjeff memset(&cm_event, 0, sizeof cm_event); 3175219820Sjeff cm_id_priv = msg->context[0]; 3176219820Sjeff 3177219820Sjeff /* Discard old sends or ones without a response. */ 3178219820Sjeff spin_lock_irq(&cm_id_priv->lock); 3179219820Sjeff state = (enum ib_cm_state) (unsigned long) msg->context[1]; 3180219820Sjeff if (msg != cm_id_priv->msg || state != cm_id_priv->id.state) 3181219820Sjeff goto discard; 3182219820Sjeff 3183219820Sjeff switch (state) { 3184219820Sjeff case IB_CM_REQ_SENT: 3185219820Sjeff case IB_CM_MRA_REQ_RCVD: 3186219820Sjeff cm_reset_to_idle(cm_id_priv); 3187219820Sjeff cm_event.event = IB_CM_REQ_ERROR; 3188219820Sjeff break; 3189219820Sjeff case IB_CM_REP_SENT: 3190219820Sjeff case IB_CM_MRA_REP_RCVD: 3191219820Sjeff cm_reset_to_idle(cm_id_priv); 3192219820Sjeff cm_event.event = IB_CM_REP_ERROR; 3193219820Sjeff break; 3194219820Sjeff case IB_CM_DREQ_SENT: 3195219820Sjeff cm_enter_timewait(cm_id_priv); 3196219820Sjeff cm_event.event = IB_CM_DREQ_ERROR; 3197219820Sjeff break; 3198219820Sjeff case IB_CM_SIDR_REQ_SENT: 3199219820Sjeff cm_id_priv->id.state = IB_CM_IDLE; 3200219820Sjeff cm_event.event = IB_CM_SIDR_REQ_ERROR; 3201219820Sjeff break; 3202219820Sjeff default: 3203219820Sjeff goto discard; 3204219820Sjeff } 3205219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 3206219820Sjeff cm_event.param.send_status = wc_status; 3207219820Sjeff 3208219820Sjeff /* No other events can occur on the cm_id at this point. */ 3209219820Sjeff ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, &cm_event); 3210219820Sjeff cm_free_msg(msg); 3211219820Sjeff if (ret) 3212219820Sjeff ib_destroy_cm_id(&cm_id_priv->id); 3213219820Sjeff return; 3214219820Sjeffdiscard: 3215219820Sjeff spin_unlock_irq(&cm_id_priv->lock); 3216219820Sjeff cm_free_msg(msg); 3217219820Sjeff} 3218219820Sjeff 3219219820Sjeffstatic void cm_send_handler(struct ib_mad_agent *mad_agent, 3220219820Sjeff struct ib_mad_send_wc *mad_send_wc) 3221219820Sjeff{ 3222219820Sjeff struct ib_mad_send_buf *msg = mad_send_wc->send_buf; 3223219820Sjeff struct cm_port *port; 3224219820Sjeff u16 attr_index; 3225219820Sjeff 3226219820Sjeff port = mad_agent->context; 3227219820Sjeff attr_index = be16_to_cpu(((struct ib_mad_hdr *) 3228219820Sjeff msg->mad)->attr_id) - CM_ATTR_ID_OFFSET; 3229219820Sjeff 3230219820Sjeff /* 3231219820Sjeff * If the send was in response to a received message (context[0] is not 3232219820Sjeff * set to a cm_id), and is not a REJ, then it is a send that was 3233219820Sjeff * manually retried. 3234219820Sjeff */ 3235219820Sjeff if (!msg->context[0] && (attr_index != CM_REJ_COUNTER)) 3236219820Sjeff msg->retries = 1; 3237219820Sjeff 3238219820Sjeff atomic_long_add(1 + msg->retries, 3239219820Sjeff &port->counter_group[CM_XMIT].counter[attr_index]); 3240219820Sjeff if (msg->retries) 3241219820Sjeff atomic_long_add(msg->retries, 3242219820Sjeff &port->counter_group[CM_XMIT_RETRIES]. 3243219820Sjeff counter[attr_index]); 3244219820Sjeff 3245219820Sjeff switch (mad_send_wc->status) { 3246219820Sjeff case IB_WC_SUCCESS: 3247219820Sjeff case IB_WC_WR_FLUSH_ERR: 3248219820Sjeff cm_free_msg(msg); 3249219820Sjeff break; 3250219820Sjeff default: 3251219820Sjeff if (msg->context[0] && msg->context[1]) 3252219820Sjeff cm_process_send_error(msg, mad_send_wc->status); 3253219820Sjeff else 3254219820Sjeff cm_free_msg(msg); 3255219820Sjeff break; 3256219820Sjeff } 3257219820Sjeff} 3258219820Sjeff 3259219820Sjeffstatic void cm_work_handler(struct work_struct *_work) 3260219820Sjeff{ 3261219820Sjeff struct cm_work *work = container_of(_work, struct cm_work, work.work); 3262219820Sjeff int ret; 3263219820Sjeff 3264219820Sjeff switch (work->cm_event.event) { 3265219820Sjeff case IB_CM_REQ_RECEIVED: 3266219820Sjeff ret = cm_req_handler(work); 3267219820Sjeff break; 3268219820Sjeff case IB_CM_MRA_RECEIVED: 3269219820Sjeff ret = cm_mra_handler(work); 3270219820Sjeff break; 3271219820Sjeff case IB_CM_REJ_RECEIVED: 3272219820Sjeff ret = cm_rej_handler(work); 3273219820Sjeff break; 3274219820Sjeff case IB_CM_REP_RECEIVED: 3275219820Sjeff ret = cm_rep_handler(work); 3276219820Sjeff break; 3277219820Sjeff case IB_CM_RTU_RECEIVED: 3278219820Sjeff ret = cm_rtu_handler(work); 3279219820Sjeff break; 3280219820Sjeff case IB_CM_USER_ESTABLISHED: 3281219820Sjeff ret = cm_establish_handler(work); 3282219820Sjeff break; 3283219820Sjeff case IB_CM_DREQ_RECEIVED: 3284219820Sjeff ret = cm_dreq_handler(work); 3285219820Sjeff break; 3286219820Sjeff case IB_CM_DREP_RECEIVED: 3287219820Sjeff ret = cm_drep_handler(work); 3288219820Sjeff break; 3289219820Sjeff case IB_CM_SIDR_REQ_RECEIVED: 3290219820Sjeff ret = cm_sidr_req_handler(work); 3291219820Sjeff break; 3292219820Sjeff case IB_CM_SIDR_REP_RECEIVED: 3293219820Sjeff ret = cm_sidr_rep_handler(work); 3294219820Sjeff break; 3295219820Sjeff case IB_CM_LAP_RECEIVED: 3296219820Sjeff ret = cm_lap_handler(work); 3297219820Sjeff break; 3298219820Sjeff case IB_CM_APR_RECEIVED: 3299219820Sjeff ret = cm_apr_handler(work); 3300219820Sjeff break; 3301219820Sjeff case IB_CM_TIMEWAIT_EXIT: 3302219820Sjeff ret = cm_timewait_handler(work); 3303219820Sjeff break; 3304219820Sjeff default: 3305219820Sjeff ret = -EINVAL; 3306219820Sjeff break; 3307219820Sjeff } 3308219820Sjeff if (ret) 3309219820Sjeff cm_free_work(work); 3310219820Sjeff} 3311219820Sjeff 3312219820Sjeffstatic int cm_establish(struct ib_cm_id *cm_id) 3313219820Sjeff{ 3314219820Sjeff struct cm_id_private *cm_id_priv; 3315219820Sjeff struct cm_work *work; 3316219820Sjeff unsigned long flags; 3317219820Sjeff int ret = 0; 3318219820Sjeff 3319219820Sjeff work = kmalloc(sizeof *work, GFP_ATOMIC); 3320219820Sjeff if (!work) 3321219820Sjeff return -ENOMEM; 3322219820Sjeff 3323219820Sjeff cm_id_priv = container_of(cm_id, struct cm_id_private, id); 3324219820Sjeff spin_lock_irqsave(&cm_id_priv->lock, flags); 3325219820Sjeff switch (cm_id->state) 3326219820Sjeff { 3327219820Sjeff case IB_CM_REP_SENT: 3328219820Sjeff case IB_CM_MRA_REP_RCVD: 3329219820Sjeff cm_id->state = IB_CM_ESTABLISHED; 3330219820Sjeff break; 3331219820Sjeff case IB_CM_ESTABLISHED: 3332219820Sjeff ret = -EISCONN; 3333219820Sjeff break; 3334219820Sjeff default: 3335219820Sjeff ret = -EINVAL; 3336219820Sjeff break; 3337219820Sjeff } 3338219820Sjeff spin_unlock_irqrestore(&cm_id_priv->lock, flags); 3339219820Sjeff 3340219820Sjeff if (ret) { 3341219820Sjeff kfree(work); 3342219820Sjeff goto out; 3343219820Sjeff } 3344219820Sjeff 3345219820Sjeff /* 3346219820Sjeff * The CM worker thread may try to destroy the cm_id before it 3347219820Sjeff * can execute this work item. To prevent potential deadlock, 3348219820Sjeff * we need to find the cm_id once we're in the context of the 3349219820Sjeff * worker thread, rather than holding a reference on it. 3350219820Sjeff */ 3351219820Sjeff INIT_DELAYED_WORK(&work->work, cm_work_handler); 3352219820Sjeff work->local_id = cm_id->local_id; 3353219820Sjeff work->remote_id = cm_id->remote_id; 3354219820Sjeff work->mad_recv_wc = NULL; 3355219820Sjeff work->cm_event.event = IB_CM_USER_ESTABLISHED; 3356219820Sjeff queue_delayed_work(cm.wq, &work->work, 0); 3357219820Sjeffout: 3358219820Sjeff return ret; 3359219820Sjeff} 3360219820Sjeff 3361219820Sjeffstatic int cm_migrate(struct ib_cm_id *cm_id) 3362219820Sjeff{ 3363219820Sjeff struct cm_id_private *cm_id_priv; 3364219820Sjeff unsigned long flags; 3365219820Sjeff int ret = 0; 3366219820Sjeff 3367219820Sjeff cm_id_priv = container_of(cm_id, struct cm_id_private, id); 3368219820Sjeff spin_lock_irqsave(&cm_id_priv->lock, flags); 3369219820Sjeff if (cm_id->state == IB_CM_ESTABLISHED && 3370219820Sjeff (cm_id->lap_state == IB_CM_LAP_UNINIT || 3371219820Sjeff cm_id->lap_state == IB_CM_LAP_IDLE)) { 3372219820Sjeff cm_id->lap_state = IB_CM_LAP_IDLE; 3373219820Sjeff cm_id_priv->av = cm_id_priv->alt_av; 3374219820Sjeff } else 3375219820Sjeff ret = -EINVAL; 3376219820Sjeff spin_unlock_irqrestore(&cm_id_priv->lock, flags); 3377219820Sjeff 3378219820Sjeff return ret; 3379219820Sjeff} 3380219820Sjeff 3381219820Sjeffint ib_cm_notify(struct ib_cm_id *cm_id, enum ib_event_type event) 3382219820Sjeff{ 3383219820Sjeff int ret; 3384219820Sjeff 3385219820Sjeff switch (event) { 3386219820Sjeff case IB_EVENT_COMM_EST: 3387219820Sjeff ret = cm_establish(cm_id); 3388219820Sjeff break; 3389219820Sjeff case IB_EVENT_PATH_MIG: 3390219820Sjeff ret = cm_migrate(cm_id); 3391219820Sjeff break; 3392219820Sjeff default: 3393219820Sjeff ret = -EINVAL; 3394219820Sjeff } 3395219820Sjeff return ret; 3396219820Sjeff} 3397219820SjeffEXPORT_SYMBOL(ib_cm_notify); 3398219820Sjeff 3399219820Sjeffstatic void cm_recv_handler(struct ib_mad_agent *mad_agent, 3400219820Sjeff struct ib_mad_recv_wc *mad_recv_wc) 3401219820Sjeff{ 3402219820Sjeff struct cm_port *port = mad_agent->context; 3403219820Sjeff struct cm_work *work; 3404219820Sjeff enum ib_cm_event_type event; 3405219820Sjeff u16 attr_id; 3406219820Sjeff int paths = 0; 3407219820Sjeff 3408219820Sjeff switch (mad_recv_wc->recv_buf.mad->mad_hdr.attr_id) { 3409219820Sjeff case CM_REQ_ATTR_ID: 3410219820Sjeff paths = 1 + (((struct cm_req_msg *) mad_recv_wc->recv_buf.mad)-> 3411219820Sjeff alt_local_lid != 0); 3412219820Sjeff event = IB_CM_REQ_RECEIVED; 3413219820Sjeff break; 3414219820Sjeff case CM_MRA_ATTR_ID: 3415219820Sjeff event = IB_CM_MRA_RECEIVED; 3416219820Sjeff break; 3417219820Sjeff case CM_REJ_ATTR_ID: 3418219820Sjeff event = IB_CM_REJ_RECEIVED; 3419219820Sjeff break; 3420219820Sjeff case CM_REP_ATTR_ID: 3421219820Sjeff event = IB_CM_REP_RECEIVED; 3422219820Sjeff break; 3423219820Sjeff case CM_RTU_ATTR_ID: 3424219820Sjeff event = IB_CM_RTU_RECEIVED; 3425219820Sjeff break; 3426219820Sjeff case CM_DREQ_ATTR_ID: 3427219820Sjeff event = IB_CM_DREQ_RECEIVED; 3428219820Sjeff break; 3429219820Sjeff case CM_DREP_ATTR_ID: 3430219820Sjeff event = IB_CM_DREP_RECEIVED; 3431219820Sjeff break; 3432219820Sjeff case CM_SIDR_REQ_ATTR_ID: 3433219820Sjeff event = IB_CM_SIDR_REQ_RECEIVED; 3434219820Sjeff break; 3435219820Sjeff case CM_SIDR_REP_ATTR_ID: 3436219820Sjeff event = IB_CM_SIDR_REP_RECEIVED; 3437219820Sjeff break; 3438219820Sjeff case CM_LAP_ATTR_ID: 3439219820Sjeff paths = 1; 3440219820Sjeff event = IB_CM_LAP_RECEIVED; 3441219820Sjeff break; 3442219820Sjeff case CM_APR_ATTR_ID: 3443219820Sjeff event = IB_CM_APR_RECEIVED; 3444219820Sjeff break; 3445219820Sjeff default: 3446219820Sjeff ib_free_recv_mad(mad_recv_wc); 3447219820Sjeff return; 3448219820Sjeff } 3449219820Sjeff 3450219820Sjeff attr_id = be16_to_cpu(mad_recv_wc->recv_buf.mad->mad_hdr.attr_id); 3451219820Sjeff atomic_long_inc(&port->counter_group[CM_RECV]. 3452219820Sjeff counter[attr_id - CM_ATTR_ID_OFFSET]); 3453219820Sjeff 3454219820Sjeff work = kmalloc(sizeof *work + sizeof(struct ib_sa_path_rec) * paths, 3455219820Sjeff GFP_KERNEL); 3456219820Sjeff if (!work) { 3457219820Sjeff ib_free_recv_mad(mad_recv_wc); 3458219820Sjeff return; 3459219820Sjeff } 3460219820Sjeff 3461219820Sjeff INIT_DELAYED_WORK(&work->work, cm_work_handler); 3462219820Sjeff work->cm_event.event = event; 3463219820Sjeff work->mad_recv_wc = mad_recv_wc; 3464219820Sjeff work->port = port; 3465219820Sjeff queue_delayed_work(cm.wq, &work->work, 0); 3466219820Sjeff} 3467219820Sjeff 3468219820Sjeffstatic int cm_init_qp_init_attr(struct cm_id_private *cm_id_priv, 3469219820Sjeff struct ib_qp_attr *qp_attr, 3470219820Sjeff int *qp_attr_mask) 3471219820Sjeff{ 3472219820Sjeff unsigned long flags; 3473219820Sjeff int ret; 3474219820Sjeff 3475219820Sjeff spin_lock_irqsave(&cm_id_priv->lock, flags); 3476219820Sjeff switch (cm_id_priv->id.state) { 3477219820Sjeff case IB_CM_REQ_SENT: 3478219820Sjeff case IB_CM_MRA_REQ_RCVD: 3479219820Sjeff case IB_CM_REQ_RCVD: 3480219820Sjeff case IB_CM_MRA_REQ_SENT: 3481219820Sjeff case IB_CM_REP_RCVD: 3482219820Sjeff case IB_CM_MRA_REP_SENT: 3483219820Sjeff case IB_CM_REP_SENT: 3484219820Sjeff case IB_CM_MRA_REP_RCVD: 3485219820Sjeff case IB_CM_ESTABLISHED: 3486219820Sjeff *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS | 3487219820Sjeff IB_QP_PKEY_INDEX | IB_QP_PORT; 3488219820Sjeff qp_attr->qp_access_flags = IB_ACCESS_REMOTE_WRITE; 3489219820Sjeff if (cm_id_priv->responder_resources) 3490219820Sjeff qp_attr->qp_access_flags |= IB_ACCESS_REMOTE_READ | 3491219820Sjeff IB_ACCESS_REMOTE_ATOMIC; 3492219820Sjeff qp_attr->pkey_index = cm_id_priv->av.pkey_index; 3493219820Sjeff qp_attr->port_num = cm_id_priv->av.port->port_num; 3494219820Sjeff ret = 0; 3495219820Sjeff break; 3496219820Sjeff default: 3497219820Sjeff ret = -EINVAL; 3498219820Sjeff break; 3499219820Sjeff } 3500219820Sjeff spin_unlock_irqrestore(&cm_id_priv->lock, flags); 3501219820Sjeff return ret; 3502219820Sjeff} 3503219820Sjeff 3504219820Sjeffstatic int cm_init_qp_rtr_attr(struct cm_id_private *cm_id_priv, 3505219820Sjeff struct ib_qp_attr *qp_attr, 3506219820Sjeff int *qp_attr_mask) 3507219820Sjeff{ 3508219820Sjeff unsigned long flags; 3509219820Sjeff int ret; 3510219820Sjeff 3511219820Sjeff spin_lock_irqsave(&cm_id_priv->lock, flags); 3512219820Sjeff switch (cm_id_priv->id.state) { 3513219820Sjeff case IB_CM_REQ_RCVD: 3514219820Sjeff case IB_CM_MRA_REQ_SENT: 3515219820Sjeff case IB_CM_REP_RCVD: 3516219820Sjeff case IB_CM_MRA_REP_SENT: 3517219820Sjeff case IB_CM_REP_SENT: 3518219820Sjeff case IB_CM_MRA_REP_RCVD: 3519219820Sjeff case IB_CM_ESTABLISHED: 3520219820Sjeff *qp_attr_mask = IB_QP_STATE | IB_QP_AV | IB_QP_PATH_MTU | 3521219820Sjeff IB_QP_DEST_QPN | IB_QP_RQ_PSN; 3522219820Sjeff qp_attr->ah_attr = cm_id_priv->av.ah_attr; 3523219820Sjeff qp_attr->path_mtu = cm_id_priv->path_mtu; 3524219820Sjeff qp_attr->dest_qp_num = be32_to_cpu(cm_id_priv->remote_qpn); 3525219820Sjeff qp_attr->rq_psn = be32_to_cpu(cm_id_priv->rq_psn); 3526219820Sjeff if (cm_id_priv->qp_type == IB_QPT_RC) { 3527219820Sjeff *qp_attr_mask |= IB_QP_MAX_DEST_RD_ATOMIC | 3528219820Sjeff IB_QP_MIN_RNR_TIMER; 3529219820Sjeff qp_attr->max_dest_rd_atomic = 3530219820Sjeff cm_id_priv->responder_resources; 3531219820Sjeff qp_attr->min_rnr_timer = 0; 3532219820Sjeff } 3533219820Sjeff if (cm_id_priv->alt_av.ah_attr.dlid) { 3534219820Sjeff *qp_attr_mask |= IB_QP_ALT_PATH; 3535219820Sjeff qp_attr->alt_port_num = cm_id_priv->alt_av.port->port_num; 3536219820Sjeff qp_attr->alt_pkey_index = cm_id_priv->alt_av.pkey_index; 3537219820Sjeff qp_attr->alt_timeout = cm_id_priv->alt_av.timeout; 3538219820Sjeff qp_attr->alt_ah_attr = cm_id_priv->alt_av.ah_attr; 3539219820Sjeff } 3540219820Sjeff ret = 0; 3541219820Sjeff break; 3542219820Sjeff default: 3543219820Sjeff ret = -EINVAL; 3544219820Sjeff break; 3545219820Sjeff } 3546219820Sjeff spin_unlock_irqrestore(&cm_id_priv->lock, flags); 3547219820Sjeff return ret; 3548219820Sjeff} 3549219820Sjeff 3550219820Sjeffstatic int cm_init_qp_rts_attr(struct cm_id_private *cm_id_priv, 3551219820Sjeff struct ib_qp_attr *qp_attr, 3552219820Sjeff int *qp_attr_mask) 3553219820Sjeff{ 3554219820Sjeff unsigned long flags; 3555219820Sjeff int ret; 3556219820Sjeff 3557219820Sjeff spin_lock_irqsave(&cm_id_priv->lock, flags); 3558219820Sjeff switch (cm_id_priv->id.state) { 3559219820Sjeff /* Allow transition to RTS before sending REP */ 3560219820Sjeff case IB_CM_REQ_RCVD: 3561219820Sjeff case IB_CM_MRA_REQ_SENT: 3562219820Sjeff 3563219820Sjeff case IB_CM_REP_RCVD: 3564219820Sjeff case IB_CM_MRA_REP_SENT: 3565219820Sjeff case IB_CM_REP_SENT: 3566219820Sjeff case IB_CM_MRA_REP_RCVD: 3567219820Sjeff case IB_CM_ESTABLISHED: 3568219820Sjeff if (cm_id_priv->id.lap_state == IB_CM_LAP_UNINIT) { 3569219820Sjeff *qp_attr_mask = IB_QP_STATE | IB_QP_SQ_PSN; 3570219820Sjeff qp_attr->sq_psn = be32_to_cpu(cm_id_priv->sq_psn); 3571219820Sjeff if (cm_id_priv->qp_type == IB_QPT_RC) { 3572219820Sjeff *qp_attr_mask |= IB_QP_TIMEOUT | IB_QP_RETRY_CNT | 3573219820Sjeff IB_QP_RNR_RETRY | 3574219820Sjeff IB_QP_MAX_QP_RD_ATOMIC; 3575219820Sjeff qp_attr->timeout = cm_id_priv->av.timeout; 3576219820Sjeff qp_attr->retry_cnt = cm_id_priv->retry_count; 3577219820Sjeff qp_attr->rnr_retry = cm_id_priv->rnr_retry_count; 3578219820Sjeff qp_attr->max_rd_atomic = 3579219820Sjeff cm_id_priv->initiator_depth; 3580219820Sjeff } 3581219820Sjeff if (cm_id_priv->alt_av.ah_attr.dlid) { 3582219820Sjeff *qp_attr_mask |= IB_QP_PATH_MIG_STATE; 3583219820Sjeff qp_attr->path_mig_state = IB_MIG_REARM; 3584219820Sjeff } 3585219820Sjeff } else { 3586219820Sjeff *qp_attr_mask = IB_QP_ALT_PATH | IB_QP_PATH_MIG_STATE; 3587219820Sjeff qp_attr->alt_port_num = cm_id_priv->alt_av.port->port_num; 3588219820Sjeff qp_attr->alt_pkey_index = cm_id_priv->alt_av.pkey_index; 3589219820Sjeff qp_attr->alt_timeout = cm_id_priv->alt_av.timeout; 3590219820Sjeff qp_attr->alt_ah_attr = cm_id_priv->alt_av.ah_attr; 3591219820Sjeff qp_attr->path_mig_state = IB_MIG_REARM; 3592219820Sjeff } 3593219820Sjeff ret = 0; 3594219820Sjeff break; 3595219820Sjeff default: 3596219820Sjeff ret = -EINVAL; 3597219820Sjeff break; 3598219820Sjeff } 3599219820Sjeff spin_unlock_irqrestore(&cm_id_priv->lock, flags); 3600219820Sjeff return ret; 3601219820Sjeff} 3602219820Sjeff 3603219820Sjeffint ib_cm_init_qp_attr(struct ib_cm_id *cm_id, 3604219820Sjeff struct ib_qp_attr *qp_attr, 3605219820Sjeff int *qp_attr_mask) 3606219820Sjeff{ 3607219820Sjeff struct cm_id_private *cm_id_priv; 3608219820Sjeff int ret; 3609219820Sjeff 3610219820Sjeff cm_id_priv = container_of(cm_id, struct cm_id_private, id); 3611219820Sjeff switch (qp_attr->qp_state) { 3612219820Sjeff case IB_QPS_INIT: 3613219820Sjeff ret = cm_init_qp_init_attr(cm_id_priv, qp_attr, qp_attr_mask); 3614219820Sjeff break; 3615219820Sjeff case IB_QPS_RTR: 3616219820Sjeff ret = cm_init_qp_rtr_attr(cm_id_priv, qp_attr, qp_attr_mask); 3617219820Sjeff break; 3618219820Sjeff case IB_QPS_RTS: 3619219820Sjeff ret = cm_init_qp_rts_attr(cm_id_priv, qp_attr, qp_attr_mask); 3620219820Sjeff break; 3621219820Sjeff default: 3622219820Sjeff ret = -EINVAL; 3623219820Sjeff break; 3624219820Sjeff } 3625219820Sjeff return ret; 3626219820Sjeff} 3627219820SjeffEXPORT_SYMBOL(ib_cm_init_qp_attr); 3628219820Sjeff 3629219820Sjeffstatic void cm_get_ack_delay(struct cm_device *cm_dev) 3630219820Sjeff{ 3631219820Sjeff struct ib_device_attr attr; 3632219820Sjeff 3633219820Sjeff if (ib_query_device(cm_dev->ib_device, &attr)) 3634219820Sjeff cm_dev->ack_delay = 0; /* acks will rely on packet life time */ 3635219820Sjeff else 3636219820Sjeff cm_dev->ack_delay = attr.local_ca_ack_delay; 3637219820Sjeff} 3638219820Sjeff 3639219820Sjeffstatic ssize_t cm_show_counter(struct kobject *obj, struct attribute *attr, 3640219820Sjeff char *buf) 3641219820Sjeff{ 3642219820Sjeff struct cm_counter_group *group; 3643219820Sjeff struct cm_counter_attribute *cm_attr; 3644219820Sjeff 3645219820Sjeff group = container_of(obj, struct cm_counter_group, obj); 3646219820Sjeff cm_attr = container_of(attr, struct cm_counter_attribute, attr); 3647219820Sjeff 3648219820Sjeff return sprintf(buf, "%ld\n", 3649219820Sjeff atomic_long_read(&group->counter[cm_attr->index])); 3650219820Sjeff} 3651219820Sjeff 3652219820Sjeffstatic struct sysfs_ops cm_counter_ops = { 3653219820Sjeff .show = cm_show_counter 3654219820Sjeff}; 3655219820Sjeff 3656219820Sjeffstatic struct kobj_type cm_counter_obj_type = { 3657219820Sjeff .sysfs_ops = &cm_counter_ops, 3658219820Sjeff .default_attrs = cm_counter_default_attrs 3659219820Sjeff}; 3660219820Sjeff 3661219820Sjeffstatic void cm_release_port_obj(struct kobject *obj) 3662219820Sjeff{ 3663219820Sjeff struct cm_port *cm_port; 3664219820Sjeff 3665219820Sjeff cm_port = container_of(obj, struct cm_port, port_obj); 3666219820Sjeff kfree(cm_port); 3667219820Sjeff} 3668219820Sjeff 3669219820Sjeffstatic struct kobj_type cm_port_obj_type = { 3670219820Sjeff .release = cm_release_port_obj 3671219820Sjeff}; 3672219820Sjeff 3673219820Sjeffstruct class cm_class = { 3674219820Sjeff .name = "infiniband_cm", 3675219820Sjeff}; 3676219820SjeffEXPORT_SYMBOL(cm_class); 3677219820Sjeff 3678219820Sjeffstatic int cm_create_port_fs(struct cm_port *port) 3679219820Sjeff{ 3680219820Sjeff int i, ret; 3681219820Sjeff 3682219820Sjeff ret = kobject_init_and_add(&port->port_obj, &cm_port_obj_type, 3683219820Sjeff &port->cm_dev->device->kobj, 3684219820Sjeff "%d", port->port_num); 3685219820Sjeff if (ret) { 3686219820Sjeff kfree(port); 3687219820Sjeff return ret; 3688219820Sjeff } 3689219820Sjeff 3690219820Sjeff for (i = 0; i < CM_COUNTER_GROUPS; i++) { 3691219820Sjeff ret = kobject_init_and_add(&port->counter_group[i].obj, 3692219820Sjeff &cm_counter_obj_type, 3693219820Sjeff &port->port_obj, 3694219820Sjeff "%s", counter_group_names[i]); 3695219820Sjeff if (ret) 3696219820Sjeff goto error; 3697219820Sjeff } 3698219820Sjeff 3699219820Sjeff return 0; 3700219820Sjeff 3701219820Sjefferror: 3702219820Sjeff while (i--) 3703219820Sjeff kobject_put(&port->counter_group[i].obj); 3704219820Sjeff kobject_put(&port->port_obj); 3705219820Sjeff return ret; 3706219820Sjeff 3707219820Sjeff} 3708219820Sjeff 3709219820Sjeffstatic void cm_remove_port_fs(struct cm_port *port) 3710219820Sjeff{ 3711219820Sjeff int i; 3712219820Sjeff 3713219820Sjeff for (i = 0; i < CM_COUNTER_GROUPS; i++) 3714219820Sjeff kobject_put(&port->counter_group[i].obj); 3715219820Sjeff 3716219820Sjeff kobject_put(&port->port_obj); 3717219820Sjeff} 3718219820Sjeff 3719219820Sjeffstatic void cm_add_one(struct ib_device *ib_device) 3720219820Sjeff{ 3721219820Sjeff struct cm_device *cm_dev; 3722219820Sjeff struct cm_port *port; 3723219820Sjeff struct ib_mad_reg_req reg_req = { 3724219820Sjeff .mgmt_class = IB_MGMT_CLASS_CM, 3725219820Sjeff .mgmt_class_version = IB_CM_CLASS_VERSION 3726219820Sjeff }; 3727219820Sjeff struct ib_port_modify port_modify = { 3728219820Sjeff .set_port_cap_mask = IB_PORT_CM_SUP 3729219820Sjeff }; 3730219820Sjeff unsigned long flags; 3731219820Sjeff int ret; 3732219820Sjeff u8 i; 3733219820Sjeff 3734219820Sjeff if (rdma_node_get_transport(ib_device->node_type) != RDMA_TRANSPORT_IB) 3735219820Sjeff return; 3736219820Sjeff 3737219820Sjeff cm_dev = kzalloc(sizeof(*cm_dev) + sizeof(*port) * 3738219820Sjeff ib_device->phys_port_cnt, GFP_KERNEL); 3739219820Sjeff if (!cm_dev) 3740219820Sjeff return; 3741219820Sjeff 3742219820Sjeff cm_dev->ib_device = ib_device; 3743219820Sjeff cm_get_ack_delay(cm_dev); 3744219820Sjeff 3745219820Sjeff cm_dev->device = device_create(&cm_class, &ib_device->dev, 3746219820Sjeff MKDEV(0, 0), NULL, 3747219820Sjeff "%s", ib_device->name); 3748219820Sjeff if (!cm_dev->device) { 3749219820Sjeff kfree(cm_dev); 3750219820Sjeff return; 3751219820Sjeff } 3752219820Sjeff 3753219820Sjeff set_bit(IB_MGMT_METHOD_SEND, reg_req.method_mask); 3754219820Sjeff for (i = 1; i <= ib_device->phys_port_cnt; i++) { 3755219820Sjeff port = kzalloc(sizeof *port, GFP_KERNEL); 3756219820Sjeff if (!port) 3757219820Sjeff goto error1; 3758219820Sjeff 3759219820Sjeff cm_dev->port[i-1] = port; 3760219820Sjeff port->cm_dev = cm_dev; 3761219820Sjeff port->port_num = i; 3762219820Sjeff 3763219820Sjeff ret = cm_create_port_fs(port); 3764219820Sjeff if (ret) 3765219820Sjeff goto error1; 3766219820Sjeff 3767219820Sjeff port->mad_agent = ib_register_mad_agent(ib_device, i, 3768219820Sjeff IB_QPT_GSI, 3769219820Sjeff ®_req, 3770219820Sjeff 0, 3771219820Sjeff cm_send_handler, 3772219820Sjeff cm_recv_handler, 3773219820Sjeff port); 3774219820Sjeff if (IS_ERR(port->mad_agent)) 3775219820Sjeff goto error2; 3776219820Sjeff 3777219820Sjeff ret = ib_modify_port(ib_device, i, 0, &port_modify); 3778219820Sjeff if (ret) 3779219820Sjeff goto error3; 3780219820Sjeff } 3781219820Sjeff ib_set_client_data(ib_device, &cm_client, cm_dev); 3782219820Sjeff 3783219820Sjeff write_lock_irqsave(&cm.device_lock, flags); 3784219820Sjeff list_add_tail(&cm_dev->list, &cm.device_list); 3785219820Sjeff write_unlock_irqrestore(&cm.device_lock, flags); 3786219820Sjeff return; 3787219820Sjeff 3788219820Sjefferror3: 3789219820Sjeff ib_unregister_mad_agent(port->mad_agent); 3790219820Sjefferror2: 3791219820Sjeff cm_remove_port_fs(port); 3792219820Sjefferror1: 3793219820Sjeff port_modify.set_port_cap_mask = 0; 3794219820Sjeff port_modify.clr_port_cap_mask = IB_PORT_CM_SUP; 3795219820Sjeff while (--i) { 3796219820Sjeff port = cm_dev->port[i-1]; 3797219820Sjeff ib_modify_port(ib_device, port->port_num, 0, &port_modify); 3798219820Sjeff ib_unregister_mad_agent(port->mad_agent); 3799219820Sjeff cm_remove_port_fs(port); 3800219820Sjeff } 3801219820Sjeff device_unregister(cm_dev->device); 3802219820Sjeff kfree(cm_dev); 3803219820Sjeff} 3804219820Sjeff 3805219820Sjeffstatic void cm_remove_one(struct ib_device *ib_device) 3806219820Sjeff{ 3807219820Sjeff struct cm_device *cm_dev; 3808219820Sjeff struct cm_port *port; 3809219820Sjeff struct ib_port_modify port_modify = { 3810219820Sjeff .clr_port_cap_mask = IB_PORT_CM_SUP 3811219820Sjeff }; 3812219820Sjeff unsigned long flags; 3813219820Sjeff int i; 3814219820Sjeff 3815219820Sjeff cm_dev = ib_get_client_data(ib_device, &cm_client); 3816219820Sjeff if (!cm_dev) 3817219820Sjeff return; 3818219820Sjeff 3819219820Sjeff write_lock_irqsave(&cm.device_lock, flags); 3820219820Sjeff list_del(&cm_dev->list); 3821219820Sjeff write_unlock_irqrestore(&cm.device_lock, flags); 3822219820Sjeff 3823219820Sjeff for (i = 1; i <= ib_device->phys_port_cnt; i++) { 3824219820Sjeff port = cm_dev->port[i-1]; 3825219820Sjeff ib_modify_port(ib_device, port->port_num, 0, &port_modify); 3826219820Sjeff ib_unregister_mad_agent(port->mad_agent); 3827219820Sjeff flush_workqueue(cm.wq); 3828219820Sjeff cm_remove_port_fs(port); 3829219820Sjeff } 3830219820Sjeff device_unregister(cm_dev->device); 3831219820Sjeff kfree(cm_dev); 3832219820Sjeff} 3833219820Sjeff 3834219820Sjeffstatic int __init ib_cm_init(void) 3835219820Sjeff{ 3836219820Sjeff int ret; 3837219820Sjeff 3838219820Sjeff memset(&cm, 0, sizeof cm); 3839219820Sjeff INIT_LIST_HEAD(&cm.device_list); 3840219820Sjeff rwlock_init(&cm.device_lock); 3841219820Sjeff spin_lock_init(&cm.lock); 3842219820Sjeff cm.listen_service_table = RB_ROOT; 3843219820Sjeff cm.listen_service_id = be64_to_cpu(IB_CM_ASSIGN_SERVICE_ID); 3844219820Sjeff cm.remote_id_table = RB_ROOT; 3845219820Sjeff cm.remote_qp_table = RB_ROOT; 3846219820Sjeff cm.remote_sidr_table = RB_ROOT; 3847219820Sjeff idr_init(&cm.local_id_table); 3848219820Sjeff get_random_bytes(&cm.random_id_operand, sizeof cm.random_id_operand); 3849219820Sjeff idr_pre_get(&cm.local_id_table, GFP_KERNEL); 3850219820Sjeff INIT_LIST_HEAD(&cm.timewait_list); 3851219820Sjeff 3852219820Sjeff ret = class_register(&cm_class); 3853219820Sjeff if (ret) 3854219820Sjeff return -ENOMEM; 3855219820Sjeff 3856219820Sjeff cm.wq = create_workqueue("ib_cm"); 3857219820Sjeff if (!cm.wq) { 3858219820Sjeff ret = -ENOMEM; 3859219820Sjeff goto error1; 3860219820Sjeff } 3861219820Sjeff 3862219820Sjeff ret = ib_register_client(&cm_client); 3863219820Sjeff if (ret) 3864219820Sjeff goto error2; 3865219820Sjeff 3866219820Sjeff return 0; 3867219820Sjefferror2: 3868219820Sjeff destroy_workqueue(cm.wq); 3869219820Sjefferror1: 3870219820Sjeff class_unregister(&cm_class); 3871219820Sjeff return ret; 3872219820Sjeff} 3873219820Sjeff 3874219820Sjeffstatic void __exit ib_cm_cleanup(void) 3875219820Sjeff{ 3876219820Sjeff struct cm_timewait_info *timewait_info, *tmp; 3877219820Sjeff 3878219820Sjeff spin_lock_irq(&cm.lock); 3879219820Sjeff list_for_each_entry(timewait_info, &cm.timewait_list, list) 3880219820Sjeff cancel_delayed_work(&timewait_info->work.work); 3881219820Sjeff spin_unlock_irq(&cm.lock); 3882219820Sjeff 3883219820Sjeff ib_unregister_client(&cm_client); 3884219820Sjeff destroy_workqueue(cm.wq); 3885219820Sjeff 3886219820Sjeff list_for_each_entry_safe(timewait_info, tmp, &cm.timewait_list, list) { 3887219820Sjeff list_del(&timewait_info->list); 3888219820Sjeff kfree(timewait_info); 3889219820Sjeff } 3890219820Sjeff 3891219820Sjeff class_unregister(&cm_class); 3892219820Sjeff idr_destroy(&cm.local_id_table); 3893219820Sjeff} 3894219820Sjeff 3895219820Sjeffmodule_init_order(ib_cm_init, SI_ORDER_SECOND); 3896271127Shselaskymodule_exit_order(ib_cm_cleanup, SI_ORDER_FIRST); 3897219820Sjeff 3898