162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2004-2007 Intel Corporation. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2004 Topspin Corporation. All rights reserved. 562306a36Sopenharmony_ci * Copyright (c) 2004, 2005 Voltaire Corporation. All rights reserved. 662306a36Sopenharmony_ci * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 762306a36Sopenharmony_ci * Copyright (c) 2019, Mellanox Technologies inc. All rights reserved. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/completion.h> 1162306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1262306a36Sopenharmony_ci#include <linux/device.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/err.h> 1562306a36Sopenharmony_ci#include <linux/idr.h> 1662306a36Sopenharmony_ci#include <linux/interrupt.h> 1762306a36Sopenharmony_ci#include <linux/random.h> 1862306a36Sopenharmony_ci#include <linux/rbtree.h> 1962306a36Sopenharmony_ci#include <linux/spinlock.h> 2062306a36Sopenharmony_ci#include <linux/slab.h> 2162306a36Sopenharmony_ci#include <linux/sysfs.h> 2262306a36Sopenharmony_ci#include <linux/workqueue.h> 2362306a36Sopenharmony_ci#include <linux/kdev_t.h> 2462306a36Sopenharmony_ci#include <linux/etherdevice.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <rdma/ib_cache.h> 2762306a36Sopenharmony_ci#include <rdma/ib_cm.h> 2862306a36Sopenharmony_ci#include <rdma/ib_sysfs.h> 2962306a36Sopenharmony_ci#include "cm_msgs.h" 3062306a36Sopenharmony_ci#include "core_priv.h" 3162306a36Sopenharmony_ci#include "cm_trace.h" 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ciMODULE_AUTHOR("Sean Hefty"); 3462306a36Sopenharmony_ciMODULE_DESCRIPTION("InfiniBand CM"); 3562306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic const char * const ibcm_rej_reason_strs[] = { 3862306a36Sopenharmony_ci [IB_CM_REJ_NO_QP] = "no QP", 3962306a36Sopenharmony_ci [IB_CM_REJ_NO_EEC] = "no EEC", 4062306a36Sopenharmony_ci [IB_CM_REJ_NO_RESOURCES] = "no resources", 4162306a36Sopenharmony_ci [IB_CM_REJ_TIMEOUT] = "timeout", 4262306a36Sopenharmony_ci [IB_CM_REJ_UNSUPPORTED] = "unsupported", 4362306a36Sopenharmony_ci [IB_CM_REJ_INVALID_COMM_ID] = "invalid comm ID", 4462306a36Sopenharmony_ci [IB_CM_REJ_INVALID_COMM_INSTANCE] = "invalid comm instance", 4562306a36Sopenharmony_ci [IB_CM_REJ_INVALID_SERVICE_ID] = "invalid service ID", 4662306a36Sopenharmony_ci [IB_CM_REJ_INVALID_TRANSPORT_TYPE] = "invalid transport type", 4762306a36Sopenharmony_ci [IB_CM_REJ_STALE_CONN] = "stale conn", 4862306a36Sopenharmony_ci [IB_CM_REJ_RDC_NOT_EXIST] = "RDC not exist", 4962306a36Sopenharmony_ci [IB_CM_REJ_INVALID_GID] = "invalid GID", 5062306a36Sopenharmony_ci [IB_CM_REJ_INVALID_LID] = "invalid LID", 5162306a36Sopenharmony_ci [IB_CM_REJ_INVALID_SL] = "invalid SL", 5262306a36Sopenharmony_ci [IB_CM_REJ_INVALID_TRAFFIC_CLASS] = "invalid traffic class", 5362306a36Sopenharmony_ci [IB_CM_REJ_INVALID_HOP_LIMIT] = "invalid hop limit", 5462306a36Sopenharmony_ci [IB_CM_REJ_INVALID_PACKET_RATE] = "invalid packet rate", 5562306a36Sopenharmony_ci [IB_CM_REJ_INVALID_ALT_GID] = "invalid alt GID", 5662306a36Sopenharmony_ci [IB_CM_REJ_INVALID_ALT_LID] = "invalid alt LID", 5762306a36Sopenharmony_ci [IB_CM_REJ_INVALID_ALT_SL] = "invalid alt SL", 5862306a36Sopenharmony_ci [IB_CM_REJ_INVALID_ALT_TRAFFIC_CLASS] = "invalid alt traffic class", 5962306a36Sopenharmony_ci [IB_CM_REJ_INVALID_ALT_HOP_LIMIT] = "invalid alt hop limit", 6062306a36Sopenharmony_ci [IB_CM_REJ_INVALID_ALT_PACKET_RATE] = "invalid alt packet rate", 6162306a36Sopenharmony_ci [IB_CM_REJ_PORT_CM_REDIRECT] = "port CM redirect", 6262306a36Sopenharmony_ci [IB_CM_REJ_PORT_REDIRECT] = "port redirect", 6362306a36Sopenharmony_ci [IB_CM_REJ_INVALID_MTU] = "invalid MTU", 6462306a36Sopenharmony_ci [IB_CM_REJ_INSUFFICIENT_RESP_RESOURCES] = "insufficient resp resources", 6562306a36Sopenharmony_ci [IB_CM_REJ_CONSUMER_DEFINED] = "consumer defined", 6662306a36Sopenharmony_ci [IB_CM_REJ_INVALID_RNR_RETRY] = "invalid RNR retry", 6762306a36Sopenharmony_ci [IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID] = "duplicate local comm ID", 6862306a36Sopenharmony_ci [IB_CM_REJ_INVALID_CLASS_VERSION] = "invalid class version", 6962306a36Sopenharmony_ci [IB_CM_REJ_INVALID_FLOW_LABEL] = "invalid flow label", 7062306a36Sopenharmony_ci [IB_CM_REJ_INVALID_ALT_FLOW_LABEL] = "invalid alt flow label", 7162306a36Sopenharmony_ci [IB_CM_REJ_VENDOR_OPTION_NOT_SUPPORTED] = 7262306a36Sopenharmony_ci "vendor option is not supported", 7362306a36Sopenharmony_ci}; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ciconst char *__attribute_const__ ibcm_reject_msg(int reason) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci size_t index = reason; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (index < ARRAY_SIZE(ibcm_rej_reason_strs) && 8062306a36Sopenharmony_ci ibcm_rej_reason_strs[index]) 8162306a36Sopenharmony_ci return ibcm_rej_reason_strs[index]; 8262306a36Sopenharmony_ci else 8362306a36Sopenharmony_ci return "unrecognized reason"; 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ciEXPORT_SYMBOL(ibcm_reject_msg); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistruct cm_id_private; 8862306a36Sopenharmony_cistruct cm_work; 8962306a36Sopenharmony_cistatic int cm_add_one(struct ib_device *device); 9062306a36Sopenharmony_cistatic void cm_remove_one(struct ib_device *device, void *client_data); 9162306a36Sopenharmony_cistatic void cm_process_work(struct cm_id_private *cm_id_priv, 9262306a36Sopenharmony_ci struct cm_work *work); 9362306a36Sopenharmony_cistatic int cm_send_sidr_rep_locked(struct cm_id_private *cm_id_priv, 9462306a36Sopenharmony_ci struct ib_cm_sidr_rep_param *param); 9562306a36Sopenharmony_cistatic int cm_send_dreq_locked(struct cm_id_private *cm_id_priv, 9662306a36Sopenharmony_ci const void *private_data, u8 private_data_len); 9762306a36Sopenharmony_cistatic int cm_send_drep_locked(struct cm_id_private *cm_id_priv, 9862306a36Sopenharmony_ci void *private_data, u8 private_data_len); 9962306a36Sopenharmony_cistatic int cm_send_rej_locked(struct cm_id_private *cm_id_priv, 10062306a36Sopenharmony_ci enum ib_cm_rej_reason reason, void *ari, 10162306a36Sopenharmony_ci u8 ari_length, const void *private_data, 10262306a36Sopenharmony_ci u8 private_data_len); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic struct ib_client cm_client = { 10562306a36Sopenharmony_ci .name = "cm", 10662306a36Sopenharmony_ci .add = cm_add_one, 10762306a36Sopenharmony_ci .remove = cm_remove_one 10862306a36Sopenharmony_ci}; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic struct ib_cm { 11162306a36Sopenharmony_ci spinlock_t lock; 11262306a36Sopenharmony_ci struct list_head device_list; 11362306a36Sopenharmony_ci rwlock_t device_lock; 11462306a36Sopenharmony_ci struct rb_root listen_service_table; 11562306a36Sopenharmony_ci u64 listen_service_id; 11662306a36Sopenharmony_ci /* struct rb_root peer_service_table; todo: fix peer to peer */ 11762306a36Sopenharmony_ci struct rb_root remote_qp_table; 11862306a36Sopenharmony_ci struct rb_root remote_id_table; 11962306a36Sopenharmony_ci struct rb_root remote_sidr_table; 12062306a36Sopenharmony_ci struct xarray local_id_table; 12162306a36Sopenharmony_ci u32 local_id_next; 12262306a36Sopenharmony_ci __be32 random_id_operand; 12362306a36Sopenharmony_ci struct list_head timewait_list; 12462306a36Sopenharmony_ci struct workqueue_struct *wq; 12562306a36Sopenharmony_ci} cm; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci/* Counter indexes ordered by attribute ID */ 12862306a36Sopenharmony_cienum { 12962306a36Sopenharmony_ci CM_REQ_COUNTER, 13062306a36Sopenharmony_ci CM_MRA_COUNTER, 13162306a36Sopenharmony_ci CM_REJ_COUNTER, 13262306a36Sopenharmony_ci CM_REP_COUNTER, 13362306a36Sopenharmony_ci CM_RTU_COUNTER, 13462306a36Sopenharmony_ci CM_DREQ_COUNTER, 13562306a36Sopenharmony_ci CM_DREP_COUNTER, 13662306a36Sopenharmony_ci CM_SIDR_REQ_COUNTER, 13762306a36Sopenharmony_ci CM_SIDR_REP_COUNTER, 13862306a36Sopenharmony_ci CM_LAP_COUNTER, 13962306a36Sopenharmony_ci CM_APR_COUNTER, 14062306a36Sopenharmony_ci CM_ATTR_COUNT, 14162306a36Sopenharmony_ci CM_ATTR_ID_OFFSET = 0x0010, 14262306a36Sopenharmony_ci}; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cienum { 14562306a36Sopenharmony_ci CM_XMIT, 14662306a36Sopenharmony_ci CM_XMIT_RETRIES, 14762306a36Sopenharmony_ci CM_RECV, 14862306a36Sopenharmony_ci CM_RECV_DUPLICATES, 14962306a36Sopenharmony_ci CM_COUNTER_GROUPS 15062306a36Sopenharmony_ci}; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistruct cm_counter_attribute { 15362306a36Sopenharmony_ci struct ib_port_attribute attr; 15462306a36Sopenharmony_ci unsigned short group; 15562306a36Sopenharmony_ci unsigned short index; 15662306a36Sopenharmony_ci}; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistruct cm_port { 15962306a36Sopenharmony_ci struct cm_device *cm_dev; 16062306a36Sopenharmony_ci struct ib_mad_agent *mad_agent; 16162306a36Sopenharmony_ci u32 port_num; 16262306a36Sopenharmony_ci atomic_long_t counters[CM_COUNTER_GROUPS][CM_ATTR_COUNT]; 16362306a36Sopenharmony_ci}; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistruct cm_device { 16662306a36Sopenharmony_ci struct kref kref; 16762306a36Sopenharmony_ci struct list_head list; 16862306a36Sopenharmony_ci spinlock_t mad_agent_lock; 16962306a36Sopenharmony_ci struct ib_device *ib_device; 17062306a36Sopenharmony_ci u8 ack_delay; 17162306a36Sopenharmony_ci int going_down; 17262306a36Sopenharmony_ci struct cm_port *port[]; 17362306a36Sopenharmony_ci}; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistruct cm_av { 17662306a36Sopenharmony_ci struct cm_port *port; 17762306a36Sopenharmony_ci struct rdma_ah_attr ah_attr; 17862306a36Sopenharmony_ci u16 dlid_datapath; 17962306a36Sopenharmony_ci u16 pkey_index; 18062306a36Sopenharmony_ci u8 timeout; 18162306a36Sopenharmony_ci}; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistruct cm_work { 18462306a36Sopenharmony_ci struct delayed_work work; 18562306a36Sopenharmony_ci struct list_head list; 18662306a36Sopenharmony_ci struct cm_port *port; 18762306a36Sopenharmony_ci struct ib_mad_recv_wc *mad_recv_wc; /* Received MADs */ 18862306a36Sopenharmony_ci __be32 local_id; /* Established / timewait */ 18962306a36Sopenharmony_ci __be32 remote_id; 19062306a36Sopenharmony_ci struct ib_cm_event cm_event; 19162306a36Sopenharmony_ci struct sa_path_rec path[]; 19262306a36Sopenharmony_ci}; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistruct cm_timewait_info { 19562306a36Sopenharmony_ci struct cm_work work; 19662306a36Sopenharmony_ci struct list_head list; 19762306a36Sopenharmony_ci struct rb_node remote_qp_node; 19862306a36Sopenharmony_ci struct rb_node remote_id_node; 19962306a36Sopenharmony_ci __be64 remote_ca_guid; 20062306a36Sopenharmony_ci __be32 remote_qpn; 20162306a36Sopenharmony_ci u8 inserted_remote_qp; 20262306a36Sopenharmony_ci u8 inserted_remote_id; 20362306a36Sopenharmony_ci}; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistruct cm_id_private { 20662306a36Sopenharmony_ci struct ib_cm_id id; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci struct rb_node service_node; 20962306a36Sopenharmony_ci struct rb_node sidr_id_node; 21062306a36Sopenharmony_ci u32 sidr_slid; 21162306a36Sopenharmony_ci spinlock_t lock; /* Do not acquire inside cm.lock */ 21262306a36Sopenharmony_ci struct completion comp; 21362306a36Sopenharmony_ci refcount_t refcount; 21462306a36Sopenharmony_ci /* Number of clients sharing this ib_cm_id. Only valid for listeners. 21562306a36Sopenharmony_ci * Protected by the cm.lock spinlock. 21662306a36Sopenharmony_ci */ 21762306a36Sopenharmony_ci int listen_sharecount; 21862306a36Sopenharmony_ci struct rcu_head rcu; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci struct ib_mad_send_buf *msg; 22162306a36Sopenharmony_ci struct cm_timewait_info *timewait_info; 22262306a36Sopenharmony_ci /* todo: use alternate port on send failure */ 22362306a36Sopenharmony_ci struct cm_av av; 22462306a36Sopenharmony_ci struct cm_av alt_av; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci void *private_data; 22762306a36Sopenharmony_ci __be64 tid; 22862306a36Sopenharmony_ci __be32 local_qpn; 22962306a36Sopenharmony_ci __be32 remote_qpn; 23062306a36Sopenharmony_ci enum ib_qp_type qp_type; 23162306a36Sopenharmony_ci __be32 sq_psn; 23262306a36Sopenharmony_ci __be32 rq_psn; 23362306a36Sopenharmony_ci int timeout_ms; 23462306a36Sopenharmony_ci enum ib_mtu path_mtu; 23562306a36Sopenharmony_ci __be16 pkey; 23662306a36Sopenharmony_ci u8 private_data_len; 23762306a36Sopenharmony_ci u8 max_cm_retries; 23862306a36Sopenharmony_ci u8 responder_resources; 23962306a36Sopenharmony_ci u8 initiator_depth; 24062306a36Sopenharmony_ci u8 retry_count; 24162306a36Sopenharmony_ci u8 rnr_retry_count; 24262306a36Sopenharmony_ci u8 service_timeout; 24362306a36Sopenharmony_ci u8 target_ack_delay; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci struct list_head work_list; 24662306a36Sopenharmony_ci atomic_t work_count; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci struct rdma_ucm_ece ece; 24962306a36Sopenharmony_ci}; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic void cm_dev_release(struct kref *kref) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci struct cm_device *cm_dev = container_of(kref, struct cm_device, kref); 25462306a36Sopenharmony_ci u32 i; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci rdma_for_each_port(cm_dev->ib_device, i) 25762306a36Sopenharmony_ci kfree(cm_dev->port[i - 1]); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci kfree(cm_dev); 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic void cm_device_put(struct cm_device *cm_dev) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci kref_put(&cm_dev->kref, cm_dev_release); 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic void cm_work_handler(struct work_struct *work); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic inline void cm_deref_id(struct cm_id_private *cm_id_priv) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci if (refcount_dec_and_test(&cm_id_priv->refcount)) 27262306a36Sopenharmony_ci complete(&cm_id_priv->comp); 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic struct ib_mad_send_buf *cm_alloc_msg(struct cm_id_private *cm_id_priv) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci struct ib_mad_agent *mad_agent; 27862306a36Sopenharmony_ci struct ib_mad_send_buf *m; 27962306a36Sopenharmony_ci struct ib_ah *ah; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci lockdep_assert_held(&cm_id_priv->lock); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (!cm_id_priv->av.port) 28462306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci spin_lock(&cm_id_priv->av.port->cm_dev->mad_agent_lock); 28762306a36Sopenharmony_ci mad_agent = cm_id_priv->av.port->mad_agent; 28862306a36Sopenharmony_ci if (!mad_agent) { 28962306a36Sopenharmony_ci m = ERR_PTR(-EINVAL); 29062306a36Sopenharmony_ci goto out; 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci ah = rdma_create_ah(mad_agent->qp->pd, &cm_id_priv->av.ah_attr, 0); 29462306a36Sopenharmony_ci if (IS_ERR(ah)) { 29562306a36Sopenharmony_ci m = ERR_CAST(ah); 29662306a36Sopenharmony_ci goto out; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci m = ib_create_send_mad(mad_agent, cm_id_priv->id.remote_cm_qpn, 30062306a36Sopenharmony_ci cm_id_priv->av.pkey_index, 30162306a36Sopenharmony_ci 0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, 30262306a36Sopenharmony_ci GFP_ATOMIC, 30362306a36Sopenharmony_ci IB_MGMT_BASE_VERSION); 30462306a36Sopenharmony_ci if (IS_ERR(m)) { 30562306a36Sopenharmony_ci rdma_destroy_ah(ah, 0); 30662306a36Sopenharmony_ci goto out; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci /* Timeout set by caller if response is expected. */ 31062306a36Sopenharmony_ci m->ah = ah; 31162306a36Sopenharmony_ci m->retries = cm_id_priv->max_cm_retries; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci refcount_inc(&cm_id_priv->refcount); 31462306a36Sopenharmony_ci m->context[0] = cm_id_priv; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ciout: 31762306a36Sopenharmony_ci spin_unlock(&cm_id_priv->av.port->cm_dev->mad_agent_lock); 31862306a36Sopenharmony_ci return m; 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic void cm_free_msg(struct ib_mad_send_buf *msg) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci struct cm_id_private *cm_id_priv = msg->context[0]; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if (msg->ah) 32662306a36Sopenharmony_ci rdma_destroy_ah(msg->ah, 0); 32762306a36Sopenharmony_ci cm_deref_id(cm_id_priv); 32862306a36Sopenharmony_ci ib_free_send_mad(msg); 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic struct ib_mad_send_buf * 33262306a36Sopenharmony_cicm_alloc_priv_msg(struct cm_id_private *cm_id_priv) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci struct ib_mad_send_buf *msg; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci lockdep_assert_held(&cm_id_priv->lock); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci msg = cm_alloc_msg(cm_id_priv); 33962306a36Sopenharmony_ci if (IS_ERR(msg)) 34062306a36Sopenharmony_ci return msg; 34162306a36Sopenharmony_ci cm_id_priv->msg = msg; 34262306a36Sopenharmony_ci return msg; 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistatic void cm_free_priv_msg(struct ib_mad_send_buf *msg) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci struct cm_id_private *cm_id_priv = msg->context[0]; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci lockdep_assert_held(&cm_id_priv->lock); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci if (!WARN_ON(cm_id_priv->msg != msg)) 35262306a36Sopenharmony_ci cm_id_priv->msg = NULL; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (msg->ah) 35562306a36Sopenharmony_ci rdma_destroy_ah(msg->ah, 0); 35662306a36Sopenharmony_ci cm_deref_id(cm_id_priv); 35762306a36Sopenharmony_ci ib_free_send_mad(msg); 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_cistatic struct ib_mad_send_buf *cm_alloc_response_msg_no_ah(struct cm_port *port, 36162306a36Sopenharmony_ci struct ib_mad_recv_wc *mad_recv_wc) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci return ib_create_send_mad(port->mad_agent, 1, mad_recv_wc->wc->pkey_index, 36462306a36Sopenharmony_ci 0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, 36562306a36Sopenharmony_ci GFP_ATOMIC, 36662306a36Sopenharmony_ci IB_MGMT_BASE_VERSION); 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic int cm_create_response_msg_ah(struct cm_port *port, 37062306a36Sopenharmony_ci struct ib_mad_recv_wc *mad_recv_wc, 37162306a36Sopenharmony_ci struct ib_mad_send_buf *msg) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci struct ib_ah *ah; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci ah = ib_create_ah_from_wc(port->mad_agent->qp->pd, mad_recv_wc->wc, 37662306a36Sopenharmony_ci mad_recv_wc->recv_buf.grh, port->port_num); 37762306a36Sopenharmony_ci if (IS_ERR(ah)) 37862306a36Sopenharmony_ci return PTR_ERR(ah); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci msg->ah = ah; 38162306a36Sopenharmony_ci return 0; 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic int cm_alloc_response_msg(struct cm_port *port, 38562306a36Sopenharmony_ci struct ib_mad_recv_wc *mad_recv_wc, 38662306a36Sopenharmony_ci struct ib_mad_send_buf **msg) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci struct ib_mad_send_buf *m; 38962306a36Sopenharmony_ci int ret; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci m = cm_alloc_response_msg_no_ah(port, mad_recv_wc); 39262306a36Sopenharmony_ci if (IS_ERR(m)) 39362306a36Sopenharmony_ci return PTR_ERR(m); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci ret = cm_create_response_msg_ah(port, mad_recv_wc, m); 39662306a36Sopenharmony_ci if (ret) { 39762306a36Sopenharmony_ci ib_free_send_mad(m); 39862306a36Sopenharmony_ci return ret; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci *msg = m; 40262306a36Sopenharmony_ci return 0; 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cistatic void cm_free_response_msg(struct ib_mad_send_buf *msg) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci if (msg->ah) 40862306a36Sopenharmony_ci rdma_destroy_ah(msg->ah, 0); 40962306a36Sopenharmony_ci ib_free_send_mad(msg); 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic void *cm_copy_private_data(const void *private_data, u8 private_data_len) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci void *data; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if (!private_data || !private_data_len) 41762306a36Sopenharmony_ci return NULL; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci data = kmemdup(private_data, private_data_len, GFP_KERNEL); 42062306a36Sopenharmony_ci if (!data) 42162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci return data; 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic void cm_set_private_data(struct cm_id_private *cm_id_priv, 42762306a36Sopenharmony_ci void *private_data, u8 private_data_len) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci if (cm_id_priv->private_data && cm_id_priv->private_data_len) 43062306a36Sopenharmony_ci kfree(cm_id_priv->private_data); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci cm_id_priv->private_data = private_data; 43362306a36Sopenharmony_ci cm_id_priv->private_data_len = private_data_len; 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic void cm_set_av_port(struct cm_av *av, struct cm_port *port) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci struct cm_port *old_port = av->port; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (old_port == port) 44162306a36Sopenharmony_ci return; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci av->port = port; 44462306a36Sopenharmony_ci if (old_port) 44562306a36Sopenharmony_ci cm_device_put(old_port->cm_dev); 44662306a36Sopenharmony_ci if (port) 44762306a36Sopenharmony_ci kref_get(&port->cm_dev->kref); 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic void cm_init_av_for_lap(struct cm_port *port, struct ib_wc *wc, 45162306a36Sopenharmony_ci struct rdma_ah_attr *ah_attr, struct cm_av *av) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci cm_set_av_port(av, port); 45462306a36Sopenharmony_ci av->pkey_index = wc->pkey_index; 45562306a36Sopenharmony_ci rdma_move_ah_attr(&av->ah_attr, ah_attr); 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic int cm_init_av_for_response(struct cm_port *port, struct ib_wc *wc, 45962306a36Sopenharmony_ci struct ib_grh *grh, struct cm_av *av) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci cm_set_av_port(av, port); 46262306a36Sopenharmony_ci av->pkey_index = wc->pkey_index; 46362306a36Sopenharmony_ci return ib_init_ah_attr_from_wc(port->cm_dev->ib_device, 46462306a36Sopenharmony_ci port->port_num, wc, 46562306a36Sopenharmony_ci grh, &av->ah_attr); 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistatic struct cm_port * 46962306a36Sopenharmony_ciget_cm_port_from_path(struct sa_path_rec *path, const struct ib_gid_attr *attr) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci struct cm_device *cm_dev; 47262306a36Sopenharmony_ci struct cm_port *port = NULL; 47362306a36Sopenharmony_ci unsigned long flags; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci if (attr) { 47662306a36Sopenharmony_ci read_lock_irqsave(&cm.device_lock, flags); 47762306a36Sopenharmony_ci list_for_each_entry(cm_dev, &cm.device_list, list) { 47862306a36Sopenharmony_ci if (cm_dev->ib_device == attr->device) { 47962306a36Sopenharmony_ci port = cm_dev->port[attr->port_num - 1]; 48062306a36Sopenharmony_ci break; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci read_unlock_irqrestore(&cm.device_lock, flags); 48462306a36Sopenharmony_ci } else { 48562306a36Sopenharmony_ci /* SGID attribute can be NULL in following 48662306a36Sopenharmony_ci * conditions. 48762306a36Sopenharmony_ci * (a) Alternative path 48862306a36Sopenharmony_ci * (b) IB link layer without GRH 48962306a36Sopenharmony_ci * (c) LAP send messages 49062306a36Sopenharmony_ci */ 49162306a36Sopenharmony_ci read_lock_irqsave(&cm.device_lock, flags); 49262306a36Sopenharmony_ci list_for_each_entry(cm_dev, &cm.device_list, list) { 49362306a36Sopenharmony_ci attr = rdma_find_gid(cm_dev->ib_device, 49462306a36Sopenharmony_ci &path->sgid, 49562306a36Sopenharmony_ci sa_conv_pathrec_to_gid_type(path), 49662306a36Sopenharmony_ci NULL); 49762306a36Sopenharmony_ci if (!IS_ERR(attr)) { 49862306a36Sopenharmony_ci port = cm_dev->port[attr->port_num - 1]; 49962306a36Sopenharmony_ci break; 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci read_unlock_irqrestore(&cm.device_lock, flags); 50362306a36Sopenharmony_ci if (port) 50462306a36Sopenharmony_ci rdma_put_gid_attr(attr); 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci return port; 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic int cm_init_av_by_path(struct sa_path_rec *path, 51062306a36Sopenharmony_ci const struct ib_gid_attr *sgid_attr, 51162306a36Sopenharmony_ci struct cm_av *av) 51262306a36Sopenharmony_ci{ 51362306a36Sopenharmony_ci struct rdma_ah_attr new_ah_attr; 51462306a36Sopenharmony_ci struct cm_device *cm_dev; 51562306a36Sopenharmony_ci struct cm_port *port; 51662306a36Sopenharmony_ci int ret; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci port = get_cm_port_from_path(path, sgid_attr); 51962306a36Sopenharmony_ci if (!port) 52062306a36Sopenharmony_ci return -EINVAL; 52162306a36Sopenharmony_ci cm_dev = port->cm_dev; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci ret = ib_find_cached_pkey(cm_dev->ib_device, port->port_num, 52462306a36Sopenharmony_ci be16_to_cpu(path->pkey), &av->pkey_index); 52562306a36Sopenharmony_ci if (ret) 52662306a36Sopenharmony_ci return ret; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci cm_set_av_port(av, port); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci /* 53162306a36Sopenharmony_ci * av->ah_attr might be initialized based on wc or during 53262306a36Sopenharmony_ci * request processing time which might have reference to sgid_attr. 53362306a36Sopenharmony_ci * So initialize a new ah_attr on stack. 53462306a36Sopenharmony_ci * If initialization fails, old ah_attr is used for sending any 53562306a36Sopenharmony_ci * responses. If initialization is successful, than new ah_attr 53662306a36Sopenharmony_ci * is used by overwriting the old one. So that right ah_attr 53762306a36Sopenharmony_ci * can be used to return an error response. 53862306a36Sopenharmony_ci */ 53962306a36Sopenharmony_ci ret = ib_init_ah_attr_from_path(cm_dev->ib_device, port->port_num, path, 54062306a36Sopenharmony_ci &new_ah_attr, sgid_attr); 54162306a36Sopenharmony_ci if (ret) 54262306a36Sopenharmony_ci return ret; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci av->timeout = path->packet_life_time + 1; 54562306a36Sopenharmony_ci rdma_move_ah_attr(&av->ah_attr, &new_ah_attr); 54662306a36Sopenharmony_ci return 0; 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci/* Move av created by cm_init_av_by_path(), so av.dgid is not moved */ 55062306a36Sopenharmony_cistatic void cm_move_av_from_path(struct cm_av *dest, struct cm_av *src) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci cm_set_av_port(dest, src->port); 55362306a36Sopenharmony_ci cm_set_av_port(src, NULL); 55462306a36Sopenharmony_ci dest->pkey_index = src->pkey_index; 55562306a36Sopenharmony_ci rdma_move_ah_attr(&dest->ah_attr, &src->ah_attr); 55662306a36Sopenharmony_ci dest->timeout = src->timeout; 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_cistatic void cm_destroy_av(struct cm_av *av) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci rdma_destroy_ah_attr(&av->ah_attr); 56262306a36Sopenharmony_ci cm_set_av_port(av, NULL); 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic u32 cm_local_id(__be32 local_id) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci return (__force u32) (local_id ^ cm.random_id_operand); 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cistatic struct cm_id_private *cm_acquire_id(__be32 local_id, __be32 remote_id) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci rcu_read_lock(); 57562306a36Sopenharmony_ci cm_id_priv = xa_load(&cm.local_id_table, cm_local_id(local_id)); 57662306a36Sopenharmony_ci if (!cm_id_priv || cm_id_priv->id.remote_id != remote_id || 57762306a36Sopenharmony_ci !refcount_inc_not_zero(&cm_id_priv->refcount)) 57862306a36Sopenharmony_ci cm_id_priv = NULL; 57962306a36Sopenharmony_ci rcu_read_unlock(); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci return cm_id_priv; 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci/* 58562306a36Sopenharmony_ci * Trivial helpers to strip endian annotation and compare; the 58662306a36Sopenharmony_ci * endianness doesn't actually matter since we just need a stable 58762306a36Sopenharmony_ci * order for the RB tree. 58862306a36Sopenharmony_ci */ 58962306a36Sopenharmony_cistatic int be32_lt(__be32 a, __be32 b) 59062306a36Sopenharmony_ci{ 59162306a36Sopenharmony_ci return (__force u32) a < (__force u32) b; 59262306a36Sopenharmony_ci} 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_cistatic int be32_gt(__be32 a, __be32 b) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci return (__force u32) a > (__force u32) b; 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cistatic int be64_lt(__be64 a, __be64 b) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci return (__force u64) a < (__force u64) b; 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cistatic int be64_gt(__be64 a, __be64 b) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci return (__force u64) a > (__force u64) b; 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci/* 61062306a36Sopenharmony_ci * Inserts a new cm_id_priv into the listen_service_table. Returns cm_id_priv 61162306a36Sopenharmony_ci * if the new ID was inserted, NULL if it could not be inserted due to a 61262306a36Sopenharmony_ci * collision, or the existing cm_id_priv ready for shared usage. 61362306a36Sopenharmony_ci */ 61462306a36Sopenharmony_cistatic struct cm_id_private *cm_insert_listen(struct cm_id_private *cm_id_priv, 61562306a36Sopenharmony_ci ib_cm_handler shared_handler) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci struct rb_node **link = &cm.listen_service_table.rb_node; 61862306a36Sopenharmony_ci struct rb_node *parent = NULL; 61962306a36Sopenharmony_ci struct cm_id_private *cur_cm_id_priv; 62062306a36Sopenharmony_ci __be64 service_id = cm_id_priv->id.service_id; 62162306a36Sopenharmony_ci unsigned long flags; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci spin_lock_irqsave(&cm.lock, flags); 62462306a36Sopenharmony_ci while (*link) { 62562306a36Sopenharmony_ci parent = *link; 62662306a36Sopenharmony_ci cur_cm_id_priv = rb_entry(parent, struct cm_id_private, 62762306a36Sopenharmony_ci service_node); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci if (cm_id_priv->id.device < cur_cm_id_priv->id.device) 63062306a36Sopenharmony_ci link = &(*link)->rb_left; 63162306a36Sopenharmony_ci else if (cm_id_priv->id.device > cur_cm_id_priv->id.device) 63262306a36Sopenharmony_ci link = &(*link)->rb_right; 63362306a36Sopenharmony_ci else if (be64_lt(service_id, cur_cm_id_priv->id.service_id)) 63462306a36Sopenharmony_ci link = &(*link)->rb_left; 63562306a36Sopenharmony_ci else if (be64_gt(service_id, cur_cm_id_priv->id.service_id)) 63662306a36Sopenharmony_ci link = &(*link)->rb_right; 63762306a36Sopenharmony_ci else { 63862306a36Sopenharmony_ci /* 63962306a36Sopenharmony_ci * Sharing an ib_cm_id with different handlers is not 64062306a36Sopenharmony_ci * supported 64162306a36Sopenharmony_ci */ 64262306a36Sopenharmony_ci if (cur_cm_id_priv->id.cm_handler != shared_handler || 64362306a36Sopenharmony_ci cur_cm_id_priv->id.context || 64462306a36Sopenharmony_ci WARN_ON(!cur_cm_id_priv->id.cm_handler)) { 64562306a36Sopenharmony_ci spin_unlock_irqrestore(&cm.lock, flags); 64662306a36Sopenharmony_ci return NULL; 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci refcount_inc(&cur_cm_id_priv->refcount); 64962306a36Sopenharmony_ci cur_cm_id_priv->listen_sharecount++; 65062306a36Sopenharmony_ci spin_unlock_irqrestore(&cm.lock, flags); 65162306a36Sopenharmony_ci return cur_cm_id_priv; 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci cm_id_priv->listen_sharecount++; 65562306a36Sopenharmony_ci rb_link_node(&cm_id_priv->service_node, parent, link); 65662306a36Sopenharmony_ci rb_insert_color(&cm_id_priv->service_node, &cm.listen_service_table); 65762306a36Sopenharmony_ci spin_unlock_irqrestore(&cm.lock, flags); 65862306a36Sopenharmony_ci return cm_id_priv; 65962306a36Sopenharmony_ci} 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_cistatic struct cm_id_private *cm_find_listen(struct ib_device *device, 66262306a36Sopenharmony_ci __be64 service_id) 66362306a36Sopenharmony_ci{ 66462306a36Sopenharmony_ci struct rb_node *node = cm.listen_service_table.rb_node; 66562306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci while (node) { 66862306a36Sopenharmony_ci cm_id_priv = rb_entry(node, struct cm_id_private, service_node); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci if (device < cm_id_priv->id.device) 67162306a36Sopenharmony_ci node = node->rb_left; 67262306a36Sopenharmony_ci else if (device > cm_id_priv->id.device) 67362306a36Sopenharmony_ci node = node->rb_right; 67462306a36Sopenharmony_ci else if (be64_lt(service_id, cm_id_priv->id.service_id)) 67562306a36Sopenharmony_ci node = node->rb_left; 67662306a36Sopenharmony_ci else if (be64_gt(service_id, cm_id_priv->id.service_id)) 67762306a36Sopenharmony_ci node = node->rb_right; 67862306a36Sopenharmony_ci else { 67962306a36Sopenharmony_ci refcount_inc(&cm_id_priv->refcount); 68062306a36Sopenharmony_ci return cm_id_priv; 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci return NULL; 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_cistatic struct cm_timewait_info * 68762306a36Sopenharmony_cicm_insert_remote_id(struct cm_timewait_info *timewait_info) 68862306a36Sopenharmony_ci{ 68962306a36Sopenharmony_ci struct rb_node **link = &cm.remote_id_table.rb_node; 69062306a36Sopenharmony_ci struct rb_node *parent = NULL; 69162306a36Sopenharmony_ci struct cm_timewait_info *cur_timewait_info; 69262306a36Sopenharmony_ci __be64 remote_ca_guid = timewait_info->remote_ca_guid; 69362306a36Sopenharmony_ci __be32 remote_id = timewait_info->work.remote_id; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci while (*link) { 69662306a36Sopenharmony_ci parent = *link; 69762306a36Sopenharmony_ci cur_timewait_info = rb_entry(parent, struct cm_timewait_info, 69862306a36Sopenharmony_ci remote_id_node); 69962306a36Sopenharmony_ci if (be32_lt(remote_id, cur_timewait_info->work.remote_id)) 70062306a36Sopenharmony_ci link = &(*link)->rb_left; 70162306a36Sopenharmony_ci else if (be32_gt(remote_id, cur_timewait_info->work.remote_id)) 70262306a36Sopenharmony_ci link = &(*link)->rb_right; 70362306a36Sopenharmony_ci else if (be64_lt(remote_ca_guid, cur_timewait_info->remote_ca_guid)) 70462306a36Sopenharmony_ci link = &(*link)->rb_left; 70562306a36Sopenharmony_ci else if (be64_gt(remote_ca_guid, cur_timewait_info->remote_ca_guid)) 70662306a36Sopenharmony_ci link = &(*link)->rb_right; 70762306a36Sopenharmony_ci else 70862306a36Sopenharmony_ci return cur_timewait_info; 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci timewait_info->inserted_remote_id = 1; 71162306a36Sopenharmony_ci rb_link_node(&timewait_info->remote_id_node, parent, link); 71262306a36Sopenharmony_ci rb_insert_color(&timewait_info->remote_id_node, &cm.remote_id_table); 71362306a36Sopenharmony_ci return NULL; 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic struct cm_id_private *cm_find_remote_id(__be64 remote_ca_guid, 71762306a36Sopenharmony_ci __be32 remote_id) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci struct rb_node *node = cm.remote_id_table.rb_node; 72062306a36Sopenharmony_ci struct cm_timewait_info *timewait_info; 72162306a36Sopenharmony_ci struct cm_id_private *res = NULL; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci spin_lock_irq(&cm.lock); 72462306a36Sopenharmony_ci while (node) { 72562306a36Sopenharmony_ci timewait_info = rb_entry(node, struct cm_timewait_info, 72662306a36Sopenharmony_ci remote_id_node); 72762306a36Sopenharmony_ci if (be32_lt(remote_id, timewait_info->work.remote_id)) 72862306a36Sopenharmony_ci node = node->rb_left; 72962306a36Sopenharmony_ci else if (be32_gt(remote_id, timewait_info->work.remote_id)) 73062306a36Sopenharmony_ci node = node->rb_right; 73162306a36Sopenharmony_ci else if (be64_lt(remote_ca_guid, timewait_info->remote_ca_guid)) 73262306a36Sopenharmony_ci node = node->rb_left; 73362306a36Sopenharmony_ci else if (be64_gt(remote_ca_guid, timewait_info->remote_ca_guid)) 73462306a36Sopenharmony_ci node = node->rb_right; 73562306a36Sopenharmony_ci else { 73662306a36Sopenharmony_ci res = cm_acquire_id(timewait_info->work.local_id, 73762306a36Sopenharmony_ci timewait_info->work.remote_id); 73862306a36Sopenharmony_ci break; 73962306a36Sopenharmony_ci } 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci spin_unlock_irq(&cm.lock); 74262306a36Sopenharmony_ci return res; 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_cistatic struct cm_timewait_info * 74662306a36Sopenharmony_cicm_insert_remote_qpn(struct cm_timewait_info *timewait_info) 74762306a36Sopenharmony_ci{ 74862306a36Sopenharmony_ci struct rb_node **link = &cm.remote_qp_table.rb_node; 74962306a36Sopenharmony_ci struct rb_node *parent = NULL; 75062306a36Sopenharmony_ci struct cm_timewait_info *cur_timewait_info; 75162306a36Sopenharmony_ci __be64 remote_ca_guid = timewait_info->remote_ca_guid; 75262306a36Sopenharmony_ci __be32 remote_qpn = timewait_info->remote_qpn; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci while (*link) { 75562306a36Sopenharmony_ci parent = *link; 75662306a36Sopenharmony_ci cur_timewait_info = rb_entry(parent, struct cm_timewait_info, 75762306a36Sopenharmony_ci remote_qp_node); 75862306a36Sopenharmony_ci if (be32_lt(remote_qpn, cur_timewait_info->remote_qpn)) 75962306a36Sopenharmony_ci link = &(*link)->rb_left; 76062306a36Sopenharmony_ci else if (be32_gt(remote_qpn, cur_timewait_info->remote_qpn)) 76162306a36Sopenharmony_ci link = &(*link)->rb_right; 76262306a36Sopenharmony_ci else if (be64_lt(remote_ca_guid, cur_timewait_info->remote_ca_guid)) 76362306a36Sopenharmony_ci link = &(*link)->rb_left; 76462306a36Sopenharmony_ci else if (be64_gt(remote_ca_guid, cur_timewait_info->remote_ca_guid)) 76562306a36Sopenharmony_ci link = &(*link)->rb_right; 76662306a36Sopenharmony_ci else 76762306a36Sopenharmony_ci return cur_timewait_info; 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci timewait_info->inserted_remote_qp = 1; 77062306a36Sopenharmony_ci rb_link_node(&timewait_info->remote_qp_node, parent, link); 77162306a36Sopenharmony_ci rb_insert_color(&timewait_info->remote_qp_node, &cm.remote_qp_table); 77262306a36Sopenharmony_ci return NULL; 77362306a36Sopenharmony_ci} 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_cistatic struct cm_id_private * 77662306a36Sopenharmony_cicm_insert_remote_sidr(struct cm_id_private *cm_id_priv) 77762306a36Sopenharmony_ci{ 77862306a36Sopenharmony_ci struct rb_node **link = &cm.remote_sidr_table.rb_node; 77962306a36Sopenharmony_ci struct rb_node *parent = NULL; 78062306a36Sopenharmony_ci struct cm_id_private *cur_cm_id_priv; 78162306a36Sopenharmony_ci __be32 remote_id = cm_id_priv->id.remote_id; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci while (*link) { 78462306a36Sopenharmony_ci parent = *link; 78562306a36Sopenharmony_ci cur_cm_id_priv = rb_entry(parent, struct cm_id_private, 78662306a36Sopenharmony_ci sidr_id_node); 78762306a36Sopenharmony_ci if (be32_lt(remote_id, cur_cm_id_priv->id.remote_id)) 78862306a36Sopenharmony_ci link = &(*link)->rb_left; 78962306a36Sopenharmony_ci else if (be32_gt(remote_id, cur_cm_id_priv->id.remote_id)) 79062306a36Sopenharmony_ci link = &(*link)->rb_right; 79162306a36Sopenharmony_ci else { 79262306a36Sopenharmony_ci if (cur_cm_id_priv->sidr_slid < cm_id_priv->sidr_slid) 79362306a36Sopenharmony_ci link = &(*link)->rb_left; 79462306a36Sopenharmony_ci else if (cur_cm_id_priv->sidr_slid > cm_id_priv->sidr_slid) 79562306a36Sopenharmony_ci link = &(*link)->rb_right; 79662306a36Sopenharmony_ci else 79762306a36Sopenharmony_ci return cur_cm_id_priv; 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci rb_link_node(&cm_id_priv->sidr_id_node, parent, link); 80162306a36Sopenharmony_ci rb_insert_color(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table); 80262306a36Sopenharmony_ci return NULL; 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_cistatic struct cm_id_private *cm_alloc_id_priv(struct ib_device *device, 80662306a36Sopenharmony_ci ib_cm_handler cm_handler, 80762306a36Sopenharmony_ci void *context) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 81062306a36Sopenharmony_ci u32 id; 81162306a36Sopenharmony_ci int ret; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci cm_id_priv = kzalloc(sizeof *cm_id_priv, GFP_KERNEL); 81462306a36Sopenharmony_ci if (!cm_id_priv) 81562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci cm_id_priv->id.state = IB_CM_IDLE; 81862306a36Sopenharmony_ci cm_id_priv->id.device = device; 81962306a36Sopenharmony_ci cm_id_priv->id.cm_handler = cm_handler; 82062306a36Sopenharmony_ci cm_id_priv->id.context = context; 82162306a36Sopenharmony_ci cm_id_priv->id.remote_cm_qpn = 1; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci RB_CLEAR_NODE(&cm_id_priv->service_node); 82462306a36Sopenharmony_ci RB_CLEAR_NODE(&cm_id_priv->sidr_id_node); 82562306a36Sopenharmony_ci spin_lock_init(&cm_id_priv->lock); 82662306a36Sopenharmony_ci init_completion(&cm_id_priv->comp); 82762306a36Sopenharmony_ci INIT_LIST_HEAD(&cm_id_priv->work_list); 82862306a36Sopenharmony_ci atomic_set(&cm_id_priv->work_count, -1); 82962306a36Sopenharmony_ci refcount_set(&cm_id_priv->refcount, 1); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci ret = xa_alloc_cyclic(&cm.local_id_table, &id, NULL, xa_limit_32b, 83262306a36Sopenharmony_ci &cm.local_id_next, GFP_KERNEL); 83362306a36Sopenharmony_ci if (ret < 0) 83462306a36Sopenharmony_ci goto error; 83562306a36Sopenharmony_ci cm_id_priv->id.local_id = (__force __be32)id ^ cm.random_id_operand; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci return cm_id_priv; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_cierror: 84062306a36Sopenharmony_ci kfree(cm_id_priv); 84162306a36Sopenharmony_ci return ERR_PTR(ret); 84262306a36Sopenharmony_ci} 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci/* 84562306a36Sopenharmony_ci * Make the ID visible to the MAD handlers and other threads that use the 84662306a36Sopenharmony_ci * xarray. 84762306a36Sopenharmony_ci */ 84862306a36Sopenharmony_cistatic void cm_finalize_id(struct cm_id_private *cm_id_priv) 84962306a36Sopenharmony_ci{ 85062306a36Sopenharmony_ci xa_store(&cm.local_id_table, cm_local_id(cm_id_priv->id.local_id), 85162306a36Sopenharmony_ci cm_id_priv, GFP_ATOMIC); 85262306a36Sopenharmony_ci} 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_cistruct ib_cm_id *ib_create_cm_id(struct ib_device *device, 85562306a36Sopenharmony_ci ib_cm_handler cm_handler, 85662306a36Sopenharmony_ci void *context) 85762306a36Sopenharmony_ci{ 85862306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci cm_id_priv = cm_alloc_id_priv(device, cm_handler, context); 86162306a36Sopenharmony_ci if (IS_ERR(cm_id_priv)) 86262306a36Sopenharmony_ci return ERR_CAST(cm_id_priv); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci cm_finalize_id(cm_id_priv); 86562306a36Sopenharmony_ci return &cm_id_priv->id; 86662306a36Sopenharmony_ci} 86762306a36Sopenharmony_ciEXPORT_SYMBOL(ib_create_cm_id); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_cistatic struct cm_work *cm_dequeue_work(struct cm_id_private *cm_id_priv) 87062306a36Sopenharmony_ci{ 87162306a36Sopenharmony_ci struct cm_work *work; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci if (list_empty(&cm_id_priv->work_list)) 87462306a36Sopenharmony_ci return NULL; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci work = list_entry(cm_id_priv->work_list.next, struct cm_work, list); 87762306a36Sopenharmony_ci list_del(&work->list); 87862306a36Sopenharmony_ci return work; 87962306a36Sopenharmony_ci} 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_cistatic void cm_free_work(struct cm_work *work) 88262306a36Sopenharmony_ci{ 88362306a36Sopenharmony_ci if (work->mad_recv_wc) 88462306a36Sopenharmony_ci ib_free_recv_mad(work->mad_recv_wc); 88562306a36Sopenharmony_ci kfree(work); 88662306a36Sopenharmony_ci} 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_cistatic void cm_queue_work_unlock(struct cm_id_private *cm_id_priv, 88962306a36Sopenharmony_ci struct cm_work *work) 89062306a36Sopenharmony_ci __releases(&cm_id_priv->lock) 89162306a36Sopenharmony_ci{ 89262306a36Sopenharmony_ci bool immediate; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci /* 89562306a36Sopenharmony_ci * To deliver the event to the user callback we have the drop the 89662306a36Sopenharmony_ci * spinlock, however, we need to ensure that the user callback is single 89762306a36Sopenharmony_ci * threaded and receives events in the temporal order. If there are 89862306a36Sopenharmony_ci * already events being processed then thread new events onto a list, 89962306a36Sopenharmony_ci * the thread currently processing will pick them up. 90062306a36Sopenharmony_ci */ 90162306a36Sopenharmony_ci immediate = atomic_inc_and_test(&cm_id_priv->work_count); 90262306a36Sopenharmony_ci if (!immediate) { 90362306a36Sopenharmony_ci list_add_tail(&work->list, &cm_id_priv->work_list); 90462306a36Sopenharmony_ci /* 90562306a36Sopenharmony_ci * This routine always consumes incoming reference. Once queued 90662306a36Sopenharmony_ci * to the work_list then a reference is held by the thread 90762306a36Sopenharmony_ci * currently running cm_process_work() and this reference is not 90862306a36Sopenharmony_ci * needed. 90962306a36Sopenharmony_ci */ 91062306a36Sopenharmony_ci cm_deref_id(cm_id_priv); 91162306a36Sopenharmony_ci } 91262306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci if (immediate) 91562306a36Sopenharmony_ci cm_process_work(cm_id_priv, work); 91662306a36Sopenharmony_ci} 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_cistatic inline int cm_convert_to_ms(int iba_time) 91962306a36Sopenharmony_ci{ 92062306a36Sopenharmony_ci /* approximate conversion to ms from 4.096us x 2^iba_time */ 92162306a36Sopenharmony_ci return 1 << max(iba_time - 8, 0); 92262306a36Sopenharmony_ci} 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci/* 92562306a36Sopenharmony_ci * calculate: 4.096x2^ack_timeout = 4.096x2^ack_delay + 2x4.096x2^life_time 92662306a36Sopenharmony_ci * Because of how ack_timeout is stored, adding one doubles the timeout. 92762306a36Sopenharmony_ci * To avoid large timeouts, select the max(ack_delay, life_time + 1), and 92862306a36Sopenharmony_ci * increment it (round up) only if the other is within 50%. 92962306a36Sopenharmony_ci */ 93062306a36Sopenharmony_cistatic u8 cm_ack_timeout(u8 ca_ack_delay, u8 packet_life_time) 93162306a36Sopenharmony_ci{ 93262306a36Sopenharmony_ci int ack_timeout = packet_life_time + 1; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci if (ack_timeout >= ca_ack_delay) 93562306a36Sopenharmony_ci ack_timeout += (ca_ack_delay >= (ack_timeout - 1)); 93662306a36Sopenharmony_ci else 93762306a36Sopenharmony_ci ack_timeout = ca_ack_delay + 93862306a36Sopenharmony_ci (ack_timeout >= (ca_ack_delay - 1)); 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci return min(31, ack_timeout); 94162306a36Sopenharmony_ci} 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_cistatic void cm_remove_remote(struct cm_id_private *cm_id_priv) 94462306a36Sopenharmony_ci{ 94562306a36Sopenharmony_ci struct cm_timewait_info *timewait_info = cm_id_priv->timewait_info; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci if (timewait_info->inserted_remote_id) { 94862306a36Sopenharmony_ci rb_erase(&timewait_info->remote_id_node, &cm.remote_id_table); 94962306a36Sopenharmony_ci timewait_info->inserted_remote_id = 0; 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci if (timewait_info->inserted_remote_qp) { 95362306a36Sopenharmony_ci rb_erase(&timewait_info->remote_qp_node, &cm.remote_qp_table); 95462306a36Sopenharmony_ci timewait_info->inserted_remote_qp = 0; 95562306a36Sopenharmony_ci } 95662306a36Sopenharmony_ci} 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_cistatic struct cm_timewait_info *cm_create_timewait_info(__be32 local_id) 95962306a36Sopenharmony_ci{ 96062306a36Sopenharmony_ci struct cm_timewait_info *timewait_info; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci timewait_info = kzalloc(sizeof *timewait_info, GFP_KERNEL); 96362306a36Sopenharmony_ci if (!timewait_info) 96462306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci timewait_info->work.local_id = local_id; 96762306a36Sopenharmony_ci INIT_DELAYED_WORK(&timewait_info->work.work, cm_work_handler); 96862306a36Sopenharmony_ci timewait_info->work.cm_event.event = IB_CM_TIMEWAIT_EXIT; 96962306a36Sopenharmony_ci return timewait_info; 97062306a36Sopenharmony_ci} 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_cistatic void cm_enter_timewait(struct cm_id_private *cm_id_priv) 97362306a36Sopenharmony_ci{ 97462306a36Sopenharmony_ci int wait_time; 97562306a36Sopenharmony_ci unsigned long flags; 97662306a36Sopenharmony_ci struct cm_device *cm_dev; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci lockdep_assert_held(&cm_id_priv->lock); 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci cm_dev = ib_get_client_data(cm_id_priv->id.device, &cm_client); 98162306a36Sopenharmony_ci if (!cm_dev) 98262306a36Sopenharmony_ci return; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci spin_lock_irqsave(&cm.lock, flags); 98562306a36Sopenharmony_ci cm_remove_remote(cm_id_priv); 98662306a36Sopenharmony_ci list_add_tail(&cm_id_priv->timewait_info->list, &cm.timewait_list); 98762306a36Sopenharmony_ci spin_unlock_irqrestore(&cm.lock, flags); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci /* 99062306a36Sopenharmony_ci * The cm_id could be destroyed by the user before we exit timewait. 99162306a36Sopenharmony_ci * To protect against this, we search for the cm_id after exiting 99262306a36Sopenharmony_ci * timewait before notifying the user that we've exited timewait. 99362306a36Sopenharmony_ci */ 99462306a36Sopenharmony_ci cm_id_priv->id.state = IB_CM_TIMEWAIT; 99562306a36Sopenharmony_ci wait_time = cm_convert_to_ms(cm_id_priv->av.timeout); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci /* Check if the device started its remove_one */ 99862306a36Sopenharmony_ci spin_lock_irqsave(&cm.lock, flags); 99962306a36Sopenharmony_ci if (!cm_dev->going_down) 100062306a36Sopenharmony_ci queue_delayed_work(cm.wq, &cm_id_priv->timewait_info->work.work, 100162306a36Sopenharmony_ci msecs_to_jiffies(wait_time)); 100262306a36Sopenharmony_ci spin_unlock_irqrestore(&cm.lock, flags); 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci /* 100562306a36Sopenharmony_ci * The timewait_info is converted into a work and gets freed during 100662306a36Sopenharmony_ci * cm_free_work() in cm_timewait_handler(). 100762306a36Sopenharmony_ci */ 100862306a36Sopenharmony_ci BUILD_BUG_ON(offsetof(struct cm_timewait_info, work) != 0); 100962306a36Sopenharmony_ci cm_id_priv->timewait_info = NULL; 101062306a36Sopenharmony_ci} 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_cistatic void cm_reset_to_idle(struct cm_id_private *cm_id_priv) 101362306a36Sopenharmony_ci{ 101462306a36Sopenharmony_ci unsigned long flags; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci lockdep_assert_held(&cm_id_priv->lock); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci cm_id_priv->id.state = IB_CM_IDLE; 101962306a36Sopenharmony_ci if (cm_id_priv->timewait_info) { 102062306a36Sopenharmony_ci spin_lock_irqsave(&cm.lock, flags); 102162306a36Sopenharmony_ci cm_remove_remote(cm_id_priv); 102262306a36Sopenharmony_ci spin_unlock_irqrestore(&cm.lock, flags); 102362306a36Sopenharmony_ci kfree(cm_id_priv->timewait_info); 102462306a36Sopenharmony_ci cm_id_priv->timewait_info = NULL; 102562306a36Sopenharmony_ci } 102662306a36Sopenharmony_ci} 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_cistatic void cm_destroy_id(struct ib_cm_id *cm_id, int err) 102962306a36Sopenharmony_ci{ 103062306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 103162306a36Sopenharmony_ci struct cm_work *work; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci cm_id_priv = container_of(cm_id, struct cm_id_private, id); 103462306a36Sopenharmony_ci spin_lock_irq(&cm_id_priv->lock); 103562306a36Sopenharmony_ciretest: 103662306a36Sopenharmony_ci switch (cm_id->state) { 103762306a36Sopenharmony_ci case IB_CM_LISTEN: 103862306a36Sopenharmony_ci spin_lock(&cm.lock); 103962306a36Sopenharmony_ci if (--cm_id_priv->listen_sharecount > 0) { 104062306a36Sopenharmony_ci /* The id is still shared. */ 104162306a36Sopenharmony_ci WARN_ON(refcount_read(&cm_id_priv->refcount) == 1); 104262306a36Sopenharmony_ci spin_unlock(&cm.lock); 104362306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 104462306a36Sopenharmony_ci cm_deref_id(cm_id_priv); 104562306a36Sopenharmony_ci return; 104662306a36Sopenharmony_ci } 104762306a36Sopenharmony_ci cm_id->state = IB_CM_IDLE; 104862306a36Sopenharmony_ci rb_erase(&cm_id_priv->service_node, &cm.listen_service_table); 104962306a36Sopenharmony_ci RB_CLEAR_NODE(&cm_id_priv->service_node); 105062306a36Sopenharmony_ci spin_unlock(&cm.lock); 105162306a36Sopenharmony_ci break; 105262306a36Sopenharmony_ci case IB_CM_SIDR_REQ_SENT: 105362306a36Sopenharmony_ci cm_id->state = IB_CM_IDLE; 105462306a36Sopenharmony_ci ib_cancel_mad(cm_id_priv->msg); 105562306a36Sopenharmony_ci break; 105662306a36Sopenharmony_ci case IB_CM_SIDR_REQ_RCVD: 105762306a36Sopenharmony_ci cm_send_sidr_rep_locked(cm_id_priv, 105862306a36Sopenharmony_ci &(struct ib_cm_sidr_rep_param){ 105962306a36Sopenharmony_ci .status = IB_SIDR_REJECT }); 106062306a36Sopenharmony_ci /* cm_send_sidr_rep_locked will not move to IDLE if it fails */ 106162306a36Sopenharmony_ci cm_id->state = IB_CM_IDLE; 106262306a36Sopenharmony_ci break; 106362306a36Sopenharmony_ci case IB_CM_REQ_SENT: 106462306a36Sopenharmony_ci case IB_CM_MRA_REQ_RCVD: 106562306a36Sopenharmony_ci ib_cancel_mad(cm_id_priv->msg); 106662306a36Sopenharmony_ci cm_send_rej_locked(cm_id_priv, IB_CM_REJ_TIMEOUT, 106762306a36Sopenharmony_ci &cm_id_priv->id.device->node_guid, 106862306a36Sopenharmony_ci sizeof(cm_id_priv->id.device->node_guid), 106962306a36Sopenharmony_ci NULL, 0); 107062306a36Sopenharmony_ci break; 107162306a36Sopenharmony_ci case IB_CM_REQ_RCVD: 107262306a36Sopenharmony_ci if (err == -ENOMEM) { 107362306a36Sopenharmony_ci /* Do not reject to allow future retries. */ 107462306a36Sopenharmony_ci cm_reset_to_idle(cm_id_priv); 107562306a36Sopenharmony_ci } else { 107662306a36Sopenharmony_ci cm_send_rej_locked(cm_id_priv, 107762306a36Sopenharmony_ci IB_CM_REJ_CONSUMER_DEFINED, NULL, 0, 107862306a36Sopenharmony_ci NULL, 0); 107962306a36Sopenharmony_ci } 108062306a36Sopenharmony_ci break; 108162306a36Sopenharmony_ci case IB_CM_REP_SENT: 108262306a36Sopenharmony_ci case IB_CM_MRA_REP_RCVD: 108362306a36Sopenharmony_ci ib_cancel_mad(cm_id_priv->msg); 108462306a36Sopenharmony_ci cm_send_rej_locked(cm_id_priv, IB_CM_REJ_CONSUMER_DEFINED, NULL, 108562306a36Sopenharmony_ci 0, NULL, 0); 108662306a36Sopenharmony_ci goto retest; 108762306a36Sopenharmony_ci case IB_CM_MRA_REQ_SENT: 108862306a36Sopenharmony_ci case IB_CM_REP_RCVD: 108962306a36Sopenharmony_ci case IB_CM_MRA_REP_SENT: 109062306a36Sopenharmony_ci cm_send_rej_locked(cm_id_priv, IB_CM_REJ_CONSUMER_DEFINED, NULL, 109162306a36Sopenharmony_ci 0, NULL, 0); 109262306a36Sopenharmony_ci break; 109362306a36Sopenharmony_ci case IB_CM_ESTABLISHED: 109462306a36Sopenharmony_ci if (cm_id_priv->qp_type == IB_QPT_XRC_TGT) { 109562306a36Sopenharmony_ci cm_id->state = IB_CM_IDLE; 109662306a36Sopenharmony_ci break; 109762306a36Sopenharmony_ci } 109862306a36Sopenharmony_ci cm_send_dreq_locked(cm_id_priv, NULL, 0); 109962306a36Sopenharmony_ci goto retest; 110062306a36Sopenharmony_ci case IB_CM_DREQ_SENT: 110162306a36Sopenharmony_ci ib_cancel_mad(cm_id_priv->msg); 110262306a36Sopenharmony_ci cm_enter_timewait(cm_id_priv); 110362306a36Sopenharmony_ci goto retest; 110462306a36Sopenharmony_ci case IB_CM_DREQ_RCVD: 110562306a36Sopenharmony_ci cm_send_drep_locked(cm_id_priv, NULL, 0); 110662306a36Sopenharmony_ci WARN_ON(cm_id->state != IB_CM_TIMEWAIT); 110762306a36Sopenharmony_ci goto retest; 110862306a36Sopenharmony_ci case IB_CM_TIMEWAIT: 110962306a36Sopenharmony_ci /* 111062306a36Sopenharmony_ci * The cm_acquire_id in cm_timewait_handler will stop working 111162306a36Sopenharmony_ci * once we do xa_erase below, so just move to idle here for 111262306a36Sopenharmony_ci * consistency. 111362306a36Sopenharmony_ci */ 111462306a36Sopenharmony_ci cm_id->state = IB_CM_IDLE; 111562306a36Sopenharmony_ci break; 111662306a36Sopenharmony_ci case IB_CM_IDLE: 111762306a36Sopenharmony_ci break; 111862306a36Sopenharmony_ci } 111962306a36Sopenharmony_ci WARN_ON(cm_id->state != IB_CM_IDLE); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci spin_lock(&cm.lock); 112262306a36Sopenharmony_ci /* Required for cleanup paths related cm_req_handler() */ 112362306a36Sopenharmony_ci if (cm_id_priv->timewait_info) { 112462306a36Sopenharmony_ci cm_remove_remote(cm_id_priv); 112562306a36Sopenharmony_ci kfree(cm_id_priv->timewait_info); 112662306a36Sopenharmony_ci cm_id_priv->timewait_info = NULL; 112762306a36Sopenharmony_ci } 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci WARN_ON(cm_id_priv->listen_sharecount); 113062306a36Sopenharmony_ci WARN_ON(!RB_EMPTY_NODE(&cm_id_priv->service_node)); 113162306a36Sopenharmony_ci if (!RB_EMPTY_NODE(&cm_id_priv->sidr_id_node)) 113262306a36Sopenharmony_ci rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table); 113362306a36Sopenharmony_ci spin_unlock(&cm.lock); 113462306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci xa_erase(&cm.local_id_table, cm_local_id(cm_id->local_id)); 113762306a36Sopenharmony_ci cm_deref_id(cm_id_priv); 113862306a36Sopenharmony_ci wait_for_completion(&cm_id_priv->comp); 113962306a36Sopenharmony_ci while ((work = cm_dequeue_work(cm_id_priv)) != NULL) 114062306a36Sopenharmony_ci cm_free_work(work); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci cm_destroy_av(&cm_id_priv->av); 114362306a36Sopenharmony_ci cm_destroy_av(&cm_id_priv->alt_av); 114462306a36Sopenharmony_ci kfree(cm_id_priv->private_data); 114562306a36Sopenharmony_ci kfree_rcu(cm_id_priv, rcu); 114662306a36Sopenharmony_ci} 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_civoid ib_destroy_cm_id(struct ib_cm_id *cm_id) 114962306a36Sopenharmony_ci{ 115062306a36Sopenharmony_ci cm_destroy_id(cm_id, 0); 115162306a36Sopenharmony_ci} 115262306a36Sopenharmony_ciEXPORT_SYMBOL(ib_destroy_cm_id); 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_cistatic int cm_init_listen(struct cm_id_private *cm_id_priv, __be64 service_id) 115562306a36Sopenharmony_ci{ 115662306a36Sopenharmony_ci if ((service_id & IB_SERVICE_ID_AGN_MASK) == IB_CM_ASSIGN_SERVICE_ID && 115762306a36Sopenharmony_ci (service_id != IB_CM_ASSIGN_SERVICE_ID)) 115862306a36Sopenharmony_ci return -EINVAL; 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci if (service_id == IB_CM_ASSIGN_SERVICE_ID) 116162306a36Sopenharmony_ci cm_id_priv->id.service_id = cpu_to_be64(cm.listen_service_id++); 116262306a36Sopenharmony_ci else 116362306a36Sopenharmony_ci cm_id_priv->id.service_id = service_id; 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci return 0; 116662306a36Sopenharmony_ci} 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci/** 116962306a36Sopenharmony_ci * ib_cm_listen - Initiates listening on the specified service ID for 117062306a36Sopenharmony_ci * connection and service ID resolution requests. 117162306a36Sopenharmony_ci * @cm_id: Connection identifier associated with the listen request. 117262306a36Sopenharmony_ci * @service_id: Service identifier matched against incoming connection 117362306a36Sopenharmony_ci * and service ID resolution requests. The service ID should be specified 117462306a36Sopenharmony_ci * network-byte order. If set to IB_CM_ASSIGN_SERVICE_ID, the CM will 117562306a36Sopenharmony_ci * assign a service ID to the caller. 117662306a36Sopenharmony_ci */ 117762306a36Sopenharmony_ciint ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id) 117862306a36Sopenharmony_ci{ 117962306a36Sopenharmony_ci struct cm_id_private *cm_id_priv = 118062306a36Sopenharmony_ci container_of(cm_id, struct cm_id_private, id); 118162306a36Sopenharmony_ci unsigned long flags; 118262306a36Sopenharmony_ci int ret; 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci spin_lock_irqsave(&cm_id_priv->lock, flags); 118562306a36Sopenharmony_ci if (cm_id_priv->id.state != IB_CM_IDLE) { 118662306a36Sopenharmony_ci ret = -EINVAL; 118762306a36Sopenharmony_ci goto out; 118862306a36Sopenharmony_ci } 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci ret = cm_init_listen(cm_id_priv, service_id); 119162306a36Sopenharmony_ci if (ret) 119262306a36Sopenharmony_ci goto out; 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci if (!cm_insert_listen(cm_id_priv, NULL)) { 119562306a36Sopenharmony_ci ret = -EBUSY; 119662306a36Sopenharmony_ci goto out; 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci cm_id_priv->id.state = IB_CM_LISTEN; 120062306a36Sopenharmony_ci ret = 0; 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ciout: 120362306a36Sopenharmony_ci spin_unlock_irqrestore(&cm_id_priv->lock, flags); 120462306a36Sopenharmony_ci return ret; 120562306a36Sopenharmony_ci} 120662306a36Sopenharmony_ciEXPORT_SYMBOL(ib_cm_listen); 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci/** 120962306a36Sopenharmony_ci * ib_cm_insert_listen - Create a new listening ib_cm_id and listen on 121062306a36Sopenharmony_ci * the given service ID. 121162306a36Sopenharmony_ci * 121262306a36Sopenharmony_ci * If there's an existing ID listening on that same device and service ID, 121362306a36Sopenharmony_ci * return it. 121462306a36Sopenharmony_ci * 121562306a36Sopenharmony_ci * @device: Device associated with the cm_id. All related communication will 121662306a36Sopenharmony_ci * be associated with the specified device. 121762306a36Sopenharmony_ci * @cm_handler: Callback invoked to notify the user of CM events. 121862306a36Sopenharmony_ci * @service_id: Service identifier matched against incoming connection 121962306a36Sopenharmony_ci * and service ID resolution requests. The service ID should be specified 122062306a36Sopenharmony_ci * network-byte order. If set to IB_CM_ASSIGN_SERVICE_ID, the CM will 122162306a36Sopenharmony_ci * assign a service ID to the caller. 122262306a36Sopenharmony_ci * 122362306a36Sopenharmony_ci * Callers should call ib_destroy_cm_id when done with the listener ID. 122462306a36Sopenharmony_ci */ 122562306a36Sopenharmony_cistruct ib_cm_id *ib_cm_insert_listen(struct ib_device *device, 122662306a36Sopenharmony_ci ib_cm_handler cm_handler, 122762306a36Sopenharmony_ci __be64 service_id) 122862306a36Sopenharmony_ci{ 122962306a36Sopenharmony_ci struct cm_id_private *listen_id_priv; 123062306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 123162306a36Sopenharmony_ci int err = 0; 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci /* Create an ID in advance, since the creation may sleep */ 123462306a36Sopenharmony_ci cm_id_priv = cm_alloc_id_priv(device, cm_handler, NULL); 123562306a36Sopenharmony_ci if (IS_ERR(cm_id_priv)) 123662306a36Sopenharmony_ci return ERR_CAST(cm_id_priv); 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci err = cm_init_listen(cm_id_priv, service_id); 123962306a36Sopenharmony_ci if (err) { 124062306a36Sopenharmony_ci ib_destroy_cm_id(&cm_id_priv->id); 124162306a36Sopenharmony_ci return ERR_PTR(err); 124262306a36Sopenharmony_ci } 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci spin_lock_irq(&cm_id_priv->lock); 124562306a36Sopenharmony_ci listen_id_priv = cm_insert_listen(cm_id_priv, cm_handler); 124662306a36Sopenharmony_ci if (listen_id_priv != cm_id_priv) { 124762306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 124862306a36Sopenharmony_ci ib_destroy_cm_id(&cm_id_priv->id); 124962306a36Sopenharmony_ci if (!listen_id_priv) 125062306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 125162306a36Sopenharmony_ci return &listen_id_priv->id; 125262306a36Sopenharmony_ci } 125362306a36Sopenharmony_ci cm_id_priv->id.state = IB_CM_LISTEN; 125462306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci /* 125762306a36Sopenharmony_ci * A listen ID does not need to be in the xarray since it does not 125862306a36Sopenharmony_ci * receive mads, is not placed in the remote_id or remote_qpn rbtree, 125962306a36Sopenharmony_ci * and does not enter timewait. 126062306a36Sopenharmony_ci */ 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci return &cm_id_priv->id; 126362306a36Sopenharmony_ci} 126462306a36Sopenharmony_ciEXPORT_SYMBOL(ib_cm_insert_listen); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_cistatic __be64 cm_form_tid(struct cm_id_private *cm_id_priv) 126762306a36Sopenharmony_ci{ 126862306a36Sopenharmony_ci u64 hi_tid = 0, low_tid; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci lockdep_assert_held(&cm_id_priv->lock); 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci low_tid = (u64)cm_id_priv->id.local_id; 127362306a36Sopenharmony_ci if (!cm_id_priv->av.port) 127462306a36Sopenharmony_ci return cpu_to_be64(low_tid); 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci spin_lock(&cm_id_priv->av.port->cm_dev->mad_agent_lock); 127762306a36Sopenharmony_ci if (cm_id_priv->av.port->mad_agent) 127862306a36Sopenharmony_ci hi_tid = ((u64)cm_id_priv->av.port->mad_agent->hi_tid) << 32; 127962306a36Sopenharmony_ci spin_unlock(&cm_id_priv->av.port->cm_dev->mad_agent_lock); 128062306a36Sopenharmony_ci return cpu_to_be64(hi_tid | low_tid); 128162306a36Sopenharmony_ci} 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_cistatic void cm_format_mad_hdr(struct ib_mad_hdr *hdr, 128462306a36Sopenharmony_ci __be16 attr_id, __be64 tid) 128562306a36Sopenharmony_ci{ 128662306a36Sopenharmony_ci hdr->base_version = IB_MGMT_BASE_VERSION; 128762306a36Sopenharmony_ci hdr->mgmt_class = IB_MGMT_CLASS_CM; 128862306a36Sopenharmony_ci hdr->class_version = IB_CM_CLASS_VERSION; 128962306a36Sopenharmony_ci hdr->method = IB_MGMT_METHOD_SEND; 129062306a36Sopenharmony_ci hdr->attr_id = attr_id; 129162306a36Sopenharmony_ci hdr->tid = tid; 129262306a36Sopenharmony_ci} 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_cistatic void cm_format_mad_ece_hdr(struct ib_mad_hdr *hdr, __be16 attr_id, 129562306a36Sopenharmony_ci __be64 tid, u32 attr_mod) 129662306a36Sopenharmony_ci{ 129762306a36Sopenharmony_ci cm_format_mad_hdr(hdr, attr_id, tid); 129862306a36Sopenharmony_ci hdr->attr_mod = cpu_to_be32(attr_mod); 129962306a36Sopenharmony_ci} 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_cistatic void cm_format_req(struct cm_req_msg *req_msg, 130262306a36Sopenharmony_ci struct cm_id_private *cm_id_priv, 130362306a36Sopenharmony_ci struct ib_cm_req_param *param) 130462306a36Sopenharmony_ci{ 130562306a36Sopenharmony_ci struct sa_path_rec *pri_path = param->primary_path; 130662306a36Sopenharmony_ci struct sa_path_rec *alt_path = param->alternate_path; 130762306a36Sopenharmony_ci bool pri_ext = false; 130862306a36Sopenharmony_ci __be16 lid; 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci if (pri_path->rec_type == SA_PATH_REC_TYPE_OPA) 131162306a36Sopenharmony_ci pri_ext = opa_is_extended_lid(pri_path->opa.dlid, 131262306a36Sopenharmony_ci pri_path->opa.slid); 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci cm_format_mad_ece_hdr(&req_msg->hdr, CM_REQ_ATTR_ID, 131562306a36Sopenharmony_ci cm_form_tid(cm_id_priv), param->ece.attr_mod); 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci IBA_SET(CM_REQ_LOCAL_COMM_ID, req_msg, 131862306a36Sopenharmony_ci be32_to_cpu(cm_id_priv->id.local_id)); 131962306a36Sopenharmony_ci IBA_SET(CM_REQ_SERVICE_ID, req_msg, be64_to_cpu(param->service_id)); 132062306a36Sopenharmony_ci IBA_SET(CM_REQ_LOCAL_CA_GUID, req_msg, 132162306a36Sopenharmony_ci be64_to_cpu(cm_id_priv->id.device->node_guid)); 132262306a36Sopenharmony_ci IBA_SET(CM_REQ_LOCAL_QPN, req_msg, param->qp_num); 132362306a36Sopenharmony_ci IBA_SET(CM_REQ_INITIATOR_DEPTH, req_msg, param->initiator_depth); 132462306a36Sopenharmony_ci IBA_SET(CM_REQ_REMOTE_CM_RESPONSE_TIMEOUT, req_msg, 132562306a36Sopenharmony_ci param->remote_cm_response_timeout); 132662306a36Sopenharmony_ci cm_req_set_qp_type(req_msg, param->qp_type); 132762306a36Sopenharmony_ci IBA_SET(CM_REQ_END_TO_END_FLOW_CONTROL, req_msg, param->flow_control); 132862306a36Sopenharmony_ci IBA_SET(CM_REQ_STARTING_PSN, req_msg, param->starting_psn); 132962306a36Sopenharmony_ci IBA_SET(CM_REQ_LOCAL_CM_RESPONSE_TIMEOUT, req_msg, 133062306a36Sopenharmony_ci param->local_cm_response_timeout); 133162306a36Sopenharmony_ci IBA_SET(CM_REQ_PARTITION_KEY, req_msg, 133262306a36Sopenharmony_ci be16_to_cpu(param->primary_path->pkey)); 133362306a36Sopenharmony_ci IBA_SET(CM_REQ_PATH_PACKET_PAYLOAD_MTU, req_msg, 133462306a36Sopenharmony_ci param->primary_path->mtu); 133562306a36Sopenharmony_ci IBA_SET(CM_REQ_MAX_CM_RETRIES, req_msg, param->max_cm_retries); 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci if (param->qp_type != IB_QPT_XRC_INI) { 133862306a36Sopenharmony_ci IBA_SET(CM_REQ_RESPONDER_RESOURCES, req_msg, 133962306a36Sopenharmony_ci param->responder_resources); 134062306a36Sopenharmony_ci IBA_SET(CM_REQ_RETRY_COUNT, req_msg, param->retry_count); 134162306a36Sopenharmony_ci IBA_SET(CM_REQ_RNR_RETRY_COUNT, req_msg, 134262306a36Sopenharmony_ci param->rnr_retry_count); 134362306a36Sopenharmony_ci IBA_SET(CM_REQ_SRQ, req_msg, param->srq); 134462306a36Sopenharmony_ci } 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci *IBA_GET_MEM_PTR(CM_REQ_PRIMARY_LOCAL_PORT_GID, req_msg) = 134762306a36Sopenharmony_ci pri_path->sgid; 134862306a36Sopenharmony_ci *IBA_GET_MEM_PTR(CM_REQ_PRIMARY_REMOTE_PORT_GID, req_msg) = 134962306a36Sopenharmony_ci pri_path->dgid; 135062306a36Sopenharmony_ci if (pri_ext) { 135162306a36Sopenharmony_ci IBA_GET_MEM_PTR(CM_REQ_PRIMARY_LOCAL_PORT_GID, req_msg) 135262306a36Sopenharmony_ci ->global.interface_id = 135362306a36Sopenharmony_ci OPA_MAKE_ID(be32_to_cpu(pri_path->opa.slid)); 135462306a36Sopenharmony_ci IBA_GET_MEM_PTR(CM_REQ_PRIMARY_REMOTE_PORT_GID, req_msg) 135562306a36Sopenharmony_ci ->global.interface_id = 135662306a36Sopenharmony_ci OPA_MAKE_ID(be32_to_cpu(pri_path->opa.dlid)); 135762306a36Sopenharmony_ci } 135862306a36Sopenharmony_ci if (pri_path->hop_limit <= 1) { 135962306a36Sopenharmony_ci IBA_SET(CM_REQ_PRIMARY_LOCAL_PORT_LID, req_msg, 136062306a36Sopenharmony_ci be16_to_cpu(pri_ext ? 0 : 136162306a36Sopenharmony_ci htons(ntohl(sa_path_get_slid( 136262306a36Sopenharmony_ci pri_path))))); 136362306a36Sopenharmony_ci IBA_SET(CM_REQ_PRIMARY_REMOTE_PORT_LID, req_msg, 136462306a36Sopenharmony_ci be16_to_cpu(pri_ext ? 0 : 136562306a36Sopenharmony_ci htons(ntohl(sa_path_get_dlid( 136662306a36Sopenharmony_ci pri_path))))); 136762306a36Sopenharmony_ci } else { 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci if (param->primary_path_inbound) { 137062306a36Sopenharmony_ci lid = param->primary_path_inbound->ib.dlid; 137162306a36Sopenharmony_ci IBA_SET(CM_REQ_PRIMARY_LOCAL_PORT_LID, req_msg, 137262306a36Sopenharmony_ci be16_to_cpu(lid)); 137362306a36Sopenharmony_ci } else 137462306a36Sopenharmony_ci IBA_SET(CM_REQ_PRIMARY_LOCAL_PORT_LID, req_msg, 137562306a36Sopenharmony_ci be16_to_cpu(IB_LID_PERMISSIVE)); 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci /* Work-around until there's a way to obtain remote LID info */ 137862306a36Sopenharmony_ci IBA_SET(CM_REQ_PRIMARY_REMOTE_PORT_LID, req_msg, 137962306a36Sopenharmony_ci be16_to_cpu(IB_LID_PERMISSIVE)); 138062306a36Sopenharmony_ci } 138162306a36Sopenharmony_ci IBA_SET(CM_REQ_PRIMARY_FLOW_LABEL, req_msg, 138262306a36Sopenharmony_ci be32_to_cpu(pri_path->flow_label)); 138362306a36Sopenharmony_ci IBA_SET(CM_REQ_PRIMARY_PACKET_RATE, req_msg, pri_path->rate); 138462306a36Sopenharmony_ci IBA_SET(CM_REQ_PRIMARY_TRAFFIC_CLASS, req_msg, pri_path->traffic_class); 138562306a36Sopenharmony_ci IBA_SET(CM_REQ_PRIMARY_HOP_LIMIT, req_msg, pri_path->hop_limit); 138662306a36Sopenharmony_ci IBA_SET(CM_REQ_PRIMARY_SL, req_msg, pri_path->sl); 138762306a36Sopenharmony_ci IBA_SET(CM_REQ_PRIMARY_SUBNET_LOCAL, req_msg, 138862306a36Sopenharmony_ci (pri_path->hop_limit <= 1)); 138962306a36Sopenharmony_ci IBA_SET(CM_REQ_PRIMARY_LOCAL_ACK_TIMEOUT, req_msg, 139062306a36Sopenharmony_ci cm_ack_timeout(cm_id_priv->av.port->cm_dev->ack_delay, 139162306a36Sopenharmony_ci pri_path->packet_life_time)); 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci if (alt_path) { 139462306a36Sopenharmony_ci bool alt_ext = false; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci if (alt_path->rec_type == SA_PATH_REC_TYPE_OPA) 139762306a36Sopenharmony_ci alt_ext = opa_is_extended_lid(alt_path->opa.dlid, 139862306a36Sopenharmony_ci alt_path->opa.slid); 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci *IBA_GET_MEM_PTR(CM_REQ_ALTERNATE_LOCAL_PORT_GID, req_msg) = 140162306a36Sopenharmony_ci alt_path->sgid; 140262306a36Sopenharmony_ci *IBA_GET_MEM_PTR(CM_REQ_ALTERNATE_REMOTE_PORT_GID, req_msg) = 140362306a36Sopenharmony_ci alt_path->dgid; 140462306a36Sopenharmony_ci if (alt_ext) { 140562306a36Sopenharmony_ci IBA_GET_MEM_PTR(CM_REQ_ALTERNATE_LOCAL_PORT_GID, 140662306a36Sopenharmony_ci req_msg) 140762306a36Sopenharmony_ci ->global.interface_id = 140862306a36Sopenharmony_ci OPA_MAKE_ID(be32_to_cpu(alt_path->opa.slid)); 140962306a36Sopenharmony_ci IBA_GET_MEM_PTR(CM_REQ_ALTERNATE_REMOTE_PORT_GID, 141062306a36Sopenharmony_ci req_msg) 141162306a36Sopenharmony_ci ->global.interface_id = 141262306a36Sopenharmony_ci OPA_MAKE_ID(be32_to_cpu(alt_path->opa.dlid)); 141362306a36Sopenharmony_ci } 141462306a36Sopenharmony_ci if (alt_path->hop_limit <= 1) { 141562306a36Sopenharmony_ci IBA_SET(CM_REQ_ALTERNATE_LOCAL_PORT_LID, req_msg, 141662306a36Sopenharmony_ci be16_to_cpu( 141762306a36Sopenharmony_ci alt_ext ? 0 : 141862306a36Sopenharmony_ci htons(ntohl(sa_path_get_slid( 141962306a36Sopenharmony_ci alt_path))))); 142062306a36Sopenharmony_ci IBA_SET(CM_REQ_ALTERNATE_REMOTE_PORT_LID, req_msg, 142162306a36Sopenharmony_ci be16_to_cpu( 142262306a36Sopenharmony_ci alt_ext ? 0 : 142362306a36Sopenharmony_ci htons(ntohl(sa_path_get_dlid( 142462306a36Sopenharmony_ci alt_path))))); 142562306a36Sopenharmony_ci } else { 142662306a36Sopenharmony_ci IBA_SET(CM_REQ_ALTERNATE_LOCAL_PORT_LID, req_msg, 142762306a36Sopenharmony_ci be16_to_cpu(IB_LID_PERMISSIVE)); 142862306a36Sopenharmony_ci IBA_SET(CM_REQ_ALTERNATE_REMOTE_PORT_LID, req_msg, 142962306a36Sopenharmony_ci be16_to_cpu(IB_LID_PERMISSIVE)); 143062306a36Sopenharmony_ci } 143162306a36Sopenharmony_ci IBA_SET(CM_REQ_ALTERNATE_FLOW_LABEL, req_msg, 143262306a36Sopenharmony_ci be32_to_cpu(alt_path->flow_label)); 143362306a36Sopenharmony_ci IBA_SET(CM_REQ_ALTERNATE_PACKET_RATE, req_msg, alt_path->rate); 143462306a36Sopenharmony_ci IBA_SET(CM_REQ_ALTERNATE_TRAFFIC_CLASS, req_msg, 143562306a36Sopenharmony_ci alt_path->traffic_class); 143662306a36Sopenharmony_ci IBA_SET(CM_REQ_ALTERNATE_HOP_LIMIT, req_msg, 143762306a36Sopenharmony_ci alt_path->hop_limit); 143862306a36Sopenharmony_ci IBA_SET(CM_REQ_ALTERNATE_SL, req_msg, alt_path->sl); 143962306a36Sopenharmony_ci IBA_SET(CM_REQ_ALTERNATE_SUBNET_LOCAL, req_msg, 144062306a36Sopenharmony_ci (alt_path->hop_limit <= 1)); 144162306a36Sopenharmony_ci IBA_SET(CM_REQ_ALTERNATE_LOCAL_ACK_TIMEOUT, req_msg, 144262306a36Sopenharmony_ci cm_ack_timeout(cm_id_priv->av.port->cm_dev->ack_delay, 144362306a36Sopenharmony_ci alt_path->packet_life_time)); 144462306a36Sopenharmony_ci } 144562306a36Sopenharmony_ci IBA_SET(CM_REQ_VENDOR_ID, req_msg, param->ece.vendor_id); 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci if (param->private_data && param->private_data_len) 144862306a36Sopenharmony_ci IBA_SET_MEM(CM_REQ_PRIVATE_DATA, req_msg, param->private_data, 144962306a36Sopenharmony_ci param->private_data_len); 145062306a36Sopenharmony_ci} 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_cistatic int cm_validate_req_param(struct ib_cm_req_param *param) 145362306a36Sopenharmony_ci{ 145462306a36Sopenharmony_ci if (!param->primary_path) 145562306a36Sopenharmony_ci return -EINVAL; 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci if (param->qp_type != IB_QPT_RC && param->qp_type != IB_QPT_UC && 145862306a36Sopenharmony_ci param->qp_type != IB_QPT_XRC_INI) 145962306a36Sopenharmony_ci return -EINVAL; 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci if (param->private_data && 146262306a36Sopenharmony_ci param->private_data_len > IB_CM_REQ_PRIVATE_DATA_SIZE) 146362306a36Sopenharmony_ci return -EINVAL; 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci if (param->alternate_path && 146662306a36Sopenharmony_ci (param->alternate_path->pkey != param->primary_path->pkey || 146762306a36Sopenharmony_ci param->alternate_path->mtu != param->primary_path->mtu)) 146862306a36Sopenharmony_ci return -EINVAL; 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci return 0; 147162306a36Sopenharmony_ci} 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ciint ib_send_cm_req(struct ib_cm_id *cm_id, 147462306a36Sopenharmony_ci struct ib_cm_req_param *param) 147562306a36Sopenharmony_ci{ 147662306a36Sopenharmony_ci struct cm_av av = {}, alt_av = {}; 147762306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 147862306a36Sopenharmony_ci struct ib_mad_send_buf *msg; 147962306a36Sopenharmony_ci struct cm_req_msg *req_msg; 148062306a36Sopenharmony_ci unsigned long flags; 148162306a36Sopenharmony_ci int ret; 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci ret = cm_validate_req_param(param); 148462306a36Sopenharmony_ci if (ret) 148562306a36Sopenharmony_ci return ret; 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci /* Verify that we're not in timewait. */ 148862306a36Sopenharmony_ci cm_id_priv = container_of(cm_id, struct cm_id_private, id); 148962306a36Sopenharmony_ci spin_lock_irqsave(&cm_id_priv->lock, flags); 149062306a36Sopenharmony_ci if (cm_id->state != IB_CM_IDLE || WARN_ON(cm_id_priv->timewait_info)) { 149162306a36Sopenharmony_ci spin_unlock_irqrestore(&cm_id_priv->lock, flags); 149262306a36Sopenharmony_ci return -EINVAL; 149362306a36Sopenharmony_ci } 149462306a36Sopenharmony_ci spin_unlock_irqrestore(&cm_id_priv->lock, flags); 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci cm_id_priv->timewait_info = cm_create_timewait_info(cm_id_priv-> 149762306a36Sopenharmony_ci id.local_id); 149862306a36Sopenharmony_ci if (IS_ERR(cm_id_priv->timewait_info)) { 149962306a36Sopenharmony_ci ret = PTR_ERR(cm_id_priv->timewait_info); 150062306a36Sopenharmony_ci cm_id_priv->timewait_info = NULL; 150162306a36Sopenharmony_ci return ret; 150262306a36Sopenharmony_ci } 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci ret = cm_init_av_by_path(param->primary_path, 150562306a36Sopenharmony_ci param->ppath_sgid_attr, &av); 150662306a36Sopenharmony_ci if (ret) 150762306a36Sopenharmony_ci return ret; 150862306a36Sopenharmony_ci if (param->alternate_path) { 150962306a36Sopenharmony_ci ret = cm_init_av_by_path(param->alternate_path, NULL, 151062306a36Sopenharmony_ci &alt_av); 151162306a36Sopenharmony_ci if (ret) { 151262306a36Sopenharmony_ci cm_destroy_av(&av); 151362306a36Sopenharmony_ci return ret; 151462306a36Sopenharmony_ci } 151562306a36Sopenharmony_ci } 151662306a36Sopenharmony_ci cm_id->service_id = param->service_id; 151762306a36Sopenharmony_ci cm_id_priv->timeout_ms = cm_convert_to_ms( 151862306a36Sopenharmony_ci param->primary_path->packet_life_time) * 2 + 151962306a36Sopenharmony_ci cm_convert_to_ms( 152062306a36Sopenharmony_ci param->remote_cm_response_timeout); 152162306a36Sopenharmony_ci cm_id_priv->max_cm_retries = param->max_cm_retries; 152262306a36Sopenharmony_ci cm_id_priv->initiator_depth = param->initiator_depth; 152362306a36Sopenharmony_ci cm_id_priv->responder_resources = param->responder_resources; 152462306a36Sopenharmony_ci cm_id_priv->retry_count = param->retry_count; 152562306a36Sopenharmony_ci cm_id_priv->path_mtu = param->primary_path->mtu; 152662306a36Sopenharmony_ci cm_id_priv->pkey = param->primary_path->pkey; 152762306a36Sopenharmony_ci cm_id_priv->qp_type = param->qp_type; 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci spin_lock_irqsave(&cm_id_priv->lock, flags); 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci cm_move_av_from_path(&cm_id_priv->av, &av); 153262306a36Sopenharmony_ci if (param->primary_path_outbound) 153362306a36Sopenharmony_ci cm_id_priv->av.dlid_datapath = 153462306a36Sopenharmony_ci be16_to_cpu(param->primary_path_outbound->ib.dlid); 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci if (param->alternate_path) 153762306a36Sopenharmony_ci cm_move_av_from_path(&cm_id_priv->alt_av, &alt_av); 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci msg = cm_alloc_priv_msg(cm_id_priv); 154062306a36Sopenharmony_ci if (IS_ERR(msg)) { 154162306a36Sopenharmony_ci ret = PTR_ERR(msg); 154262306a36Sopenharmony_ci goto out_unlock; 154362306a36Sopenharmony_ci } 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci req_msg = (struct cm_req_msg *)msg->mad; 154662306a36Sopenharmony_ci cm_format_req(req_msg, cm_id_priv, param); 154762306a36Sopenharmony_ci cm_id_priv->tid = req_msg->hdr.tid; 154862306a36Sopenharmony_ci msg->timeout_ms = cm_id_priv->timeout_ms; 154962306a36Sopenharmony_ci msg->context[1] = (void *)(unsigned long)IB_CM_REQ_SENT; 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci cm_id_priv->local_qpn = cpu_to_be32(IBA_GET(CM_REQ_LOCAL_QPN, req_msg)); 155262306a36Sopenharmony_ci cm_id_priv->rq_psn = cpu_to_be32(IBA_GET(CM_REQ_STARTING_PSN, req_msg)); 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci trace_icm_send_req(&cm_id_priv->id); 155562306a36Sopenharmony_ci ret = ib_post_send_mad(msg, NULL); 155662306a36Sopenharmony_ci if (ret) 155762306a36Sopenharmony_ci goto out_free; 155862306a36Sopenharmony_ci BUG_ON(cm_id->state != IB_CM_IDLE); 155962306a36Sopenharmony_ci cm_id->state = IB_CM_REQ_SENT; 156062306a36Sopenharmony_ci spin_unlock_irqrestore(&cm_id_priv->lock, flags); 156162306a36Sopenharmony_ci return 0; 156262306a36Sopenharmony_ciout_free: 156362306a36Sopenharmony_ci cm_free_priv_msg(msg); 156462306a36Sopenharmony_ciout_unlock: 156562306a36Sopenharmony_ci spin_unlock_irqrestore(&cm_id_priv->lock, flags); 156662306a36Sopenharmony_ci return ret; 156762306a36Sopenharmony_ci} 156862306a36Sopenharmony_ciEXPORT_SYMBOL(ib_send_cm_req); 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_cistatic int cm_issue_rej(struct cm_port *port, 157162306a36Sopenharmony_ci struct ib_mad_recv_wc *mad_recv_wc, 157262306a36Sopenharmony_ci enum ib_cm_rej_reason reason, 157362306a36Sopenharmony_ci enum cm_msg_response msg_rejected, 157462306a36Sopenharmony_ci void *ari, u8 ari_length) 157562306a36Sopenharmony_ci{ 157662306a36Sopenharmony_ci struct ib_mad_send_buf *msg = NULL; 157762306a36Sopenharmony_ci struct cm_rej_msg *rej_msg, *rcv_msg; 157862306a36Sopenharmony_ci int ret; 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci ret = cm_alloc_response_msg(port, mad_recv_wc, &msg); 158162306a36Sopenharmony_ci if (ret) 158262306a36Sopenharmony_ci return ret; 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci /* We just need common CM header information. Cast to any message. */ 158562306a36Sopenharmony_ci rcv_msg = (struct cm_rej_msg *) mad_recv_wc->recv_buf.mad; 158662306a36Sopenharmony_ci rej_msg = (struct cm_rej_msg *) msg->mad; 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci cm_format_mad_hdr(&rej_msg->hdr, CM_REJ_ATTR_ID, rcv_msg->hdr.tid); 158962306a36Sopenharmony_ci IBA_SET(CM_REJ_REMOTE_COMM_ID, rej_msg, 159062306a36Sopenharmony_ci IBA_GET(CM_REJ_LOCAL_COMM_ID, rcv_msg)); 159162306a36Sopenharmony_ci IBA_SET(CM_REJ_LOCAL_COMM_ID, rej_msg, 159262306a36Sopenharmony_ci IBA_GET(CM_REJ_REMOTE_COMM_ID, rcv_msg)); 159362306a36Sopenharmony_ci IBA_SET(CM_REJ_MESSAGE_REJECTED, rej_msg, msg_rejected); 159462306a36Sopenharmony_ci IBA_SET(CM_REJ_REASON, rej_msg, reason); 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci if (ari && ari_length) { 159762306a36Sopenharmony_ci IBA_SET(CM_REJ_REJECTED_INFO_LENGTH, rej_msg, ari_length); 159862306a36Sopenharmony_ci IBA_SET_MEM(CM_REJ_ARI, rej_msg, ari, ari_length); 159962306a36Sopenharmony_ci } 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci trace_icm_issue_rej( 160262306a36Sopenharmony_ci IBA_GET(CM_REJ_LOCAL_COMM_ID, rcv_msg), 160362306a36Sopenharmony_ci IBA_GET(CM_REJ_REMOTE_COMM_ID, rcv_msg)); 160462306a36Sopenharmony_ci ret = ib_post_send_mad(msg, NULL); 160562306a36Sopenharmony_ci if (ret) 160662306a36Sopenharmony_ci cm_free_response_msg(msg); 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci return ret; 160962306a36Sopenharmony_ci} 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_cistatic bool cm_req_has_alt_path(struct cm_req_msg *req_msg) 161262306a36Sopenharmony_ci{ 161362306a36Sopenharmony_ci return ((cpu_to_be16( 161462306a36Sopenharmony_ci IBA_GET(CM_REQ_ALTERNATE_LOCAL_PORT_LID, req_msg))) || 161562306a36Sopenharmony_ci (ib_is_opa_gid(IBA_GET_MEM_PTR(CM_REQ_ALTERNATE_LOCAL_PORT_GID, 161662306a36Sopenharmony_ci req_msg)))); 161762306a36Sopenharmony_ci} 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_cistatic void cm_path_set_rec_type(struct ib_device *ib_device, u32 port_num, 162062306a36Sopenharmony_ci struct sa_path_rec *path, union ib_gid *gid) 162162306a36Sopenharmony_ci{ 162262306a36Sopenharmony_ci if (ib_is_opa_gid(gid) && rdma_cap_opa_ah(ib_device, port_num)) 162362306a36Sopenharmony_ci path->rec_type = SA_PATH_REC_TYPE_OPA; 162462306a36Sopenharmony_ci else 162562306a36Sopenharmony_ci path->rec_type = SA_PATH_REC_TYPE_IB; 162662306a36Sopenharmony_ci} 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_cistatic void cm_format_path_lid_from_req(struct cm_req_msg *req_msg, 162962306a36Sopenharmony_ci struct sa_path_rec *primary_path, 163062306a36Sopenharmony_ci struct sa_path_rec *alt_path, 163162306a36Sopenharmony_ci struct ib_wc *wc) 163262306a36Sopenharmony_ci{ 163362306a36Sopenharmony_ci u32 lid; 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci if (primary_path->rec_type != SA_PATH_REC_TYPE_OPA) { 163662306a36Sopenharmony_ci sa_path_set_dlid(primary_path, wc->slid); 163762306a36Sopenharmony_ci sa_path_set_slid(primary_path, 163862306a36Sopenharmony_ci IBA_GET(CM_REQ_PRIMARY_REMOTE_PORT_LID, 163962306a36Sopenharmony_ci req_msg)); 164062306a36Sopenharmony_ci } else { 164162306a36Sopenharmony_ci lid = opa_get_lid_from_gid(IBA_GET_MEM_PTR( 164262306a36Sopenharmony_ci CM_REQ_PRIMARY_LOCAL_PORT_GID, req_msg)); 164362306a36Sopenharmony_ci sa_path_set_dlid(primary_path, lid); 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci lid = opa_get_lid_from_gid(IBA_GET_MEM_PTR( 164662306a36Sopenharmony_ci CM_REQ_PRIMARY_REMOTE_PORT_GID, req_msg)); 164762306a36Sopenharmony_ci sa_path_set_slid(primary_path, lid); 164862306a36Sopenharmony_ci } 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci if (!cm_req_has_alt_path(req_msg)) 165162306a36Sopenharmony_ci return; 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci if (alt_path->rec_type != SA_PATH_REC_TYPE_OPA) { 165462306a36Sopenharmony_ci sa_path_set_dlid(alt_path, 165562306a36Sopenharmony_ci IBA_GET(CM_REQ_ALTERNATE_LOCAL_PORT_LID, 165662306a36Sopenharmony_ci req_msg)); 165762306a36Sopenharmony_ci sa_path_set_slid(alt_path, 165862306a36Sopenharmony_ci IBA_GET(CM_REQ_ALTERNATE_REMOTE_PORT_LID, 165962306a36Sopenharmony_ci req_msg)); 166062306a36Sopenharmony_ci } else { 166162306a36Sopenharmony_ci lid = opa_get_lid_from_gid(IBA_GET_MEM_PTR( 166262306a36Sopenharmony_ci CM_REQ_ALTERNATE_LOCAL_PORT_GID, req_msg)); 166362306a36Sopenharmony_ci sa_path_set_dlid(alt_path, lid); 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci lid = opa_get_lid_from_gid(IBA_GET_MEM_PTR( 166662306a36Sopenharmony_ci CM_REQ_ALTERNATE_REMOTE_PORT_GID, req_msg)); 166762306a36Sopenharmony_ci sa_path_set_slid(alt_path, lid); 166862306a36Sopenharmony_ci } 166962306a36Sopenharmony_ci} 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_cistatic void cm_format_paths_from_req(struct cm_req_msg *req_msg, 167262306a36Sopenharmony_ci struct sa_path_rec *primary_path, 167362306a36Sopenharmony_ci struct sa_path_rec *alt_path, 167462306a36Sopenharmony_ci struct ib_wc *wc) 167562306a36Sopenharmony_ci{ 167662306a36Sopenharmony_ci primary_path->dgid = 167762306a36Sopenharmony_ci *IBA_GET_MEM_PTR(CM_REQ_PRIMARY_LOCAL_PORT_GID, req_msg); 167862306a36Sopenharmony_ci primary_path->sgid = 167962306a36Sopenharmony_ci *IBA_GET_MEM_PTR(CM_REQ_PRIMARY_REMOTE_PORT_GID, req_msg); 168062306a36Sopenharmony_ci primary_path->flow_label = 168162306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_REQ_PRIMARY_FLOW_LABEL, req_msg)); 168262306a36Sopenharmony_ci primary_path->hop_limit = IBA_GET(CM_REQ_PRIMARY_HOP_LIMIT, req_msg); 168362306a36Sopenharmony_ci primary_path->traffic_class = 168462306a36Sopenharmony_ci IBA_GET(CM_REQ_PRIMARY_TRAFFIC_CLASS, req_msg); 168562306a36Sopenharmony_ci primary_path->reversible = 1; 168662306a36Sopenharmony_ci primary_path->pkey = 168762306a36Sopenharmony_ci cpu_to_be16(IBA_GET(CM_REQ_PARTITION_KEY, req_msg)); 168862306a36Sopenharmony_ci primary_path->sl = IBA_GET(CM_REQ_PRIMARY_SL, req_msg); 168962306a36Sopenharmony_ci primary_path->mtu_selector = IB_SA_EQ; 169062306a36Sopenharmony_ci primary_path->mtu = IBA_GET(CM_REQ_PATH_PACKET_PAYLOAD_MTU, req_msg); 169162306a36Sopenharmony_ci primary_path->rate_selector = IB_SA_EQ; 169262306a36Sopenharmony_ci primary_path->rate = IBA_GET(CM_REQ_PRIMARY_PACKET_RATE, req_msg); 169362306a36Sopenharmony_ci primary_path->packet_life_time_selector = IB_SA_EQ; 169462306a36Sopenharmony_ci primary_path->packet_life_time = 169562306a36Sopenharmony_ci IBA_GET(CM_REQ_PRIMARY_LOCAL_ACK_TIMEOUT, req_msg); 169662306a36Sopenharmony_ci primary_path->packet_life_time -= (primary_path->packet_life_time > 0); 169762306a36Sopenharmony_ci primary_path->service_id = 169862306a36Sopenharmony_ci cpu_to_be64(IBA_GET(CM_REQ_SERVICE_ID, req_msg)); 169962306a36Sopenharmony_ci if (sa_path_is_roce(primary_path)) 170062306a36Sopenharmony_ci primary_path->roce.route_resolved = false; 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci if (cm_req_has_alt_path(req_msg)) { 170362306a36Sopenharmony_ci alt_path->dgid = *IBA_GET_MEM_PTR( 170462306a36Sopenharmony_ci CM_REQ_ALTERNATE_LOCAL_PORT_GID, req_msg); 170562306a36Sopenharmony_ci alt_path->sgid = *IBA_GET_MEM_PTR( 170662306a36Sopenharmony_ci CM_REQ_ALTERNATE_REMOTE_PORT_GID, req_msg); 170762306a36Sopenharmony_ci alt_path->flow_label = cpu_to_be32( 170862306a36Sopenharmony_ci IBA_GET(CM_REQ_ALTERNATE_FLOW_LABEL, req_msg)); 170962306a36Sopenharmony_ci alt_path->hop_limit = 171062306a36Sopenharmony_ci IBA_GET(CM_REQ_ALTERNATE_HOP_LIMIT, req_msg); 171162306a36Sopenharmony_ci alt_path->traffic_class = 171262306a36Sopenharmony_ci IBA_GET(CM_REQ_ALTERNATE_TRAFFIC_CLASS, req_msg); 171362306a36Sopenharmony_ci alt_path->reversible = 1; 171462306a36Sopenharmony_ci alt_path->pkey = 171562306a36Sopenharmony_ci cpu_to_be16(IBA_GET(CM_REQ_PARTITION_KEY, req_msg)); 171662306a36Sopenharmony_ci alt_path->sl = IBA_GET(CM_REQ_ALTERNATE_SL, req_msg); 171762306a36Sopenharmony_ci alt_path->mtu_selector = IB_SA_EQ; 171862306a36Sopenharmony_ci alt_path->mtu = 171962306a36Sopenharmony_ci IBA_GET(CM_REQ_PATH_PACKET_PAYLOAD_MTU, req_msg); 172062306a36Sopenharmony_ci alt_path->rate_selector = IB_SA_EQ; 172162306a36Sopenharmony_ci alt_path->rate = IBA_GET(CM_REQ_ALTERNATE_PACKET_RATE, req_msg); 172262306a36Sopenharmony_ci alt_path->packet_life_time_selector = IB_SA_EQ; 172362306a36Sopenharmony_ci alt_path->packet_life_time = 172462306a36Sopenharmony_ci IBA_GET(CM_REQ_ALTERNATE_LOCAL_ACK_TIMEOUT, req_msg); 172562306a36Sopenharmony_ci alt_path->packet_life_time -= (alt_path->packet_life_time > 0); 172662306a36Sopenharmony_ci alt_path->service_id = 172762306a36Sopenharmony_ci cpu_to_be64(IBA_GET(CM_REQ_SERVICE_ID, req_msg)); 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci if (sa_path_is_roce(alt_path)) 173062306a36Sopenharmony_ci alt_path->roce.route_resolved = false; 173162306a36Sopenharmony_ci } 173262306a36Sopenharmony_ci cm_format_path_lid_from_req(req_msg, primary_path, alt_path, wc); 173362306a36Sopenharmony_ci} 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_cistatic u16 cm_get_bth_pkey(struct cm_work *work) 173662306a36Sopenharmony_ci{ 173762306a36Sopenharmony_ci struct ib_device *ib_dev = work->port->cm_dev->ib_device; 173862306a36Sopenharmony_ci u32 port_num = work->port->port_num; 173962306a36Sopenharmony_ci u16 pkey_index = work->mad_recv_wc->wc->pkey_index; 174062306a36Sopenharmony_ci u16 pkey; 174162306a36Sopenharmony_ci int ret; 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci ret = ib_get_cached_pkey(ib_dev, port_num, pkey_index, &pkey); 174462306a36Sopenharmony_ci if (ret) { 174562306a36Sopenharmony_ci dev_warn_ratelimited(&ib_dev->dev, "ib_cm: Couldn't retrieve pkey for incoming request (port %u, pkey index %u). %d\n", 174662306a36Sopenharmony_ci port_num, pkey_index, ret); 174762306a36Sopenharmony_ci return 0; 174862306a36Sopenharmony_ci } 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci return pkey; 175162306a36Sopenharmony_ci} 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci/** 175462306a36Sopenharmony_ci * cm_opa_to_ib_sgid - Convert OPA SGID to IB SGID 175562306a36Sopenharmony_ci * ULPs (such as IPoIB) do not understand OPA GIDs and will 175662306a36Sopenharmony_ci * reject them as the local_gid will not match the sgid. Therefore, 175762306a36Sopenharmony_ci * change the pathrec's SGID to an IB SGID. 175862306a36Sopenharmony_ci * 175962306a36Sopenharmony_ci * @work: Work completion 176062306a36Sopenharmony_ci * @path: Path record 176162306a36Sopenharmony_ci */ 176262306a36Sopenharmony_cistatic void cm_opa_to_ib_sgid(struct cm_work *work, 176362306a36Sopenharmony_ci struct sa_path_rec *path) 176462306a36Sopenharmony_ci{ 176562306a36Sopenharmony_ci struct ib_device *dev = work->port->cm_dev->ib_device; 176662306a36Sopenharmony_ci u32 port_num = work->port->port_num; 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_ci if (rdma_cap_opa_ah(dev, port_num) && 176962306a36Sopenharmony_ci (ib_is_opa_gid(&path->sgid))) { 177062306a36Sopenharmony_ci union ib_gid sgid; 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci if (rdma_query_gid(dev, port_num, 0, &sgid)) { 177362306a36Sopenharmony_ci dev_warn(&dev->dev, 177462306a36Sopenharmony_ci "Error updating sgid in CM request\n"); 177562306a36Sopenharmony_ci return; 177662306a36Sopenharmony_ci } 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci path->sgid = sgid; 177962306a36Sopenharmony_ci } 178062306a36Sopenharmony_ci} 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_cistatic void cm_format_req_event(struct cm_work *work, 178362306a36Sopenharmony_ci struct cm_id_private *cm_id_priv, 178462306a36Sopenharmony_ci struct ib_cm_id *listen_id) 178562306a36Sopenharmony_ci{ 178662306a36Sopenharmony_ci struct cm_req_msg *req_msg; 178762306a36Sopenharmony_ci struct ib_cm_req_event_param *param; 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci req_msg = (struct cm_req_msg *)work->mad_recv_wc->recv_buf.mad; 179062306a36Sopenharmony_ci param = &work->cm_event.param.req_rcvd; 179162306a36Sopenharmony_ci param->listen_id = listen_id; 179262306a36Sopenharmony_ci param->bth_pkey = cm_get_bth_pkey(work); 179362306a36Sopenharmony_ci param->port = cm_id_priv->av.port->port_num; 179462306a36Sopenharmony_ci param->primary_path = &work->path[0]; 179562306a36Sopenharmony_ci cm_opa_to_ib_sgid(work, param->primary_path); 179662306a36Sopenharmony_ci if (cm_req_has_alt_path(req_msg)) { 179762306a36Sopenharmony_ci param->alternate_path = &work->path[1]; 179862306a36Sopenharmony_ci cm_opa_to_ib_sgid(work, param->alternate_path); 179962306a36Sopenharmony_ci } else { 180062306a36Sopenharmony_ci param->alternate_path = NULL; 180162306a36Sopenharmony_ci } 180262306a36Sopenharmony_ci param->remote_ca_guid = 180362306a36Sopenharmony_ci cpu_to_be64(IBA_GET(CM_REQ_LOCAL_CA_GUID, req_msg)); 180462306a36Sopenharmony_ci param->remote_qkey = IBA_GET(CM_REQ_LOCAL_Q_KEY, req_msg); 180562306a36Sopenharmony_ci param->remote_qpn = IBA_GET(CM_REQ_LOCAL_QPN, req_msg); 180662306a36Sopenharmony_ci param->qp_type = cm_req_get_qp_type(req_msg); 180762306a36Sopenharmony_ci param->starting_psn = IBA_GET(CM_REQ_STARTING_PSN, req_msg); 180862306a36Sopenharmony_ci param->responder_resources = IBA_GET(CM_REQ_INITIATOR_DEPTH, req_msg); 180962306a36Sopenharmony_ci param->initiator_depth = IBA_GET(CM_REQ_RESPONDER_RESOURCES, req_msg); 181062306a36Sopenharmony_ci param->local_cm_response_timeout = 181162306a36Sopenharmony_ci IBA_GET(CM_REQ_REMOTE_CM_RESPONSE_TIMEOUT, req_msg); 181262306a36Sopenharmony_ci param->flow_control = IBA_GET(CM_REQ_END_TO_END_FLOW_CONTROL, req_msg); 181362306a36Sopenharmony_ci param->remote_cm_response_timeout = 181462306a36Sopenharmony_ci IBA_GET(CM_REQ_LOCAL_CM_RESPONSE_TIMEOUT, req_msg); 181562306a36Sopenharmony_ci param->retry_count = IBA_GET(CM_REQ_RETRY_COUNT, req_msg); 181662306a36Sopenharmony_ci param->rnr_retry_count = IBA_GET(CM_REQ_RNR_RETRY_COUNT, req_msg); 181762306a36Sopenharmony_ci param->srq = IBA_GET(CM_REQ_SRQ, req_msg); 181862306a36Sopenharmony_ci param->ppath_sgid_attr = cm_id_priv->av.ah_attr.grh.sgid_attr; 181962306a36Sopenharmony_ci param->ece.vendor_id = IBA_GET(CM_REQ_VENDOR_ID, req_msg); 182062306a36Sopenharmony_ci param->ece.attr_mod = be32_to_cpu(req_msg->hdr.attr_mod); 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci work->cm_event.private_data = 182362306a36Sopenharmony_ci IBA_GET_MEM_PTR(CM_REQ_PRIVATE_DATA, req_msg); 182462306a36Sopenharmony_ci} 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_cistatic void cm_process_work(struct cm_id_private *cm_id_priv, 182762306a36Sopenharmony_ci struct cm_work *work) 182862306a36Sopenharmony_ci{ 182962306a36Sopenharmony_ci int ret; 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci /* We will typically only have the current event to report. */ 183262306a36Sopenharmony_ci ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, &work->cm_event); 183362306a36Sopenharmony_ci cm_free_work(work); 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci while (!ret && !atomic_add_negative(-1, &cm_id_priv->work_count)) { 183662306a36Sopenharmony_ci spin_lock_irq(&cm_id_priv->lock); 183762306a36Sopenharmony_ci work = cm_dequeue_work(cm_id_priv); 183862306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 183962306a36Sopenharmony_ci if (!work) 184062306a36Sopenharmony_ci return; 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, 184362306a36Sopenharmony_ci &work->cm_event); 184462306a36Sopenharmony_ci cm_free_work(work); 184562306a36Sopenharmony_ci } 184662306a36Sopenharmony_ci cm_deref_id(cm_id_priv); 184762306a36Sopenharmony_ci if (ret) 184862306a36Sopenharmony_ci cm_destroy_id(&cm_id_priv->id, ret); 184962306a36Sopenharmony_ci} 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_cistatic void cm_format_mra(struct cm_mra_msg *mra_msg, 185262306a36Sopenharmony_ci struct cm_id_private *cm_id_priv, 185362306a36Sopenharmony_ci enum cm_msg_response msg_mraed, u8 service_timeout, 185462306a36Sopenharmony_ci const void *private_data, u8 private_data_len) 185562306a36Sopenharmony_ci{ 185662306a36Sopenharmony_ci cm_format_mad_hdr(&mra_msg->hdr, CM_MRA_ATTR_ID, cm_id_priv->tid); 185762306a36Sopenharmony_ci IBA_SET(CM_MRA_MESSAGE_MRAED, mra_msg, msg_mraed); 185862306a36Sopenharmony_ci IBA_SET(CM_MRA_LOCAL_COMM_ID, mra_msg, 185962306a36Sopenharmony_ci be32_to_cpu(cm_id_priv->id.local_id)); 186062306a36Sopenharmony_ci IBA_SET(CM_MRA_REMOTE_COMM_ID, mra_msg, 186162306a36Sopenharmony_ci be32_to_cpu(cm_id_priv->id.remote_id)); 186262306a36Sopenharmony_ci IBA_SET(CM_MRA_SERVICE_TIMEOUT, mra_msg, service_timeout); 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci if (private_data && private_data_len) 186562306a36Sopenharmony_ci IBA_SET_MEM(CM_MRA_PRIVATE_DATA, mra_msg, private_data, 186662306a36Sopenharmony_ci private_data_len); 186762306a36Sopenharmony_ci} 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_cistatic void cm_format_rej(struct cm_rej_msg *rej_msg, 187062306a36Sopenharmony_ci struct cm_id_private *cm_id_priv, 187162306a36Sopenharmony_ci enum ib_cm_rej_reason reason, void *ari, 187262306a36Sopenharmony_ci u8 ari_length, const void *private_data, 187362306a36Sopenharmony_ci u8 private_data_len, enum ib_cm_state state) 187462306a36Sopenharmony_ci{ 187562306a36Sopenharmony_ci lockdep_assert_held(&cm_id_priv->lock); 187662306a36Sopenharmony_ci 187762306a36Sopenharmony_ci cm_format_mad_hdr(&rej_msg->hdr, CM_REJ_ATTR_ID, cm_id_priv->tid); 187862306a36Sopenharmony_ci IBA_SET(CM_REJ_REMOTE_COMM_ID, rej_msg, 187962306a36Sopenharmony_ci be32_to_cpu(cm_id_priv->id.remote_id)); 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci switch (state) { 188262306a36Sopenharmony_ci case IB_CM_REQ_RCVD: 188362306a36Sopenharmony_ci IBA_SET(CM_REJ_LOCAL_COMM_ID, rej_msg, be32_to_cpu(0)); 188462306a36Sopenharmony_ci IBA_SET(CM_REJ_MESSAGE_REJECTED, rej_msg, CM_MSG_RESPONSE_REQ); 188562306a36Sopenharmony_ci break; 188662306a36Sopenharmony_ci case IB_CM_MRA_REQ_SENT: 188762306a36Sopenharmony_ci IBA_SET(CM_REJ_LOCAL_COMM_ID, rej_msg, 188862306a36Sopenharmony_ci be32_to_cpu(cm_id_priv->id.local_id)); 188962306a36Sopenharmony_ci IBA_SET(CM_REJ_MESSAGE_REJECTED, rej_msg, CM_MSG_RESPONSE_REQ); 189062306a36Sopenharmony_ci break; 189162306a36Sopenharmony_ci case IB_CM_REP_RCVD: 189262306a36Sopenharmony_ci case IB_CM_MRA_REP_SENT: 189362306a36Sopenharmony_ci IBA_SET(CM_REJ_LOCAL_COMM_ID, rej_msg, 189462306a36Sopenharmony_ci be32_to_cpu(cm_id_priv->id.local_id)); 189562306a36Sopenharmony_ci IBA_SET(CM_REJ_MESSAGE_REJECTED, rej_msg, CM_MSG_RESPONSE_REP); 189662306a36Sopenharmony_ci break; 189762306a36Sopenharmony_ci default: 189862306a36Sopenharmony_ci IBA_SET(CM_REJ_LOCAL_COMM_ID, rej_msg, 189962306a36Sopenharmony_ci be32_to_cpu(cm_id_priv->id.local_id)); 190062306a36Sopenharmony_ci IBA_SET(CM_REJ_MESSAGE_REJECTED, rej_msg, 190162306a36Sopenharmony_ci CM_MSG_RESPONSE_OTHER); 190262306a36Sopenharmony_ci break; 190362306a36Sopenharmony_ci } 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci IBA_SET(CM_REJ_REASON, rej_msg, reason); 190662306a36Sopenharmony_ci if (ari && ari_length) { 190762306a36Sopenharmony_ci IBA_SET(CM_REJ_REJECTED_INFO_LENGTH, rej_msg, ari_length); 190862306a36Sopenharmony_ci IBA_SET_MEM(CM_REJ_ARI, rej_msg, ari, ari_length); 190962306a36Sopenharmony_ci } 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci if (private_data && private_data_len) 191262306a36Sopenharmony_ci IBA_SET_MEM(CM_REJ_PRIVATE_DATA, rej_msg, private_data, 191362306a36Sopenharmony_ci private_data_len); 191462306a36Sopenharmony_ci} 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_cistatic void cm_dup_req_handler(struct cm_work *work, 191762306a36Sopenharmony_ci struct cm_id_private *cm_id_priv) 191862306a36Sopenharmony_ci{ 191962306a36Sopenharmony_ci struct ib_mad_send_buf *msg = NULL; 192062306a36Sopenharmony_ci int ret; 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_ci atomic_long_inc( 192362306a36Sopenharmony_ci &work->port->counters[CM_RECV_DUPLICATES][CM_REQ_COUNTER]); 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_ci /* Quick state check to discard duplicate REQs. */ 192662306a36Sopenharmony_ci spin_lock_irq(&cm_id_priv->lock); 192762306a36Sopenharmony_ci if (cm_id_priv->id.state == IB_CM_REQ_RCVD) { 192862306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 192962306a36Sopenharmony_ci return; 193062306a36Sopenharmony_ci } 193162306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 193262306a36Sopenharmony_ci 193362306a36Sopenharmony_ci ret = cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg); 193462306a36Sopenharmony_ci if (ret) 193562306a36Sopenharmony_ci return; 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci spin_lock_irq(&cm_id_priv->lock); 193862306a36Sopenharmony_ci switch (cm_id_priv->id.state) { 193962306a36Sopenharmony_ci case IB_CM_MRA_REQ_SENT: 194062306a36Sopenharmony_ci cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, 194162306a36Sopenharmony_ci CM_MSG_RESPONSE_REQ, cm_id_priv->service_timeout, 194262306a36Sopenharmony_ci cm_id_priv->private_data, 194362306a36Sopenharmony_ci cm_id_priv->private_data_len); 194462306a36Sopenharmony_ci break; 194562306a36Sopenharmony_ci case IB_CM_TIMEWAIT: 194662306a36Sopenharmony_ci cm_format_rej((struct cm_rej_msg *)msg->mad, cm_id_priv, 194762306a36Sopenharmony_ci IB_CM_REJ_STALE_CONN, NULL, 0, NULL, 0, 194862306a36Sopenharmony_ci IB_CM_TIMEWAIT); 194962306a36Sopenharmony_ci break; 195062306a36Sopenharmony_ci default: 195162306a36Sopenharmony_ci goto unlock; 195262306a36Sopenharmony_ci } 195362306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_ci trace_icm_send_dup_req(&cm_id_priv->id); 195662306a36Sopenharmony_ci ret = ib_post_send_mad(msg, NULL); 195762306a36Sopenharmony_ci if (ret) 195862306a36Sopenharmony_ci goto free; 195962306a36Sopenharmony_ci return; 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ciunlock: spin_unlock_irq(&cm_id_priv->lock); 196262306a36Sopenharmony_cifree: cm_free_response_msg(msg); 196362306a36Sopenharmony_ci} 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_cistatic struct cm_id_private *cm_match_req(struct cm_work *work, 196662306a36Sopenharmony_ci struct cm_id_private *cm_id_priv) 196762306a36Sopenharmony_ci{ 196862306a36Sopenharmony_ci struct cm_id_private *listen_cm_id_priv, *cur_cm_id_priv; 196962306a36Sopenharmony_ci struct cm_timewait_info *timewait_info; 197062306a36Sopenharmony_ci struct cm_req_msg *req_msg; 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci req_msg = (struct cm_req_msg *)work->mad_recv_wc->recv_buf.mad; 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_ci /* Check for possible duplicate REQ. */ 197562306a36Sopenharmony_ci spin_lock_irq(&cm.lock); 197662306a36Sopenharmony_ci timewait_info = cm_insert_remote_id(cm_id_priv->timewait_info); 197762306a36Sopenharmony_ci if (timewait_info) { 197862306a36Sopenharmony_ci cur_cm_id_priv = cm_acquire_id(timewait_info->work.local_id, 197962306a36Sopenharmony_ci timewait_info->work.remote_id); 198062306a36Sopenharmony_ci spin_unlock_irq(&cm.lock); 198162306a36Sopenharmony_ci if (cur_cm_id_priv) { 198262306a36Sopenharmony_ci cm_dup_req_handler(work, cur_cm_id_priv); 198362306a36Sopenharmony_ci cm_deref_id(cur_cm_id_priv); 198462306a36Sopenharmony_ci } 198562306a36Sopenharmony_ci return NULL; 198662306a36Sopenharmony_ci } 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_ci /* Check for stale connections. */ 198962306a36Sopenharmony_ci timewait_info = cm_insert_remote_qpn(cm_id_priv->timewait_info); 199062306a36Sopenharmony_ci if (timewait_info) { 199162306a36Sopenharmony_ci cm_remove_remote(cm_id_priv); 199262306a36Sopenharmony_ci cur_cm_id_priv = cm_acquire_id(timewait_info->work.local_id, 199362306a36Sopenharmony_ci timewait_info->work.remote_id); 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_ci spin_unlock_irq(&cm.lock); 199662306a36Sopenharmony_ci cm_issue_rej(work->port, work->mad_recv_wc, 199762306a36Sopenharmony_ci IB_CM_REJ_STALE_CONN, CM_MSG_RESPONSE_REQ, 199862306a36Sopenharmony_ci NULL, 0); 199962306a36Sopenharmony_ci if (cur_cm_id_priv) { 200062306a36Sopenharmony_ci ib_send_cm_dreq(&cur_cm_id_priv->id, NULL, 0); 200162306a36Sopenharmony_ci cm_deref_id(cur_cm_id_priv); 200262306a36Sopenharmony_ci } 200362306a36Sopenharmony_ci return NULL; 200462306a36Sopenharmony_ci } 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci /* Find matching listen request. */ 200762306a36Sopenharmony_ci listen_cm_id_priv = cm_find_listen( 200862306a36Sopenharmony_ci cm_id_priv->id.device, 200962306a36Sopenharmony_ci cpu_to_be64(IBA_GET(CM_REQ_SERVICE_ID, req_msg))); 201062306a36Sopenharmony_ci if (!listen_cm_id_priv) { 201162306a36Sopenharmony_ci cm_remove_remote(cm_id_priv); 201262306a36Sopenharmony_ci spin_unlock_irq(&cm.lock); 201362306a36Sopenharmony_ci cm_issue_rej(work->port, work->mad_recv_wc, 201462306a36Sopenharmony_ci IB_CM_REJ_INVALID_SERVICE_ID, CM_MSG_RESPONSE_REQ, 201562306a36Sopenharmony_ci NULL, 0); 201662306a36Sopenharmony_ci return NULL; 201762306a36Sopenharmony_ci } 201862306a36Sopenharmony_ci spin_unlock_irq(&cm.lock); 201962306a36Sopenharmony_ci return listen_cm_id_priv; 202062306a36Sopenharmony_ci} 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci/* 202362306a36Sopenharmony_ci * Work-around for inter-subnet connections. If the LIDs are permissive, 202462306a36Sopenharmony_ci * we need to override the LID/SL data in the REQ with the LID information 202562306a36Sopenharmony_ci * in the work completion. 202662306a36Sopenharmony_ci */ 202762306a36Sopenharmony_cistatic void cm_process_routed_req(struct cm_req_msg *req_msg, struct ib_wc *wc) 202862306a36Sopenharmony_ci{ 202962306a36Sopenharmony_ci if (!IBA_GET(CM_REQ_PRIMARY_SUBNET_LOCAL, req_msg)) { 203062306a36Sopenharmony_ci if (cpu_to_be16(IBA_GET(CM_REQ_PRIMARY_LOCAL_PORT_LID, 203162306a36Sopenharmony_ci req_msg)) == IB_LID_PERMISSIVE) { 203262306a36Sopenharmony_ci IBA_SET(CM_REQ_PRIMARY_LOCAL_PORT_LID, req_msg, 203362306a36Sopenharmony_ci be16_to_cpu(ib_lid_be16(wc->slid))); 203462306a36Sopenharmony_ci IBA_SET(CM_REQ_PRIMARY_SL, req_msg, wc->sl); 203562306a36Sopenharmony_ci } 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci if (cpu_to_be16(IBA_GET(CM_REQ_PRIMARY_REMOTE_PORT_LID, 203862306a36Sopenharmony_ci req_msg)) == IB_LID_PERMISSIVE) 203962306a36Sopenharmony_ci IBA_SET(CM_REQ_PRIMARY_REMOTE_PORT_LID, req_msg, 204062306a36Sopenharmony_ci wc->dlid_path_bits); 204162306a36Sopenharmony_ci } 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ci if (!IBA_GET(CM_REQ_ALTERNATE_SUBNET_LOCAL, req_msg)) { 204462306a36Sopenharmony_ci if (cpu_to_be16(IBA_GET(CM_REQ_ALTERNATE_LOCAL_PORT_LID, 204562306a36Sopenharmony_ci req_msg)) == IB_LID_PERMISSIVE) { 204662306a36Sopenharmony_ci IBA_SET(CM_REQ_ALTERNATE_LOCAL_PORT_LID, req_msg, 204762306a36Sopenharmony_ci be16_to_cpu(ib_lid_be16(wc->slid))); 204862306a36Sopenharmony_ci IBA_SET(CM_REQ_ALTERNATE_SL, req_msg, wc->sl); 204962306a36Sopenharmony_ci } 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci if (cpu_to_be16(IBA_GET(CM_REQ_ALTERNATE_REMOTE_PORT_LID, 205262306a36Sopenharmony_ci req_msg)) == IB_LID_PERMISSIVE) 205362306a36Sopenharmony_ci IBA_SET(CM_REQ_ALTERNATE_REMOTE_PORT_LID, req_msg, 205462306a36Sopenharmony_ci wc->dlid_path_bits); 205562306a36Sopenharmony_ci } 205662306a36Sopenharmony_ci} 205762306a36Sopenharmony_ci 205862306a36Sopenharmony_cistatic int cm_req_handler(struct cm_work *work) 205962306a36Sopenharmony_ci{ 206062306a36Sopenharmony_ci struct cm_id_private *cm_id_priv, *listen_cm_id_priv; 206162306a36Sopenharmony_ci struct cm_req_msg *req_msg; 206262306a36Sopenharmony_ci const struct ib_global_route *grh; 206362306a36Sopenharmony_ci const struct ib_gid_attr *gid_attr; 206462306a36Sopenharmony_ci int ret; 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci req_msg = (struct cm_req_msg *)work->mad_recv_wc->recv_buf.mad; 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci cm_id_priv = 206962306a36Sopenharmony_ci cm_alloc_id_priv(work->port->cm_dev->ib_device, NULL, NULL); 207062306a36Sopenharmony_ci if (IS_ERR(cm_id_priv)) 207162306a36Sopenharmony_ci return PTR_ERR(cm_id_priv); 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci cm_id_priv->id.remote_id = 207462306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_REQ_LOCAL_COMM_ID, req_msg)); 207562306a36Sopenharmony_ci cm_id_priv->id.service_id = 207662306a36Sopenharmony_ci cpu_to_be64(IBA_GET(CM_REQ_SERVICE_ID, req_msg)); 207762306a36Sopenharmony_ci cm_id_priv->tid = req_msg->hdr.tid; 207862306a36Sopenharmony_ci cm_id_priv->timeout_ms = cm_convert_to_ms( 207962306a36Sopenharmony_ci IBA_GET(CM_REQ_LOCAL_CM_RESPONSE_TIMEOUT, req_msg)); 208062306a36Sopenharmony_ci cm_id_priv->max_cm_retries = IBA_GET(CM_REQ_MAX_CM_RETRIES, req_msg); 208162306a36Sopenharmony_ci cm_id_priv->remote_qpn = 208262306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_REQ_LOCAL_QPN, req_msg)); 208362306a36Sopenharmony_ci cm_id_priv->initiator_depth = 208462306a36Sopenharmony_ci IBA_GET(CM_REQ_RESPONDER_RESOURCES, req_msg); 208562306a36Sopenharmony_ci cm_id_priv->responder_resources = 208662306a36Sopenharmony_ci IBA_GET(CM_REQ_INITIATOR_DEPTH, req_msg); 208762306a36Sopenharmony_ci cm_id_priv->path_mtu = IBA_GET(CM_REQ_PATH_PACKET_PAYLOAD_MTU, req_msg); 208862306a36Sopenharmony_ci cm_id_priv->pkey = cpu_to_be16(IBA_GET(CM_REQ_PARTITION_KEY, req_msg)); 208962306a36Sopenharmony_ci cm_id_priv->sq_psn = cpu_to_be32(IBA_GET(CM_REQ_STARTING_PSN, req_msg)); 209062306a36Sopenharmony_ci cm_id_priv->retry_count = IBA_GET(CM_REQ_RETRY_COUNT, req_msg); 209162306a36Sopenharmony_ci cm_id_priv->rnr_retry_count = IBA_GET(CM_REQ_RNR_RETRY_COUNT, req_msg); 209262306a36Sopenharmony_ci cm_id_priv->qp_type = cm_req_get_qp_type(req_msg); 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci ret = cm_init_av_for_response(work->port, work->mad_recv_wc->wc, 209562306a36Sopenharmony_ci work->mad_recv_wc->recv_buf.grh, 209662306a36Sopenharmony_ci &cm_id_priv->av); 209762306a36Sopenharmony_ci if (ret) 209862306a36Sopenharmony_ci goto destroy; 209962306a36Sopenharmony_ci cm_id_priv->timewait_info = cm_create_timewait_info(cm_id_priv-> 210062306a36Sopenharmony_ci id.local_id); 210162306a36Sopenharmony_ci if (IS_ERR(cm_id_priv->timewait_info)) { 210262306a36Sopenharmony_ci ret = PTR_ERR(cm_id_priv->timewait_info); 210362306a36Sopenharmony_ci cm_id_priv->timewait_info = NULL; 210462306a36Sopenharmony_ci goto destroy; 210562306a36Sopenharmony_ci } 210662306a36Sopenharmony_ci cm_id_priv->timewait_info->work.remote_id = cm_id_priv->id.remote_id; 210762306a36Sopenharmony_ci cm_id_priv->timewait_info->remote_ca_guid = 210862306a36Sopenharmony_ci cpu_to_be64(IBA_GET(CM_REQ_LOCAL_CA_GUID, req_msg)); 210962306a36Sopenharmony_ci cm_id_priv->timewait_info->remote_qpn = cm_id_priv->remote_qpn; 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci /* 211262306a36Sopenharmony_ci * Note that the ID pointer is not in the xarray at this point, 211362306a36Sopenharmony_ci * so this set is only visible to the local thread. 211462306a36Sopenharmony_ci */ 211562306a36Sopenharmony_ci cm_id_priv->id.state = IB_CM_REQ_RCVD; 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci listen_cm_id_priv = cm_match_req(work, cm_id_priv); 211862306a36Sopenharmony_ci if (!listen_cm_id_priv) { 211962306a36Sopenharmony_ci trace_icm_no_listener_err(&cm_id_priv->id); 212062306a36Sopenharmony_ci cm_id_priv->id.state = IB_CM_IDLE; 212162306a36Sopenharmony_ci ret = -EINVAL; 212262306a36Sopenharmony_ci goto destroy; 212362306a36Sopenharmony_ci } 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ci memset(&work->path[0], 0, sizeof(work->path[0])); 212662306a36Sopenharmony_ci if (cm_req_has_alt_path(req_msg)) 212762306a36Sopenharmony_ci memset(&work->path[1], 0, sizeof(work->path[1])); 212862306a36Sopenharmony_ci grh = rdma_ah_read_grh(&cm_id_priv->av.ah_attr); 212962306a36Sopenharmony_ci gid_attr = grh->sgid_attr; 213062306a36Sopenharmony_ci 213162306a36Sopenharmony_ci if (cm_id_priv->av.ah_attr.type == RDMA_AH_ATTR_TYPE_ROCE) { 213262306a36Sopenharmony_ci work->path[0].rec_type = 213362306a36Sopenharmony_ci sa_conv_gid_to_pathrec_type(gid_attr->gid_type); 213462306a36Sopenharmony_ci } else { 213562306a36Sopenharmony_ci cm_process_routed_req(req_msg, work->mad_recv_wc->wc); 213662306a36Sopenharmony_ci cm_path_set_rec_type( 213762306a36Sopenharmony_ci work->port->cm_dev->ib_device, work->port->port_num, 213862306a36Sopenharmony_ci &work->path[0], 213962306a36Sopenharmony_ci IBA_GET_MEM_PTR(CM_REQ_PRIMARY_LOCAL_PORT_GID, 214062306a36Sopenharmony_ci req_msg)); 214162306a36Sopenharmony_ci } 214262306a36Sopenharmony_ci if (cm_req_has_alt_path(req_msg)) 214362306a36Sopenharmony_ci work->path[1].rec_type = work->path[0].rec_type; 214462306a36Sopenharmony_ci cm_format_paths_from_req(req_msg, &work->path[0], 214562306a36Sopenharmony_ci &work->path[1], work->mad_recv_wc->wc); 214662306a36Sopenharmony_ci if (cm_id_priv->av.ah_attr.type == RDMA_AH_ATTR_TYPE_ROCE) 214762306a36Sopenharmony_ci sa_path_set_dmac(&work->path[0], 214862306a36Sopenharmony_ci cm_id_priv->av.ah_attr.roce.dmac); 214962306a36Sopenharmony_ci work->path[0].hop_limit = grh->hop_limit; 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_ci /* This destroy call is needed to pair with cm_init_av_for_response */ 215262306a36Sopenharmony_ci cm_destroy_av(&cm_id_priv->av); 215362306a36Sopenharmony_ci ret = cm_init_av_by_path(&work->path[0], gid_attr, &cm_id_priv->av); 215462306a36Sopenharmony_ci if (ret) { 215562306a36Sopenharmony_ci int err; 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_ci err = rdma_query_gid(work->port->cm_dev->ib_device, 215862306a36Sopenharmony_ci work->port->port_num, 0, 215962306a36Sopenharmony_ci &work->path[0].sgid); 216062306a36Sopenharmony_ci if (err) 216162306a36Sopenharmony_ci ib_send_cm_rej(&cm_id_priv->id, IB_CM_REJ_INVALID_GID, 216262306a36Sopenharmony_ci NULL, 0, NULL, 0); 216362306a36Sopenharmony_ci else 216462306a36Sopenharmony_ci ib_send_cm_rej(&cm_id_priv->id, IB_CM_REJ_INVALID_GID, 216562306a36Sopenharmony_ci &work->path[0].sgid, 216662306a36Sopenharmony_ci sizeof(work->path[0].sgid), 216762306a36Sopenharmony_ci NULL, 0); 216862306a36Sopenharmony_ci goto rejected; 216962306a36Sopenharmony_ci } 217062306a36Sopenharmony_ci if (cm_id_priv->av.ah_attr.type == RDMA_AH_ATTR_TYPE_IB) 217162306a36Sopenharmony_ci cm_id_priv->av.dlid_datapath = 217262306a36Sopenharmony_ci IBA_GET(CM_REQ_PRIMARY_LOCAL_PORT_LID, req_msg); 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_ci if (cm_req_has_alt_path(req_msg)) { 217562306a36Sopenharmony_ci ret = cm_init_av_by_path(&work->path[1], NULL, 217662306a36Sopenharmony_ci &cm_id_priv->alt_av); 217762306a36Sopenharmony_ci if (ret) { 217862306a36Sopenharmony_ci ib_send_cm_rej(&cm_id_priv->id, 217962306a36Sopenharmony_ci IB_CM_REJ_INVALID_ALT_GID, 218062306a36Sopenharmony_ci &work->path[0].sgid, 218162306a36Sopenharmony_ci sizeof(work->path[0].sgid), NULL, 0); 218262306a36Sopenharmony_ci goto rejected; 218362306a36Sopenharmony_ci } 218462306a36Sopenharmony_ci } 218562306a36Sopenharmony_ci 218662306a36Sopenharmony_ci cm_id_priv->id.cm_handler = listen_cm_id_priv->id.cm_handler; 218762306a36Sopenharmony_ci cm_id_priv->id.context = listen_cm_id_priv->id.context; 218862306a36Sopenharmony_ci cm_format_req_event(work, cm_id_priv, &listen_cm_id_priv->id); 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_ci /* Now MAD handlers can see the new ID */ 219162306a36Sopenharmony_ci spin_lock_irq(&cm_id_priv->lock); 219262306a36Sopenharmony_ci cm_finalize_id(cm_id_priv); 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_ci /* Refcount belongs to the event, pairs with cm_process_work() */ 219562306a36Sopenharmony_ci refcount_inc(&cm_id_priv->refcount); 219662306a36Sopenharmony_ci cm_queue_work_unlock(cm_id_priv, work); 219762306a36Sopenharmony_ci /* 219862306a36Sopenharmony_ci * Since this ID was just created and was not made visible to other MAD 219962306a36Sopenharmony_ci * handlers until the cm_finalize_id() above we know that the 220062306a36Sopenharmony_ci * cm_process_work() will deliver the event and the listen_cm_id 220162306a36Sopenharmony_ci * embedded in the event can be derefed here. 220262306a36Sopenharmony_ci */ 220362306a36Sopenharmony_ci cm_deref_id(listen_cm_id_priv); 220462306a36Sopenharmony_ci return 0; 220562306a36Sopenharmony_ci 220662306a36Sopenharmony_cirejected: 220762306a36Sopenharmony_ci cm_deref_id(listen_cm_id_priv); 220862306a36Sopenharmony_cidestroy: 220962306a36Sopenharmony_ci ib_destroy_cm_id(&cm_id_priv->id); 221062306a36Sopenharmony_ci return ret; 221162306a36Sopenharmony_ci} 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_cistatic void cm_format_rep(struct cm_rep_msg *rep_msg, 221462306a36Sopenharmony_ci struct cm_id_private *cm_id_priv, 221562306a36Sopenharmony_ci struct ib_cm_rep_param *param) 221662306a36Sopenharmony_ci{ 221762306a36Sopenharmony_ci cm_format_mad_ece_hdr(&rep_msg->hdr, CM_REP_ATTR_ID, cm_id_priv->tid, 221862306a36Sopenharmony_ci param->ece.attr_mod); 221962306a36Sopenharmony_ci IBA_SET(CM_REP_LOCAL_COMM_ID, rep_msg, 222062306a36Sopenharmony_ci be32_to_cpu(cm_id_priv->id.local_id)); 222162306a36Sopenharmony_ci IBA_SET(CM_REP_REMOTE_COMM_ID, rep_msg, 222262306a36Sopenharmony_ci be32_to_cpu(cm_id_priv->id.remote_id)); 222362306a36Sopenharmony_ci IBA_SET(CM_REP_STARTING_PSN, rep_msg, param->starting_psn); 222462306a36Sopenharmony_ci IBA_SET(CM_REP_RESPONDER_RESOURCES, rep_msg, 222562306a36Sopenharmony_ci param->responder_resources); 222662306a36Sopenharmony_ci IBA_SET(CM_REP_TARGET_ACK_DELAY, rep_msg, 222762306a36Sopenharmony_ci cm_id_priv->av.port->cm_dev->ack_delay); 222862306a36Sopenharmony_ci IBA_SET(CM_REP_FAILOVER_ACCEPTED, rep_msg, param->failover_accepted); 222962306a36Sopenharmony_ci IBA_SET(CM_REP_RNR_RETRY_COUNT, rep_msg, param->rnr_retry_count); 223062306a36Sopenharmony_ci IBA_SET(CM_REP_LOCAL_CA_GUID, rep_msg, 223162306a36Sopenharmony_ci be64_to_cpu(cm_id_priv->id.device->node_guid)); 223262306a36Sopenharmony_ci 223362306a36Sopenharmony_ci if (cm_id_priv->qp_type != IB_QPT_XRC_TGT) { 223462306a36Sopenharmony_ci IBA_SET(CM_REP_INITIATOR_DEPTH, rep_msg, 223562306a36Sopenharmony_ci param->initiator_depth); 223662306a36Sopenharmony_ci IBA_SET(CM_REP_END_TO_END_FLOW_CONTROL, rep_msg, 223762306a36Sopenharmony_ci param->flow_control); 223862306a36Sopenharmony_ci IBA_SET(CM_REP_SRQ, rep_msg, param->srq); 223962306a36Sopenharmony_ci IBA_SET(CM_REP_LOCAL_QPN, rep_msg, param->qp_num); 224062306a36Sopenharmony_ci } else { 224162306a36Sopenharmony_ci IBA_SET(CM_REP_SRQ, rep_msg, 1); 224262306a36Sopenharmony_ci IBA_SET(CM_REP_LOCAL_EE_CONTEXT_NUMBER, rep_msg, param->qp_num); 224362306a36Sopenharmony_ci } 224462306a36Sopenharmony_ci 224562306a36Sopenharmony_ci IBA_SET(CM_REP_VENDOR_ID_L, rep_msg, param->ece.vendor_id); 224662306a36Sopenharmony_ci IBA_SET(CM_REP_VENDOR_ID_M, rep_msg, param->ece.vendor_id >> 8); 224762306a36Sopenharmony_ci IBA_SET(CM_REP_VENDOR_ID_H, rep_msg, param->ece.vendor_id >> 16); 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci if (param->private_data && param->private_data_len) 225062306a36Sopenharmony_ci IBA_SET_MEM(CM_REP_PRIVATE_DATA, rep_msg, param->private_data, 225162306a36Sopenharmony_ci param->private_data_len); 225262306a36Sopenharmony_ci} 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ciint ib_send_cm_rep(struct ib_cm_id *cm_id, 225562306a36Sopenharmony_ci struct ib_cm_rep_param *param) 225662306a36Sopenharmony_ci{ 225762306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 225862306a36Sopenharmony_ci struct ib_mad_send_buf *msg; 225962306a36Sopenharmony_ci struct cm_rep_msg *rep_msg; 226062306a36Sopenharmony_ci unsigned long flags; 226162306a36Sopenharmony_ci int ret; 226262306a36Sopenharmony_ci 226362306a36Sopenharmony_ci if (param->private_data && 226462306a36Sopenharmony_ci param->private_data_len > IB_CM_REP_PRIVATE_DATA_SIZE) 226562306a36Sopenharmony_ci return -EINVAL; 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_ci cm_id_priv = container_of(cm_id, struct cm_id_private, id); 226862306a36Sopenharmony_ci spin_lock_irqsave(&cm_id_priv->lock, flags); 226962306a36Sopenharmony_ci if (cm_id->state != IB_CM_REQ_RCVD && 227062306a36Sopenharmony_ci cm_id->state != IB_CM_MRA_REQ_SENT) { 227162306a36Sopenharmony_ci trace_icm_send_rep_err(cm_id_priv->id.local_id, cm_id->state); 227262306a36Sopenharmony_ci ret = -EINVAL; 227362306a36Sopenharmony_ci goto out; 227462306a36Sopenharmony_ci } 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_ci msg = cm_alloc_priv_msg(cm_id_priv); 227762306a36Sopenharmony_ci if (IS_ERR(msg)) { 227862306a36Sopenharmony_ci ret = PTR_ERR(msg); 227962306a36Sopenharmony_ci goto out; 228062306a36Sopenharmony_ci } 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_ci rep_msg = (struct cm_rep_msg *) msg->mad; 228362306a36Sopenharmony_ci cm_format_rep(rep_msg, cm_id_priv, param); 228462306a36Sopenharmony_ci msg->timeout_ms = cm_id_priv->timeout_ms; 228562306a36Sopenharmony_ci msg->context[1] = (void *) (unsigned long) IB_CM_REP_SENT; 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ci trace_icm_send_rep(cm_id); 228862306a36Sopenharmony_ci ret = ib_post_send_mad(msg, NULL); 228962306a36Sopenharmony_ci if (ret) 229062306a36Sopenharmony_ci goto out_free; 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_ci cm_id->state = IB_CM_REP_SENT; 229362306a36Sopenharmony_ci cm_id_priv->initiator_depth = param->initiator_depth; 229462306a36Sopenharmony_ci cm_id_priv->responder_resources = param->responder_resources; 229562306a36Sopenharmony_ci cm_id_priv->rq_psn = cpu_to_be32(IBA_GET(CM_REP_STARTING_PSN, rep_msg)); 229662306a36Sopenharmony_ci WARN_ONCE(param->qp_num & 0xFF000000, 229762306a36Sopenharmony_ci "IBTA declares QPN to be 24 bits, but it is 0x%X\n", 229862306a36Sopenharmony_ci param->qp_num); 229962306a36Sopenharmony_ci cm_id_priv->local_qpn = cpu_to_be32(param->qp_num & 0xFFFFFF); 230062306a36Sopenharmony_ci spin_unlock_irqrestore(&cm_id_priv->lock, flags); 230162306a36Sopenharmony_ci return 0; 230262306a36Sopenharmony_ci 230362306a36Sopenharmony_ciout_free: 230462306a36Sopenharmony_ci cm_free_priv_msg(msg); 230562306a36Sopenharmony_ciout: 230662306a36Sopenharmony_ci spin_unlock_irqrestore(&cm_id_priv->lock, flags); 230762306a36Sopenharmony_ci return ret; 230862306a36Sopenharmony_ci} 230962306a36Sopenharmony_ciEXPORT_SYMBOL(ib_send_cm_rep); 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_cistatic void cm_format_rtu(struct cm_rtu_msg *rtu_msg, 231262306a36Sopenharmony_ci struct cm_id_private *cm_id_priv, 231362306a36Sopenharmony_ci const void *private_data, 231462306a36Sopenharmony_ci u8 private_data_len) 231562306a36Sopenharmony_ci{ 231662306a36Sopenharmony_ci cm_format_mad_hdr(&rtu_msg->hdr, CM_RTU_ATTR_ID, cm_id_priv->tid); 231762306a36Sopenharmony_ci IBA_SET(CM_RTU_LOCAL_COMM_ID, rtu_msg, 231862306a36Sopenharmony_ci be32_to_cpu(cm_id_priv->id.local_id)); 231962306a36Sopenharmony_ci IBA_SET(CM_RTU_REMOTE_COMM_ID, rtu_msg, 232062306a36Sopenharmony_ci be32_to_cpu(cm_id_priv->id.remote_id)); 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci if (private_data && private_data_len) 232362306a36Sopenharmony_ci IBA_SET_MEM(CM_RTU_PRIVATE_DATA, rtu_msg, private_data, 232462306a36Sopenharmony_ci private_data_len); 232562306a36Sopenharmony_ci} 232662306a36Sopenharmony_ci 232762306a36Sopenharmony_ciint ib_send_cm_rtu(struct ib_cm_id *cm_id, 232862306a36Sopenharmony_ci const void *private_data, 232962306a36Sopenharmony_ci u8 private_data_len) 233062306a36Sopenharmony_ci{ 233162306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 233262306a36Sopenharmony_ci struct ib_mad_send_buf *msg; 233362306a36Sopenharmony_ci unsigned long flags; 233462306a36Sopenharmony_ci void *data; 233562306a36Sopenharmony_ci int ret; 233662306a36Sopenharmony_ci 233762306a36Sopenharmony_ci if (private_data && private_data_len > IB_CM_RTU_PRIVATE_DATA_SIZE) 233862306a36Sopenharmony_ci return -EINVAL; 233962306a36Sopenharmony_ci 234062306a36Sopenharmony_ci data = cm_copy_private_data(private_data, private_data_len); 234162306a36Sopenharmony_ci if (IS_ERR(data)) 234262306a36Sopenharmony_ci return PTR_ERR(data); 234362306a36Sopenharmony_ci 234462306a36Sopenharmony_ci cm_id_priv = container_of(cm_id, struct cm_id_private, id); 234562306a36Sopenharmony_ci spin_lock_irqsave(&cm_id_priv->lock, flags); 234662306a36Sopenharmony_ci if (cm_id->state != IB_CM_REP_RCVD && 234762306a36Sopenharmony_ci cm_id->state != IB_CM_MRA_REP_SENT) { 234862306a36Sopenharmony_ci trace_icm_send_cm_rtu_err(cm_id); 234962306a36Sopenharmony_ci ret = -EINVAL; 235062306a36Sopenharmony_ci goto error; 235162306a36Sopenharmony_ci } 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_ci msg = cm_alloc_msg(cm_id_priv); 235462306a36Sopenharmony_ci if (IS_ERR(msg)) { 235562306a36Sopenharmony_ci ret = PTR_ERR(msg); 235662306a36Sopenharmony_ci goto error; 235762306a36Sopenharmony_ci } 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_ci cm_format_rtu((struct cm_rtu_msg *) msg->mad, cm_id_priv, 236062306a36Sopenharmony_ci private_data, private_data_len); 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_ci trace_icm_send_rtu(cm_id); 236362306a36Sopenharmony_ci ret = ib_post_send_mad(msg, NULL); 236462306a36Sopenharmony_ci if (ret) { 236562306a36Sopenharmony_ci spin_unlock_irqrestore(&cm_id_priv->lock, flags); 236662306a36Sopenharmony_ci cm_free_msg(msg); 236762306a36Sopenharmony_ci kfree(data); 236862306a36Sopenharmony_ci return ret; 236962306a36Sopenharmony_ci } 237062306a36Sopenharmony_ci 237162306a36Sopenharmony_ci cm_id->state = IB_CM_ESTABLISHED; 237262306a36Sopenharmony_ci cm_set_private_data(cm_id_priv, data, private_data_len); 237362306a36Sopenharmony_ci spin_unlock_irqrestore(&cm_id_priv->lock, flags); 237462306a36Sopenharmony_ci return 0; 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_cierror: spin_unlock_irqrestore(&cm_id_priv->lock, flags); 237762306a36Sopenharmony_ci kfree(data); 237862306a36Sopenharmony_ci return ret; 237962306a36Sopenharmony_ci} 238062306a36Sopenharmony_ciEXPORT_SYMBOL(ib_send_cm_rtu); 238162306a36Sopenharmony_ci 238262306a36Sopenharmony_cistatic void cm_format_rep_event(struct cm_work *work, enum ib_qp_type qp_type) 238362306a36Sopenharmony_ci{ 238462306a36Sopenharmony_ci struct cm_rep_msg *rep_msg; 238562306a36Sopenharmony_ci struct ib_cm_rep_event_param *param; 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_ci rep_msg = (struct cm_rep_msg *)work->mad_recv_wc->recv_buf.mad; 238862306a36Sopenharmony_ci param = &work->cm_event.param.rep_rcvd; 238962306a36Sopenharmony_ci param->remote_ca_guid = 239062306a36Sopenharmony_ci cpu_to_be64(IBA_GET(CM_REP_LOCAL_CA_GUID, rep_msg)); 239162306a36Sopenharmony_ci param->remote_qkey = IBA_GET(CM_REP_LOCAL_Q_KEY, rep_msg); 239262306a36Sopenharmony_ci param->remote_qpn = be32_to_cpu(cm_rep_get_qpn(rep_msg, qp_type)); 239362306a36Sopenharmony_ci param->starting_psn = IBA_GET(CM_REP_STARTING_PSN, rep_msg); 239462306a36Sopenharmony_ci param->responder_resources = IBA_GET(CM_REP_INITIATOR_DEPTH, rep_msg); 239562306a36Sopenharmony_ci param->initiator_depth = IBA_GET(CM_REP_RESPONDER_RESOURCES, rep_msg); 239662306a36Sopenharmony_ci param->target_ack_delay = IBA_GET(CM_REP_TARGET_ACK_DELAY, rep_msg); 239762306a36Sopenharmony_ci param->failover_accepted = IBA_GET(CM_REP_FAILOVER_ACCEPTED, rep_msg); 239862306a36Sopenharmony_ci param->flow_control = IBA_GET(CM_REP_END_TO_END_FLOW_CONTROL, rep_msg); 239962306a36Sopenharmony_ci param->rnr_retry_count = IBA_GET(CM_REP_RNR_RETRY_COUNT, rep_msg); 240062306a36Sopenharmony_ci param->srq = IBA_GET(CM_REP_SRQ, rep_msg); 240162306a36Sopenharmony_ci param->ece.vendor_id = IBA_GET(CM_REP_VENDOR_ID_H, rep_msg) << 16; 240262306a36Sopenharmony_ci param->ece.vendor_id |= IBA_GET(CM_REP_VENDOR_ID_M, rep_msg) << 8; 240362306a36Sopenharmony_ci param->ece.vendor_id |= IBA_GET(CM_REP_VENDOR_ID_L, rep_msg); 240462306a36Sopenharmony_ci param->ece.attr_mod = be32_to_cpu(rep_msg->hdr.attr_mod); 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci work->cm_event.private_data = 240762306a36Sopenharmony_ci IBA_GET_MEM_PTR(CM_REP_PRIVATE_DATA, rep_msg); 240862306a36Sopenharmony_ci} 240962306a36Sopenharmony_ci 241062306a36Sopenharmony_cistatic void cm_dup_rep_handler(struct cm_work *work) 241162306a36Sopenharmony_ci{ 241262306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 241362306a36Sopenharmony_ci struct cm_rep_msg *rep_msg; 241462306a36Sopenharmony_ci struct ib_mad_send_buf *msg = NULL; 241562306a36Sopenharmony_ci int ret; 241662306a36Sopenharmony_ci 241762306a36Sopenharmony_ci rep_msg = (struct cm_rep_msg *) work->mad_recv_wc->recv_buf.mad; 241862306a36Sopenharmony_ci cm_id_priv = cm_acquire_id( 241962306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_REP_REMOTE_COMM_ID, rep_msg)), 242062306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_REP_LOCAL_COMM_ID, rep_msg))); 242162306a36Sopenharmony_ci if (!cm_id_priv) 242262306a36Sopenharmony_ci return; 242362306a36Sopenharmony_ci 242462306a36Sopenharmony_ci atomic_long_inc( 242562306a36Sopenharmony_ci &work->port->counters[CM_RECV_DUPLICATES][CM_REP_COUNTER]); 242662306a36Sopenharmony_ci ret = cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg); 242762306a36Sopenharmony_ci if (ret) 242862306a36Sopenharmony_ci goto deref; 242962306a36Sopenharmony_ci 243062306a36Sopenharmony_ci spin_lock_irq(&cm_id_priv->lock); 243162306a36Sopenharmony_ci if (cm_id_priv->id.state == IB_CM_ESTABLISHED) 243262306a36Sopenharmony_ci cm_format_rtu((struct cm_rtu_msg *) msg->mad, cm_id_priv, 243362306a36Sopenharmony_ci cm_id_priv->private_data, 243462306a36Sopenharmony_ci cm_id_priv->private_data_len); 243562306a36Sopenharmony_ci else if (cm_id_priv->id.state == IB_CM_MRA_REP_SENT) 243662306a36Sopenharmony_ci cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, 243762306a36Sopenharmony_ci CM_MSG_RESPONSE_REP, cm_id_priv->service_timeout, 243862306a36Sopenharmony_ci cm_id_priv->private_data, 243962306a36Sopenharmony_ci cm_id_priv->private_data_len); 244062306a36Sopenharmony_ci else 244162306a36Sopenharmony_ci goto unlock; 244262306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci trace_icm_send_dup_rep(&cm_id_priv->id); 244562306a36Sopenharmony_ci ret = ib_post_send_mad(msg, NULL); 244662306a36Sopenharmony_ci if (ret) 244762306a36Sopenharmony_ci goto free; 244862306a36Sopenharmony_ci goto deref; 244962306a36Sopenharmony_ci 245062306a36Sopenharmony_ciunlock: spin_unlock_irq(&cm_id_priv->lock); 245162306a36Sopenharmony_cifree: cm_free_response_msg(msg); 245262306a36Sopenharmony_cideref: cm_deref_id(cm_id_priv); 245362306a36Sopenharmony_ci} 245462306a36Sopenharmony_ci 245562306a36Sopenharmony_cistatic int cm_rep_handler(struct cm_work *work) 245662306a36Sopenharmony_ci{ 245762306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 245862306a36Sopenharmony_ci struct cm_rep_msg *rep_msg; 245962306a36Sopenharmony_ci int ret; 246062306a36Sopenharmony_ci struct cm_id_private *cur_cm_id_priv; 246162306a36Sopenharmony_ci struct cm_timewait_info *timewait_info; 246262306a36Sopenharmony_ci 246362306a36Sopenharmony_ci rep_msg = (struct cm_rep_msg *)work->mad_recv_wc->recv_buf.mad; 246462306a36Sopenharmony_ci cm_id_priv = cm_acquire_id( 246562306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_REP_REMOTE_COMM_ID, rep_msg)), 0); 246662306a36Sopenharmony_ci if (!cm_id_priv) { 246762306a36Sopenharmony_ci cm_dup_rep_handler(work); 246862306a36Sopenharmony_ci trace_icm_remote_no_priv_err( 246962306a36Sopenharmony_ci IBA_GET(CM_REP_REMOTE_COMM_ID, rep_msg)); 247062306a36Sopenharmony_ci return -EINVAL; 247162306a36Sopenharmony_ci } 247262306a36Sopenharmony_ci 247362306a36Sopenharmony_ci cm_format_rep_event(work, cm_id_priv->qp_type); 247462306a36Sopenharmony_ci 247562306a36Sopenharmony_ci spin_lock_irq(&cm_id_priv->lock); 247662306a36Sopenharmony_ci switch (cm_id_priv->id.state) { 247762306a36Sopenharmony_ci case IB_CM_REQ_SENT: 247862306a36Sopenharmony_ci case IB_CM_MRA_REQ_RCVD: 247962306a36Sopenharmony_ci break; 248062306a36Sopenharmony_ci default: 248162306a36Sopenharmony_ci ret = -EINVAL; 248262306a36Sopenharmony_ci trace_icm_rep_unknown_err( 248362306a36Sopenharmony_ci IBA_GET(CM_REP_LOCAL_COMM_ID, rep_msg), 248462306a36Sopenharmony_ci IBA_GET(CM_REP_REMOTE_COMM_ID, rep_msg), 248562306a36Sopenharmony_ci cm_id_priv->id.state); 248662306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 248762306a36Sopenharmony_ci goto error; 248862306a36Sopenharmony_ci } 248962306a36Sopenharmony_ci 249062306a36Sopenharmony_ci cm_id_priv->timewait_info->work.remote_id = 249162306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_REP_LOCAL_COMM_ID, rep_msg)); 249262306a36Sopenharmony_ci cm_id_priv->timewait_info->remote_ca_guid = 249362306a36Sopenharmony_ci cpu_to_be64(IBA_GET(CM_REP_LOCAL_CA_GUID, rep_msg)); 249462306a36Sopenharmony_ci cm_id_priv->timewait_info->remote_qpn = cm_rep_get_qpn(rep_msg, cm_id_priv->qp_type); 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ci spin_lock(&cm.lock); 249762306a36Sopenharmony_ci /* Check for duplicate REP. */ 249862306a36Sopenharmony_ci if (cm_insert_remote_id(cm_id_priv->timewait_info)) { 249962306a36Sopenharmony_ci spin_unlock(&cm.lock); 250062306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 250162306a36Sopenharmony_ci ret = -EINVAL; 250262306a36Sopenharmony_ci trace_icm_insert_failed_err( 250362306a36Sopenharmony_ci IBA_GET(CM_REP_REMOTE_COMM_ID, rep_msg)); 250462306a36Sopenharmony_ci goto error; 250562306a36Sopenharmony_ci } 250662306a36Sopenharmony_ci /* Check for a stale connection. */ 250762306a36Sopenharmony_ci timewait_info = cm_insert_remote_qpn(cm_id_priv->timewait_info); 250862306a36Sopenharmony_ci if (timewait_info) { 250962306a36Sopenharmony_ci cm_remove_remote(cm_id_priv); 251062306a36Sopenharmony_ci cur_cm_id_priv = cm_acquire_id(timewait_info->work.local_id, 251162306a36Sopenharmony_ci timewait_info->work.remote_id); 251262306a36Sopenharmony_ci 251362306a36Sopenharmony_ci spin_unlock(&cm.lock); 251462306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 251562306a36Sopenharmony_ci cm_issue_rej(work->port, work->mad_recv_wc, 251662306a36Sopenharmony_ci IB_CM_REJ_STALE_CONN, CM_MSG_RESPONSE_REP, 251762306a36Sopenharmony_ci NULL, 0); 251862306a36Sopenharmony_ci ret = -EINVAL; 251962306a36Sopenharmony_ci trace_icm_staleconn_err( 252062306a36Sopenharmony_ci IBA_GET(CM_REP_LOCAL_COMM_ID, rep_msg), 252162306a36Sopenharmony_ci IBA_GET(CM_REP_REMOTE_COMM_ID, rep_msg)); 252262306a36Sopenharmony_ci 252362306a36Sopenharmony_ci if (cur_cm_id_priv) { 252462306a36Sopenharmony_ci ib_send_cm_dreq(&cur_cm_id_priv->id, NULL, 0); 252562306a36Sopenharmony_ci cm_deref_id(cur_cm_id_priv); 252662306a36Sopenharmony_ci } 252762306a36Sopenharmony_ci 252862306a36Sopenharmony_ci goto error; 252962306a36Sopenharmony_ci } 253062306a36Sopenharmony_ci spin_unlock(&cm.lock); 253162306a36Sopenharmony_ci 253262306a36Sopenharmony_ci cm_id_priv->id.state = IB_CM_REP_RCVD; 253362306a36Sopenharmony_ci cm_id_priv->id.remote_id = 253462306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_REP_LOCAL_COMM_ID, rep_msg)); 253562306a36Sopenharmony_ci cm_id_priv->remote_qpn = cm_rep_get_qpn(rep_msg, cm_id_priv->qp_type); 253662306a36Sopenharmony_ci cm_id_priv->initiator_depth = 253762306a36Sopenharmony_ci IBA_GET(CM_REP_RESPONDER_RESOURCES, rep_msg); 253862306a36Sopenharmony_ci cm_id_priv->responder_resources = 253962306a36Sopenharmony_ci IBA_GET(CM_REP_INITIATOR_DEPTH, rep_msg); 254062306a36Sopenharmony_ci cm_id_priv->sq_psn = cpu_to_be32(IBA_GET(CM_REP_STARTING_PSN, rep_msg)); 254162306a36Sopenharmony_ci cm_id_priv->rnr_retry_count = IBA_GET(CM_REP_RNR_RETRY_COUNT, rep_msg); 254262306a36Sopenharmony_ci cm_id_priv->target_ack_delay = 254362306a36Sopenharmony_ci IBA_GET(CM_REP_TARGET_ACK_DELAY, rep_msg); 254462306a36Sopenharmony_ci cm_id_priv->av.timeout = 254562306a36Sopenharmony_ci cm_ack_timeout(cm_id_priv->target_ack_delay, 254662306a36Sopenharmony_ci cm_id_priv->av.timeout - 1); 254762306a36Sopenharmony_ci cm_id_priv->alt_av.timeout = 254862306a36Sopenharmony_ci cm_ack_timeout(cm_id_priv->target_ack_delay, 254962306a36Sopenharmony_ci cm_id_priv->alt_av.timeout - 1); 255062306a36Sopenharmony_ci 255162306a36Sopenharmony_ci ib_cancel_mad(cm_id_priv->msg); 255262306a36Sopenharmony_ci cm_queue_work_unlock(cm_id_priv, work); 255362306a36Sopenharmony_ci return 0; 255462306a36Sopenharmony_ci 255562306a36Sopenharmony_cierror: 255662306a36Sopenharmony_ci cm_deref_id(cm_id_priv); 255762306a36Sopenharmony_ci return ret; 255862306a36Sopenharmony_ci} 255962306a36Sopenharmony_ci 256062306a36Sopenharmony_cistatic int cm_establish_handler(struct cm_work *work) 256162306a36Sopenharmony_ci{ 256262306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 256362306a36Sopenharmony_ci 256462306a36Sopenharmony_ci /* See comment in cm_establish about lookup. */ 256562306a36Sopenharmony_ci cm_id_priv = cm_acquire_id(work->local_id, work->remote_id); 256662306a36Sopenharmony_ci if (!cm_id_priv) 256762306a36Sopenharmony_ci return -EINVAL; 256862306a36Sopenharmony_ci 256962306a36Sopenharmony_ci spin_lock_irq(&cm_id_priv->lock); 257062306a36Sopenharmony_ci if (cm_id_priv->id.state != IB_CM_ESTABLISHED) { 257162306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 257262306a36Sopenharmony_ci goto out; 257362306a36Sopenharmony_ci } 257462306a36Sopenharmony_ci 257562306a36Sopenharmony_ci ib_cancel_mad(cm_id_priv->msg); 257662306a36Sopenharmony_ci cm_queue_work_unlock(cm_id_priv, work); 257762306a36Sopenharmony_ci return 0; 257862306a36Sopenharmony_ciout: 257962306a36Sopenharmony_ci cm_deref_id(cm_id_priv); 258062306a36Sopenharmony_ci return -EINVAL; 258162306a36Sopenharmony_ci} 258262306a36Sopenharmony_ci 258362306a36Sopenharmony_cistatic int cm_rtu_handler(struct cm_work *work) 258462306a36Sopenharmony_ci{ 258562306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 258662306a36Sopenharmony_ci struct cm_rtu_msg *rtu_msg; 258762306a36Sopenharmony_ci 258862306a36Sopenharmony_ci rtu_msg = (struct cm_rtu_msg *)work->mad_recv_wc->recv_buf.mad; 258962306a36Sopenharmony_ci cm_id_priv = cm_acquire_id( 259062306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_RTU_REMOTE_COMM_ID, rtu_msg)), 259162306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_RTU_LOCAL_COMM_ID, rtu_msg))); 259262306a36Sopenharmony_ci if (!cm_id_priv) 259362306a36Sopenharmony_ci return -EINVAL; 259462306a36Sopenharmony_ci 259562306a36Sopenharmony_ci work->cm_event.private_data = 259662306a36Sopenharmony_ci IBA_GET_MEM_PTR(CM_RTU_PRIVATE_DATA, rtu_msg); 259762306a36Sopenharmony_ci 259862306a36Sopenharmony_ci spin_lock_irq(&cm_id_priv->lock); 259962306a36Sopenharmony_ci if (cm_id_priv->id.state != IB_CM_REP_SENT && 260062306a36Sopenharmony_ci cm_id_priv->id.state != IB_CM_MRA_REP_RCVD) { 260162306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 260262306a36Sopenharmony_ci atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES] 260362306a36Sopenharmony_ci [CM_RTU_COUNTER]); 260462306a36Sopenharmony_ci goto out; 260562306a36Sopenharmony_ci } 260662306a36Sopenharmony_ci cm_id_priv->id.state = IB_CM_ESTABLISHED; 260762306a36Sopenharmony_ci 260862306a36Sopenharmony_ci ib_cancel_mad(cm_id_priv->msg); 260962306a36Sopenharmony_ci cm_queue_work_unlock(cm_id_priv, work); 261062306a36Sopenharmony_ci return 0; 261162306a36Sopenharmony_ciout: 261262306a36Sopenharmony_ci cm_deref_id(cm_id_priv); 261362306a36Sopenharmony_ci return -EINVAL; 261462306a36Sopenharmony_ci} 261562306a36Sopenharmony_ci 261662306a36Sopenharmony_cistatic void cm_format_dreq(struct cm_dreq_msg *dreq_msg, 261762306a36Sopenharmony_ci struct cm_id_private *cm_id_priv, 261862306a36Sopenharmony_ci const void *private_data, 261962306a36Sopenharmony_ci u8 private_data_len) 262062306a36Sopenharmony_ci{ 262162306a36Sopenharmony_ci cm_format_mad_hdr(&dreq_msg->hdr, CM_DREQ_ATTR_ID, 262262306a36Sopenharmony_ci cm_form_tid(cm_id_priv)); 262362306a36Sopenharmony_ci IBA_SET(CM_DREQ_LOCAL_COMM_ID, dreq_msg, 262462306a36Sopenharmony_ci be32_to_cpu(cm_id_priv->id.local_id)); 262562306a36Sopenharmony_ci IBA_SET(CM_DREQ_REMOTE_COMM_ID, dreq_msg, 262662306a36Sopenharmony_ci be32_to_cpu(cm_id_priv->id.remote_id)); 262762306a36Sopenharmony_ci IBA_SET(CM_DREQ_REMOTE_QPN_EECN, dreq_msg, 262862306a36Sopenharmony_ci be32_to_cpu(cm_id_priv->remote_qpn)); 262962306a36Sopenharmony_ci 263062306a36Sopenharmony_ci if (private_data && private_data_len) 263162306a36Sopenharmony_ci IBA_SET_MEM(CM_DREQ_PRIVATE_DATA, dreq_msg, private_data, 263262306a36Sopenharmony_ci private_data_len); 263362306a36Sopenharmony_ci} 263462306a36Sopenharmony_ci 263562306a36Sopenharmony_cistatic int cm_send_dreq_locked(struct cm_id_private *cm_id_priv, 263662306a36Sopenharmony_ci const void *private_data, u8 private_data_len) 263762306a36Sopenharmony_ci{ 263862306a36Sopenharmony_ci struct ib_mad_send_buf *msg; 263962306a36Sopenharmony_ci int ret; 264062306a36Sopenharmony_ci 264162306a36Sopenharmony_ci lockdep_assert_held(&cm_id_priv->lock); 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_ci if (private_data && private_data_len > IB_CM_DREQ_PRIVATE_DATA_SIZE) 264462306a36Sopenharmony_ci return -EINVAL; 264562306a36Sopenharmony_ci 264662306a36Sopenharmony_ci if (cm_id_priv->id.state != IB_CM_ESTABLISHED) { 264762306a36Sopenharmony_ci trace_icm_dreq_skipped(&cm_id_priv->id); 264862306a36Sopenharmony_ci return -EINVAL; 264962306a36Sopenharmony_ci } 265062306a36Sopenharmony_ci 265162306a36Sopenharmony_ci if (cm_id_priv->id.lap_state == IB_CM_LAP_SENT || 265262306a36Sopenharmony_ci cm_id_priv->id.lap_state == IB_CM_MRA_LAP_RCVD) 265362306a36Sopenharmony_ci ib_cancel_mad(cm_id_priv->msg); 265462306a36Sopenharmony_ci 265562306a36Sopenharmony_ci msg = cm_alloc_priv_msg(cm_id_priv); 265662306a36Sopenharmony_ci if (IS_ERR(msg)) { 265762306a36Sopenharmony_ci cm_enter_timewait(cm_id_priv); 265862306a36Sopenharmony_ci return PTR_ERR(msg); 265962306a36Sopenharmony_ci } 266062306a36Sopenharmony_ci 266162306a36Sopenharmony_ci cm_format_dreq((struct cm_dreq_msg *) msg->mad, cm_id_priv, 266262306a36Sopenharmony_ci private_data, private_data_len); 266362306a36Sopenharmony_ci msg->timeout_ms = cm_id_priv->timeout_ms; 266462306a36Sopenharmony_ci msg->context[1] = (void *) (unsigned long) IB_CM_DREQ_SENT; 266562306a36Sopenharmony_ci 266662306a36Sopenharmony_ci trace_icm_send_dreq(&cm_id_priv->id); 266762306a36Sopenharmony_ci ret = ib_post_send_mad(msg, NULL); 266862306a36Sopenharmony_ci if (ret) { 266962306a36Sopenharmony_ci cm_enter_timewait(cm_id_priv); 267062306a36Sopenharmony_ci cm_free_priv_msg(msg); 267162306a36Sopenharmony_ci return ret; 267262306a36Sopenharmony_ci } 267362306a36Sopenharmony_ci 267462306a36Sopenharmony_ci cm_id_priv->id.state = IB_CM_DREQ_SENT; 267562306a36Sopenharmony_ci return 0; 267662306a36Sopenharmony_ci} 267762306a36Sopenharmony_ci 267862306a36Sopenharmony_ciint ib_send_cm_dreq(struct ib_cm_id *cm_id, const void *private_data, 267962306a36Sopenharmony_ci u8 private_data_len) 268062306a36Sopenharmony_ci{ 268162306a36Sopenharmony_ci struct cm_id_private *cm_id_priv = 268262306a36Sopenharmony_ci container_of(cm_id, struct cm_id_private, id); 268362306a36Sopenharmony_ci unsigned long flags; 268462306a36Sopenharmony_ci int ret; 268562306a36Sopenharmony_ci 268662306a36Sopenharmony_ci spin_lock_irqsave(&cm_id_priv->lock, flags); 268762306a36Sopenharmony_ci ret = cm_send_dreq_locked(cm_id_priv, private_data, private_data_len); 268862306a36Sopenharmony_ci spin_unlock_irqrestore(&cm_id_priv->lock, flags); 268962306a36Sopenharmony_ci return ret; 269062306a36Sopenharmony_ci} 269162306a36Sopenharmony_ciEXPORT_SYMBOL(ib_send_cm_dreq); 269262306a36Sopenharmony_ci 269362306a36Sopenharmony_cistatic void cm_format_drep(struct cm_drep_msg *drep_msg, 269462306a36Sopenharmony_ci struct cm_id_private *cm_id_priv, 269562306a36Sopenharmony_ci const void *private_data, 269662306a36Sopenharmony_ci u8 private_data_len) 269762306a36Sopenharmony_ci{ 269862306a36Sopenharmony_ci cm_format_mad_hdr(&drep_msg->hdr, CM_DREP_ATTR_ID, cm_id_priv->tid); 269962306a36Sopenharmony_ci IBA_SET(CM_DREP_LOCAL_COMM_ID, drep_msg, 270062306a36Sopenharmony_ci be32_to_cpu(cm_id_priv->id.local_id)); 270162306a36Sopenharmony_ci IBA_SET(CM_DREP_REMOTE_COMM_ID, drep_msg, 270262306a36Sopenharmony_ci be32_to_cpu(cm_id_priv->id.remote_id)); 270362306a36Sopenharmony_ci 270462306a36Sopenharmony_ci if (private_data && private_data_len) 270562306a36Sopenharmony_ci IBA_SET_MEM(CM_DREP_PRIVATE_DATA, drep_msg, private_data, 270662306a36Sopenharmony_ci private_data_len); 270762306a36Sopenharmony_ci} 270862306a36Sopenharmony_ci 270962306a36Sopenharmony_cistatic int cm_send_drep_locked(struct cm_id_private *cm_id_priv, 271062306a36Sopenharmony_ci void *private_data, u8 private_data_len) 271162306a36Sopenharmony_ci{ 271262306a36Sopenharmony_ci struct ib_mad_send_buf *msg; 271362306a36Sopenharmony_ci int ret; 271462306a36Sopenharmony_ci 271562306a36Sopenharmony_ci lockdep_assert_held(&cm_id_priv->lock); 271662306a36Sopenharmony_ci 271762306a36Sopenharmony_ci if (private_data && private_data_len > IB_CM_DREP_PRIVATE_DATA_SIZE) 271862306a36Sopenharmony_ci return -EINVAL; 271962306a36Sopenharmony_ci 272062306a36Sopenharmony_ci if (cm_id_priv->id.state != IB_CM_DREQ_RCVD) { 272162306a36Sopenharmony_ci trace_icm_send_drep_err(&cm_id_priv->id); 272262306a36Sopenharmony_ci kfree(private_data); 272362306a36Sopenharmony_ci return -EINVAL; 272462306a36Sopenharmony_ci } 272562306a36Sopenharmony_ci 272662306a36Sopenharmony_ci cm_set_private_data(cm_id_priv, private_data, private_data_len); 272762306a36Sopenharmony_ci cm_enter_timewait(cm_id_priv); 272862306a36Sopenharmony_ci 272962306a36Sopenharmony_ci msg = cm_alloc_msg(cm_id_priv); 273062306a36Sopenharmony_ci if (IS_ERR(msg)) 273162306a36Sopenharmony_ci return PTR_ERR(msg); 273262306a36Sopenharmony_ci 273362306a36Sopenharmony_ci cm_format_drep((struct cm_drep_msg *) msg->mad, cm_id_priv, 273462306a36Sopenharmony_ci private_data, private_data_len); 273562306a36Sopenharmony_ci 273662306a36Sopenharmony_ci trace_icm_send_drep(&cm_id_priv->id); 273762306a36Sopenharmony_ci ret = ib_post_send_mad(msg, NULL); 273862306a36Sopenharmony_ci if (ret) { 273962306a36Sopenharmony_ci cm_free_msg(msg); 274062306a36Sopenharmony_ci return ret; 274162306a36Sopenharmony_ci } 274262306a36Sopenharmony_ci return 0; 274362306a36Sopenharmony_ci} 274462306a36Sopenharmony_ci 274562306a36Sopenharmony_ciint ib_send_cm_drep(struct ib_cm_id *cm_id, const void *private_data, 274662306a36Sopenharmony_ci u8 private_data_len) 274762306a36Sopenharmony_ci{ 274862306a36Sopenharmony_ci struct cm_id_private *cm_id_priv = 274962306a36Sopenharmony_ci container_of(cm_id, struct cm_id_private, id); 275062306a36Sopenharmony_ci unsigned long flags; 275162306a36Sopenharmony_ci void *data; 275262306a36Sopenharmony_ci int ret; 275362306a36Sopenharmony_ci 275462306a36Sopenharmony_ci data = cm_copy_private_data(private_data, private_data_len); 275562306a36Sopenharmony_ci if (IS_ERR(data)) 275662306a36Sopenharmony_ci return PTR_ERR(data); 275762306a36Sopenharmony_ci 275862306a36Sopenharmony_ci spin_lock_irqsave(&cm_id_priv->lock, flags); 275962306a36Sopenharmony_ci ret = cm_send_drep_locked(cm_id_priv, data, private_data_len); 276062306a36Sopenharmony_ci spin_unlock_irqrestore(&cm_id_priv->lock, flags); 276162306a36Sopenharmony_ci return ret; 276262306a36Sopenharmony_ci} 276362306a36Sopenharmony_ciEXPORT_SYMBOL(ib_send_cm_drep); 276462306a36Sopenharmony_ci 276562306a36Sopenharmony_cistatic int cm_issue_drep(struct cm_port *port, 276662306a36Sopenharmony_ci struct ib_mad_recv_wc *mad_recv_wc) 276762306a36Sopenharmony_ci{ 276862306a36Sopenharmony_ci struct ib_mad_send_buf *msg = NULL; 276962306a36Sopenharmony_ci struct cm_dreq_msg *dreq_msg; 277062306a36Sopenharmony_ci struct cm_drep_msg *drep_msg; 277162306a36Sopenharmony_ci int ret; 277262306a36Sopenharmony_ci 277362306a36Sopenharmony_ci ret = cm_alloc_response_msg(port, mad_recv_wc, &msg); 277462306a36Sopenharmony_ci if (ret) 277562306a36Sopenharmony_ci return ret; 277662306a36Sopenharmony_ci 277762306a36Sopenharmony_ci dreq_msg = (struct cm_dreq_msg *) mad_recv_wc->recv_buf.mad; 277862306a36Sopenharmony_ci drep_msg = (struct cm_drep_msg *) msg->mad; 277962306a36Sopenharmony_ci 278062306a36Sopenharmony_ci cm_format_mad_hdr(&drep_msg->hdr, CM_DREP_ATTR_ID, dreq_msg->hdr.tid); 278162306a36Sopenharmony_ci IBA_SET(CM_DREP_REMOTE_COMM_ID, drep_msg, 278262306a36Sopenharmony_ci IBA_GET(CM_DREQ_LOCAL_COMM_ID, dreq_msg)); 278362306a36Sopenharmony_ci IBA_SET(CM_DREP_LOCAL_COMM_ID, drep_msg, 278462306a36Sopenharmony_ci IBA_GET(CM_DREQ_REMOTE_COMM_ID, dreq_msg)); 278562306a36Sopenharmony_ci 278662306a36Sopenharmony_ci trace_icm_issue_drep( 278762306a36Sopenharmony_ci IBA_GET(CM_DREQ_LOCAL_COMM_ID, dreq_msg), 278862306a36Sopenharmony_ci IBA_GET(CM_DREQ_REMOTE_COMM_ID, dreq_msg)); 278962306a36Sopenharmony_ci ret = ib_post_send_mad(msg, NULL); 279062306a36Sopenharmony_ci if (ret) 279162306a36Sopenharmony_ci cm_free_response_msg(msg); 279262306a36Sopenharmony_ci 279362306a36Sopenharmony_ci return ret; 279462306a36Sopenharmony_ci} 279562306a36Sopenharmony_ci 279662306a36Sopenharmony_cistatic int cm_dreq_handler(struct cm_work *work) 279762306a36Sopenharmony_ci{ 279862306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 279962306a36Sopenharmony_ci struct cm_dreq_msg *dreq_msg; 280062306a36Sopenharmony_ci struct ib_mad_send_buf *msg = NULL; 280162306a36Sopenharmony_ci 280262306a36Sopenharmony_ci dreq_msg = (struct cm_dreq_msg *)work->mad_recv_wc->recv_buf.mad; 280362306a36Sopenharmony_ci cm_id_priv = cm_acquire_id( 280462306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_DREQ_REMOTE_COMM_ID, dreq_msg)), 280562306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_DREQ_LOCAL_COMM_ID, dreq_msg))); 280662306a36Sopenharmony_ci if (!cm_id_priv) { 280762306a36Sopenharmony_ci atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES] 280862306a36Sopenharmony_ci [CM_DREQ_COUNTER]); 280962306a36Sopenharmony_ci cm_issue_drep(work->port, work->mad_recv_wc); 281062306a36Sopenharmony_ci trace_icm_no_priv_err( 281162306a36Sopenharmony_ci IBA_GET(CM_DREQ_LOCAL_COMM_ID, dreq_msg), 281262306a36Sopenharmony_ci IBA_GET(CM_DREQ_REMOTE_COMM_ID, dreq_msg)); 281362306a36Sopenharmony_ci return -EINVAL; 281462306a36Sopenharmony_ci } 281562306a36Sopenharmony_ci 281662306a36Sopenharmony_ci work->cm_event.private_data = 281762306a36Sopenharmony_ci IBA_GET_MEM_PTR(CM_DREQ_PRIVATE_DATA, dreq_msg); 281862306a36Sopenharmony_ci 281962306a36Sopenharmony_ci spin_lock_irq(&cm_id_priv->lock); 282062306a36Sopenharmony_ci if (cm_id_priv->local_qpn != 282162306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_DREQ_REMOTE_QPN_EECN, dreq_msg))) 282262306a36Sopenharmony_ci goto unlock; 282362306a36Sopenharmony_ci 282462306a36Sopenharmony_ci switch (cm_id_priv->id.state) { 282562306a36Sopenharmony_ci case IB_CM_REP_SENT: 282662306a36Sopenharmony_ci case IB_CM_DREQ_SENT: 282762306a36Sopenharmony_ci case IB_CM_MRA_REP_RCVD: 282862306a36Sopenharmony_ci ib_cancel_mad(cm_id_priv->msg); 282962306a36Sopenharmony_ci break; 283062306a36Sopenharmony_ci case IB_CM_ESTABLISHED: 283162306a36Sopenharmony_ci if (cm_id_priv->id.lap_state == IB_CM_LAP_SENT || 283262306a36Sopenharmony_ci cm_id_priv->id.lap_state == IB_CM_MRA_LAP_RCVD) 283362306a36Sopenharmony_ci ib_cancel_mad(cm_id_priv->msg); 283462306a36Sopenharmony_ci break; 283562306a36Sopenharmony_ci case IB_CM_TIMEWAIT: 283662306a36Sopenharmony_ci atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES] 283762306a36Sopenharmony_ci [CM_DREQ_COUNTER]); 283862306a36Sopenharmony_ci msg = cm_alloc_response_msg_no_ah(work->port, work->mad_recv_wc); 283962306a36Sopenharmony_ci if (IS_ERR(msg)) 284062306a36Sopenharmony_ci goto unlock; 284162306a36Sopenharmony_ci 284262306a36Sopenharmony_ci cm_format_drep((struct cm_drep_msg *) msg->mad, cm_id_priv, 284362306a36Sopenharmony_ci cm_id_priv->private_data, 284462306a36Sopenharmony_ci cm_id_priv->private_data_len); 284562306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 284662306a36Sopenharmony_ci 284762306a36Sopenharmony_ci if (cm_create_response_msg_ah(work->port, work->mad_recv_wc, msg) || 284862306a36Sopenharmony_ci ib_post_send_mad(msg, NULL)) 284962306a36Sopenharmony_ci cm_free_response_msg(msg); 285062306a36Sopenharmony_ci goto deref; 285162306a36Sopenharmony_ci case IB_CM_DREQ_RCVD: 285262306a36Sopenharmony_ci atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES] 285362306a36Sopenharmony_ci [CM_DREQ_COUNTER]); 285462306a36Sopenharmony_ci goto unlock; 285562306a36Sopenharmony_ci default: 285662306a36Sopenharmony_ci trace_icm_dreq_unknown_err(&cm_id_priv->id); 285762306a36Sopenharmony_ci goto unlock; 285862306a36Sopenharmony_ci } 285962306a36Sopenharmony_ci cm_id_priv->id.state = IB_CM_DREQ_RCVD; 286062306a36Sopenharmony_ci cm_id_priv->tid = dreq_msg->hdr.tid; 286162306a36Sopenharmony_ci cm_queue_work_unlock(cm_id_priv, work); 286262306a36Sopenharmony_ci return 0; 286362306a36Sopenharmony_ci 286462306a36Sopenharmony_ciunlock: spin_unlock_irq(&cm_id_priv->lock); 286562306a36Sopenharmony_cideref: cm_deref_id(cm_id_priv); 286662306a36Sopenharmony_ci return -EINVAL; 286762306a36Sopenharmony_ci} 286862306a36Sopenharmony_ci 286962306a36Sopenharmony_cistatic int cm_drep_handler(struct cm_work *work) 287062306a36Sopenharmony_ci{ 287162306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 287262306a36Sopenharmony_ci struct cm_drep_msg *drep_msg; 287362306a36Sopenharmony_ci 287462306a36Sopenharmony_ci drep_msg = (struct cm_drep_msg *)work->mad_recv_wc->recv_buf.mad; 287562306a36Sopenharmony_ci cm_id_priv = cm_acquire_id( 287662306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_DREP_REMOTE_COMM_ID, drep_msg)), 287762306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_DREP_LOCAL_COMM_ID, drep_msg))); 287862306a36Sopenharmony_ci if (!cm_id_priv) 287962306a36Sopenharmony_ci return -EINVAL; 288062306a36Sopenharmony_ci 288162306a36Sopenharmony_ci work->cm_event.private_data = 288262306a36Sopenharmony_ci IBA_GET_MEM_PTR(CM_DREP_PRIVATE_DATA, drep_msg); 288362306a36Sopenharmony_ci 288462306a36Sopenharmony_ci spin_lock_irq(&cm_id_priv->lock); 288562306a36Sopenharmony_ci if (cm_id_priv->id.state != IB_CM_DREQ_SENT && 288662306a36Sopenharmony_ci cm_id_priv->id.state != IB_CM_DREQ_RCVD) { 288762306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 288862306a36Sopenharmony_ci goto out; 288962306a36Sopenharmony_ci } 289062306a36Sopenharmony_ci cm_enter_timewait(cm_id_priv); 289162306a36Sopenharmony_ci 289262306a36Sopenharmony_ci ib_cancel_mad(cm_id_priv->msg); 289362306a36Sopenharmony_ci cm_queue_work_unlock(cm_id_priv, work); 289462306a36Sopenharmony_ci return 0; 289562306a36Sopenharmony_ciout: 289662306a36Sopenharmony_ci cm_deref_id(cm_id_priv); 289762306a36Sopenharmony_ci return -EINVAL; 289862306a36Sopenharmony_ci} 289962306a36Sopenharmony_ci 290062306a36Sopenharmony_cistatic int cm_send_rej_locked(struct cm_id_private *cm_id_priv, 290162306a36Sopenharmony_ci enum ib_cm_rej_reason reason, void *ari, 290262306a36Sopenharmony_ci u8 ari_length, const void *private_data, 290362306a36Sopenharmony_ci u8 private_data_len) 290462306a36Sopenharmony_ci{ 290562306a36Sopenharmony_ci enum ib_cm_state state = cm_id_priv->id.state; 290662306a36Sopenharmony_ci struct ib_mad_send_buf *msg; 290762306a36Sopenharmony_ci int ret; 290862306a36Sopenharmony_ci 290962306a36Sopenharmony_ci lockdep_assert_held(&cm_id_priv->lock); 291062306a36Sopenharmony_ci 291162306a36Sopenharmony_ci if ((private_data && private_data_len > IB_CM_REJ_PRIVATE_DATA_SIZE) || 291262306a36Sopenharmony_ci (ari && ari_length > IB_CM_REJ_ARI_LENGTH)) 291362306a36Sopenharmony_ci return -EINVAL; 291462306a36Sopenharmony_ci 291562306a36Sopenharmony_ci trace_icm_send_rej(&cm_id_priv->id, reason); 291662306a36Sopenharmony_ci 291762306a36Sopenharmony_ci switch (state) { 291862306a36Sopenharmony_ci case IB_CM_REQ_SENT: 291962306a36Sopenharmony_ci case IB_CM_MRA_REQ_RCVD: 292062306a36Sopenharmony_ci case IB_CM_REQ_RCVD: 292162306a36Sopenharmony_ci case IB_CM_MRA_REQ_SENT: 292262306a36Sopenharmony_ci case IB_CM_REP_RCVD: 292362306a36Sopenharmony_ci case IB_CM_MRA_REP_SENT: 292462306a36Sopenharmony_ci cm_reset_to_idle(cm_id_priv); 292562306a36Sopenharmony_ci msg = cm_alloc_msg(cm_id_priv); 292662306a36Sopenharmony_ci if (IS_ERR(msg)) 292762306a36Sopenharmony_ci return PTR_ERR(msg); 292862306a36Sopenharmony_ci cm_format_rej((struct cm_rej_msg *)msg->mad, cm_id_priv, reason, 292962306a36Sopenharmony_ci ari, ari_length, private_data, private_data_len, 293062306a36Sopenharmony_ci state); 293162306a36Sopenharmony_ci break; 293262306a36Sopenharmony_ci case IB_CM_REP_SENT: 293362306a36Sopenharmony_ci case IB_CM_MRA_REP_RCVD: 293462306a36Sopenharmony_ci cm_enter_timewait(cm_id_priv); 293562306a36Sopenharmony_ci msg = cm_alloc_msg(cm_id_priv); 293662306a36Sopenharmony_ci if (IS_ERR(msg)) 293762306a36Sopenharmony_ci return PTR_ERR(msg); 293862306a36Sopenharmony_ci cm_format_rej((struct cm_rej_msg *)msg->mad, cm_id_priv, reason, 293962306a36Sopenharmony_ci ari, ari_length, private_data, private_data_len, 294062306a36Sopenharmony_ci state); 294162306a36Sopenharmony_ci break; 294262306a36Sopenharmony_ci default: 294362306a36Sopenharmony_ci trace_icm_send_unknown_rej_err(&cm_id_priv->id); 294462306a36Sopenharmony_ci return -EINVAL; 294562306a36Sopenharmony_ci } 294662306a36Sopenharmony_ci 294762306a36Sopenharmony_ci ret = ib_post_send_mad(msg, NULL); 294862306a36Sopenharmony_ci if (ret) { 294962306a36Sopenharmony_ci cm_free_msg(msg); 295062306a36Sopenharmony_ci return ret; 295162306a36Sopenharmony_ci } 295262306a36Sopenharmony_ci 295362306a36Sopenharmony_ci return 0; 295462306a36Sopenharmony_ci} 295562306a36Sopenharmony_ci 295662306a36Sopenharmony_ciint ib_send_cm_rej(struct ib_cm_id *cm_id, enum ib_cm_rej_reason reason, 295762306a36Sopenharmony_ci void *ari, u8 ari_length, const void *private_data, 295862306a36Sopenharmony_ci u8 private_data_len) 295962306a36Sopenharmony_ci{ 296062306a36Sopenharmony_ci struct cm_id_private *cm_id_priv = 296162306a36Sopenharmony_ci container_of(cm_id, struct cm_id_private, id); 296262306a36Sopenharmony_ci unsigned long flags; 296362306a36Sopenharmony_ci int ret; 296462306a36Sopenharmony_ci 296562306a36Sopenharmony_ci spin_lock_irqsave(&cm_id_priv->lock, flags); 296662306a36Sopenharmony_ci ret = cm_send_rej_locked(cm_id_priv, reason, ari, ari_length, 296762306a36Sopenharmony_ci private_data, private_data_len); 296862306a36Sopenharmony_ci spin_unlock_irqrestore(&cm_id_priv->lock, flags); 296962306a36Sopenharmony_ci return ret; 297062306a36Sopenharmony_ci} 297162306a36Sopenharmony_ciEXPORT_SYMBOL(ib_send_cm_rej); 297262306a36Sopenharmony_ci 297362306a36Sopenharmony_cistatic void cm_format_rej_event(struct cm_work *work) 297462306a36Sopenharmony_ci{ 297562306a36Sopenharmony_ci struct cm_rej_msg *rej_msg; 297662306a36Sopenharmony_ci struct ib_cm_rej_event_param *param; 297762306a36Sopenharmony_ci 297862306a36Sopenharmony_ci rej_msg = (struct cm_rej_msg *)work->mad_recv_wc->recv_buf.mad; 297962306a36Sopenharmony_ci param = &work->cm_event.param.rej_rcvd; 298062306a36Sopenharmony_ci param->ari = IBA_GET_MEM_PTR(CM_REJ_ARI, rej_msg); 298162306a36Sopenharmony_ci param->ari_length = IBA_GET(CM_REJ_REJECTED_INFO_LENGTH, rej_msg); 298262306a36Sopenharmony_ci param->reason = IBA_GET(CM_REJ_REASON, rej_msg); 298362306a36Sopenharmony_ci work->cm_event.private_data = 298462306a36Sopenharmony_ci IBA_GET_MEM_PTR(CM_REJ_PRIVATE_DATA, rej_msg); 298562306a36Sopenharmony_ci} 298662306a36Sopenharmony_ci 298762306a36Sopenharmony_cistatic struct cm_id_private *cm_acquire_rejected_id(struct cm_rej_msg *rej_msg) 298862306a36Sopenharmony_ci{ 298962306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 299062306a36Sopenharmony_ci __be32 remote_id; 299162306a36Sopenharmony_ci 299262306a36Sopenharmony_ci remote_id = cpu_to_be32(IBA_GET(CM_REJ_LOCAL_COMM_ID, rej_msg)); 299362306a36Sopenharmony_ci 299462306a36Sopenharmony_ci if (IBA_GET(CM_REJ_REASON, rej_msg) == IB_CM_REJ_TIMEOUT) { 299562306a36Sopenharmony_ci cm_id_priv = cm_find_remote_id( 299662306a36Sopenharmony_ci *((__be64 *)IBA_GET_MEM_PTR(CM_REJ_ARI, rej_msg)), 299762306a36Sopenharmony_ci remote_id); 299862306a36Sopenharmony_ci } else if (IBA_GET(CM_REJ_MESSAGE_REJECTED, rej_msg) == 299962306a36Sopenharmony_ci CM_MSG_RESPONSE_REQ) 300062306a36Sopenharmony_ci cm_id_priv = cm_acquire_id( 300162306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_REJ_REMOTE_COMM_ID, rej_msg)), 300262306a36Sopenharmony_ci 0); 300362306a36Sopenharmony_ci else 300462306a36Sopenharmony_ci cm_id_priv = cm_acquire_id( 300562306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_REJ_REMOTE_COMM_ID, rej_msg)), 300662306a36Sopenharmony_ci remote_id); 300762306a36Sopenharmony_ci 300862306a36Sopenharmony_ci return cm_id_priv; 300962306a36Sopenharmony_ci} 301062306a36Sopenharmony_ci 301162306a36Sopenharmony_cistatic int cm_rej_handler(struct cm_work *work) 301262306a36Sopenharmony_ci{ 301362306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 301462306a36Sopenharmony_ci struct cm_rej_msg *rej_msg; 301562306a36Sopenharmony_ci 301662306a36Sopenharmony_ci rej_msg = (struct cm_rej_msg *)work->mad_recv_wc->recv_buf.mad; 301762306a36Sopenharmony_ci cm_id_priv = cm_acquire_rejected_id(rej_msg); 301862306a36Sopenharmony_ci if (!cm_id_priv) 301962306a36Sopenharmony_ci return -EINVAL; 302062306a36Sopenharmony_ci 302162306a36Sopenharmony_ci cm_format_rej_event(work); 302262306a36Sopenharmony_ci 302362306a36Sopenharmony_ci spin_lock_irq(&cm_id_priv->lock); 302462306a36Sopenharmony_ci switch (cm_id_priv->id.state) { 302562306a36Sopenharmony_ci case IB_CM_REQ_SENT: 302662306a36Sopenharmony_ci case IB_CM_MRA_REQ_RCVD: 302762306a36Sopenharmony_ci case IB_CM_REP_SENT: 302862306a36Sopenharmony_ci case IB_CM_MRA_REP_RCVD: 302962306a36Sopenharmony_ci ib_cancel_mad(cm_id_priv->msg); 303062306a36Sopenharmony_ci fallthrough; 303162306a36Sopenharmony_ci case IB_CM_REQ_RCVD: 303262306a36Sopenharmony_ci case IB_CM_MRA_REQ_SENT: 303362306a36Sopenharmony_ci if (IBA_GET(CM_REJ_REASON, rej_msg) == IB_CM_REJ_STALE_CONN) 303462306a36Sopenharmony_ci cm_enter_timewait(cm_id_priv); 303562306a36Sopenharmony_ci else 303662306a36Sopenharmony_ci cm_reset_to_idle(cm_id_priv); 303762306a36Sopenharmony_ci break; 303862306a36Sopenharmony_ci case IB_CM_DREQ_SENT: 303962306a36Sopenharmony_ci ib_cancel_mad(cm_id_priv->msg); 304062306a36Sopenharmony_ci fallthrough; 304162306a36Sopenharmony_ci case IB_CM_REP_RCVD: 304262306a36Sopenharmony_ci case IB_CM_MRA_REP_SENT: 304362306a36Sopenharmony_ci cm_enter_timewait(cm_id_priv); 304462306a36Sopenharmony_ci break; 304562306a36Sopenharmony_ci case IB_CM_ESTABLISHED: 304662306a36Sopenharmony_ci if (cm_id_priv->id.lap_state == IB_CM_LAP_UNINIT || 304762306a36Sopenharmony_ci cm_id_priv->id.lap_state == IB_CM_LAP_SENT) { 304862306a36Sopenharmony_ci if (cm_id_priv->id.lap_state == IB_CM_LAP_SENT) 304962306a36Sopenharmony_ci ib_cancel_mad(cm_id_priv->msg); 305062306a36Sopenharmony_ci cm_enter_timewait(cm_id_priv); 305162306a36Sopenharmony_ci break; 305262306a36Sopenharmony_ci } 305362306a36Sopenharmony_ci fallthrough; 305462306a36Sopenharmony_ci default: 305562306a36Sopenharmony_ci trace_icm_rej_unknown_err(&cm_id_priv->id); 305662306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 305762306a36Sopenharmony_ci goto out; 305862306a36Sopenharmony_ci } 305962306a36Sopenharmony_ci 306062306a36Sopenharmony_ci cm_queue_work_unlock(cm_id_priv, work); 306162306a36Sopenharmony_ci return 0; 306262306a36Sopenharmony_ciout: 306362306a36Sopenharmony_ci cm_deref_id(cm_id_priv); 306462306a36Sopenharmony_ci return -EINVAL; 306562306a36Sopenharmony_ci} 306662306a36Sopenharmony_ci 306762306a36Sopenharmony_ciint ib_send_cm_mra(struct ib_cm_id *cm_id, 306862306a36Sopenharmony_ci u8 service_timeout, 306962306a36Sopenharmony_ci const void *private_data, 307062306a36Sopenharmony_ci u8 private_data_len) 307162306a36Sopenharmony_ci{ 307262306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 307362306a36Sopenharmony_ci struct ib_mad_send_buf *msg; 307462306a36Sopenharmony_ci enum ib_cm_state cm_state; 307562306a36Sopenharmony_ci enum ib_cm_lap_state lap_state; 307662306a36Sopenharmony_ci enum cm_msg_response msg_response; 307762306a36Sopenharmony_ci void *data; 307862306a36Sopenharmony_ci unsigned long flags; 307962306a36Sopenharmony_ci int ret; 308062306a36Sopenharmony_ci 308162306a36Sopenharmony_ci if (private_data && private_data_len > IB_CM_MRA_PRIVATE_DATA_SIZE) 308262306a36Sopenharmony_ci return -EINVAL; 308362306a36Sopenharmony_ci 308462306a36Sopenharmony_ci data = cm_copy_private_data(private_data, private_data_len); 308562306a36Sopenharmony_ci if (IS_ERR(data)) 308662306a36Sopenharmony_ci return PTR_ERR(data); 308762306a36Sopenharmony_ci 308862306a36Sopenharmony_ci cm_id_priv = container_of(cm_id, struct cm_id_private, id); 308962306a36Sopenharmony_ci 309062306a36Sopenharmony_ci spin_lock_irqsave(&cm_id_priv->lock, flags); 309162306a36Sopenharmony_ci switch (cm_id_priv->id.state) { 309262306a36Sopenharmony_ci case IB_CM_REQ_RCVD: 309362306a36Sopenharmony_ci cm_state = IB_CM_MRA_REQ_SENT; 309462306a36Sopenharmony_ci lap_state = cm_id->lap_state; 309562306a36Sopenharmony_ci msg_response = CM_MSG_RESPONSE_REQ; 309662306a36Sopenharmony_ci break; 309762306a36Sopenharmony_ci case IB_CM_REP_RCVD: 309862306a36Sopenharmony_ci cm_state = IB_CM_MRA_REP_SENT; 309962306a36Sopenharmony_ci lap_state = cm_id->lap_state; 310062306a36Sopenharmony_ci msg_response = CM_MSG_RESPONSE_REP; 310162306a36Sopenharmony_ci break; 310262306a36Sopenharmony_ci case IB_CM_ESTABLISHED: 310362306a36Sopenharmony_ci if (cm_id->lap_state == IB_CM_LAP_RCVD) { 310462306a36Sopenharmony_ci cm_state = cm_id->state; 310562306a36Sopenharmony_ci lap_state = IB_CM_MRA_LAP_SENT; 310662306a36Sopenharmony_ci msg_response = CM_MSG_RESPONSE_OTHER; 310762306a36Sopenharmony_ci break; 310862306a36Sopenharmony_ci } 310962306a36Sopenharmony_ci fallthrough; 311062306a36Sopenharmony_ci default: 311162306a36Sopenharmony_ci trace_icm_send_mra_unknown_err(&cm_id_priv->id); 311262306a36Sopenharmony_ci ret = -EINVAL; 311362306a36Sopenharmony_ci goto error_unlock; 311462306a36Sopenharmony_ci } 311562306a36Sopenharmony_ci 311662306a36Sopenharmony_ci if (!(service_timeout & IB_CM_MRA_FLAG_DELAY)) { 311762306a36Sopenharmony_ci msg = cm_alloc_msg(cm_id_priv); 311862306a36Sopenharmony_ci if (IS_ERR(msg)) { 311962306a36Sopenharmony_ci ret = PTR_ERR(msg); 312062306a36Sopenharmony_ci goto error_unlock; 312162306a36Sopenharmony_ci } 312262306a36Sopenharmony_ci 312362306a36Sopenharmony_ci cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, 312462306a36Sopenharmony_ci msg_response, service_timeout, 312562306a36Sopenharmony_ci private_data, private_data_len); 312662306a36Sopenharmony_ci trace_icm_send_mra(cm_id); 312762306a36Sopenharmony_ci ret = ib_post_send_mad(msg, NULL); 312862306a36Sopenharmony_ci if (ret) 312962306a36Sopenharmony_ci goto error_free_msg; 313062306a36Sopenharmony_ci } 313162306a36Sopenharmony_ci 313262306a36Sopenharmony_ci cm_id->state = cm_state; 313362306a36Sopenharmony_ci cm_id->lap_state = lap_state; 313462306a36Sopenharmony_ci cm_id_priv->service_timeout = service_timeout; 313562306a36Sopenharmony_ci cm_set_private_data(cm_id_priv, data, private_data_len); 313662306a36Sopenharmony_ci spin_unlock_irqrestore(&cm_id_priv->lock, flags); 313762306a36Sopenharmony_ci return 0; 313862306a36Sopenharmony_ci 313962306a36Sopenharmony_cierror_free_msg: 314062306a36Sopenharmony_ci cm_free_msg(msg); 314162306a36Sopenharmony_cierror_unlock: 314262306a36Sopenharmony_ci spin_unlock_irqrestore(&cm_id_priv->lock, flags); 314362306a36Sopenharmony_ci kfree(data); 314462306a36Sopenharmony_ci return ret; 314562306a36Sopenharmony_ci} 314662306a36Sopenharmony_ciEXPORT_SYMBOL(ib_send_cm_mra); 314762306a36Sopenharmony_ci 314862306a36Sopenharmony_cistatic struct cm_id_private *cm_acquire_mraed_id(struct cm_mra_msg *mra_msg) 314962306a36Sopenharmony_ci{ 315062306a36Sopenharmony_ci switch (IBA_GET(CM_MRA_MESSAGE_MRAED, mra_msg)) { 315162306a36Sopenharmony_ci case CM_MSG_RESPONSE_REQ: 315262306a36Sopenharmony_ci return cm_acquire_id( 315362306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_MRA_REMOTE_COMM_ID, mra_msg)), 315462306a36Sopenharmony_ci 0); 315562306a36Sopenharmony_ci case CM_MSG_RESPONSE_REP: 315662306a36Sopenharmony_ci case CM_MSG_RESPONSE_OTHER: 315762306a36Sopenharmony_ci return cm_acquire_id( 315862306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_MRA_REMOTE_COMM_ID, mra_msg)), 315962306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_MRA_LOCAL_COMM_ID, mra_msg))); 316062306a36Sopenharmony_ci default: 316162306a36Sopenharmony_ci return NULL; 316262306a36Sopenharmony_ci } 316362306a36Sopenharmony_ci} 316462306a36Sopenharmony_ci 316562306a36Sopenharmony_cistatic int cm_mra_handler(struct cm_work *work) 316662306a36Sopenharmony_ci{ 316762306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 316862306a36Sopenharmony_ci struct cm_mra_msg *mra_msg; 316962306a36Sopenharmony_ci int timeout; 317062306a36Sopenharmony_ci 317162306a36Sopenharmony_ci mra_msg = (struct cm_mra_msg *)work->mad_recv_wc->recv_buf.mad; 317262306a36Sopenharmony_ci cm_id_priv = cm_acquire_mraed_id(mra_msg); 317362306a36Sopenharmony_ci if (!cm_id_priv) 317462306a36Sopenharmony_ci return -EINVAL; 317562306a36Sopenharmony_ci 317662306a36Sopenharmony_ci work->cm_event.private_data = 317762306a36Sopenharmony_ci IBA_GET_MEM_PTR(CM_MRA_PRIVATE_DATA, mra_msg); 317862306a36Sopenharmony_ci work->cm_event.param.mra_rcvd.service_timeout = 317962306a36Sopenharmony_ci IBA_GET(CM_MRA_SERVICE_TIMEOUT, mra_msg); 318062306a36Sopenharmony_ci timeout = cm_convert_to_ms(IBA_GET(CM_MRA_SERVICE_TIMEOUT, mra_msg)) + 318162306a36Sopenharmony_ci cm_convert_to_ms(cm_id_priv->av.timeout); 318262306a36Sopenharmony_ci 318362306a36Sopenharmony_ci spin_lock_irq(&cm_id_priv->lock); 318462306a36Sopenharmony_ci switch (cm_id_priv->id.state) { 318562306a36Sopenharmony_ci case IB_CM_REQ_SENT: 318662306a36Sopenharmony_ci if (IBA_GET(CM_MRA_MESSAGE_MRAED, mra_msg) != 318762306a36Sopenharmony_ci CM_MSG_RESPONSE_REQ || 318862306a36Sopenharmony_ci ib_modify_mad(cm_id_priv->msg, timeout)) 318962306a36Sopenharmony_ci goto out; 319062306a36Sopenharmony_ci cm_id_priv->id.state = IB_CM_MRA_REQ_RCVD; 319162306a36Sopenharmony_ci break; 319262306a36Sopenharmony_ci case IB_CM_REP_SENT: 319362306a36Sopenharmony_ci if (IBA_GET(CM_MRA_MESSAGE_MRAED, mra_msg) != 319462306a36Sopenharmony_ci CM_MSG_RESPONSE_REP || 319562306a36Sopenharmony_ci ib_modify_mad(cm_id_priv->msg, timeout)) 319662306a36Sopenharmony_ci goto out; 319762306a36Sopenharmony_ci cm_id_priv->id.state = IB_CM_MRA_REP_RCVD; 319862306a36Sopenharmony_ci break; 319962306a36Sopenharmony_ci case IB_CM_ESTABLISHED: 320062306a36Sopenharmony_ci if (IBA_GET(CM_MRA_MESSAGE_MRAED, mra_msg) != 320162306a36Sopenharmony_ci CM_MSG_RESPONSE_OTHER || 320262306a36Sopenharmony_ci cm_id_priv->id.lap_state != IB_CM_LAP_SENT || 320362306a36Sopenharmony_ci ib_modify_mad(cm_id_priv->msg, timeout)) { 320462306a36Sopenharmony_ci if (cm_id_priv->id.lap_state == IB_CM_MRA_LAP_RCVD) 320562306a36Sopenharmony_ci atomic_long_inc( 320662306a36Sopenharmony_ci &work->port->counters[CM_RECV_DUPLICATES] 320762306a36Sopenharmony_ci [CM_MRA_COUNTER]); 320862306a36Sopenharmony_ci goto out; 320962306a36Sopenharmony_ci } 321062306a36Sopenharmony_ci cm_id_priv->id.lap_state = IB_CM_MRA_LAP_RCVD; 321162306a36Sopenharmony_ci break; 321262306a36Sopenharmony_ci case IB_CM_MRA_REQ_RCVD: 321362306a36Sopenharmony_ci case IB_CM_MRA_REP_RCVD: 321462306a36Sopenharmony_ci atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES] 321562306a36Sopenharmony_ci [CM_MRA_COUNTER]); 321662306a36Sopenharmony_ci fallthrough; 321762306a36Sopenharmony_ci default: 321862306a36Sopenharmony_ci trace_icm_mra_unknown_err(&cm_id_priv->id); 321962306a36Sopenharmony_ci goto out; 322062306a36Sopenharmony_ci } 322162306a36Sopenharmony_ci 322262306a36Sopenharmony_ci cm_id_priv->msg->context[1] = (void *) (unsigned long) 322362306a36Sopenharmony_ci cm_id_priv->id.state; 322462306a36Sopenharmony_ci cm_queue_work_unlock(cm_id_priv, work); 322562306a36Sopenharmony_ci return 0; 322662306a36Sopenharmony_ciout: 322762306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 322862306a36Sopenharmony_ci cm_deref_id(cm_id_priv); 322962306a36Sopenharmony_ci return -EINVAL; 323062306a36Sopenharmony_ci} 323162306a36Sopenharmony_ci 323262306a36Sopenharmony_cistatic void cm_format_path_lid_from_lap(struct cm_lap_msg *lap_msg, 323362306a36Sopenharmony_ci struct sa_path_rec *path) 323462306a36Sopenharmony_ci{ 323562306a36Sopenharmony_ci u32 lid; 323662306a36Sopenharmony_ci 323762306a36Sopenharmony_ci if (path->rec_type != SA_PATH_REC_TYPE_OPA) { 323862306a36Sopenharmony_ci sa_path_set_dlid(path, IBA_GET(CM_LAP_ALTERNATE_LOCAL_PORT_LID, 323962306a36Sopenharmony_ci lap_msg)); 324062306a36Sopenharmony_ci sa_path_set_slid(path, IBA_GET(CM_LAP_ALTERNATE_REMOTE_PORT_LID, 324162306a36Sopenharmony_ci lap_msg)); 324262306a36Sopenharmony_ci } else { 324362306a36Sopenharmony_ci lid = opa_get_lid_from_gid(IBA_GET_MEM_PTR( 324462306a36Sopenharmony_ci CM_LAP_ALTERNATE_LOCAL_PORT_GID, lap_msg)); 324562306a36Sopenharmony_ci sa_path_set_dlid(path, lid); 324662306a36Sopenharmony_ci 324762306a36Sopenharmony_ci lid = opa_get_lid_from_gid(IBA_GET_MEM_PTR( 324862306a36Sopenharmony_ci CM_LAP_ALTERNATE_REMOTE_PORT_GID, lap_msg)); 324962306a36Sopenharmony_ci sa_path_set_slid(path, lid); 325062306a36Sopenharmony_ci } 325162306a36Sopenharmony_ci} 325262306a36Sopenharmony_ci 325362306a36Sopenharmony_cistatic void cm_format_path_from_lap(struct cm_id_private *cm_id_priv, 325462306a36Sopenharmony_ci struct sa_path_rec *path, 325562306a36Sopenharmony_ci struct cm_lap_msg *lap_msg) 325662306a36Sopenharmony_ci{ 325762306a36Sopenharmony_ci path->dgid = *IBA_GET_MEM_PTR(CM_LAP_ALTERNATE_LOCAL_PORT_GID, lap_msg); 325862306a36Sopenharmony_ci path->sgid = 325962306a36Sopenharmony_ci *IBA_GET_MEM_PTR(CM_LAP_ALTERNATE_REMOTE_PORT_GID, lap_msg); 326062306a36Sopenharmony_ci path->flow_label = 326162306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_LAP_ALTERNATE_FLOW_LABEL, lap_msg)); 326262306a36Sopenharmony_ci path->hop_limit = IBA_GET(CM_LAP_ALTERNATE_HOP_LIMIT, lap_msg); 326362306a36Sopenharmony_ci path->traffic_class = IBA_GET(CM_LAP_ALTERNATE_TRAFFIC_CLASS, lap_msg); 326462306a36Sopenharmony_ci path->reversible = 1; 326562306a36Sopenharmony_ci path->pkey = cm_id_priv->pkey; 326662306a36Sopenharmony_ci path->sl = IBA_GET(CM_LAP_ALTERNATE_SL, lap_msg); 326762306a36Sopenharmony_ci path->mtu_selector = IB_SA_EQ; 326862306a36Sopenharmony_ci path->mtu = cm_id_priv->path_mtu; 326962306a36Sopenharmony_ci path->rate_selector = IB_SA_EQ; 327062306a36Sopenharmony_ci path->rate = IBA_GET(CM_LAP_ALTERNATE_PACKET_RATE, lap_msg); 327162306a36Sopenharmony_ci path->packet_life_time_selector = IB_SA_EQ; 327262306a36Sopenharmony_ci path->packet_life_time = 327362306a36Sopenharmony_ci IBA_GET(CM_LAP_ALTERNATE_LOCAL_ACK_TIMEOUT, lap_msg); 327462306a36Sopenharmony_ci path->packet_life_time -= (path->packet_life_time > 0); 327562306a36Sopenharmony_ci cm_format_path_lid_from_lap(lap_msg, path); 327662306a36Sopenharmony_ci} 327762306a36Sopenharmony_ci 327862306a36Sopenharmony_cistatic int cm_lap_handler(struct cm_work *work) 327962306a36Sopenharmony_ci{ 328062306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 328162306a36Sopenharmony_ci struct cm_lap_msg *lap_msg; 328262306a36Sopenharmony_ci struct ib_cm_lap_event_param *param; 328362306a36Sopenharmony_ci struct ib_mad_send_buf *msg = NULL; 328462306a36Sopenharmony_ci struct rdma_ah_attr ah_attr; 328562306a36Sopenharmony_ci struct cm_av alt_av = {}; 328662306a36Sopenharmony_ci int ret; 328762306a36Sopenharmony_ci 328862306a36Sopenharmony_ci /* Currently Alternate path messages are not supported for 328962306a36Sopenharmony_ci * RoCE link layer. 329062306a36Sopenharmony_ci */ 329162306a36Sopenharmony_ci if (rdma_protocol_roce(work->port->cm_dev->ib_device, 329262306a36Sopenharmony_ci work->port->port_num)) 329362306a36Sopenharmony_ci return -EINVAL; 329462306a36Sopenharmony_ci 329562306a36Sopenharmony_ci /* todo: verify LAP request and send reject APR if invalid. */ 329662306a36Sopenharmony_ci lap_msg = (struct cm_lap_msg *)work->mad_recv_wc->recv_buf.mad; 329762306a36Sopenharmony_ci cm_id_priv = cm_acquire_id( 329862306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_LAP_REMOTE_COMM_ID, lap_msg)), 329962306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_LAP_LOCAL_COMM_ID, lap_msg))); 330062306a36Sopenharmony_ci if (!cm_id_priv) 330162306a36Sopenharmony_ci return -EINVAL; 330262306a36Sopenharmony_ci 330362306a36Sopenharmony_ci param = &work->cm_event.param.lap_rcvd; 330462306a36Sopenharmony_ci memset(&work->path[0], 0, sizeof(work->path[1])); 330562306a36Sopenharmony_ci cm_path_set_rec_type(work->port->cm_dev->ib_device, 330662306a36Sopenharmony_ci work->port->port_num, &work->path[0], 330762306a36Sopenharmony_ci IBA_GET_MEM_PTR(CM_LAP_ALTERNATE_LOCAL_PORT_GID, 330862306a36Sopenharmony_ci lap_msg)); 330962306a36Sopenharmony_ci param->alternate_path = &work->path[0]; 331062306a36Sopenharmony_ci cm_format_path_from_lap(cm_id_priv, param->alternate_path, lap_msg); 331162306a36Sopenharmony_ci work->cm_event.private_data = 331262306a36Sopenharmony_ci IBA_GET_MEM_PTR(CM_LAP_PRIVATE_DATA, lap_msg); 331362306a36Sopenharmony_ci 331462306a36Sopenharmony_ci ret = ib_init_ah_attr_from_wc(work->port->cm_dev->ib_device, 331562306a36Sopenharmony_ci work->port->port_num, 331662306a36Sopenharmony_ci work->mad_recv_wc->wc, 331762306a36Sopenharmony_ci work->mad_recv_wc->recv_buf.grh, 331862306a36Sopenharmony_ci &ah_attr); 331962306a36Sopenharmony_ci if (ret) 332062306a36Sopenharmony_ci goto deref; 332162306a36Sopenharmony_ci 332262306a36Sopenharmony_ci ret = cm_init_av_by_path(param->alternate_path, NULL, &alt_av); 332362306a36Sopenharmony_ci if (ret) { 332462306a36Sopenharmony_ci rdma_destroy_ah_attr(&ah_attr); 332562306a36Sopenharmony_ci goto deref; 332662306a36Sopenharmony_ci } 332762306a36Sopenharmony_ci 332862306a36Sopenharmony_ci spin_lock_irq(&cm_id_priv->lock); 332962306a36Sopenharmony_ci cm_init_av_for_lap(work->port, work->mad_recv_wc->wc, 333062306a36Sopenharmony_ci &ah_attr, &cm_id_priv->av); 333162306a36Sopenharmony_ci cm_move_av_from_path(&cm_id_priv->alt_av, &alt_av); 333262306a36Sopenharmony_ci 333362306a36Sopenharmony_ci if (cm_id_priv->id.state != IB_CM_ESTABLISHED) 333462306a36Sopenharmony_ci goto unlock; 333562306a36Sopenharmony_ci 333662306a36Sopenharmony_ci switch (cm_id_priv->id.lap_state) { 333762306a36Sopenharmony_ci case IB_CM_LAP_UNINIT: 333862306a36Sopenharmony_ci case IB_CM_LAP_IDLE: 333962306a36Sopenharmony_ci break; 334062306a36Sopenharmony_ci case IB_CM_MRA_LAP_SENT: 334162306a36Sopenharmony_ci atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES] 334262306a36Sopenharmony_ci [CM_LAP_COUNTER]); 334362306a36Sopenharmony_ci msg = cm_alloc_response_msg_no_ah(work->port, work->mad_recv_wc); 334462306a36Sopenharmony_ci if (IS_ERR(msg)) 334562306a36Sopenharmony_ci goto unlock; 334662306a36Sopenharmony_ci 334762306a36Sopenharmony_ci cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, 334862306a36Sopenharmony_ci CM_MSG_RESPONSE_OTHER, 334962306a36Sopenharmony_ci cm_id_priv->service_timeout, 335062306a36Sopenharmony_ci cm_id_priv->private_data, 335162306a36Sopenharmony_ci cm_id_priv->private_data_len); 335262306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 335362306a36Sopenharmony_ci 335462306a36Sopenharmony_ci if (cm_create_response_msg_ah(work->port, work->mad_recv_wc, msg) || 335562306a36Sopenharmony_ci ib_post_send_mad(msg, NULL)) 335662306a36Sopenharmony_ci cm_free_response_msg(msg); 335762306a36Sopenharmony_ci goto deref; 335862306a36Sopenharmony_ci case IB_CM_LAP_RCVD: 335962306a36Sopenharmony_ci atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES] 336062306a36Sopenharmony_ci [CM_LAP_COUNTER]); 336162306a36Sopenharmony_ci goto unlock; 336262306a36Sopenharmony_ci default: 336362306a36Sopenharmony_ci goto unlock; 336462306a36Sopenharmony_ci } 336562306a36Sopenharmony_ci 336662306a36Sopenharmony_ci cm_id_priv->id.lap_state = IB_CM_LAP_RCVD; 336762306a36Sopenharmony_ci cm_id_priv->tid = lap_msg->hdr.tid; 336862306a36Sopenharmony_ci cm_queue_work_unlock(cm_id_priv, work); 336962306a36Sopenharmony_ci return 0; 337062306a36Sopenharmony_ci 337162306a36Sopenharmony_ciunlock: spin_unlock_irq(&cm_id_priv->lock); 337262306a36Sopenharmony_cideref: cm_deref_id(cm_id_priv); 337362306a36Sopenharmony_ci return -EINVAL; 337462306a36Sopenharmony_ci} 337562306a36Sopenharmony_ci 337662306a36Sopenharmony_cistatic int cm_apr_handler(struct cm_work *work) 337762306a36Sopenharmony_ci{ 337862306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 337962306a36Sopenharmony_ci struct cm_apr_msg *apr_msg; 338062306a36Sopenharmony_ci 338162306a36Sopenharmony_ci /* Currently Alternate path messages are not supported for 338262306a36Sopenharmony_ci * RoCE link layer. 338362306a36Sopenharmony_ci */ 338462306a36Sopenharmony_ci if (rdma_protocol_roce(work->port->cm_dev->ib_device, 338562306a36Sopenharmony_ci work->port->port_num)) 338662306a36Sopenharmony_ci return -EINVAL; 338762306a36Sopenharmony_ci 338862306a36Sopenharmony_ci apr_msg = (struct cm_apr_msg *)work->mad_recv_wc->recv_buf.mad; 338962306a36Sopenharmony_ci cm_id_priv = cm_acquire_id( 339062306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_APR_REMOTE_COMM_ID, apr_msg)), 339162306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_APR_LOCAL_COMM_ID, apr_msg))); 339262306a36Sopenharmony_ci if (!cm_id_priv) 339362306a36Sopenharmony_ci return -EINVAL; /* Unmatched reply. */ 339462306a36Sopenharmony_ci 339562306a36Sopenharmony_ci work->cm_event.param.apr_rcvd.ap_status = 339662306a36Sopenharmony_ci IBA_GET(CM_APR_AR_STATUS, apr_msg); 339762306a36Sopenharmony_ci work->cm_event.param.apr_rcvd.apr_info = 339862306a36Sopenharmony_ci IBA_GET_MEM_PTR(CM_APR_ADDITIONAL_INFORMATION, apr_msg); 339962306a36Sopenharmony_ci work->cm_event.param.apr_rcvd.info_len = 340062306a36Sopenharmony_ci IBA_GET(CM_APR_ADDITIONAL_INFORMATION_LENGTH, apr_msg); 340162306a36Sopenharmony_ci work->cm_event.private_data = 340262306a36Sopenharmony_ci IBA_GET_MEM_PTR(CM_APR_PRIVATE_DATA, apr_msg); 340362306a36Sopenharmony_ci 340462306a36Sopenharmony_ci spin_lock_irq(&cm_id_priv->lock); 340562306a36Sopenharmony_ci if (cm_id_priv->id.state != IB_CM_ESTABLISHED || 340662306a36Sopenharmony_ci (cm_id_priv->id.lap_state != IB_CM_LAP_SENT && 340762306a36Sopenharmony_ci cm_id_priv->id.lap_state != IB_CM_MRA_LAP_RCVD)) { 340862306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 340962306a36Sopenharmony_ci goto out; 341062306a36Sopenharmony_ci } 341162306a36Sopenharmony_ci cm_id_priv->id.lap_state = IB_CM_LAP_IDLE; 341262306a36Sopenharmony_ci ib_cancel_mad(cm_id_priv->msg); 341362306a36Sopenharmony_ci cm_queue_work_unlock(cm_id_priv, work); 341462306a36Sopenharmony_ci return 0; 341562306a36Sopenharmony_ciout: 341662306a36Sopenharmony_ci cm_deref_id(cm_id_priv); 341762306a36Sopenharmony_ci return -EINVAL; 341862306a36Sopenharmony_ci} 341962306a36Sopenharmony_ci 342062306a36Sopenharmony_cistatic int cm_timewait_handler(struct cm_work *work) 342162306a36Sopenharmony_ci{ 342262306a36Sopenharmony_ci struct cm_timewait_info *timewait_info; 342362306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 342462306a36Sopenharmony_ci 342562306a36Sopenharmony_ci timewait_info = container_of(work, struct cm_timewait_info, work); 342662306a36Sopenharmony_ci spin_lock_irq(&cm.lock); 342762306a36Sopenharmony_ci list_del(&timewait_info->list); 342862306a36Sopenharmony_ci spin_unlock_irq(&cm.lock); 342962306a36Sopenharmony_ci 343062306a36Sopenharmony_ci cm_id_priv = cm_acquire_id(timewait_info->work.local_id, 343162306a36Sopenharmony_ci timewait_info->work.remote_id); 343262306a36Sopenharmony_ci if (!cm_id_priv) 343362306a36Sopenharmony_ci return -EINVAL; 343462306a36Sopenharmony_ci 343562306a36Sopenharmony_ci spin_lock_irq(&cm_id_priv->lock); 343662306a36Sopenharmony_ci if (cm_id_priv->id.state != IB_CM_TIMEWAIT || 343762306a36Sopenharmony_ci cm_id_priv->remote_qpn != timewait_info->remote_qpn) { 343862306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 343962306a36Sopenharmony_ci goto out; 344062306a36Sopenharmony_ci } 344162306a36Sopenharmony_ci cm_id_priv->id.state = IB_CM_IDLE; 344262306a36Sopenharmony_ci cm_queue_work_unlock(cm_id_priv, work); 344362306a36Sopenharmony_ci return 0; 344462306a36Sopenharmony_ciout: 344562306a36Sopenharmony_ci cm_deref_id(cm_id_priv); 344662306a36Sopenharmony_ci return -EINVAL; 344762306a36Sopenharmony_ci} 344862306a36Sopenharmony_ci 344962306a36Sopenharmony_cistatic void cm_format_sidr_req(struct cm_sidr_req_msg *sidr_req_msg, 345062306a36Sopenharmony_ci struct cm_id_private *cm_id_priv, 345162306a36Sopenharmony_ci struct ib_cm_sidr_req_param *param) 345262306a36Sopenharmony_ci{ 345362306a36Sopenharmony_ci cm_format_mad_hdr(&sidr_req_msg->hdr, CM_SIDR_REQ_ATTR_ID, 345462306a36Sopenharmony_ci cm_form_tid(cm_id_priv)); 345562306a36Sopenharmony_ci IBA_SET(CM_SIDR_REQ_REQUESTID, sidr_req_msg, 345662306a36Sopenharmony_ci be32_to_cpu(cm_id_priv->id.local_id)); 345762306a36Sopenharmony_ci IBA_SET(CM_SIDR_REQ_PARTITION_KEY, sidr_req_msg, 345862306a36Sopenharmony_ci be16_to_cpu(param->path->pkey)); 345962306a36Sopenharmony_ci IBA_SET(CM_SIDR_REQ_SERVICEID, sidr_req_msg, 346062306a36Sopenharmony_ci be64_to_cpu(param->service_id)); 346162306a36Sopenharmony_ci 346262306a36Sopenharmony_ci if (param->private_data && param->private_data_len) 346362306a36Sopenharmony_ci IBA_SET_MEM(CM_SIDR_REQ_PRIVATE_DATA, sidr_req_msg, 346462306a36Sopenharmony_ci param->private_data, param->private_data_len); 346562306a36Sopenharmony_ci} 346662306a36Sopenharmony_ci 346762306a36Sopenharmony_ciint ib_send_cm_sidr_req(struct ib_cm_id *cm_id, 346862306a36Sopenharmony_ci struct ib_cm_sidr_req_param *param) 346962306a36Sopenharmony_ci{ 347062306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 347162306a36Sopenharmony_ci struct ib_mad_send_buf *msg; 347262306a36Sopenharmony_ci struct cm_av av = {}; 347362306a36Sopenharmony_ci unsigned long flags; 347462306a36Sopenharmony_ci int ret; 347562306a36Sopenharmony_ci 347662306a36Sopenharmony_ci if (!param->path || (param->private_data && 347762306a36Sopenharmony_ci param->private_data_len > IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE)) 347862306a36Sopenharmony_ci return -EINVAL; 347962306a36Sopenharmony_ci 348062306a36Sopenharmony_ci cm_id_priv = container_of(cm_id, struct cm_id_private, id); 348162306a36Sopenharmony_ci ret = cm_init_av_by_path(param->path, param->sgid_attr, &av); 348262306a36Sopenharmony_ci if (ret) 348362306a36Sopenharmony_ci return ret; 348462306a36Sopenharmony_ci 348562306a36Sopenharmony_ci spin_lock_irqsave(&cm_id_priv->lock, flags); 348662306a36Sopenharmony_ci cm_move_av_from_path(&cm_id_priv->av, &av); 348762306a36Sopenharmony_ci cm_id->service_id = param->service_id; 348862306a36Sopenharmony_ci cm_id_priv->timeout_ms = param->timeout_ms; 348962306a36Sopenharmony_ci cm_id_priv->max_cm_retries = param->max_cm_retries; 349062306a36Sopenharmony_ci if (cm_id->state != IB_CM_IDLE) { 349162306a36Sopenharmony_ci ret = -EINVAL; 349262306a36Sopenharmony_ci goto out_unlock; 349362306a36Sopenharmony_ci } 349462306a36Sopenharmony_ci 349562306a36Sopenharmony_ci msg = cm_alloc_priv_msg(cm_id_priv); 349662306a36Sopenharmony_ci if (IS_ERR(msg)) { 349762306a36Sopenharmony_ci ret = PTR_ERR(msg); 349862306a36Sopenharmony_ci goto out_unlock; 349962306a36Sopenharmony_ci } 350062306a36Sopenharmony_ci 350162306a36Sopenharmony_ci cm_format_sidr_req((struct cm_sidr_req_msg *)msg->mad, cm_id_priv, 350262306a36Sopenharmony_ci param); 350362306a36Sopenharmony_ci msg->timeout_ms = cm_id_priv->timeout_ms; 350462306a36Sopenharmony_ci msg->context[1] = (void *)(unsigned long)IB_CM_SIDR_REQ_SENT; 350562306a36Sopenharmony_ci 350662306a36Sopenharmony_ci trace_icm_send_sidr_req(&cm_id_priv->id); 350762306a36Sopenharmony_ci ret = ib_post_send_mad(msg, NULL); 350862306a36Sopenharmony_ci if (ret) 350962306a36Sopenharmony_ci goto out_free; 351062306a36Sopenharmony_ci cm_id->state = IB_CM_SIDR_REQ_SENT; 351162306a36Sopenharmony_ci spin_unlock_irqrestore(&cm_id_priv->lock, flags); 351262306a36Sopenharmony_ci return 0; 351362306a36Sopenharmony_ciout_free: 351462306a36Sopenharmony_ci cm_free_priv_msg(msg); 351562306a36Sopenharmony_ciout_unlock: 351662306a36Sopenharmony_ci spin_unlock_irqrestore(&cm_id_priv->lock, flags); 351762306a36Sopenharmony_ci return ret; 351862306a36Sopenharmony_ci} 351962306a36Sopenharmony_ciEXPORT_SYMBOL(ib_send_cm_sidr_req); 352062306a36Sopenharmony_ci 352162306a36Sopenharmony_cistatic void cm_format_sidr_req_event(struct cm_work *work, 352262306a36Sopenharmony_ci const struct cm_id_private *rx_cm_id, 352362306a36Sopenharmony_ci struct ib_cm_id *listen_id) 352462306a36Sopenharmony_ci{ 352562306a36Sopenharmony_ci struct cm_sidr_req_msg *sidr_req_msg; 352662306a36Sopenharmony_ci struct ib_cm_sidr_req_event_param *param; 352762306a36Sopenharmony_ci 352862306a36Sopenharmony_ci sidr_req_msg = (struct cm_sidr_req_msg *) 352962306a36Sopenharmony_ci work->mad_recv_wc->recv_buf.mad; 353062306a36Sopenharmony_ci param = &work->cm_event.param.sidr_req_rcvd; 353162306a36Sopenharmony_ci param->pkey = IBA_GET(CM_SIDR_REQ_PARTITION_KEY, sidr_req_msg); 353262306a36Sopenharmony_ci param->listen_id = listen_id; 353362306a36Sopenharmony_ci param->service_id = 353462306a36Sopenharmony_ci cpu_to_be64(IBA_GET(CM_SIDR_REQ_SERVICEID, sidr_req_msg)); 353562306a36Sopenharmony_ci param->bth_pkey = cm_get_bth_pkey(work); 353662306a36Sopenharmony_ci param->port = work->port->port_num; 353762306a36Sopenharmony_ci param->sgid_attr = rx_cm_id->av.ah_attr.grh.sgid_attr; 353862306a36Sopenharmony_ci work->cm_event.private_data = 353962306a36Sopenharmony_ci IBA_GET_MEM_PTR(CM_SIDR_REQ_PRIVATE_DATA, sidr_req_msg); 354062306a36Sopenharmony_ci} 354162306a36Sopenharmony_ci 354262306a36Sopenharmony_cistatic int cm_sidr_req_handler(struct cm_work *work) 354362306a36Sopenharmony_ci{ 354462306a36Sopenharmony_ci struct cm_id_private *cm_id_priv, *listen_cm_id_priv; 354562306a36Sopenharmony_ci struct cm_sidr_req_msg *sidr_req_msg; 354662306a36Sopenharmony_ci struct ib_wc *wc; 354762306a36Sopenharmony_ci int ret; 354862306a36Sopenharmony_ci 354962306a36Sopenharmony_ci cm_id_priv = 355062306a36Sopenharmony_ci cm_alloc_id_priv(work->port->cm_dev->ib_device, NULL, NULL); 355162306a36Sopenharmony_ci if (IS_ERR(cm_id_priv)) 355262306a36Sopenharmony_ci return PTR_ERR(cm_id_priv); 355362306a36Sopenharmony_ci 355462306a36Sopenharmony_ci /* Record SGID/SLID and request ID for lookup. */ 355562306a36Sopenharmony_ci sidr_req_msg = (struct cm_sidr_req_msg *) 355662306a36Sopenharmony_ci work->mad_recv_wc->recv_buf.mad; 355762306a36Sopenharmony_ci 355862306a36Sopenharmony_ci cm_id_priv->id.remote_id = 355962306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_SIDR_REQ_REQUESTID, sidr_req_msg)); 356062306a36Sopenharmony_ci cm_id_priv->id.service_id = 356162306a36Sopenharmony_ci cpu_to_be64(IBA_GET(CM_SIDR_REQ_SERVICEID, sidr_req_msg)); 356262306a36Sopenharmony_ci cm_id_priv->tid = sidr_req_msg->hdr.tid; 356362306a36Sopenharmony_ci 356462306a36Sopenharmony_ci wc = work->mad_recv_wc->wc; 356562306a36Sopenharmony_ci cm_id_priv->sidr_slid = wc->slid; 356662306a36Sopenharmony_ci ret = cm_init_av_for_response(work->port, work->mad_recv_wc->wc, 356762306a36Sopenharmony_ci work->mad_recv_wc->recv_buf.grh, 356862306a36Sopenharmony_ci &cm_id_priv->av); 356962306a36Sopenharmony_ci if (ret) 357062306a36Sopenharmony_ci goto out; 357162306a36Sopenharmony_ci 357262306a36Sopenharmony_ci spin_lock_irq(&cm.lock); 357362306a36Sopenharmony_ci listen_cm_id_priv = cm_insert_remote_sidr(cm_id_priv); 357462306a36Sopenharmony_ci if (listen_cm_id_priv) { 357562306a36Sopenharmony_ci spin_unlock_irq(&cm.lock); 357662306a36Sopenharmony_ci atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES] 357762306a36Sopenharmony_ci [CM_SIDR_REQ_COUNTER]); 357862306a36Sopenharmony_ci goto out; /* Duplicate message. */ 357962306a36Sopenharmony_ci } 358062306a36Sopenharmony_ci cm_id_priv->id.state = IB_CM_SIDR_REQ_RCVD; 358162306a36Sopenharmony_ci listen_cm_id_priv = cm_find_listen(cm_id_priv->id.device, 358262306a36Sopenharmony_ci cm_id_priv->id.service_id); 358362306a36Sopenharmony_ci if (!listen_cm_id_priv) { 358462306a36Sopenharmony_ci spin_unlock_irq(&cm.lock); 358562306a36Sopenharmony_ci ib_send_cm_sidr_rep(&cm_id_priv->id, 358662306a36Sopenharmony_ci &(struct ib_cm_sidr_rep_param){ 358762306a36Sopenharmony_ci .status = IB_SIDR_UNSUPPORTED }); 358862306a36Sopenharmony_ci goto out; /* No match. */ 358962306a36Sopenharmony_ci } 359062306a36Sopenharmony_ci spin_unlock_irq(&cm.lock); 359162306a36Sopenharmony_ci 359262306a36Sopenharmony_ci cm_id_priv->id.cm_handler = listen_cm_id_priv->id.cm_handler; 359362306a36Sopenharmony_ci cm_id_priv->id.context = listen_cm_id_priv->id.context; 359462306a36Sopenharmony_ci 359562306a36Sopenharmony_ci /* 359662306a36Sopenharmony_ci * A SIDR ID does not need to be in the xarray since it does not receive 359762306a36Sopenharmony_ci * mads, is not placed in the remote_id or remote_qpn rbtree, and does 359862306a36Sopenharmony_ci * not enter timewait. 359962306a36Sopenharmony_ci */ 360062306a36Sopenharmony_ci 360162306a36Sopenharmony_ci cm_format_sidr_req_event(work, cm_id_priv, &listen_cm_id_priv->id); 360262306a36Sopenharmony_ci ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, &work->cm_event); 360362306a36Sopenharmony_ci cm_free_work(work); 360462306a36Sopenharmony_ci /* 360562306a36Sopenharmony_ci * A pointer to the listen_cm_id is held in the event, so this deref 360662306a36Sopenharmony_ci * must be after the event is delivered above. 360762306a36Sopenharmony_ci */ 360862306a36Sopenharmony_ci cm_deref_id(listen_cm_id_priv); 360962306a36Sopenharmony_ci if (ret) 361062306a36Sopenharmony_ci cm_destroy_id(&cm_id_priv->id, ret); 361162306a36Sopenharmony_ci return 0; 361262306a36Sopenharmony_ciout: 361362306a36Sopenharmony_ci ib_destroy_cm_id(&cm_id_priv->id); 361462306a36Sopenharmony_ci return -EINVAL; 361562306a36Sopenharmony_ci} 361662306a36Sopenharmony_ci 361762306a36Sopenharmony_cistatic void cm_format_sidr_rep(struct cm_sidr_rep_msg *sidr_rep_msg, 361862306a36Sopenharmony_ci struct cm_id_private *cm_id_priv, 361962306a36Sopenharmony_ci struct ib_cm_sidr_rep_param *param) 362062306a36Sopenharmony_ci{ 362162306a36Sopenharmony_ci cm_format_mad_ece_hdr(&sidr_rep_msg->hdr, CM_SIDR_REP_ATTR_ID, 362262306a36Sopenharmony_ci cm_id_priv->tid, param->ece.attr_mod); 362362306a36Sopenharmony_ci IBA_SET(CM_SIDR_REP_REQUESTID, sidr_rep_msg, 362462306a36Sopenharmony_ci be32_to_cpu(cm_id_priv->id.remote_id)); 362562306a36Sopenharmony_ci IBA_SET(CM_SIDR_REP_STATUS, sidr_rep_msg, param->status); 362662306a36Sopenharmony_ci IBA_SET(CM_SIDR_REP_QPN, sidr_rep_msg, param->qp_num); 362762306a36Sopenharmony_ci IBA_SET(CM_SIDR_REP_SERVICEID, sidr_rep_msg, 362862306a36Sopenharmony_ci be64_to_cpu(cm_id_priv->id.service_id)); 362962306a36Sopenharmony_ci IBA_SET(CM_SIDR_REP_Q_KEY, sidr_rep_msg, param->qkey); 363062306a36Sopenharmony_ci IBA_SET(CM_SIDR_REP_VENDOR_ID_L, sidr_rep_msg, 363162306a36Sopenharmony_ci param->ece.vendor_id & 0xFF); 363262306a36Sopenharmony_ci IBA_SET(CM_SIDR_REP_VENDOR_ID_H, sidr_rep_msg, 363362306a36Sopenharmony_ci (param->ece.vendor_id >> 8) & 0xFF); 363462306a36Sopenharmony_ci 363562306a36Sopenharmony_ci if (param->info && param->info_length) 363662306a36Sopenharmony_ci IBA_SET_MEM(CM_SIDR_REP_ADDITIONAL_INFORMATION, sidr_rep_msg, 363762306a36Sopenharmony_ci param->info, param->info_length); 363862306a36Sopenharmony_ci 363962306a36Sopenharmony_ci if (param->private_data && param->private_data_len) 364062306a36Sopenharmony_ci IBA_SET_MEM(CM_SIDR_REP_PRIVATE_DATA, sidr_rep_msg, 364162306a36Sopenharmony_ci param->private_data, param->private_data_len); 364262306a36Sopenharmony_ci} 364362306a36Sopenharmony_ci 364462306a36Sopenharmony_cistatic int cm_send_sidr_rep_locked(struct cm_id_private *cm_id_priv, 364562306a36Sopenharmony_ci struct ib_cm_sidr_rep_param *param) 364662306a36Sopenharmony_ci{ 364762306a36Sopenharmony_ci struct ib_mad_send_buf *msg; 364862306a36Sopenharmony_ci unsigned long flags; 364962306a36Sopenharmony_ci int ret; 365062306a36Sopenharmony_ci 365162306a36Sopenharmony_ci lockdep_assert_held(&cm_id_priv->lock); 365262306a36Sopenharmony_ci 365362306a36Sopenharmony_ci if ((param->info && param->info_length > IB_CM_SIDR_REP_INFO_LENGTH) || 365462306a36Sopenharmony_ci (param->private_data && 365562306a36Sopenharmony_ci param->private_data_len > IB_CM_SIDR_REP_PRIVATE_DATA_SIZE)) 365662306a36Sopenharmony_ci return -EINVAL; 365762306a36Sopenharmony_ci 365862306a36Sopenharmony_ci if (cm_id_priv->id.state != IB_CM_SIDR_REQ_RCVD) 365962306a36Sopenharmony_ci return -EINVAL; 366062306a36Sopenharmony_ci 366162306a36Sopenharmony_ci msg = cm_alloc_msg(cm_id_priv); 366262306a36Sopenharmony_ci if (IS_ERR(msg)) 366362306a36Sopenharmony_ci return PTR_ERR(msg); 366462306a36Sopenharmony_ci 366562306a36Sopenharmony_ci cm_format_sidr_rep((struct cm_sidr_rep_msg *) msg->mad, cm_id_priv, 366662306a36Sopenharmony_ci param); 366762306a36Sopenharmony_ci trace_icm_send_sidr_rep(&cm_id_priv->id); 366862306a36Sopenharmony_ci ret = ib_post_send_mad(msg, NULL); 366962306a36Sopenharmony_ci if (ret) { 367062306a36Sopenharmony_ci cm_free_msg(msg); 367162306a36Sopenharmony_ci return ret; 367262306a36Sopenharmony_ci } 367362306a36Sopenharmony_ci cm_id_priv->id.state = IB_CM_IDLE; 367462306a36Sopenharmony_ci spin_lock_irqsave(&cm.lock, flags); 367562306a36Sopenharmony_ci if (!RB_EMPTY_NODE(&cm_id_priv->sidr_id_node)) { 367662306a36Sopenharmony_ci rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table); 367762306a36Sopenharmony_ci RB_CLEAR_NODE(&cm_id_priv->sidr_id_node); 367862306a36Sopenharmony_ci } 367962306a36Sopenharmony_ci spin_unlock_irqrestore(&cm.lock, flags); 368062306a36Sopenharmony_ci return 0; 368162306a36Sopenharmony_ci} 368262306a36Sopenharmony_ci 368362306a36Sopenharmony_ciint ib_send_cm_sidr_rep(struct ib_cm_id *cm_id, 368462306a36Sopenharmony_ci struct ib_cm_sidr_rep_param *param) 368562306a36Sopenharmony_ci{ 368662306a36Sopenharmony_ci struct cm_id_private *cm_id_priv = 368762306a36Sopenharmony_ci container_of(cm_id, struct cm_id_private, id); 368862306a36Sopenharmony_ci unsigned long flags; 368962306a36Sopenharmony_ci int ret; 369062306a36Sopenharmony_ci 369162306a36Sopenharmony_ci spin_lock_irqsave(&cm_id_priv->lock, flags); 369262306a36Sopenharmony_ci ret = cm_send_sidr_rep_locked(cm_id_priv, param); 369362306a36Sopenharmony_ci spin_unlock_irqrestore(&cm_id_priv->lock, flags); 369462306a36Sopenharmony_ci return ret; 369562306a36Sopenharmony_ci} 369662306a36Sopenharmony_ciEXPORT_SYMBOL(ib_send_cm_sidr_rep); 369762306a36Sopenharmony_ci 369862306a36Sopenharmony_cistatic void cm_format_sidr_rep_event(struct cm_work *work, 369962306a36Sopenharmony_ci const struct cm_id_private *cm_id_priv) 370062306a36Sopenharmony_ci{ 370162306a36Sopenharmony_ci struct cm_sidr_rep_msg *sidr_rep_msg; 370262306a36Sopenharmony_ci struct ib_cm_sidr_rep_event_param *param; 370362306a36Sopenharmony_ci 370462306a36Sopenharmony_ci sidr_rep_msg = (struct cm_sidr_rep_msg *) 370562306a36Sopenharmony_ci work->mad_recv_wc->recv_buf.mad; 370662306a36Sopenharmony_ci param = &work->cm_event.param.sidr_rep_rcvd; 370762306a36Sopenharmony_ci param->status = IBA_GET(CM_SIDR_REP_STATUS, sidr_rep_msg); 370862306a36Sopenharmony_ci param->qkey = IBA_GET(CM_SIDR_REP_Q_KEY, sidr_rep_msg); 370962306a36Sopenharmony_ci param->qpn = IBA_GET(CM_SIDR_REP_QPN, sidr_rep_msg); 371062306a36Sopenharmony_ci param->info = IBA_GET_MEM_PTR(CM_SIDR_REP_ADDITIONAL_INFORMATION, 371162306a36Sopenharmony_ci sidr_rep_msg); 371262306a36Sopenharmony_ci param->info_len = IBA_GET(CM_SIDR_REP_ADDITIONAL_INFORMATION_LENGTH, 371362306a36Sopenharmony_ci sidr_rep_msg); 371462306a36Sopenharmony_ci param->sgid_attr = cm_id_priv->av.ah_attr.grh.sgid_attr; 371562306a36Sopenharmony_ci work->cm_event.private_data = 371662306a36Sopenharmony_ci IBA_GET_MEM_PTR(CM_SIDR_REP_PRIVATE_DATA, sidr_rep_msg); 371762306a36Sopenharmony_ci} 371862306a36Sopenharmony_ci 371962306a36Sopenharmony_cistatic int cm_sidr_rep_handler(struct cm_work *work) 372062306a36Sopenharmony_ci{ 372162306a36Sopenharmony_ci struct cm_sidr_rep_msg *sidr_rep_msg; 372262306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 372362306a36Sopenharmony_ci 372462306a36Sopenharmony_ci sidr_rep_msg = (struct cm_sidr_rep_msg *) 372562306a36Sopenharmony_ci work->mad_recv_wc->recv_buf.mad; 372662306a36Sopenharmony_ci cm_id_priv = cm_acquire_id( 372762306a36Sopenharmony_ci cpu_to_be32(IBA_GET(CM_SIDR_REP_REQUESTID, sidr_rep_msg)), 0); 372862306a36Sopenharmony_ci if (!cm_id_priv) 372962306a36Sopenharmony_ci return -EINVAL; /* Unmatched reply. */ 373062306a36Sopenharmony_ci 373162306a36Sopenharmony_ci spin_lock_irq(&cm_id_priv->lock); 373262306a36Sopenharmony_ci if (cm_id_priv->id.state != IB_CM_SIDR_REQ_SENT) { 373362306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 373462306a36Sopenharmony_ci goto out; 373562306a36Sopenharmony_ci } 373662306a36Sopenharmony_ci cm_id_priv->id.state = IB_CM_IDLE; 373762306a36Sopenharmony_ci ib_cancel_mad(cm_id_priv->msg); 373862306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 373962306a36Sopenharmony_ci 374062306a36Sopenharmony_ci cm_format_sidr_rep_event(work, cm_id_priv); 374162306a36Sopenharmony_ci cm_process_work(cm_id_priv, work); 374262306a36Sopenharmony_ci return 0; 374362306a36Sopenharmony_ciout: 374462306a36Sopenharmony_ci cm_deref_id(cm_id_priv); 374562306a36Sopenharmony_ci return -EINVAL; 374662306a36Sopenharmony_ci} 374762306a36Sopenharmony_ci 374862306a36Sopenharmony_cistatic void cm_process_send_error(struct cm_id_private *cm_id_priv, 374962306a36Sopenharmony_ci struct ib_mad_send_buf *msg, 375062306a36Sopenharmony_ci enum ib_cm_state state, 375162306a36Sopenharmony_ci enum ib_wc_status wc_status) 375262306a36Sopenharmony_ci{ 375362306a36Sopenharmony_ci struct ib_cm_event cm_event = {}; 375462306a36Sopenharmony_ci int ret; 375562306a36Sopenharmony_ci 375662306a36Sopenharmony_ci /* Discard old sends or ones without a response. */ 375762306a36Sopenharmony_ci spin_lock_irq(&cm_id_priv->lock); 375862306a36Sopenharmony_ci if (msg != cm_id_priv->msg) { 375962306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 376062306a36Sopenharmony_ci cm_free_msg(msg); 376162306a36Sopenharmony_ci return; 376262306a36Sopenharmony_ci } 376362306a36Sopenharmony_ci cm_free_priv_msg(msg); 376462306a36Sopenharmony_ci 376562306a36Sopenharmony_ci if (state != cm_id_priv->id.state || wc_status == IB_WC_SUCCESS || 376662306a36Sopenharmony_ci wc_status == IB_WC_WR_FLUSH_ERR) 376762306a36Sopenharmony_ci goto out_unlock; 376862306a36Sopenharmony_ci 376962306a36Sopenharmony_ci trace_icm_mad_send_err(state, wc_status); 377062306a36Sopenharmony_ci switch (state) { 377162306a36Sopenharmony_ci case IB_CM_REQ_SENT: 377262306a36Sopenharmony_ci case IB_CM_MRA_REQ_RCVD: 377362306a36Sopenharmony_ci cm_reset_to_idle(cm_id_priv); 377462306a36Sopenharmony_ci cm_event.event = IB_CM_REQ_ERROR; 377562306a36Sopenharmony_ci break; 377662306a36Sopenharmony_ci case IB_CM_REP_SENT: 377762306a36Sopenharmony_ci case IB_CM_MRA_REP_RCVD: 377862306a36Sopenharmony_ci cm_reset_to_idle(cm_id_priv); 377962306a36Sopenharmony_ci cm_event.event = IB_CM_REP_ERROR; 378062306a36Sopenharmony_ci break; 378162306a36Sopenharmony_ci case IB_CM_DREQ_SENT: 378262306a36Sopenharmony_ci cm_enter_timewait(cm_id_priv); 378362306a36Sopenharmony_ci cm_event.event = IB_CM_DREQ_ERROR; 378462306a36Sopenharmony_ci break; 378562306a36Sopenharmony_ci case IB_CM_SIDR_REQ_SENT: 378662306a36Sopenharmony_ci cm_id_priv->id.state = IB_CM_IDLE; 378762306a36Sopenharmony_ci cm_event.event = IB_CM_SIDR_REQ_ERROR; 378862306a36Sopenharmony_ci break; 378962306a36Sopenharmony_ci default: 379062306a36Sopenharmony_ci goto out_unlock; 379162306a36Sopenharmony_ci } 379262306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 379362306a36Sopenharmony_ci cm_event.param.send_status = wc_status; 379462306a36Sopenharmony_ci 379562306a36Sopenharmony_ci /* No other events can occur on the cm_id at this point. */ 379662306a36Sopenharmony_ci ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, &cm_event); 379762306a36Sopenharmony_ci if (ret) 379862306a36Sopenharmony_ci ib_destroy_cm_id(&cm_id_priv->id); 379962306a36Sopenharmony_ci return; 380062306a36Sopenharmony_ciout_unlock: 380162306a36Sopenharmony_ci spin_unlock_irq(&cm_id_priv->lock); 380262306a36Sopenharmony_ci} 380362306a36Sopenharmony_ci 380462306a36Sopenharmony_cistatic void cm_send_handler(struct ib_mad_agent *mad_agent, 380562306a36Sopenharmony_ci struct ib_mad_send_wc *mad_send_wc) 380662306a36Sopenharmony_ci{ 380762306a36Sopenharmony_ci struct ib_mad_send_buf *msg = mad_send_wc->send_buf; 380862306a36Sopenharmony_ci struct cm_id_private *cm_id_priv = msg->context[0]; 380962306a36Sopenharmony_ci enum ib_cm_state state = 381062306a36Sopenharmony_ci (enum ib_cm_state)(unsigned long)msg->context[1]; 381162306a36Sopenharmony_ci struct cm_port *port; 381262306a36Sopenharmony_ci u16 attr_index; 381362306a36Sopenharmony_ci 381462306a36Sopenharmony_ci port = mad_agent->context; 381562306a36Sopenharmony_ci attr_index = be16_to_cpu(((struct ib_mad_hdr *) 381662306a36Sopenharmony_ci msg->mad)->attr_id) - CM_ATTR_ID_OFFSET; 381762306a36Sopenharmony_ci 381862306a36Sopenharmony_ci /* 381962306a36Sopenharmony_ci * If the send was in response to a received message (context[0] is not 382062306a36Sopenharmony_ci * set to a cm_id), and is not a REJ, then it is a send that was 382162306a36Sopenharmony_ci * manually retried. 382262306a36Sopenharmony_ci */ 382362306a36Sopenharmony_ci if (!cm_id_priv && (attr_index != CM_REJ_COUNTER)) 382462306a36Sopenharmony_ci msg->retries = 1; 382562306a36Sopenharmony_ci 382662306a36Sopenharmony_ci atomic_long_add(1 + msg->retries, &port->counters[CM_XMIT][attr_index]); 382762306a36Sopenharmony_ci if (msg->retries) 382862306a36Sopenharmony_ci atomic_long_add(msg->retries, 382962306a36Sopenharmony_ci &port->counters[CM_XMIT_RETRIES][attr_index]); 383062306a36Sopenharmony_ci 383162306a36Sopenharmony_ci if (cm_id_priv) 383262306a36Sopenharmony_ci cm_process_send_error(cm_id_priv, msg, state, 383362306a36Sopenharmony_ci mad_send_wc->status); 383462306a36Sopenharmony_ci else 383562306a36Sopenharmony_ci cm_free_response_msg(msg); 383662306a36Sopenharmony_ci} 383762306a36Sopenharmony_ci 383862306a36Sopenharmony_cistatic void cm_work_handler(struct work_struct *_work) 383962306a36Sopenharmony_ci{ 384062306a36Sopenharmony_ci struct cm_work *work = container_of(_work, struct cm_work, work.work); 384162306a36Sopenharmony_ci int ret; 384262306a36Sopenharmony_ci 384362306a36Sopenharmony_ci switch (work->cm_event.event) { 384462306a36Sopenharmony_ci case IB_CM_REQ_RECEIVED: 384562306a36Sopenharmony_ci ret = cm_req_handler(work); 384662306a36Sopenharmony_ci break; 384762306a36Sopenharmony_ci case IB_CM_MRA_RECEIVED: 384862306a36Sopenharmony_ci ret = cm_mra_handler(work); 384962306a36Sopenharmony_ci break; 385062306a36Sopenharmony_ci case IB_CM_REJ_RECEIVED: 385162306a36Sopenharmony_ci ret = cm_rej_handler(work); 385262306a36Sopenharmony_ci break; 385362306a36Sopenharmony_ci case IB_CM_REP_RECEIVED: 385462306a36Sopenharmony_ci ret = cm_rep_handler(work); 385562306a36Sopenharmony_ci break; 385662306a36Sopenharmony_ci case IB_CM_RTU_RECEIVED: 385762306a36Sopenharmony_ci ret = cm_rtu_handler(work); 385862306a36Sopenharmony_ci break; 385962306a36Sopenharmony_ci case IB_CM_USER_ESTABLISHED: 386062306a36Sopenharmony_ci ret = cm_establish_handler(work); 386162306a36Sopenharmony_ci break; 386262306a36Sopenharmony_ci case IB_CM_DREQ_RECEIVED: 386362306a36Sopenharmony_ci ret = cm_dreq_handler(work); 386462306a36Sopenharmony_ci break; 386562306a36Sopenharmony_ci case IB_CM_DREP_RECEIVED: 386662306a36Sopenharmony_ci ret = cm_drep_handler(work); 386762306a36Sopenharmony_ci break; 386862306a36Sopenharmony_ci case IB_CM_SIDR_REQ_RECEIVED: 386962306a36Sopenharmony_ci ret = cm_sidr_req_handler(work); 387062306a36Sopenharmony_ci break; 387162306a36Sopenharmony_ci case IB_CM_SIDR_REP_RECEIVED: 387262306a36Sopenharmony_ci ret = cm_sidr_rep_handler(work); 387362306a36Sopenharmony_ci break; 387462306a36Sopenharmony_ci case IB_CM_LAP_RECEIVED: 387562306a36Sopenharmony_ci ret = cm_lap_handler(work); 387662306a36Sopenharmony_ci break; 387762306a36Sopenharmony_ci case IB_CM_APR_RECEIVED: 387862306a36Sopenharmony_ci ret = cm_apr_handler(work); 387962306a36Sopenharmony_ci break; 388062306a36Sopenharmony_ci case IB_CM_TIMEWAIT_EXIT: 388162306a36Sopenharmony_ci ret = cm_timewait_handler(work); 388262306a36Sopenharmony_ci break; 388362306a36Sopenharmony_ci default: 388462306a36Sopenharmony_ci trace_icm_handler_err(work->cm_event.event); 388562306a36Sopenharmony_ci ret = -EINVAL; 388662306a36Sopenharmony_ci break; 388762306a36Sopenharmony_ci } 388862306a36Sopenharmony_ci if (ret) 388962306a36Sopenharmony_ci cm_free_work(work); 389062306a36Sopenharmony_ci} 389162306a36Sopenharmony_ci 389262306a36Sopenharmony_cistatic int cm_establish(struct ib_cm_id *cm_id) 389362306a36Sopenharmony_ci{ 389462306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 389562306a36Sopenharmony_ci struct cm_work *work; 389662306a36Sopenharmony_ci unsigned long flags; 389762306a36Sopenharmony_ci int ret = 0; 389862306a36Sopenharmony_ci struct cm_device *cm_dev; 389962306a36Sopenharmony_ci 390062306a36Sopenharmony_ci cm_dev = ib_get_client_data(cm_id->device, &cm_client); 390162306a36Sopenharmony_ci if (!cm_dev) 390262306a36Sopenharmony_ci return -ENODEV; 390362306a36Sopenharmony_ci 390462306a36Sopenharmony_ci work = kmalloc(sizeof *work, GFP_ATOMIC); 390562306a36Sopenharmony_ci if (!work) 390662306a36Sopenharmony_ci return -ENOMEM; 390762306a36Sopenharmony_ci 390862306a36Sopenharmony_ci cm_id_priv = container_of(cm_id, struct cm_id_private, id); 390962306a36Sopenharmony_ci spin_lock_irqsave(&cm_id_priv->lock, flags); 391062306a36Sopenharmony_ci switch (cm_id->state) { 391162306a36Sopenharmony_ci case IB_CM_REP_SENT: 391262306a36Sopenharmony_ci case IB_CM_MRA_REP_RCVD: 391362306a36Sopenharmony_ci cm_id->state = IB_CM_ESTABLISHED; 391462306a36Sopenharmony_ci break; 391562306a36Sopenharmony_ci case IB_CM_ESTABLISHED: 391662306a36Sopenharmony_ci ret = -EISCONN; 391762306a36Sopenharmony_ci break; 391862306a36Sopenharmony_ci default: 391962306a36Sopenharmony_ci trace_icm_establish_err(cm_id); 392062306a36Sopenharmony_ci ret = -EINVAL; 392162306a36Sopenharmony_ci break; 392262306a36Sopenharmony_ci } 392362306a36Sopenharmony_ci spin_unlock_irqrestore(&cm_id_priv->lock, flags); 392462306a36Sopenharmony_ci 392562306a36Sopenharmony_ci if (ret) { 392662306a36Sopenharmony_ci kfree(work); 392762306a36Sopenharmony_ci goto out; 392862306a36Sopenharmony_ci } 392962306a36Sopenharmony_ci 393062306a36Sopenharmony_ci /* 393162306a36Sopenharmony_ci * The CM worker thread may try to destroy the cm_id before it 393262306a36Sopenharmony_ci * can execute this work item. To prevent potential deadlock, 393362306a36Sopenharmony_ci * we need to find the cm_id once we're in the context of the 393462306a36Sopenharmony_ci * worker thread, rather than holding a reference on it. 393562306a36Sopenharmony_ci */ 393662306a36Sopenharmony_ci INIT_DELAYED_WORK(&work->work, cm_work_handler); 393762306a36Sopenharmony_ci work->local_id = cm_id->local_id; 393862306a36Sopenharmony_ci work->remote_id = cm_id->remote_id; 393962306a36Sopenharmony_ci work->mad_recv_wc = NULL; 394062306a36Sopenharmony_ci work->cm_event.event = IB_CM_USER_ESTABLISHED; 394162306a36Sopenharmony_ci 394262306a36Sopenharmony_ci /* Check if the device started its remove_one */ 394362306a36Sopenharmony_ci spin_lock_irqsave(&cm.lock, flags); 394462306a36Sopenharmony_ci if (!cm_dev->going_down) { 394562306a36Sopenharmony_ci queue_delayed_work(cm.wq, &work->work, 0); 394662306a36Sopenharmony_ci } else { 394762306a36Sopenharmony_ci kfree(work); 394862306a36Sopenharmony_ci ret = -ENODEV; 394962306a36Sopenharmony_ci } 395062306a36Sopenharmony_ci spin_unlock_irqrestore(&cm.lock, flags); 395162306a36Sopenharmony_ci 395262306a36Sopenharmony_ciout: 395362306a36Sopenharmony_ci return ret; 395462306a36Sopenharmony_ci} 395562306a36Sopenharmony_ci 395662306a36Sopenharmony_cistatic int cm_migrate(struct ib_cm_id *cm_id) 395762306a36Sopenharmony_ci{ 395862306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 395962306a36Sopenharmony_ci unsigned long flags; 396062306a36Sopenharmony_ci int ret = 0; 396162306a36Sopenharmony_ci 396262306a36Sopenharmony_ci cm_id_priv = container_of(cm_id, struct cm_id_private, id); 396362306a36Sopenharmony_ci spin_lock_irqsave(&cm_id_priv->lock, flags); 396462306a36Sopenharmony_ci if (cm_id->state == IB_CM_ESTABLISHED && 396562306a36Sopenharmony_ci (cm_id->lap_state == IB_CM_LAP_UNINIT || 396662306a36Sopenharmony_ci cm_id->lap_state == IB_CM_LAP_IDLE)) { 396762306a36Sopenharmony_ci cm_id->lap_state = IB_CM_LAP_IDLE; 396862306a36Sopenharmony_ci cm_id_priv->av = cm_id_priv->alt_av; 396962306a36Sopenharmony_ci } else 397062306a36Sopenharmony_ci ret = -EINVAL; 397162306a36Sopenharmony_ci spin_unlock_irqrestore(&cm_id_priv->lock, flags); 397262306a36Sopenharmony_ci 397362306a36Sopenharmony_ci return ret; 397462306a36Sopenharmony_ci} 397562306a36Sopenharmony_ci 397662306a36Sopenharmony_ciint ib_cm_notify(struct ib_cm_id *cm_id, enum ib_event_type event) 397762306a36Sopenharmony_ci{ 397862306a36Sopenharmony_ci int ret; 397962306a36Sopenharmony_ci 398062306a36Sopenharmony_ci switch (event) { 398162306a36Sopenharmony_ci case IB_EVENT_COMM_EST: 398262306a36Sopenharmony_ci ret = cm_establish(cm_id); 398362306a36Sopenharmony_ci break; 398462306a36Sopenharmony_ci case IB_EVENT_PATH_MIG: 398562306a36Sopenharmony_ci ret = cm_migrate(cm_id); 398662306a36Sopenharmony_ci break; 398762306a36Sopenharmony_ci default: 398862306a36Sopenharmony_ci ret = -EINVAL; 398962306a36Sopenharmony_ci } 399062306a36Sopenharmony_ci return ret; 399162306a36Sopenharmony_ci} 399262306a36Sopenharmony_ciEXPORT_SYMBOL(ib_cm_notify); 399362306a36Sopenharmony_ci 399462306a36Sopenharmony_cistatic void cm_recv_handler(struct ib_mad_agent *mad_agent, 399562306a36Sopenharmony_ci struct ib_mad_send_buf *send_buf, 399662306a36Sopenharmony_ci struct ib_mad_recv_wc *mad_recv_wc) 399762306a36Sopenharmony_ci{ 399862306a36Sopenharmony_ci struct cm_port *port = mad_agent->context; 399962306a36Sopenharmony_ci struct cm_work *work; 400062306a36Sopenharmony_ci enum ib_cm_event_type event; 400162306a36Sopenharmony_ci bool alt_path = false; 400262306a36Sopenharmony_ci u16 attr_id; 400362306a36Sopenharmony_ci int paths = 0; 400462306a36Sopenharmony_ci int going_down = 0; 400562306a36Sopenharmony_ci 400662306a36Sopenharmony_ci switch (mad_recv_wc->recv_buf.mad->mad_hdr.attr_id) { 400762306a36Sopenharmony_ci case CM_REQ_ATTR_ID: 400862306a36Sopenharmony_ci alt_path = cm_req_has_alt_path((struct cm_req_msg *) 400962306a36Sopenharmony_ci mad_recv_wc->recv_buf.mad); 401062306a36Sopenharmony_ci paths = 1 + (alt_path != 0); 401162306a36Sopenharmony_ci event = IB_CM_REQ_RECEIVED; 401262306a36Sopenharmony_ci break; 401362306a36Sopenharmony_ci case CM_MRA_ATTR_ID: 401462306a36Sopenharmony_ci event = IB_CM_MRA_RECEIVED; 401562306a36Sopenharmony_ci break; 401662306a36Sopenharmony_ci case CM_REJ_ATTR_ID: 401762306a36Sopenharmony_ci event = IB_CM_REJ_RECEIVED; 401862306a36Sopenharmony_ci break; 401962306a36Sopenharmony_ci case CM_REP_ATTR_ID: 402062306a36Sopenharmony_ci event = IB_CM_REP_RECEIVED; 402162306a36Sopenharmony_ci break; 402262306a36Sopenharmony_ci case CM_RTU_ATTR_ID: 402362306a36Sopenharmony_ci event = IB_CM_RTU_RECEIVED; 402462306a36Sopenharmony_ci break; 402562306a36Sopenharmony_ci case CM_DREQ_ATTR_ID: 402662306a36Sopenharmony_ci event = IB_CM_DREQ_RECEIVED; 402762306a36Sopenharmony_ci break; 402862306a36Sopenharmony_ci case CM_DREP_ATTR_ID: 402962306a36Sopenharmony_ci event = IB_CM_DREP_RECEIVED; 403062306a36Sopenharmony_ci break; 403162306a36Sopenharmony_ci case CM_SIDR_REQ_ATTR_ID: 403262306a36Sopenharmony_ci event = IB_CM_SIDR_REQ_RECEIVED; 403362306a36Sopenharmony_ci break; 403462306a36Sopenharmony_ci case CM_SIDR_REP_ATTR_ID: 403562306a36Sopenharmony_ci event = IB_CM_SIDR_REP_RECEIVED; 403662306a36Sopenharmony_ci break; 403762306a36Sopenharmony_ci case CM_LAP_ATTR_ID: 403862306a36Sopenharmony_ci paths = 1; 403962306a36Sopenharmony_ci event = IB_CM_LAP_RECEIVED; 404062306a36Sopenharmony_ci break; 404162306a36Sopenharmony_ci case CM_APR_ATTR_ID: 404262306a36Sopenharmony_ci event = IB_CM_APR_RECEIVED; 404362306a36Sopenharmony_ci break; 404462306a36Sopenharmony_ci default: 404562306a36Sopenharmony_ci ib_free_recv_mad(mad_recv_wc); 404662306a36Sopenharmony_ci return; 404762306a36Sopenharmony_ci } 404862306a36Sopenharmony_ci 404962306a36Sopenharmony_ci attr_id = be16_to_cpu(mad_recv_wc->recv_buf.mad->mad_hdr.attr_id); 405062306a36Sopenharmony_ci atomic_long_inc(&port->counters[CM_RECV][attr_id - CM_ATTR_ID_OFFSET]); 405162306a36Sopenharmony_ci 405262306a36Sopenharmony_ci work = kmalloc(struct_size(work, path, paths), GFP_KERNEL); 405362306a36Sopenharmony_ci if (!work) { 405462306a36Sopenharmony_ci ib_free_recv_mad(mad_recv_wc); 405562306a36Sopenharmony_ci return; 405662306a36Sopenharmony_ci } 405762306a36Sopenharmony_ci 405862306a36Sopenharmony_ci INIT_DELAYED_WORK(&work->work, cm_work_handler); 405962306a36Sopenharmony_ci work->cm_event.event = event; 406062306a36Sopenharmony_ci work->mad_recv_wc = mad_recv_wc; 406162306a36Sopenharmony_ci work->port = port; 406262306a36Sopenharmony_ci 406362306a36Sopenharmony_ci /* Check if the device started its remove_one */ 406462306a36Sopenharmony_ci spin_lock_irq(&cm.lock); 406562306a36Sopenharmony_ci if (!port->cm_dev->going_down) 406662306a36Sopenharmony_ci queue_delayed_work(cm.wq, &work->work, 0); 406762306a36Sopenharmony_ci else 406862306a36Sopenharmony_ci going_down = 1; 406962306a36Sopenharmony_ci spin_unlock_irq(&cm.lock); 407062306a36Sopenharmony_ci 407162306a36Sopenharmony_ci if (going_down) { 407262306a36Sopenharmony_ci kfree(work); 407362306a36Sopenharmony_ci ib_free_recv_mad(mad_recv_wc); 407462306a36Sopenharmony_ci } 407562306a36Sopenharmony_ci} 407662306a36Sopenharmony_ci 407762306a36Sopenharmony_cistatic int cm_init_qp_init_attr(struct cm_id_private *cm_id_priv, 407862306a36Sopenharmony_ci struct ib_qp_attr *qp_attr, 407962306a36Sopenharmony_ci int *qp_attr_mask) 408062306a36Sopenharmony_ci{ 408162306a36Sopenharmony_ci unsigned long flags; 408262306a36Sopenharmony_ci int ret; 408362306a36Sopenharmony_ci 408462306a36Sopenharmony_ci spin_lock_irqsave(&cm_id_priv->lock, flags); 408562306a36Sopenharmony_ci switch (cm_id_priv->id.state) { 408662306a36Sopenharmony_ci case IB_CM_REQ_SENT: 408762306a36Sopenharmony_ci case IB_CM_MRA_REQ_RCVD: 408862306a36Sopenharmony_ci case IB_CM_REQ_RCVD: 408962306a36Sopenharmony_ci case IB_CM_MRA_REQ_SENT: 409062306a36Sopenharmony_ci case IB_CM_REP_RCVD: 409162306a36Sopenharmony_ci case IB_CM_MRA_REP_SENT: 409262306a36Sopenharmony_ci case IB_CM_REP_SENT: 409362306a36Sopenharmony_ci case IB_CM_MRA_REP_RCVD: 409462306a36Sopenharmony_ci case IB_CM_ESTABLISHED: 409562306a36Sopenharmony_ci *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS | 409662306a36Sopenharmony_ci IB_QP_PKEY_INDEX | IB_QP_PORT; 409762306a36Sopenharmony_ci qp_attr->qp_access_flags = IB_ACCESS_REMOTE_WRITE; 409862306a36Sopenharmony_ci if (cm_id_priv->responder_resources) { 409962306a36Sopenharmony_ci struct ib_device *ib_dev = cm_id_priv->id.device; 410062306a36Sopenharmony_ci u64 support_flush = ib_dev->attrs.device_cap_flags & 410162306a36Sopenharmony_ci (IB_DEVICE_FLUSH_GLOBAL | IB_DEVICE_FLUSH_PERSISTENT); 410262306a36Sopenharmony_ci u32 flushable = support_flush ? 410362306a36Sopenharmony_ci (IB_ACCESS_FLUSH_GLOBAL | 410462306a36Sopenharmony_ci IB_ACCESS_FLUSH_PERSISTENT) : 0; 410562306a36Sopenharmony_ci 410662306a36Sopenharmony_ci qp_attr->qp_access_flags |= IB_ACCESS_REMOTE_READ | 410762306a36Sopenharmony_ci IB_ACCESS_REMOTE_ATOMIC | 410862306a36Sopenharmony_ci flushable; 410962306a36Sopenharmony_ci } 411062306a36Sopenharmony_ci qp_attr->pkey_index = cm_id_priv->av.pkey_index; 411162306a36Sopenharmony_ci if (cm_id_priv->av.port) 411262306a36Sopenharmony_ci qp_attr->port_num = cm_id_priv->av.port->port_num; 411362306a36Sopenharmony_ci ret = 0; 411462306a36Sopenharmony_ci break; 411562306a36Sopenharmony_ci default: 411662306a36Sopenharmony_ci trace_icm_qp_init_err(&cm_id_priv->id); 411762306a36Sopenharmony_ci ret = -EINVAL; 411862306a36Sopenharmony_ci break; 411962306a36Sopenharmony_ci } 412062306a36Sopenharmony_ci spin_unlock_irqrestore(&cm_id_priv->lock, flags); 412162306a36Sopenharmony_ci return ret; 412262306a36Sopenharmony_ci} 412362306a36Sopenharmony_ci 412462306a36Sopenharmony_cistatic int cm_init_qp_rtr_attr(struct cm_id_private *cm_id_priv, 412562306a36Sopenharmony_ci struct ib_qp_attr *qp_attr, 412662306a36Sopenharmony_ci int *qp_attr_mask) 412762306a36Sopenharmony_ci{ 412862306a36Sopenharmony_ci unsigned long flags; 412962306a36Sopenharmony_ci int ret; 413062306a36Sopenharmony_ci 413162306a36Sopenharmony_ci spin_lock_irqsave(&cm_id_priv->lock, flags); 413262306a36Sopenharmony_ci switch (cm_id_priv->id.state) { 413362306a36Sopenharmony_ci case IB_CM_REQ_RCVD: 413462306a36Sopenharmony_ci case IB_CM_MRA_REQ_SENT: 413562306a36Sopenharmony_ci case IB_CM_REP_RCVD: 413662306a36Sopenharmony_ci case IB_CM_MRA_REP_SENT: 413762306a36Sopenharmony_ci case IB_CM_REP_SENT: 413862306a36Sopenharmony_ci case IB_CM_MRA_REP_RCVD: 413962306a36Sopenharmony_ci case IB_CM_ESTABLISHED: 414062306a36Sopenharmony_ci *qp_attr_mask = IB_QP_STATE | IB_QP_AV | IB_QP_PATH_MTU | 414162306a36Sopenharmony_ci IB_QP_DEST_QPN | IB_QP_RQ_PSN; 414262306a36Sopenharmony_ci qp_attr->ah_attr = cm_id_priv->av.ah_attr; 414362306a36Sopenharmony_ci if ((qp_attr->ah_attr.type == RDMA_AH_ATTR_TYPE_IB) && 414462306a36Sopenharmony_ci cm_id_priv->av.dlid_datapath && 414562306a36Sopenharmony_ci (cm_id_priv->av.dlid_datapath != 0xffff)) 414662306a36Sopenharmony_ci qp_attr->ah_attr.ib.dlid = cm_id_priv->av.dlid_datapath; 414762306a36Sopenharmony_ci qp_attr->path_mtu = cm_id_priv->path_mtu; 414862306a36Sopenharmony_ci qp_attr->dest_qp_num = be32_to_cpu(cm_id_priv->remote_qpn); 414962306a36Sopenharmony_ci qp_attr->rq_psn = be32_to_cpu(cm_id_priv->rq_psn); 415062306a36Sopenharmony_ci if (cm_id_priv->qp_type == IB_QPT_RC || 415162306a36Sopenharmony_ci cm_id_priv->qp_type == IB_QPT_XRC_TGT) { 415262306a36Sopenharmony_ci *qp_attr_mask |= IB_QP_MAX_DEST_RD_ATOMIC | 415362306a36Sopenharmony_ci IB_QP_MIN_RNR_TIMER; 415462306a36Sopenharmony_ci qp_attr->max_dest_rd_atomic = 415562306a36Sopenharmony_ci cm_id_priv->responder_resources; 415662306a36Sopenharmony_ci qp_attr->min_rnr_timer = 0; 415762306a36Sopenharmony_ci } 415862306a36Sopenharmony_ci if (rdma_ah_get_dlid(&cm_id_priv->alt_av.ah_attr) && 415962306a36Sopenharmony_ci cm_id_priv->alt_av.port) { 416062306a36Sopenharmony_ci *qp_attr_mask |= IB_QP_ALT_PATH; 416162306a36Sopenharmony_ci qp_attr->alt_port_num = cm_id_priv->alt_av.port->port_num; 416262306a36Sopenharmony_ci qp_attr->alt_pkey_index = cm_id_priv->alt_av.pkey_index; 416362306a36Sopenharmony_ci qp_attr->alt_timeout = cm_id_priv->alt_av.timeout; 416462306a36Sopenharmony_ci qp_attr->alt_ah_attr = cm_id_priv->alt_av.ah_attr; 416562306a36Sopenharmony_ci } 416662306a36Sopenharmony_ci ret = 0; 416762306a36Sopenharmony_ci break; 416862306a36Sopenharmony_ci default: 416962306a36Sopenharmony_ci trace_icm_qp_rtr_err(&cm_id_priv->id); 417062306a36Sopenharmony_ci ret = -EINVAL; 417162306a36Sopenharmony_ci break; 417262306a36Sopenharmony_ci } 417362306a36Sopenharmony_ci spin_unlock_irqrestore(&cm_id_priv->lock, flags); 417462306a36Sopenharmony_ci return ret; 417562306a36Sopenharmony_ci} 417662306a36Sopenharmony_ci 417762306a36Sopenharmony_cistatic int cm_init_qp_rts_attr(struct cm_id_private *cm_id_priv, 417862306a36Sopenharmony_ci struct ib_qp_attr *qp_attr, 417962306a36Sopenharmony_ci int *qp_attr_mask) 418062306a36Sopenharmony_ci{ 418162306a36Sopenharmony_ci unsigned long flags; 418262306a36Sopenharmony_ci int ret; 418362306a36Sopenharmony_ci 418462306a36Sopenharmony_ci spin_lock_irqsave(&cm_id_priv->lock, flags); 418562306a36Sopenharmony_ci switch (cm_id_priv->id.state) { 418662306a36Sopenharmony_ci /* Allow transition to RTS before sending REP */ 418762306a36Sopenharmony_ci case IB_CM_REQ_RCVD: 418862306a36Sopenharmony_ci case IB_CM_MRA_REQ_SENT: 418962306a36Sopenharmony_ci 419062306a36Sopenharmony_ci case IB_CM_REP_RCVD: 419162306a36Sopenharmony_ci case IB_CM_MRA_REP_SENT: 419262306a36Sopenharmony_ci case IB_CM_REP_SENT: 419362306a36Sopenharmony_ci case IB_CM_MRA_REP_RCVD: 419462306a36Sopenharmony_ci case IB_CM_ESTABLISHED: 419562306a36Sopenharmony_ci if (cm_id_priv->id.lap_state == IB_CM_LAP_UNINIT) { 419662306a36Sopenharmony_ci *qp_attr_mask = IB_QP_STATE | IB_QP_SQ_PSN; 419762306a36Sopenharmony_ci qp_attr->sq_psn = be32_to_cpu(cm_id_priv->sq_psn); 419862306a36Sopenharmony_ci switch (cm_id_priv->qp_type) { 419962306a36Sopenharmony_ci case IB_QPT_RC: 420062306a36Sopenharmony_ci case IB_QPT_XRC_INI: 420162306a36Sopenharmony_ci *qp_attr_mask |= IB_QP_RETRY_CNT | IB_QP_RNR_RETRY | 420262306a36Sopenharmony_ci IB_QP_MAX_QP_RD_ATOMIC; 420362306a36Sopenharmony_ci qp_attr->retry_cnt = cm_id_priv->retry_count; 420462306a36Sopenharmony_ci qp_attr->rnr_retry = cm_id_priv->rnr_retry_count; 420562306a36Sopenharmony_ci qp_attr->max_rd_atomic = cm_id_priv->initiator_depth; 420662306a36Sopenharmony_ci fallthrough; 420762306a36Sopenharmony_ci case IB_QPT_XRC_TGT: 420862306a36Sopenharmony_ci *qp_attr_mask |= IB_QP_TIMEOUT; 420962306a36Sopenharmony_ci qp_attr->timeout = cm_id_priv->av.timeout; 421062306a36Sopenharmony_ci break; 421162306a36Sopenharmony_ci default: 421262306a36Sopenharmony_ci break; 421362306a36Sopenharmony_ci } 421462306a36Sopenharmony_ci if (rdma_ah_get_dlid(&cm_id_priv->alt_av.ah_attr)) { 421562306a36Sopenharmony_ci *qp_attr_mask |= IB_QP_PATH_MIG_STATE; 421662306a36Sopenharmony_ci qp_attr->path_mig_state = IB_MIG_REARM; 421762306a36Sopenharmony_ci } 421862306a36Sopenharmony_ci } else { 421962306a36Sopenharmony_ci *qp_attr_mask = IB_QP_ALT_PATH | IB_QP_PATH_MIG_STATE; 422062306a36Sopenharmony_ci if (cm_id_priv->alt_av.port) 422162306a36Sopenharmony_ci qp_attr->alt_port_num = 422262306a36Sopenharmony_ci cm_id_priv->alt_av.port->port_num; 422362306a36Sopenharmony_ci qp_attr->alt_pkey_index = cm_id_priv->alt_av.pkey_index; 422462306a36Sopenharmony_ci qp_attr->alt_timeout = cm_id_priv->alt_av.timeout; 422562306a36Sopenharmony_ci qp_attr->alt_ah_attr = cm_id_priv->alt_av.ah_attr; 422662306a36Sopenharmony_ci qp_attr->path_mig_state = IB_MIG_REARM; 422762306a36Sopenharmony_ci } 422862306a36Sopenharmony_ci ret = 0; 422962306a36Sopenharmony_ci break; 423062306a36Sopenharmony_ci default: 423162306a36Sopenharmony_ci trace_icm_qp_rts_err(&cm_id_priv->id); 423262306a36Sopenharmony_ci ret = -EINVAL; 423362306a36Sopenharmony_ci break; 423462306a36Sopenharmony_ci } 423562306a36Sopenharmony_ci spin_unlock_irqrestore(&cm_id_priv->lock, flags); 423662306a36Sopenharmony_ci return ret; 423762306a36Sopenharmony_ci} 423862306a36Sopenharmony_ci 423962306a36Sopenharmony_ciint ib_cm_init_qp_attr(struct ib_cm_id *cm_id, 424062306a36Sopenharmony_ci struct ib_qp_attr *qp_attr, 424162306a36Sopenharmony_ci int *qp_attr_mask) 424262306a36Sopenharmony_ci{ 424362306a36Sopenharmony_ci struct cm_id_private *cm_id_priv; 424462306a36Sopenharmony_ci int ret; 424562306a36Sopenharmony_ci 424662306a36Sopenharmony_ci cm_id_priv = container_of(cm_id, struct cm_id_private, id); 424762306a36Sopenharmony_ci switch (qp_attr->qp_state) { 424862306a36Sopenharmony_ci case IB_QPS_INIT: 424962306a36Sopenharmony_ci ret = cm_init_qp_init_attr(cm_id_priv, qp_attr, qp_attr_mask); 425062306a36Sopenharmony_ci break; 425162306a36Sopenharmony_ci case IB_QPS_RTR: 425262306a36Sopenharmony_ci ret = cm_init_qp_rtr_attr(cm_id_priv, qp_attr, qp_attr_mask); 425362306a36Sopenharmony_ci break; 425462306a36Sopenharmony_ci case IB_QPS_RTS: 425562306a36Sopenharmony_ci ret = cm_init_qp_rts_attr(cm_id_priv, qp_attr, qp_attr_mask); 425662306a36Sopenharmony_ci break; 425762306a36Sopenharmony_ci default: 425862306a36Sopenharmony_ci ret = -EINVAL; 425962306a36Sopenharmony_ci break; 426062306a36Sopenharmony_ci } 426162306a36Sopenharmony_ci return ret; 426262306a36Sopenharmony_ci} 426362306a36Sopenharmony_ciEXPORT_SYMBOL(ib_cm_init_qp_attr); 426462306a36Sopenharmony_ci 426562306a36Sopenharmony_cistatic ssize_t cm_show_counter(struct ib_device *ibdev, u32 port_num, 426662306a36Sopenharmony_ci struct ib_port_attribute *attr, char *buf) 426762306a36Sopenharmony_ci{ 426862306a36Sopenharmony_ci struct cm_counter_attribute *cm_attr = 426962306a36Sopenharmony_ci container_of(attr, struct cm_counter_attribute, attr); 427062306a36Sopenharmony_ci struct cm_device *cm_dev = ib_get_client_data(ibdev, &cm_client); 427162306a36Sopenharmony_ci 427262306a36Sopenharmony_ci if (WARN_ON(!cm_dev)) 427362306a36Sopenharmony_ci return -EINVAL; 427462306a36Sopenharmony_ci 427562306a36Sopenharmony_ci return sysfs_emit( 427662306a36Sopenharmony_ci buf, "%ld\n", 427762306a36Sopenharmony_ci atomic_long_read( 427862306a36Sopenharmony_ci &cm_dev->port[port_num - 1] 427962306a36Sopenharmony_ci ->counters[cm_attr->group][cm_attr->index])); 428062306a36Sopenharmony_ci} 428162306a36Sopenharmony_ci 428262306a36Sopenharmony_ci#define CM_COUNTER_ATTR(_name, _group, _index) \ 428362306a36Sopenharmony_ci { \ 428462306a36Sopenharmony_ci .attr = __ATTR(_name, 0444, cm_show_counter, NULL), \ 428562306a36Sopenharmony_ci .group = _group, .index = _index \ 428662306a36Sopenharmony_ci } 428762306a36Sopenharmony_ci 428862306a36Sopenharmony_ci#define CM_COUNTER_GROUP(_group, _name) \ 428962306a36Sopenharmony_ci static struct cm_counter_attribute cm_counter_attr_##_group[] = { \ 429062306a36Sopenharmony_ci CM_COUNTER_ATTR(req, _group, CM_REQ_COUNTER), \ 429162306a36Sopenharmony_ci CM_COUNTER_ATTR(mra, _group, CM_MRA_COUNTER), \ 429262306a36Sopenharmony_ci CM_COUNTER_ATTR(rej, _group, CM_REJ_COUNTER), \ 429362306a36Sopenharmony_ci CM_COUNTER_ATTR(rep, _group, CM_REP_COUNTER), \ 429462306a36Sopenharmony_ci CM_COUNTER_ATTR(rtu, _group, CM_RTU_COUNTER), \ 429562306a36Sopenharmony_ci CM_COUNTER_ATTR(dreq, _group, CM_DREQ_COUNTER), \ 429662306a36Sopenharmony_ci CM_COUNTER_ATTR(drep, _group, CM_DREP_COUNTER), \ 429762306a36Sopenharmony_ci CM_COUNTER_ATTR(sidr_req, _group, CM_SIDR_REQ_COUNTER), \ 429862306a36Sopenharmony_ci CM_COUNTER_ATTR(sidr_rep, _group, CM_SIDR_REP_COUNTER), \ 429962306a36Sopenharmony_ci CM_COUNTER_ATTR(lap, _group, CM_LAP_COUNTER), \ 430062306a36Sopenharmony_ci CM_COUNTER_ATTR(apr, _group, CM_APR_COUNTER), \ 430162306a36Sopenharmony_ci }; \ 430262306a36Sopenharmony_ci static struct attribute *cm_counter_attrs_##_group[] = { \ 430362306a36Sopenharmony_ci &cm_counter_attr_##_group[0].attr.attr, \ 430462306a36Sopenharmony_ci &cm_counter_attr_##_group[1].attr.attr, \ 430562306a36Sopenharmony_ci &cm_counter_attr_##_group[2].attr.attr, \ 430662306a36Sopenharmony_ci &cm_counter_attr_##_group[3].attr.attr, \ 430762306a36Sopenharmony_ci &cm_counter_attr_##_group[4].attr.attr, \ 430862306a36Sopenharmony_ci &cm_counter_attr_##_group[5].attr.attr, \ 430962306a36Sopenharmony_ci &cm_counter_attr_##_group[6].attr.attr, \ 431062306a36Sopenharmony_ci &cm_counter_attr_##_group[7].attr.attr, \ 431162306a36Sopenharmony_ci &cm_counter_attr_##_group[8].attr.attr, \ 431262306a36Sopenharmony_ci &cm_counter_attr_##_group[9].attr.attr, \ 431362306a36Sopenharmony_ci &cm_counter_attr_##_group[10].attr.attr, \ 431462306a36Sopenharmony_ci NULL, \ 431562306a36Sopenharmony_ci }; \ 431662306a36Sopenharmony_ci static const struct attribute_group cm_counter_group_##_group = { \ 431762306a36Sopenharmony_ci .name = _name, \ 431862306a36Sopenharmony_ci .attrs = cm_counter_attrs_##_group, \ 431962306a36Sopenharmony_ci }; 432062306a36Sopenharmony_ci 432162306a36Sopenharmony_ciCM_COUNTER_GROUP(CM_XMIT, "cm_tx_msgs") 432262306a36Sopenharmony_ciCM_COUNTER_GROUP(CM_XMIT_RETRIES, "cm_tx_retries") 432362306a36Sopenharmony_ciCM_COUNTER_GROUP(CM_RECV, "cm_rx_msgs") 432462306a36Sopenharmony_ciCM_COUNTER_GROUP(CM_RECV_DUPLICATES, "cm_rx_duplicates") 432562306a36Sopenharmony_ci 432662306a36Sopenharmony_cistatic const struct attribute_group *cm_counter_groups[] = { 432762306a36Sopenharmony_ci &cm_counter_group_CM_XMIT, 432862306a36Sopenharmony_ci &cm_counter_group_CM_XMIT_RETRIES, 432962306a36Sopenharmony_ci &cm_counter_group_CM_RECV, 433062306a36Sopenharmony_ci &cm_counter_group_CM_RECV_DUPLICATES, 433162306a36Sopenharmony_ci NULL, 433262306a36Sopenharmony_ci}; 433362306a36Sopenharmony_ci 433462306a36Sopenharmony_cistatic int cm_add_one(struct ib_device *ib_device) 433562306a36Sopenharmony_ci{ 433662306a36Sopenharmony_ci struct cm_device *cm_dev; 433762306a36Sopenharmony_ci struct cm_port *port; 433862306a36Sopenharmony_ci struct ib_mad_reg_req reg_req = { 433962306a36Sopenharmony_ci .mgmt_class = IB_MGMT_CLASS_CM, 434062306a36Sopenharmony_ci .mgmt_class_version = IB_CM_CLASS_VERSION, 434162306a36Sopenharmony_ci }; 434262306a36Sopenharmony_ci struct ib_port_modify port_modify = { 434362306a36Sopenharmony_ci .set_port_cap_mask = IB_PORT_CM_SUP 434462306a36Sopenharmony_ci }; 434562306a36Sopenharmony_ci unsigned long flags; 434662306a36Sopenharmony_ci int ret; 434762306a36Sopenharmony_ci int count = 0; 434862306a36Sopenharmony_ci u32 i; 434962306a36Sopenharmony_ci 435062306a36Sopenharmony_ci cm_dev = kzalloc(struct_size(cm_dev, port, ib_device->phys_port_cnt), 435162306a36Sopenharmony_ci GFP_KERNEL); 435262306a36Sopenharmony_ci if (!cm_dev) 435362306a36Sopenharmony_ci return -ENOMEM; 435462306a36Sopenharmony_ci 435562306a36Sopenharmony_ci kref_init(&cm_dev->kref); 435662306a36Sopenharmony_ci spin_lock_init(&cm_dev->mad_agent_lock); 435762306a36Sopenharmony_ci cm_dev->ib_device = ib_device; 435862306a36Sopenharmony_ci cm_dev->ack_delay = ib_device->attrs.local_ca_ack_delay; 435962306a36Sopenharmony_ci cm_dev->going_down = 0; 436062306a36Sopenharmony_ci 436162306a36Sopenharmony_ci ib_set_client_data(ib_device, &cm_client, cm_dev); 436262306a36Sopenharmony_ci 436362306a36Sopenharmony_ci set_bit(IB_MGMT_METHOD_SEND, reg_req.method_mask); 436462306a36Sopenharmony_ci rdma_for_each_port (ib_device, i) { 436562306a36Sopenharmony_ci if (!rdma_cap_ib_cm(ib_device, i)) 436662306a36Sopenharmony_ci continue; 436762306a36Sopenharmony_ci 436862306a36Sopenharmony_ci port = kzalloc(sizeof *port, GFP_KERNEL); 436962306a36Sopenharmony_ci if (!port) { 437062306a36Sopenharmony_ci ret = -ENOMEM; 437162306a36Sopenharmony_ci goto error1; 437262306a36Sopenharmony_ci } 437362306a36Sopenharmony_ci 437462306a36Sopenharmony_ci cm_dev->port[i-1] = port; 437562306a36Sopenharmony_ci port->cm_dev = cm_dev; 437662306a36Sopenharmony_ci port->port_num = i; 437762306a36Sopenharmony_ci 437862306a36Sopenharmony_ci ret = ib_port_register_client_groups(ib_device, i, 437962306a36Sopenharmony_ci cm_counter_groups); 438062306a36Sopenharmony_ci if (ret) 438162306a36Sopenharmony_ci goto error1; 438262306a36Sopenharmony_ci 438362306a36Sopenharmony_ci port->mad_agent = ib_register_mad_agent(ib_device, i, 438462306a36Sopenharmony_ci IB_QPT_GSI, 438562306a36Sopenharmony_ci ®_req, 438662306a36Sopenharmony_ci 0, 438762306a36Sopenharmony_ci cm_send_handler, 438862306a36Sopenharmony_ci cm_recv_handler, 438962306a36Sopenharmony_ci port, 439062306a36Sopenharmony_ci 0); 439162306a36Sopenharmony_ci if (IS_ERR(port->mad_agent)) { 439262306a36Sopenharmony_ci ret = PTR_ERR(port->mad_agent); 439362306a36Sopenharmony_ci goto error2; 439462306a36Sopenharmony_ci } 439562306a36Sopenharmony_ci 439662306a36Sopenharmony_ci ret = ib_modify_port(ib_device, i, 0, &port_modify); 439762306a36Sopenharmony_ci if (ret) 439862306a36Sopenharmony_ci goto error3; 439962306a36Sopenharmony_ci 440062306a36Sopenharmony_ci count++; 440162306a36Sopenharmony_ci } 440262306a36Sopenharmony_ci 440362306a36Sopenharmony_ci if (!count) { 440462306a36Sopenharmony_ci ret = -EOPNOTSUPP; 440562306a36Sopenharmony_ci goto free; 440662306a36Sopenharmony_ci } 440762306a36Sopenharmony_ci 440862306a36Sopenharmony_ci write_lock_irqsave(&cm.device_lock, flags); 440962306a36Sopenharmony_ci list_add_tail(&cm_dev->list, &cm.device_list); 441062306a36Sopenharmony_ci write_unlock_irqrestore(&cm.device_lock, flags); 441162306a36Sopenharmony_ci return 0; 441262306a36Sopenharmony_ci 441362306a36Sopenharmony_cierror3: 441462306a36Sopenharmony_ci ib_unregister_mad_agent(port->mad_agent); 441562306a36Sopenharmony_cierror2: 441662306a36Sopenharmony_ci ib_port_unregister_client_groups(ib_device, i, cm_counter_groups); 441762306a36Sopenharmony_cierror1: 441862306a36Sopenharmony_ci port_modify.set_port_cap_mask = 0; 441962306a36Sopenharmony_ci port_modify.clr_port_cap_mask = IB_PORT_CM_SUP; 442062306a36Sopenharmony_ci while (--i) { 442162306a36Sopenharmony_ci if (!rdma_cap_ib_cm(ib_device, i)) 442262306a36Sopenharmony_ci continue; 442362306a36Sopenharmony_ci 442462306a36Sopenharmony_ci port = cm_dev->port[i-1]; 442562306a36Sopenharmony_ci ib_modify_port(ib_device, port->port_num, 0, &port_modify); 442662306a36Sopenharmony_ci ib_unregister_mad_agent(port->mad_agent); 442762306a36Sopenharmony_ci ib_port_unregister_client_groups(ib_device, i, 442862306a36Sopenharmony_ci cm_counter_groups); 442962306a36Sopenharmony_ci } 443062306a36Sopenharmony_cifree: 443162306a36Sopenharmony_ci cm_device_put(cm_dev); 443262306a36Sopenharmony_ci return ret; 443362306a36Sopenharmony_ci} 443462306a36Sopenharmony_ci 443562306a36Sopenharmony_cistatic void cm_remove_one(struct ib_device *ib_device, void *client_data) 443662306a36Sopenharmony_ci{ 443762306a36Sopenharmony_ci struct cm_device *cm_dev = client_data; 443862306a36Sopenharmony_ci struct cm_port *port; 443962306a36Sopenharmony_ci struct ib_port_modify port_modify = { 444062306a36Sopenharmony_ci .clr_port_cap_mask = IB_PORT_CM_SUP 444162306a36Sopenharmony_ci }; 444262306a36Sopenharmony_ci unsigned long flags; 444362306a36Sopenharmony_ci u32 i; 444462306a36Sopenharmony_ci 444562306a36Sopenharmony_ci write_lock_irqsave(&cm.device_lock, flags); 444662306a36Sopenharmony_ci list_del(&cm_dev->list); 444762306a36Sopenharmony_ci write_unlock_irqrestore(&cm.device_lock, flags); 444862306a36Sopenharmony_ci 444962306a36Sopenharmony_ci spin_lock_irq(&cm.lock); 445062306a36Sopenharmony_ci cm_dev->going_down = 1; 445162306a36Sopenharmony_ci spin_unlock_irq(&cm.lock); 445262306a36Sopenharmony_ci 445362306a36Sopenharmony_ci rdma_for_each_port (ib_device, i) { 445462306a36Sopenharmony_ci struct ib_mad_agent *mad_agent; 445562306a36Sopenharmony_ci 445662306a36Sopenharmony_ci if (!rdma_cap_ib_cm(ib_device, i)) 445762306a36Sopenharmony_ci continue; 445862306a36Sopenharmony_ci 445962306a36Sopenharmony_ci port = cm_dev->port[i-1]; 446062306a36Sopenharmony_ci mad_agent = port->mad_agent; 446162306a36Sopenharmony_ci ib_modify_port(ib_device, port->port_num, 0, &port_modify); 446262306a36Sopenharmony_ci /* 446362306a36Sopenharmony_ci * We flush the queue here after the going_down set, this 446462306a36Sopenharmony_ci * verify that no new works will be queued in the recv handler, 446562306a36Sopenharmony_ci * after that we can call the unregister_mad_agent 446662306a36Sopenharmony_ci */ 446762306a36Sopenharmony_ci flush_workqueue(cm.wq); 446862306a36Sopenharmony_ci /* 446962306a36Sopenharmony_ci * The above ensures no call paths from the work are running, 447062306a36Sopenharmony_ci * the remaining paths all take the mad_agent_lock. 447162306a36Sopenharmony_ci */ 447262306a36Sopenharmony_ci spin_lock(&cm_dev->mad_agent_lock); 447362306a36Sopenharmony_ci port->mad_agent = NULL; 447462306a36Sopenharmony_ci spin_unlock(&cm_dev->mad_agent_lock); 447562306a36Sopenharmony_ci ib_unregister_mad_agent(mad_agent); 447662306a36Sopenharmony_ci ib_port_unregister_client_groups(ib_device, i, 447762306a36Sopenharmony_ci cm_counter_groups); 447862306a36Sopenharmony_ci } 447962306a36Sopenharmony_ci 448062306a36Sopenharmony_ci cm_device_put(cm_dev); 448162306a36Sopenharmony_ci} 448262306a36Sopenharmony_ci 448362306a36Sopenharmony_cistatic int __init ib_cm_init(void) 448462306a36Sopenharmony_ci{ 448562306a36Sopenharmony_ci int ret; 448662306a36Sopenharmony_ci 448762306a36Sopenharmony_ci INIT_LIST_HEAD(&cm.device_list); 448862306a36Sopenharmony_ci rwlock_init(&cm.device_lock); 448962306a36Sopenharmony_ci spin_lock_init(&cm.lock); 449062306a36Sopenharmony_ci cm.listen_service_table = RB_ROOT; 449162306a36Sopenharmony_ci cm.listen_service_id = be64_to_cpu(IB_CM_ASSIGN_SERVICE_ID); 449262306a36Sopenharmony_ci cm.remote_id_table = RB_ROOT; 449362306a36Sopenharmony_ci cm.remote_qp_table = RB_ROOT; 449462306a36Sopenharmony_ci cm.remote_sidr_table = RB_ROOT; 449562306a36Sopenharmony_ci xa_init_flags(&cm.local_id_table, XA_FLAGS_ALLOC); 449662306a36Sopenharmony_ci get_random_bytes(&cm.random_id_operand, sizeof cm.random_id_operand); 449762306a36Sopenharmony_ci INIT_LIST_HEAD(&cm.timewait_list); 449862306a36Sopenharmony_ci 449962306a36Sopenharmony_ci cm.wq = alloc_workqueue("ib_cm", 0, 1); 450062306a36Sopenharmony_ci if (!cm.wq) { 450162306a36Sopenharmony_ci ret = -ENOMEM; 450262306a36Sopenharmony_ci goto error2; 450362306a36Sopenharmony_ci } 450462306a36Sopenharmony_ci 450562306a36Sopenharmony_ci ret = ib_register_client(&cm_client); 450662306a36Sopenharmony_ci if (ret) 450762306a36Sopenharmony_ci goto error3; 450862306a36Sopenharmony_ci 450962306a36Sopenharmony_ci return 0; 451062306a36Sopenharmony_cierror3: 451162306a36Sopenharmony_ci destroy_workqueue(cm.wq); 451262306a36Sopenharmony_cierror2: 451362306a36Sopenharmony_ci return ret; 451462306a36Sopenharmony_ci} 451562306a36Sopenharmony_ci 451662306a36Sopenharmony_cistatic void __exit ib_cm_cleanup(void) 451762306a36Sopenharmony_ci{ 451862306a36Sopenharmony_ci struct cm_timewait_info *timewait_info, *tmp; 451962306a36Sopenharmony_ci 452062306a36Sopenharmony_ci spin_lock_irq(&cm.lock); 452162306a36Sopenharmony_ci list_for_each_entry(timewait_info, &cm.timewait_list, list) 452262306a36Sopenharmony_ci cancel_delayed_work(&timewait_info->work.work); 452362306a36Sopenharmony_ci spin_unlock_irq(&cm.lock); 452462306a36Sopenharmony_ci 452562306a36Sopenharmony_ci ib_unregister_client(&cm_client); 452662306a36Sopenharmony_ci destroy_workqueue(cm.wq); 452762306a36Sopenharmony_ci 452862306a36Sopenharmony_ci list_for_each_entry_safe(timewait_info, tmp, &cm.timewait_list, list) { 452962306a36Sopenharmony_ci list_del(&timewait_info->list); 453062306a36Sopenharmony_ci kfree(timewait_info); 453162306a36Sopenharmony_ci } 453262306a36Sopenharmony_ci 453362306a36Sopenharmony_ci WARN_ON(!xa_empty(&cm.local_id_table)); 453462306a36Sopenharmony_ci} 453562306a36Sopenharmony_ci 453662306a36Sopenharmony_cimodule_init(ib_cm_init); 453762306a36Sopenharmony_cimodule_exit(ib_cm_cleanup); 4538