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							&reg_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