124f52149SLeon Romanovsky // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2a977049dSHal Rosenstock /*
39af57b7aSSean Hefty * Copyright (c) 2004-2007 Intel Corporation. All rights reserved.
4a977049dSHal Rosenstock * Copyright (c) 2004 Topspin Corporation. All rights reserved.
5a977049dSHal Rosenstock * Copyright (c) 2004, 2005 Voltaire Corporation. All rights reserved.
6a977049dSHal Rosenstock * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
724f52149SLeon Romanovsky * Copyright (c) 2019, Mellanox Technologies inc. All rights reserved.
8a977049dSHal Rosenstock */
91b52fa98SSean Hefty
101b52fa98SSean Hefty #include <linux/completion.h>
11a977049dSHal Rosenstock #include <linux/dma-mapping.h>
129af57b7aSSean Hefty #include <linux/device.h>
13e4dd23d7SPaul Gortmaker #include <linux/module.h>
14a977049dSHal Rosenstock #include <linux/err.h>
15a977049dSHal Rosenstock #include <linux/idr.h>
16a977049dSHal Rosenstock #include <linux/interrupt.h>
17f06d2653SSean Hefty #include <linux/random.h>
18a977049dSHal Rosenstock #include <linux/rbtree.h>
19a977049dSHal Rosenstock #include <linux/spinlock.h>
205a0e3ad6STejun Heo #include <linux/slab.h>
219af57b7aSSean Hefty #include <linux/sysfs.h>
22a977049dSHal Rosenstock #include <linux/workqueue.h>
23110cf374SGreg Kroah-Hartman #include <linux/kdev_t.h>
24dd5f03beSMatan Barak #include <linux/etherdevice.h>
25a977049dSHal Rosenstock
26a4d61e84SRoland Dreier #include <rdma/ib_cache.h>
27a4d61e84SRoland Dreier #include <rdma/ib_cm.h>
28526a12c8SJason Gunthorpe #include <rdma/ib_sysfs.h>
29a977049dSHal Rosenstock #include "cm_msgs.h"
30c87e65cfSLeon Romanovsky #include "core_priv.h"
3175874b3dSChuck Lever #include "cm_trace.h"
32a977049dSHal Rosenstock
33a977049dSHal Rosenstock MODULE_AUTHOR("Sean Hefty");
34a977049dSHal Rosenstock MODULE_DESCRIPTION("InfiniBand CM");
35a977049dSHal Rosenstock MODULE_LICENSE("Dual BSD/GPL");
36a977049dSHal Rosenstock
372e90774fSManjunath Patil #define CM_DESTROY_ID_WAIT_TIMEOUT 10000 /* msecs */
3877a5db13SSteve Wise static const char * const ibcm_rej_reason_strs[] = {
3977a5db13SSteve Wise [IB_CM_REJ_NO_QP] = "no QP",
4077a5db13SSteve Wise [IB_CM_REJ_NO_EEC] = "no EEC",
4177a5db13SSteve Wise [IB_CM_REJ_NO_RESOURCES] = "no resources",
4277a5db13SSteve Wise [IB_CM_REJ_TIMEOUT] = "timeout",
4377a5db13SSteve Wise [IB_CM_REJ_UNSUPPORTED] = "unsupported",
4477a5db13SSteve Wise [IB_CM_REJ_INVALID_COMM_ID] = "invalid comm ID",
4577a5db13SSteve Wise [IB_CM_REJ_INVALID_COMM_INSTANCE] = "invalid comm instance",
4677a5db13SSteve Wise [IB_CM_REJ_INVALID_SERVICE_ID] = "invalid service ID",
4777a5db13SSteve Wise [IB_CM_REJ_INVALID_TRANSPORT_TYPE] = "invalid transport type",
4877a5db13SSteve Wise [IB_CM_REJ_STALE_CONN] = "stale conn",
4977a5db13SSteve Wise [IB_CM_REJ_RDC_NOT_EXIST] = "RDC not exist",
5077a5db13SSteve Wise [IB_CM_REJ_INVALID_GID] = "invalid GID",
5177a5db13SSteve Wise [IB_CM_REJ_INVALID_LID] = "invalid LID",
5277a5db13SSteve Wise [IB_CM_REJ_INVALID_SL] = "invalid SL",
5377a5db13SSteve Wise [IB_CM_REJ_INVALID_TRAFFIC_CLASS] = "invalid traffic class",
5477a5db13SSteve Wise [IB_CM_REJ_INVALID_HOP_LIMIT] = "invalid hop limit",
5577a5db13SSteve Wise [IB_CM_REJ_INVALID_PACKET_RATE] = "invalid packet rate",
5677a5db13SSteve Wise [IB_CM_REJ_INVALID_ALT_GID] = "invalid alt GID",
5777a5db13SSteve Wise [IB_CM_REJ_INVALID_ALT_LID] = "invalid alt LID",
5877a5db13SSteve Wise [IB_CM_REJ_INVALID_ALT_SL] = "invalid alt SL",
5977a5db13SSteve Wise [IB_CM_REJ_INVALID_ALT_TRAFFIC_CLASS] = "invalid alt traffic class",
6077a5db13SSteve Wise [IB_CM_REJ_INVALID_ALT_HOP_LIMIT] = "invalid alt hop limit",
6177a5db13SSteve Wise [IB_CM_REJ_INVALID_ALT_PACKET_RATE] = "invalid alt packet rate",
6277a5db13SSteve Wise [IB_CM_REJ_PORT_CM_REDIRECT] = "port CM redirect",
6377a5db13SSteve Wise [IB_CM_REJ_PORT_REDIRECT] = "port redirect",
6477a5db13SSteve Wise [IB_CM_REJ_INVALID_MTU] = "invalid MTU",
6577a5db13SSteve Wise [IB_CM_REJ_INSUFFICIENT_RESP_RESOURCES] = "insufficient resp resources",
6677a5db13SSteve Wise [IB_CM_REJ_CONSUMER_DEFINED] = "consumer defined",
6777a5db13SSteve Wise [IB_CM_REJ_INVALID_RNR_RETRY] = "invalid RNR retry",
6877a5db13SSteve Wise [IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID] = "duplicate local comm ID",
6977a5db13SSteve Wise [IB_CM_REJ_INVALID_CLASS_VERSION] = "invalid class version",
7077a5db13SSteve Wise [IB_CM_REJ_INVALID_FLOW_LABEL] = "invalid flow label",
7177a5db13SSteve Wise [IB_CM_REJ_INVALID_ALT_FLOW_LABEL] = "invalid alt flow label",
72a20652e1SLeon Romanovsky [IB_CM_REJ_VENDOR_OPTION_NOT_SUPPORTED] =
73a20652e1SLeon Romanovsky "vendor option is not supported",
7477a5db13SSteve Wise };
7577a5db13SSteve Wise
ibcm_reject_msg(int reason)7677a5db13SSteve Wise const char *__attribute_const__ ibcm_reject_msg(int reason)
7777a5db13SSteve Wise {
7877a5db13SSteve Wise size_t index = reason;
7977a5db13SSteve Wise
8077a5db13SSteve Wise if (index < ARRAY_SIZE(ibcm_rej_reason_strs) &&
8177a5db13SSteve Wise ibcm_rej_reason_strs[index])
8277a5db13SSteve Wise return ibcm_rej_reason_strs[index];
8377a5db13SSteve Wise else
8477a5db13SSteve Wise return "unrecognized reason";
8577a5db13SSteve Wise }
8677a5db13SSteve Wise EXPORT_SYMBOL(ibcm_reject_msg);
8777a5db13SSteve Wise
88e029fdc0SJason Gunthorpe struct cm_id_private;
89e83f195aSJason Gunthorpe struct cm_work;
9011a0ae4cSJason Gunthorpe static int cm_add_one(struct ib_device *device);
917c1eb45aSHaggai Eran static void cm_remove_one(struct ib_device *device, void *client_data);
92e83f195aSJason Gunthorpe static void cm_process_work(struct cm_id_private *cm_id_priv,
93e83f195aSJason Gunthorpe struct cm_work *work);
946a8824a7SJason Gunthorpe static int cm_send_sidr_rep_locked(struct cm_id_private *cm_id_priv,
956a8824a7SJason Gunthorpe struct ib_cm_sidr_rep_param *param);
96e029fdc0SJason Gunthorpe static int cm_send_dreq_locked(struct cm_id_private *cm_id_priv,
97e029fdc0SJason Gunthorpe const void *private_data, u8 private_data_len);
9887cabf3eSJason Gunthorpe static int cm_send_drep_locked(struct cm_id_private *cm_id_priv,
9987cabf3eSJason Gunthorpe void *private_data, u8 private_data_len);
10081ddb41fSJason Gunthorpe static int cm_send_rej_locked(struct cm_id_private *cm_id_priv,
10181ddb41fSJason Gunthorpe enum ib_cm_rej_reason reason, void *ari,
10281ddb41fSJason Gunthorpe u8 ari_length, const void *private_data,
10381ddb41fSJason Gunthorpe u8 private_data_len);
104a977049dSHal Rosenstock
105a977049dSHal Rosenstock static struct ib_client cm_client = {
106a977049dSHal Rosenstock .name = "cm",
107a977049dSHal Rosenstock .add = cm_add_one,
108a977049dSHal Rosenstock .remove = cm_remove_one
109a977049dSHal Rosenstock };
110a977049dSHal Rosenstock
111a977049dSHal Rosenstock static struct ib_cm {
112a977049dSHal Rosenstock spinlock_t lock;
113a977049dSHal Rosenstock struct list_head device_list;
114a977049dSHal Rosenstock rwlock_t device_lock;
115a977049dSHal Rosenstock struct rb_root listen_service_table;
116a977049dSHal Rosenstock u64 listen_service_id;
117a977049dSHal Rosenstock /* struct rb_root peer_service_table; todo: fix peer to peer */
118a977049dSHal Rosenstock struct rb_root remote_qp_table;
119a977049dSHal Rosenstock struct rb_root remote_id_table;
120a977049dSHal Rosenstock struct rb_root remote_sidr_table;
121ae78ff3aSMatthew Wilcox struct xarray local_id_table;
122ae78ff3aSMatthew Wilcox u32 local_id_next;
123f06d2653SSean Hefty __be32 random_id_operand;
1248575329dSSean Hefty struct list_head timewait_list;
125a977049dSHal Rosenstock struct workqueue_struct *wq;
126a977049dSHal Rosenstock } cm;
127a977049dSHal Rosenstock
1289af57b7aSSean Hefty /* Counter indexes ordered by attribute ID */
1299af57b7aSSean Hefty enum {
1309af57b7aSSean Hefty CM_REQ_COUNTER,
1319af57b7aSSean Hefty CM_MRA_COUNTER,
1329af57b7aSSean Hefty CM_REJ_COUNTER,
1339af57b7aSSean Hefty CM_REP_COUNTER,
1349af57b7aSSean Hefty CM_RTU_COUNTER,
1359af57b7aSSean Hefty CM_DREQ_COUNTER,
1369af57b7aSSean Hefty CM_DREP_COUNTER,
1379af57b7aSSean Hefty CM_SIDR_REQ_COUNTER,
1389af57b7aSSean Hefty CM_SIDR_REP_COUNTER,
1399af57b7aSSean Hefty CM_LAP_COUNTER,
1409af57b7aSSean Hefty CM_APR_COUNTER,
1419af57b7aSSean Hefty CM_ATTR_COUNT,
1429af57b7aSSean Hefty CM_ATTR_ID_OFFSET = 0x0010,
1439af57b7aSSean Hefty };
1449af57b7aSSean Hefty
1459af57b7aSSean Hefty enum {
1469af57b7aSSean Hefty CM_XMIT,
1479af57b7aSSean Hefty CM_XMIT_RETRIES,
1489af57b7aSSean Hefty CM_RECV,
1499af57b7aSSean Hefty CM_RECV_DUPLICATES,
1509af57b7aSSean Hefty CM_COUNTER_GROUPS
1519af57b7aSSean Hefty };
1529af57b7aSSean Hefty
1539af57b7aSSean Hefty struct cm_counter_attribute {
154526a12c8SJason Gunthorpe struct ib_port_attribute attr;
155526a12c8SJason Gunthorpe unsigned short group;
156526a12c8SJason Gunthorpe unsigned short index;
1579af57b7aSSean Hefty };
1589af57b7aSSean Hefty
159a977049dSHal Rosenstock struct cm_port {
160a977049dSHal Rosenstock struct cm_device *cm_dev;
161a977049dSHal Rosenstock struct ib_mad_agent *mad_agent;
1621fb7f897SMark Bloch u32 port_num;
163526a12c8SJason Gunthorpe atomic_long_t counters[CM_COUNTER_GROUPS][CM_ATTR_COUNT];
164a977049dSHal Rosenstock };
165a977049dSHal Rosenstock
166a977049dSHal Rosenstock struct cm_device {
16776039ac9SMark Zhang struct kref kref;
168a977049dSHal Rosenstock struct list_head list;
16976039ac9SMark Zhang spinlock_t mad_agent_lock;
170d4c4196fSGreg Kroah-Hartman struct ib_device *ib_device;
1711d846126SSean Hefty u8 ack_delay;
172be4b4993SErez Shitrit int going_down;
1735b361328SGustavo A. R. Silva struct cm_port *port[];
174a977049dSHal Rosenstock };
175a977049dSHal Rosenstock
176a977049dSHal Rosenstock struct cm_av {
177a977049dSHal Rosenstock struct cm_port *port;
17890898850SDasaratharaman Chandramouli struct rdma_ah_attr ah_attr;
179eb8336dbSMark Zhang u16 dlid_datapath;
180a977049dSHal Rosenstock u16 pkey_index;
1811d846126SSean Hefty u8 timeout;
182a977049dSHal Rosenstock };
183a977049dSHal Rosenstock
184a977049dSHal Rosenstock struct cm_work {
185c4028958SDavid Howells struct delayed_work work;
186a977049dSHal Rosenstock struct list_head list;
187a977049dSHal Rosenstock struct cm_port *port;
188a977049dSHal Rosenstock struct ib_mad_recv_wc *mad_recv_wc; /* Received MADs */
18997f52eb4SSean Hefty __be32 local_id; /* Established / timewait */
19097f52eb4SSean Hefty __be32 remote_id;
191a977049dSHal Rosenstock struct ib_cm_event cm_event;
1925b361328SGustavo A. R. Silva struct sa_path_rec path[];
193a977049dSHal Rosenstock };
194a977049dSHal Rosenstock
195a977049dSHal Rosenstock struct cm_timewait_info {
196909624d8SParav Pandit struct cm_work work;
1978575329dSSean Hefty struct list_head list;
198a977049dSHal Rosenstock struct rb_node remote_qp_node;
199a977049dSHal Rosenstock struct rb_node remote_id_node;
20097f52eb4SSean Hefty __be64 remote_ca_guid;
20197f52eb4SSean Hefty __be32 remote_qpn;
202a977049dSHal Rosenstock u8 inserted_remote_qp;
203a977049dSHal Rosenstock u8 inserted_remote_id;
204a977049dSHal Rosenstock };
205a977049dSHal Rosenstock
206a977049dSHal Rosenstock struct cm_id_private {
207a977049dSHal Rosenstock struct ib_cm_id id;
208a977049dSHal Rosenstock
209a977049dSHal Rosenstock struct rb_node service_node;
210a977049dSHal Rosenstock struct rb_node sidr_id_node;
211bf0480a2SJason Gunthorpe u32 sidr_slid;
21287fd1a11SSean Hefty spinlock_t lock; /* Do not acquire inside cm.lock */
2131b52fa98SSean Hefty struct completion comp;
2140acc637dSDanit Goldberg refcount_t refcount;
215067b171bSHaggai Eran /* Number of clients sharing this ib_cm_id. Only valid for listeners.
21626caea5fSWenpeng Liang * Protected by the cm.lock spinlock.
21726caea5fSWenpeng Liang */
218067b171bSHaggai Eran int listen_sharecount;
2194d6e8a03SDanit Goldberg struct rcu_head rcu;
220a977049dSHal Rosenstock
221a977049dSHal Rosenstock struct ib_mad_send_buf *msg;
222a977049dSHal Rosenstock struct cm_timewait_info *timewait_info;
223a977049dSHal Rosenstock /* todo: use alternate port on send failure */
224a977049dSHal Rosenstock struct cm_av av;
225a977049dSHal Rosenstock struct cm_av alt_av;
226a977049dSHal Rosenstock
227a977049dSHal Rosenstock void *private_data;
22897f52eb4SSean Hefty __be64 tid;
22997f52eb4SSean Hefty __be32 local_qpn;
23097f52eb4SSean Hefty __be32 remote_qpn;
231ae7971a7SSean Hefty enum ib_qp_type qp_type;
23297f52eb4SSean Hefty __be32 sq_psn;
23397f52eb4SSean Hefty __be32 rq_psn;
234a977049dSHal Rosenstock int timeout_ms;
235a977049dSHal Rosenstock enum ib_mtu path_mtu;
236e1444b5aSSean Hefty __be16 pkey;
237a977049dSHal Rosenstock u8 private_data_len;
238a977049dSHal Rosenstock u8 max_cm_retries;
239a977049dSHal Rosenstock u8 responder_resources;
240a977049dSHal Rosenstock u8 initiator_depth;
241a977049dSHal Rosenstock u8 retry_count;
242a977049dSHal Rosenstock u8 rnr_retry_count;
243a977049dSHal Rosenstock u8 service_timeout;
2441d846126SSean Hefty u8 target_ack_delay;
245a977049dSHal Rosenstock
246a977049dSHal Rosenstock struct list_head work_list;
247a977049dSHal Rosenstock atomic_t work_count;
248a20652e1SLeon Romanovsky
249a20652e1SLeon Romanovsky struct rdma_ucm_ece ece;
250a977049dSHal Rosenstock };
251a977049dSHal Rosenstock
cm_dev_release(struct kref * kref)25276039ac9SMark Zhang static void cm_dev_release(struct kref *kref)
25376039ac9SMark Zhang {
25476039ac9SMark Zhang struct cm_device *cm_dev = container_of(kref, struct cm_device, kref);
25576039ac9SMark Zhang u32 i;
25676039ac9SMark Zhang
25776039ac9SMark Zhang rdma_for_each_port(cm_dev->ib_device, i)
25876039ac9SMark Zhang kfree(cm_dev->port[i - 1]);
25976039ac9SMark Zhang
26076039ac9SMark Zhang kfree(cm_dev);
26176039ac9SMark Zhang }
26276039ac9SMark Zhang
cm_device_put(struct cm_device * cm_dev)26376039ac9SMark Zhang static void cm_device_put(struct cm_device *cm_dev)
26476039ac9SMark Zhang {
26576039ac9SMark Zhang kref_put(&cm_dev->kref, cm_dev_release);
26676039ac9SMark Zhang }
26776039ac9SMark Zhang
268c4028958SDavid Howells static void cm_work_handler(struct work_struct *work);
269a977049dSHal Rosenstock
cm_deref_id(struct cm_id_private * cm_id_priv)270a977049dSHal Rosenstock static inline void cm_deref_id(struct cm_id_private *cm_id_priv)
271a977049dSHal Rosenstock {
2720acc637dSDanit Goldberg if (refcount_dec_and_test(&cm_id_priv->refcount))
2731b52fa98SSean Hefty complete(&cm_id_priv->comp);
274a977049dSHal Rosenstock }
275a977049dSHal Rosenstock
cm_alloc_msg(struct cm_id_private * cm_id_priv)2764b4e586eSJason Gunthorpe static struct ib_mad_send_buf *cm_alloc_msg(struct cm_id_private *cm_id_priv)
277a977049dSHal Rosenstock {
278a977049dSHal Rosenstock struct ib_mad_agent *mad_agent;
279a977049dSHal Rosenstock struct ib_mad_send_buf *m;
280a977049dSHal Rosenstock struct ib_ah *ah;
281a977049dSHal Rosenstock
28276039ac9SMark Zhang lockdep_assert_held(&cm_id_priv->lock);
28376039ac9SMark Zhang
28476039ac9SMark Zhang if (!cm_id_priv->av.port)
28576039ac9SMark Zhang return ERR_PTR(-EINVAL);
28676039ac9SMark Zhang
28776039ac9SMark Zhang spin_lock(&cm_id_priv->av.port->cm_dev->mad_agent_lock);
288a977049dSHal Rosenstock mad_agent = cm_id_priv->av.port->mad_agent;
28976039ac9SMark Zhang if (!mad_agent) {
29076039ac9SMark Zhang m = ERR_PTR(-EINVAL);
29176039ac9SMark Zhang goto out;
29276039ac9SMark Zhang }
29376039ac9SMark Zhang
2943595c398SMark Zhang ah = rdma_create_ah(mad_agent->qp->pd, &cm_id_priv->av.ah_attr, 0);
29576039ac9SMark Zhang if (IS_ERR(ah)) {
29676039ac9SMark Zhang m = ERR_CAST(ah);
29776039ac9SMark Zhang goto out;
29876039ac9SMark Zhang }
299a977049dSHal Rosenstock
300354ba39cSJohn Kingman m = ib_create_send_mad(mad_agent, cm_id_priv->id.remote_cm_qpn,
3013595c398SMark Zhang cm_id_priv->av.pkey_index,
30234816ad9SSean Hefty 0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA,
303da2dfaa3SIra Weiny GFP_ATOMIC,
304da2dfaa3SIra Weiny IB_MGMT_BASE_VERSION);
305a977049dSHal Rosenstock if (IS_ERR(m)) {
3062553ba21SGal Pressman rdma_destroy_ah(ah, 0);
30776039ac9SMark Zhang goto out;
308a977049dSHal Rosenstock }
309a977049dSHal Rosenstock
310a977049dSHal Rosenstock /* Timeout set by caller if response is expected. */
31134816ad9SSean Hefty m->ah = ah;
31234816ad9SSean Hefty m->retries = cm_id_priv->max_cm_retries;
313a977049dSHal Rosenstock
3140acc637dSDanit Goldberg refcount_inc(&cm_id_priv->refcount);
315a977049dSHal Rosenstock m->context[0] = cm_id_priv;
31676039ac9SMark Zhang
31776039ac9SMark Zhang out:
31876039ac9SMark Zhang spin_unlock(&cm_id_priv->av.port->cm_dev->mad_agent_lock);
3194b4e586eSJason Gunthorpe return m;
3204b4e586eSJason Gunthorpe }
3214b4e586eSJason Gunthorpe
cm_free_msg(struct ib_mad_send_buf * msg)322efafae67SJason Gunthorpe static void cm_free_msg(struct ib_mad_send_buf *msg)
323efafae67SJason Gunthorpe {
324efafae67SJason Gunthorpe struct cm_id_private *cm_id_priv = msg->context[0];
325efafae67SJason Gunthorpe
326efafae67SJason Gunthorpe if (msg->ah)
327efafae67SJason Gunthorpe rdma_destroy_ah(msg->ah, 0);
328efafae67SJason Gunthorpe cm_deref_id(cm_id_priv);
329efafae67SJason Gunthorpe ib_free_send_mad(msg);
330efafae67SJason Gunthorpe }
331efafae67SJason Gunthorpe
3324b4e586eSJason Gunthorpe static struct ib_mad_send_buf *
cm_alloc_priv_msg(struct cm_id_private * cm_id_priv)3334b4e586eSJason Gunthorpe cm_alloc_priv_msg(struct cm_id_private *cm_id_priv)
3344b4e586eSJason Gunthorpe {
3354b4e586eSJason Gunthorpe struct ib_mad_send_buf *msg;
3364b4e586eSJason Gunthorpe
3374b4e586eSJason Gunthorpe lockdep_assert_held(&cm_id_priv->lock);
3384b4e586eSJason Gunthorpe
3394b4e586eSJason Gunthorpe msg = cm_alloc_msg(cm_id_priv);
3404b4e586eSJason Gunthorpe if (IS_ERR(msg))
3414b4e586eSJason Gunthorpe return msg;
3424b4e586eSJason Gunthorpe cm_id_priv->msg = msg;
3434b4e586eSJason Gunthorpe return msg;
3444b4e586eSJason Gunthorpe }
3454b4e586eSJason Gunthorpe
cm_free_priv_msg(struct ib_mad_send_buf * msg)3464b4e586eSJason Gunthorpe static void cm_free_priv_msg(struct ib_mad_send_buf *msg)
3474b4e586eSJason Gunthorpe {
3484b4e586eSJason Gunthorpe struct cm_id_private *cm_id_priv = msg->context[0];
3494b4e586eSJason Gunthorpe
3504b4e586eSJason Gunthorpe lockdep_assert_held(&cm_id_priv->lock);
3514b4e586eSJason Gunthorpe
3524b4e586eSJason Gunthorpe if (!WARN_ON(cm_id_priv->msg != msg))
3534b4e586eSJason Gunthorpe cm_id_priv->msg = NULL;
3544b4e586eSJason Gunthorpe
3554b4e586eSJason Gunthorpe if (msg->ah)
3564b4e586eSJason Gunthorpe rdma_destroy_ah(msg->ah, 0);
3574b4e586eSJason Gunthorpe cm_deref_id(cm_id_priv);
3584b4e586eSJason Gunthorpe ib_free_send_mad(msg);
359a977049dSHal Rosenstock }
360a977049dSHal Rosenstock
cm_alloc_response_msg_no_ah(struct cm_port * port,struct ib_mad_recv_wc * mad_recv_wc)361c7616118SRoland Dreier static struct ib_mad_send_buf *cm_alloc_response_msg_no_ah(struct cm_port *port,
362c7616118SRoland Dreier struct ib_mad_recv_wc *mad_recv_wc)
363a977049dSHal Rosenstock {
364c7616118SRoland Dreier return ib_create_send_mad(port->mad_agent, 1, mad_recv_wc->wc->pkey_index,
365c7616118SRoland Dreier 0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA,
366c7616118SRoland Dreier GFP_ATOMIC,
367c7616118SRoland Dreier IB_MGMT_BASE_VERSION);
368c7616118SRoland Dreier }
369c7616118SRoland Dreier
cm_create_response_msg_ah(struct cm_port * port,struct ib_mad_recv_wc * mad_recv_wc,struct ib_mad_send_buf * msg)370c7616118SRoland Dreier static int cm_create_response_msg_ah(struct cm_port *port,
371c7616118SRoland Dreier struct ib_mad_recv_wc *mad_recv_wc,
372c7616118SRoland Dreier struct ib_mad_send_buf *msg)
373c7616118SRoland Dreier {
374a977049dSHal Rosenstock struct ib_ah *ah;
375a977049dSHal Rosenstock
376a977049dSHal Rosenstock ah = ib_create_ah_from_wc(port->mad_agent->qp->pd, mad_recv_wc->wc,
377a977049dSHal Rosenstock mad_recv_wc->recv_buf.grh, port->port_num);
378a977049dSHal Rosenstock if (IS_ERR(ah))
379a977049dSHal Rosenstock return PTR_ERR(ah);
380a977049dSHal Rosenstock
381c7616118SRoland Dreier msg->ah = ah;
382a977049dSHal Rosenstock return 0;
383a977049dSHal Rosenstock }
384a977049dSHal Rosenstock
cm_alloc_response_msg(struct cm_port * port,struct ib_mad_recv_wc * mad_recv_wc,struct ib_mad_send_buf ** msg)385c7616118SRoland Dreier static int cm_alloc_response_msg(struct cm_port *port,
386c7616118SRoland Dreier struct ib_mad_recv_wc *mad_recv_wc,
387c7616118SRoland Dreier struct ib_mad_send_buf **msg)
388c7616118SRoland Dreier {
389c7616118SRoland Dreier struct ib_mad_send_buf *m;
390c7616118SRoland Dreier int ret;
391c7616118SRoland Dreier
392c7616118SRoland Dreier m = cm_alloc_response_msg_no_ah(port, mad_recv_wc);
393c7616118SRoland Dreier if (IS_ERR(m))
394c7616118SRoland Dreier return PTR_ERR(m);
395c7616118SRoland Dreier
396c7616118SRoland Dreier ret = cm_create_response_msg_ah(port, mad_recv_wc, m);
397c7616118SRoland Dreier if (ret) {
39896376a40SJason Gunthorpe ib_free_send_mad(m);
399c7616118SRoland Dreier return ret;
400c7616118SRoland Dreier }
401c7616118SRoland Dreier
402c7616118SRoland Dreier *msg = m;
403c7616118SRoland Dreier return 0;
404c7616118SRoland Dreier }
405c7616118SRoland Dreier
cm_free_response_msg(struct ib_mad_send_buf * msg)40696376a40SJason Gunthorpe static void cm_free_response_msg(struct ib_mad_send_buf *msg)
40796376a40SJason Gunthorpe {
40896376a40SJason Gunthorpe if (msg->ah)
40996376a40SJason Gunthorpe rdma_destroy_ah(msg->ah, 0);
41096376a40SJason Gunthorpe ib_free_send_mad(msg);
41196376a40SJason Gunthorpe }
41296376a40SJason Gunthorpe
cm_copy_private_data(const void * private_data,u8 private_data_len)413f681967aSWenpeng Liang static void *cm_copy_private_data(const void *private_data, u8 private_data_len)
414a977049dSHal Rosenstock {
415a977049dSHal Rosenstock void *data;
416a977049dSHal Rosenstock
417a977049dSHal Rosenstock if (!private_data || !private_data_len)
418a977049dSHal Rosenstock return NULL;
419a977049dSHal Rosenstock
420bed8bdfdSEric Sesterhenn data = kmemdup(private_data, private_data_len, GFP_KERNEL);
421a977049dSHal Rosenstock if (!data)
422a977049dSHal Rosenstock return ERR_PTR(-ENOMEM);
423a977049dSHal Rosenstock
424a977049dSHal Rosenstock return data;
425a977049dSHal Rosenstock }
426a977049dSHal Rosenstock
cm_set_private_data(struct cm_id_private * cm_id_priv,void * private_data,u8 private_data_len)427a977049dSHal Rosenstock static void cm_set_private_data(struct cm_id_private *cm_id_priv,
428a977049dSHal Rosenstock void *private_data, u8 private_data_len)
429a977049dSHal Rosenstock {
430a977049dSHal Rosenstock if (cm_id_priv->private_data && cm_id_priv->private_data_len)
431a977049dSHal Rosenstock kfree(cm_id_priv->private_data);
432a977049dSHal Rosenstock
433a977049dSHal Rosenstock cm_id_priv->private_data = private_data;
434a977049dSHal Rosenstock cm_id_priv->private_data_len = private_data_len;
435a977049dSHal Rosenstock }
436a977049dSHal Rosenstock
cm_set_av_port(struct cm_av * av,struct cm_port * port)43776039ac9SMark Zhang static void cm_set_av_port(struct cm_av *av, struct cm_port *port)
43876039ac9SMark Zhang {
43976039ac9SMark Zhang struct cm_port *old_port = av->port;
44076039ac9SMark Zhang
44176039ac9SMark Zhang if (old_port == port)
44276039ac9SMark Zhang return;
44376039ac9SMark Zhang
44476039ac9SMark Zhang av->port = port;
44576039ac9SMark Zhang if (old_port)
44676039ac9SMark Zhang cm_device_put(old_port->cm_dev);
44776039ac9SMark Zhang if (port)
44876039ac9SMark Zhang kref_get(&port->cm_dev->kref);
44976039ac9SMark Zhang }
45076039ac9SMark Zhang
cm_init_av_for_lap(struct cm_port * port,struct ib_wc * wc,struct rdma_ah_attr * ah_attr,struct cm_av * av)4517345201cSMark Zhang static void cm_init_av_for_lap(struct cm_port *port, struct ib_wc *wc,
4527345201cSMark Zhang struct rdma_ah_attr *ah_attr, struct cm_av *av)
4530e225dcbSParav Pandit {
45476039ac9SMark Zhang cm_set_av_port(av, port);
4550e225dcbSParav Pandit av->pkey_index = wc->pkey_index;
4567345201cSMark Zhang rdma_move_ah_attr(&av->ah_attr, ah_attr);
4570e225dcbSParav Pandit }
4580e225dcbSParav Pandit
cm_init_av_for_response(struct cm_port * port,struct ib_wc * wc,struct ib_grh * grh,struct cm_av * av)4590c4386ecSParav Pandit static int cm_init_av_for_response(struct cm_port *port, struct ib_wc *wc,
460ca222c6bSSean Hefty struct ib_grh *grh, struct cm_av *av)
461a977049dSHal Rosenstock {
46276039ac9SMark Zhang cm_set_av_port(av, port);
463a977049dSHal Rosenstock av->pkey_index = wc->pkey_index;
464f6bdb142SParav Pandit return ib_init_ah_attr_from_wc(port->cm_dev->ib_device,
465f6bdb142SParav Pandit port->port_num, wc,
466ca222c6bSSean Hefty grh, &av->ah_attr);
467a977049dSHal Rosenstock }
468a977049dSHal Rosenstock
46939839107SParav Pandit static struct cm_port *
get_cm_port_from_path(struct sa_path_rec * path,const struct ib_gid_attr * attr)47039839107SParav Pandit get_cm_port_from_path(struct sa_path_rec *path, const struct ib_gid_attr *attr)
471a977049dSHal Rosenstock {
472a977049dSHal Rosenstock struct cm_device *cm_dev;
473a977049dSHal Rosenstock struct cm_port *port = NULL;
474a977049dSHal Rosenstock unsigned long flags;
475a977049dSHal Rosenstock
47639839107SParav Pandit if (attr) {
477a977049dSHal Rosenstock read_lock_irqsave(&cm.device_lock, flags);
478a977049dSHal Rosenstock list_for_each_entry(cm_dev, &cm.device_list, list) {
47939839107SParav Pandit if (cm_dev->ib_device == attr->device) {
48039839107SParav Pandit port = cm_dev->port[attr->port_num - 1];
481a977049dSHal Rosenstock break;
482a977049dSHal Rosenstock }
483a977049dSHal Rosenstock }
484a977049dSHal Rosenstock read_unlock_irqrestore(&cm.device_lock, flags);
48539839107SParav Pandit } else {
48639839107SParav Pandit /* SGID attribute can be NULL in following
48739839107SParav Pandit * conditions.
48839839107SParav Pandit * (a) Alternative path
48939839107SParav Pandit * (b) IB link layer without GRH
49039839107SParav Pandit * (c) LAP send messages
49139839107SParav Pandit */
49239839107SParav Pandit read_lock_irqsave(&cm.device_lock, flags);
49339839107SParav Pandit list_for_each_entry(cm_dev, &cm.device_list, list) {
49439839107SParav Pandit attr = rdma_find_gid(cm_dev->ib_device,
49539839107SParav Pandit &path->sgid,
49639839107SParav Pandit sa_conv_pathrec_to_gid_type(path),
49739839107SParav Pandit NULL);
49839839107SParav Pandit if (!IS_ERR(attr)) {
49939839107SParav Pandit port = cm_dev->port[attr->port_num - 1];
50039839107SParav Pandit break;
50139839107SParav Pandit }
50239839107SParav Pandit }
50339839107SParav Pandit read_unlock_irqrestore(&cm.device_lock, flags);
50439839107SParav Pandit if (port)
50539839107SParav Pandit rdma_put_gid_attr(attr);
50639839107SParav Pandit }
507cb12a8e2SParav Pandit return port;
508cb12a8e2SParav Pandit }
509c2c6ff13SMatan Barak
cm_init_av_by_path(struct sa_path_rec * path,const struct ib_gid_attr * sgid_attr,struct cm_av * av)51039839107SParav Pandit static int cm_init_av_by_path(struct sa_path_rec *path,
51139839107SParav Pandit const struct ib_gid_attr *sgid_attr,
5123595c398SMark Zhang struct cm_av *av)
513cb12a8e2SParav Pandit {
514e822ff21SParav Pandit struct rdma_ah_attr new_ah_attr;
515cb12a8e2SParav Pandit struct cm_device *cm_dev;
516cb12a8e2SParav Pandit struct cm_port *port;
517cb12a8e2SParav Pandit int ret;
518cb12a8e2SParav Pandit
51939839107SParav Pandit port = get_cm_port_from_path(path, sgid_attr);
520a977049dSHal Rosenstock if (!port)
521a977049dSHal Rosenstock return -EINVAL;
522cb12a8e2SParav Pandit cm_dev = port->cm_dev;
523a977049dSHal Rosenstock
524d4c4196fSGreg Kroah-Hartman ret = ib_find_cached_pkey(cm_dev->ib_device, port->port_num,
525a977049dSHal Rosenstock be16_to_cpu(path->pkey), &av->pkey_index);
526a977049dSHal Rosenstock if (ret)
527a977049dSHal Rosenstock return ret;
528a977049dSHal Rosenstock
52976039ac9SMark Zhang cm_set_av_port(av, port);
530e822ff21SParav Pandit
531e822ff21SParav Pandit /*
532e822ff21SParav Pandit * av->ah_attr might be initialized based on wc or during
533aa74f487SParav Pandit * request processing time which might have reference to sgid_attr.
534aa74f487SParav Pandit * So initialize a new ah_attr on stack.
535e822ff21SParav Pandit * If initialization fails, old ah_attr is used for sending any
536e822ff21SParav Pandit * responses. If initialization is successful, than new ah_attr
537aa74f487SParav Pandit * is used by overwriting the old one. So that right ah_attr
538aa74f487SParav Pandit * can be used to return an error response.
539e822ff21SParav Pandit */
5404ad6a024SParav Pandit ret = ib_init_ah_attr_from_path(cm_dev->ib_device, port->port_num, path,
54139839107SParav Pandit &new_ah_attr, sgid_attr);
5425cf3968aSParav Pandit if (ret)
5435cf3968aSParav Pandit return ret;
5445cf3968aSParav Pandit
5451d846126SSean Hefty av->timeout = path->packet_life_time + 1;
546d97099feSJason Gunthorpe rdma_move_ah_attr(&av->ah_attr, &new_ah_attr);
547e822ff21SParav Pandit return 0;
548a977049dSHal Rosenstock }
549a977049dSHal Rosenstock
5507345201cSMark Zhang /* Move av created by cm_init_av_by_path(), so av.dgid is not moved */
cm_move_av_from_path(struct cm_av * dest,struct cm_av * src)5517345201cSMark Zhang static void cm_move_av_from_path(struct cm_av *dest, struct cm_av *src)
5527345201cSMark Zhang {
55376039ac9SMark Zhang cm_set_av_port(dest, src->port);
55476039ac9SMark Zhang cm_set_av_port(src, NULL);
5557345201cSMark Zhang dest->pkey_index = src->pkey_index;
5567345201cSMark Zhang rdma_move_ah_attr(&dest->ah_attr, &src->ah_attr);
5577345201cSMark Zhang dest->timeout = src->timeout;
5587345201cSMark Zhang }
5597345201cSMark Zhang
cm_destroy_av(struct cm_av * av)5607345201cSMark Zhang static void cm_destroy_av(struct cm_av *av)
5617345201cSMark Zhang {
5627345201cSMark Zhang rdma_destroy_ah_attr(&av->ah_attr);
56376039ac9SMark Zhang cm_set_av_port(av, NULL);
5647345201cSMark Zhang }
5657345201cSMark Zhang
cm_local_id(__be32 local_id)566ae78ff3aSMatthew Wilcox static u32 cm_local_id(__be32 local_id)
567ae78ff3aSMatthew Wilcox {
568ae78ff3aSMatthew Wilcox return (__force u32) (local_id ^ cm.random_id_operand);
569a977049dSHal Rosenstock }
570a977049dSHal Rosenstock
cm_acquire_id(__be32 local_id,__be32 remote_id)57197f52eb4SSean Hefty static struct cm_id_private *cm_acquire_id(__be32 local_id, __be32 remote_id)
572a977049dSHal Rosenstock {
573a977049dSHal Rosenstock struct cm_id_private *cm_id_priv;
574a977049dSHal Rosenstock
5754d6e8a03SDanit Goldberg rcu_read_lock();
5764d6e8a03SDanit Goldberg cm_id_priv = xa_load(&cm.local_id_table, cm_local_id(local_id));
5774d6e8a03SDanit Goldberg if (!cm_id_priv || cm_id_priv->id.remote_id != remote_id ||
5784d6e8a03SDanit Goldberg !refcount_inc_not_zero(&cm_id_priv->refcount))
5794d6e8a03SDanit Goldberg cm_id_priv = NULL;
5804d6e8a03SDanit Goldberg rcu_read_unlock();
581a977049dSHal Rosenstock
582a977049dSHal Rosenstock return cm_id_priv;
583a977049dSHal Rosenstock }
584a977049dSHal Rosenstock
585a88f4888SRoland Dreier /*
586a88f4888SRoland Dreier * Trivial helpers to strip endian annotation and compare; the
587a88f4888SRoland Dreier * endianness doesn't actually matter since we just need a stable
588a88f4888SRoland Dreier * order for the RB tree.
589a88f4888SRoland Dreier */
be32_lt(__be32 a,__be32 b)590a88f4888SRoland Dreier static int be32_lt(__be32 a, __be32 b)
591a88f4888SRoland Dreier {
592a88f4888SRoland Dreier return (__force u32) a < (__force u32) b;
593a88f4888SRoland Dreier }
594a88f4888SRoland Dreier
be32_gt(__be32 a,__be32 b)595a88f4888SRoland Dreier static int be32_gt(__be32 a, __be32 b)
596a88f4888SRoland Dreier {
597a88f4888SRoland Dreier return (__force u32) a > (__force u32) b;
598a88f4888SRoland Dreier }
599a88f4888SRoland Dreier
be64_lt(__be64 a,__be64 b)600a88f4888SRoland Dreier static int be64_lt(__be64 a, __be64 b)
601a88f4888SRoland Dreier {
602a88f4888SRoland Dreier return (__force u64) a < (__force u64) b;
603a88f4888SRoland Dreier }
604a88f4888SRoland Dreier
be64_gt(__be64 a,__be64 b)605a88f4888SRoland Dreier static int be64_gt(__be64 a, __be64 b)
606a88f4888SRoland Dreier {
607a88f4888SRoland Dreier return (__force u64) a > (__force u64) b;
608a88f4888SRoland Dreier }
609a88f4888SRoland Dreier
61098f67156SJason Gunthorpe /*
61198f67156SJason Gunthorpe * Inserts a new cm_id_priv into the listen_service_table. Returns cm_id_priv
61298f67156SJason Gunthorpe * if the new ID was inserted, NULL if it could not be inserted due to a
61398f67156SJason Gunthorpe * collision, or the existing cm_id_priv ready for shared usage.
61498f67156SJason Gunthorpe */
cm_insert_listen(struct cm_id_private * cm_id_priv,ib_cm_handler shared_handler)61598f67156SJason Gunthorpe static struct cm_id_private *cm_insert_listen(struct cm_id_private *cm_id_priv,
61698f67156SJason Gunthorpe ib_cm_handler shared_handler)
617a977049dSHal Rosenstock {
618a977049dSHal Rosenstock struct rb_node **link = &cm.listen_service_table.rb_node;
619a977049dSHal Rosenstock struct rb_node *parent = NULL;
620a977049dSHal Rosenstock struct cm_id_private *cur_cm_id_priv;
62197f52eb4SSean Hefty __be64 service_id = cm_id_priv->id.service_id;
62298f67156SJason Gunthorpe unsigned long flags;
623a977049dSHal Rosenstock
62498f67156SJason Gunthorpe spin_lock_irqsave(&cm.lock, flags);
625a977049dSHal Rosenstock while (*link) {
626a977049dSHal Rosenstock parent = *link;
627a977049dSHal Rosenstock cur_cm_id_priv = rb_entry(parent, struct cm_id_private,
628a977049dSHal Rosenstock service_node);
629637ff8eaSMark Zhang
630637ff8eaSMark Zhang if (cm_id_priv->id.device < cur_cm_id_priv->id.device)
631637ff8eaSMark Zhang link = &(*link)->rb_left;
632637ff8eaSMark Zhang else if (cm_id_priv->id.device > cur_cm_id_priv->id.device)
633637ff8eaSMark Zhang link = &(*link)->rb_right;
634637ff8eaSMark Zhang else if (be64_lt(service_id, cur_cm_id_priv->id.service_id))
635637ff8eaSMark Zhang link = &(*link)->rb_left;
636637ff8eaSMark Zhang else if (be64_gt(service_id, cur_cm_id_priv->id.service_id))
637637ff8eaSMark Zhang link = &(*link)->rb_right;
638637ff8eaSMark Zhang else {
63998f67156SJason Gunthorpe /*
64098f67156SJason Gunthorpe * Sharing an ib_cm_id with different handlers is not
64198f67156SJason Gunthorpe * supported
64298f67156SJason Gunthorpe */
64398f67156SJason Gunthorpe if (cur_cm_id_priv->id.cm_handler != shared_handler ||
64498f67156SJason Gunthorpe cur_cm_id_priv->id.context ||
64598f67156SJason Gunthorpe WARN_ON(!cur_cm_id_priv->id.cm_handler)) {
64698f67156SJason Gunthorpe spin_unlock_irqrestore(&cm.lock, flags);
64798f67156SJason Gunthorpe return NULL;
64898f67156SJason Gunthorpe }
64998f67156SJason Gunthorpe refcount_inc(&cur_cm_id_priv->refcount);
65098f67156SJason Gunthorpe cur_cm_id_priv->listen_sharecount++;
65198f67156SJason Gunthorpe spin_unlock_irqrestore(&cm.lock, flags);
65207d357d0SSean Hefty return cur_cm_id_priv;
65398f67156SJason Gunthorpe }
654a977049dSHal Rosenstock }
65598f67156SJason Gunthorpe cm_id_priv->listen_sharecount++;
656a977049dSHal Rosenstock rb_link_node(&cm_id_priv->service_node, parent, link);
657a977049dSHal Rosenstock rb_insert_color(&cm_id_priv->service_node, &cm.listen_service_table);
65898f67156SJason Gunthorpe spin_unlock_irqrestore(&cm.lock, flags);
65998f67156SJason Gunthorpe return cm_id_priv;
660a977049dSHal Rosenstock }
661a977049dSHal Rosenstock
cm_find_listen(struct ib_device * device,__be64 service_id)66207d357d0SSean Hefty static struct cm_id_private *cm_find_listen(struct ib_device *device,
66373fec7fdSHaggai Eran __be64 service_id)
664a977049dSHal Rosenstock {
665a977049dSHal Rosenstock struct rb_node *node = cm.listen_service_table.rb_node;
666a977049dSHal Rosenstock struct cm_id_private *cm_id_priv;
667a977049dSHal Rosenstock
668a977049dSHal Rosenstock while (node) {
669a977049dSHal Rosenstock cm_id_priv = rb_entry(node, struct cm_id_private, service_node);
670637ff8eaSMark Zhang
67107d357d0SSean Hefty if (device < cm_id_priv->id.device)
67207d357d0SSean Hefty node = node->rb_left;
67307d357d0SSean Hefty else if (device > cm_id_priv->id.device)
67407d357d0SSean Hefty node = node->rb_right;
675a88f4888SRoland Dreier else if (be64_lt(service_id, cm_id_priv->id.service_id))
676a977049dSHal Rosenstock node = node->rb_left;
677a88f4888SRoland Dreier else if (be64_gt(service_id, cm_id_priv->id.service_id))
6786e61d04fSSean Hefty node = node->rb_right;
679637ff8eaSMark Zhang else {
680637ff8eaSMark Zhang refcount_inc(&cm_id_priv->refcount);
681637ff8eaSMark Zhang return cm_id_priv;
682637ff8eaSMark Zhang }
683a977049dSHal Rosenstock }
684a977049dSHal Rosenstock return NULL;
685a977049dSHal Rosenstock }
686a977049dSHal Rosenstock
687f681967aSWenpeng Liang static struct cm_timewait_info *
cm_insert_remote_id(struct cm_timewait_info * timewait_info)688f681967aSWenpeng Liang cm_insert_remote_id(struct cm_timewait_info *timewait_info)
689a977049dSHal Rosenstock {
690a977049dSHal Rosenstock struct rb_node **link = &cm.remote_id_table.rb_node;
691a977049dSHal Rosenstock struct rb_node *parent = NULL;
692a977049dSHal Rosenstock struct cm_timewait_info *cur_timewait_info;
69397f52eb4SSean Hefty __be64 remote_ca_guid = timewait_info->remote_ca_guid;
69497f52eb4SSean Hefty __be32 remote_id = timewait_info->work.remote_id;
695a977049dSHal Rosenstock
696a977049dSHal Rosenstock while (*link) {
697a977049dSHal Rosenstock parent = *link;
698a977049dSHal Rosenstock cur_timewait_info = rb_entry(parent, struct cm_timewait_info,
699a977049dSHal Rosenstock remote_id_node);
700a88f4888SRoland Dreier if (be32_lt(remote_id, cur_timewait_info->work.remote_id))
701a977049dSHal Rosenstock link = &(*link)->rb_left;
702a88f4888SRoland Dreier else if (be32_gt(remote_id, cur_timewait_info->work.remote_id))
703a977049dSHal Rosenstock link = &(*link)->rb_right;
704a88f4888SRoland Dreier else if (be64_lt(remote_ca_guid, cur_timewait_info->remote_ca_guid))
705a977049dSHal Rosenstock link = &(*link)->rb_left;
706a88f4888SRoland Dreier else if (be64_gt(remote_ca_guid, cur_timewait_info->remote_ca_guid))
707a977049dSHal Rosenstock link = &(*link)->rb_right;
708a977049dSHal Rosenstock else
709a977049dSHal Rosenstock return cur_timewait_info;
710a977049dSHal Rosenstock }
711a977049dSHal Rosenstock timewait_info->inserted_remote_id = 1;
712a977049dSHal Rosenstock rb_link_node(&timewait_info->remote_id_node, parent, link);
713a977049dSHal Rosenstock rb_insert_color(&timewait_info->remote_id_node, &cm.remote_id_table);
714a977049dSHal Rosenstock return NULL;
715a977049dSHal Rosenstock }
716a977049dSHal Rosenstock
cm_find_remote_id(__be64 remote_ca_guid,__be32 remote_id)717cfa68b0dSJason Gunthorpe static struct cm_id_private *cm_find_remote_id(__be64 remote_ca_guid,
71897f52eb4SSean Hefty __be32 remote_id)
719a977049dSHal Rosenstock {
720a977049dSHal Rosenstock struct rb_node *node = cm.remote_id_table.rb_node;
721a977049dSHal Rosenstock struct cm_timewait_info *timewait_info;
722cfa68b0dSJason Gunthorpe struct cm_id_private *res = NULL;
723a977049dSHal Rosenstock
724cfa68b0dSJason Gunthorpe spin_lock_irq(&cm.lock);
725a977049dSHal Rosenstock while (node) {
726a977049dSHal Rosenstock timewait_info = rb_entry(node, struct cm_timewait_info,
727a977049dSHal Rosenstock remote_id_node);
728a88f4888SRoland Dreier if (be32_lt(remote_id, timewait_info->work.remote_id))
729a977049dSHal Rosenstock node = node->rb_left;
730a88f4888SRoland Dreier else if (be32_gt(remote_id, timewait_info->work.remote_id))
731a977049dSHal Rosenstock node = node->rb_right;
732a88f4888SRoland Dreier else if (be64_lt(remote_ca_guid, timewait_info->remote_ca_guid))
733a977049dSHal Rosenstock node = node->rb_left;
734a88f4888SRoland Dreier else if (be64_gt(remote_ca_guid, timewait_info->remote_ca_guid))
735a977049dSHal Rosenstock node = node->rb_right;
736cfa68b0dSJason Gunthorpe else {
737cfa68b0dSJason Gunthorpe res = cm_acquire_id(timewait_info->work.local_id,
738cfa68b0dSJason Gunthorpe timewait_info->work.remote_id);
739cfa68b0dSJason Gunthorpe break;
740a977049dSHal Rosenstock }
741cfa68b0dSJason Gunthorpe }
742cfa68b0dSJason Gunthorpe spin_unlock_irq(&cm.lock);
743cfa68b0dSJason Gunthorpe return res;
744a977049dSHal Rosenstock }
745a977049dSHal Rosenstock
746f681967aSWenpeng Liang static struct cm_timewait_info *
cm_insert_remote_qpn(struct cm_timewait_info * timewait_info)747f681967aSWenpeng Liang cm_insert_remote_qpn(struct cm_timewait_info *timewait_info)
748a977049dSHal Rosenstock {
749a977049dSHal Rosenstock struct rb_node **link = &cm.remote_qp_table.rb_node;
750a977049dSHal Rosenstock struct rb_node *parent = NULL;
751a977049dSHal Rosenstock struct cm_timewait_info *cur_timewait_info;
75297f52eb4SSean Hefty __be64 remote_ca_guid = timewait_info->remote_ca_guid;
75397f52eb4SSean Hefty __be32 remote_qpn = timewait_info->remote_qpn;
754a977049dSHal Rosenstock
755a977049dSHal Rosenstock while (*link) {
756a977049dSHal Rosenstock parent = *link;
757a977049dSHal Rosenstock cur_timewait_info = rb_entry(parent, struct cm_timewait_info,
758a977049dSHal Rosenstock remote_qp_node);
759a88f4888SRoland Dreier if (be32_lt(remote_qpn, cur_timewait_info->remote_qpn))
760a977049dSHal Rosenstock link = &(*link)->rb_left;
761a88f4888SRoland Dreier else if (be32_gt(remote_qpn, cur_timewait_info->remote_qpn))
762a977049dSHal Rosenstock link = &(*link)->rb_right;
763a88f4888SRoland Dreier else if (be64_lt(remote_ca_guid, cur_timewait_info->remote_ca_guid))
764a977049dSHal Rosenstock link = &(*link)->rb_left;
765a88f4888SRoland Dreier else if (be64_gt(remote_ca_guid, cur_timewait_info->remote_ca_guid))
766a977049dSHal Rosenstock link = &(*link)->rb_right;
767a977049dSHal Rosenstock else
768a977049dSHal Rosenstock return cur_timewait_info;
769a977049dSHal Rosenstock }
770a977049dSHal Rosenstock timewait_info->inserted_remote_qp = 1;
771a977049dSHal Rosenstock rb_link_node(&timewait_info->remote_qp_node, parent, link);
772a977049dSHal Rosenstock rb_insert_color(&timewait_info->remote_qp_node, &cm.remote_qp_table);
773a977049dSHal Rosenstock return NULL;
774a977049dSHal Rosenstock }
775a977049dSHal Rosenstock
776f681967aSWenpeng Liang static struct cm_id_private *
cm_insert_remote_sidr(struct cm_id_private * cm_id_priv)777f681967aSWenpeng Liang cm_insert_remote_sidr(struct cm_id_private *cm_id_priv)
778a977049dSHal Rosenstock {
779a977049dSHal Rosenstock struct rb_node **link = &cm.remote_sidr_table.rb_node;
780a977049dSHal Rosenstock struct rb_node *parent = NULL;
781a977049dSHal Rosenstock struct cm_id_private *cur_cm_id_priv;
78297f52eb4SSean Hefty __be32 remote_id = cm_id_priv->id.remote_id;
783a977049dSHal Rosenstock
784a977049dSHal Rosenstock while (*link) {
785a977049dSHal Rosenstock parent = *link;
786a977049dSHal Rosenstock cur_cm_id_priv = rb_entry(parent, struct cm_id_private,
787a977049dSHal Rosenstock sidr_id_node);
788a88f4888SRoland Dreier if (be32_lt(remote_id, cur_cm_id_priv->id.remote_id))
789a977049dSHal Rosenstock link = &(*link)->rb_left;
790a88f4888SRoland Dreier else if (be32_gt(remote_id, cur_cm_id_priv->id.remote_id))
791a977049dSHal Rosenstock link = &(*link)->rb_right;
792a977049dSHal Rosenstock else {
793bf0480a2SJason Gunthorpe if (cur_cm_id_priv->sidr_slid < cm_id_priv->sidr_slid)
794a977049dSHal Rosenstock link = &(*link)->rb_left;
795bf0480a2SJason Gunthorpe else if (cur_cm_id_priv->sidr_slid > cm_id_priv->sidr_slid)
796a977049dSHal Rosenstock link = &(*link)->rb_right;
797a977049dSHal Rosenstock else
798a977049dSHal Rosenstock return cur_cm_id_priv;
799a977049dSHal Rosenstock }
800a977049dSHal Rosenstock }
801a977049dSHal Rosenstock rb_link_node(&cm_id_priv->sidr_id_node, parent, link);
802a977049dSHal Rosenstock rb_insert_color(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table);
803a977049dSHal Rosenstock return NULL;
804a977049dSHal Rosenstock }
805a977049dSHal Rosenstock
cm_alloc_id_priv(struct ib_device * device,ib_cm_handler cm_handler,void * context)80698f67156SJason Gunthorpe static struct cm_id_private *cm_alloc_id_priv(struct ib_device *device,
80707d357d0SSean Hefty ib_cm_handler cm_handler,
808a977049dSHal Rosenstock void *context)
809a977049dSHal Rosenstock {
810a977049dSHal Rosenstock struct cm_id_private *cm_id_priv;
811e8dc4e88SJason Gunthorpe u32 id;
812a977049dSHal Rosenstock int ret;
813a977049dSHal Rosenstock
814de6eb66bSRoland Dreier cm_id_priv = kzalloc(sizeof *cm_id_priv, GFP_KERNEL);
815a977049dSHal Rosenstock if (!cm_id_priv)
816a977049dSHal Rosenstock return ERR_PTR(-ENOMEM);
817a977049dSHal Rosenstock
818a977049dSHal Rosenstock cm_id_priv->id.state = IB_CM_IDLE;
81907d357d0SSean Hefty cm_id_priv->id.device = device;
820a977049dSHal Rosenstock cm_id_priv->id.cm_handler = cm_handler;
821a977049dSHal Rosenstock cm_id_priv->id.context = context;
822354ba39cSJohn Kingman cm_id_priv->id.remote_cm_qpn = 1;
823a977049dSHal Rosenstock
8242305d686SJason Gunthorpe RB_CLEAR_NODE(&cm_id_priv->service_node);
8252305d686SJason Gunthorpe RB_CLEAR_NODE(&cm_id_priv->sidr_id_node);
826a977049dSHal Rosenstock spin_lock_init(&cm_id_priv->lock);
8271b52fa98SSean Hefty init_completion(&cm_id_priv->comp);
828a977049dSHal Rosenstock INIT_LIST_HEAD(&cm_id_priv->work_list);
829a977049dSHal Rosenstock atomic_set(&cm_id_priv->work_count, -1);
8300acc637dSDanit Goldberg refcount_set(&cm_id_priv->refcount, 1);
831e8dc4e88SJason Gunthorpe
832eb73060bSJason Gunthorpe ret = xa_alloc_cyclic(&cm.local_id_table, &id, NULL, xa_limit_32b,
833e8dc4e88SJason Gunthorpe &cm.local_id_next, GFP_KERNEL);
83498365351SDan Carpenter if (ret < 0)
835e8dc4e88SJason Gunthorpe goto error;
836e8dc4e88SJason Gunthorpe cm_id_priv->id.local_id = (__force __be32)id ^ cm.random_id_operand;
837e8dc4e88SJason Gunthorpe
83898f67156SJason Gunthorpe return cm_id_priv;
839a977049dSHal Rosenstock
840a977049dSHal Rosenstock error:
841a977049dSHal Rosenstock kfree(cm_id_priv);
842e8dc4e88SJason Gunthorpe return ERR_PTR(ret);
843a977049dSHal Rosenstock }
84498f67156SJason Gunthorpe
84598f67156SJason Gunthorpe /*
84698f67156SJason Gunthorpe * Make the ID visible to the MAD handlers and other threads that use the
84798f67156SJason Gunthorpe * xarray.
84898f67156SJason Gunthorpe */
cm_finalize_id(struct cm_id_private * cm_id_priv)84998f67156SJason Gunthorpe static void cm_finalize_id(struct cm_id_private *cm_id_priv)
85098f67156SJason Gunthorpe {
851eb73060bSJason Gunthorpe xa_store(&cm.local_id_table, cm_local_id(cm_id_priv->id.local_id),
852eb73060bSJason Gunthorpe cm_id_priv, GFP_ATOMIC);
85398f67156SJason Gunthorpe }
85498f67156SJason Gunthorpe
ib_create_cm_id(struct ib_device * device,ib_cm_handler cm_handler,void * context)85598f67156SJason Gunthorpe struct ib_cm_id *ib_create_cm_id(struct ib_device *device,
85698f67156SJason Gunthorpe ib_cm_handler cm_handler,
85798f67156SJason Gunthorpe void *context)
85898f67156SJason Gunthorpe {
85998f67156SJason Gunthorpe struct cm_id_private *cm_id_priv;
86098f67156SJason Gunthorpe
86198f67156SJason Gunthorpe cm_id_priv = cm_alloc_id_priv(device, cm_handler, context);
86298f67156SJason Gunthorpe if (IS_ERR(cm_id_priv))
86398f67156SJason Gunthorpe return ERR_CAST(cm_id_priv);
86498f67156SJason Gunthorpe
86598f67156SJason Gunthorpe cm_finalize_id(cm_id_priv);
86698f67156SJason Gunthorpe return &cm_id_priv->id;
86798f67156SJason Gunthorpe }
868a977049dSHal Rosenstock EXPORT_SYMBOL(ib_create_cm_id);
869a977049dSHal Rosenstock
cm_dequeue_work(struct cm_id_private * cm_id_priv)870a977049dSHal Rosenstock static struct cm_work *cm_dequeue_work(struct cm_id_private *cm_id_priv)
871a977049dSHal Rosenstock {
872a977049dSHal Rosenstock struct cm_work *work;
873a977049dSHal Rosenstock
874a977049dSHal Rosenstock if (list_empty(&cm_id_priv->work_list))
875a977049dSHal Rosenstock return NULL;
876a977049dSHal Rosenstock
877a977049dSHal Rosenstock work = list_entry(cm_id_priv->work_list.next, struct cm_work, list);
878a977049dSHal Rosenstock list_del(&work->list);
879a977049dSHal Rosenstock return work;
880a977049dSHal Rosenstock }
881a977049dSHal Rosenstock
cm_free_work(struct cm_work * work)882a977049dSHal Rosenstock static void cm_free_work(struct cm_work *work)
883a977049dSHal Rosenstock {
884a977049dSHal Rosenstock if (work->mad_recv_wc)
885a977049dSHal Rosenstock ib_free_recv_mad(work->mad_recv_wc);
886a977049dSHal Rosenstock kfree(work);
887a977049dSHal Rosenstock }
888a977049dSHal Rosenstock
cm_queue_work_unlock(struct cm_id_private * cm_id_priv,struct cm_work * work)889e83f195aSJason Gunthorpe static void cm_queue_work_unlock(struct cm_id_private *cm_id_priv,
890e83f195aSJason Gunthorpe struct cm_work *work)
8911ea7c546SLeon Romanovsky __releases(&cm_id_priv->lock)
892e83f195aSJason Gunthorpe {
893e83f195aSJason Gunthorpe bool immediate;
894e83f195aSJason Gunthorpe
895e83f195aSJason Gunthorpe /*
896e83f195aSJason Gunthorpe * To deliver the event to the user callback we have the drop the
897e83f195aSJason Gunthorpe * spinlock, however, we need to ensure that the user callback is single
898e83f195aSJason Gunthorpe * threaded and receives events in the temporal order. If there are
899e83f195aSJason Gunthorpe * already events being processed then thread new events onto a list,
900e83f195aSJason Gunthorpe * the thread currently processing will pick them up.
901e83f195aSJason Gunthorpe */
902e83f195aSJason Gunthorpe immediate = atomic_inc_and_test(&cm_id_priv->work_count);
903e83f195aSJason Gunthorpe if (!immediate) {
904e83f195aSJason Gunthorpe list_add_tail(&work->list, &cm_id_priv->work_list);
905e83f195aSJason Gunthorpe /*
906e83f195aSJason Gunthorpe * This routine always consumes incoming reference. Once queued
907e83f195aSJason Gunthorpe * to the work_list then a reference is held by the thread
908e83f195aSJason Gunthorpe * currently running cm_process_work() and this reference is not
909e83f195aSJason Gunthorpe * needed.
910e83f195aSJason Gunthorpe */
911e83f195aSJason Gunthorpe cm_deref_id(cm_id_priv);
912e83f195aSJason Gunthorpe }
913e83f195aSJason Gunthorpe spin_unlock_irq(&cm_id_priv->lock);
914e83f195aSJason Gunthorpe
915e83f195aSJason Gunthorpe if (immediate)
916e83f195aSJason Gunthorpe cm_process_work(cm_id_priv, work);
917e83f195aSJason Gunthorpe }
918e83f195aSJason Gunthorpe
cm_convert_to_ms(int iba_time)919a977049dSHal Rosenstock static inline int cm_convert_to_ms(int iba_time)
920a977049dSHal Rosenstock {
921a977049dSHal Rosenstock /* approximate conversion to ms from 4.096us x 2^iba_time */
922a977049dSHal Rosenstock return 1 << max(iba_time - 8, 0);
923a977049dSHal Rosenstock }
924a977049dSHal Rosenstock
9251d846126SSean Hefty /*
9261d846126SSean Hefty * calculate: 4.096x2^ack_timeout = 4.096x2^ack_delay + 2x4.096x2^life_time
9271d846126SSean Hefty * Because of how ack_timeout is stored, adding one doubles the timeout.
9281d846126SSean Hefty * To avoid large timeouts, select the max(ack_delay, life_time + 1), and
9291d846126SSean Hefty * increment it (round up) only if the other is within 50%.
9301d846126SSean Hefty */
cm_ack_timeout(u8 ca_ack_delay,u8 packet_life_time)9311d846126SSean Hefty static u8 cm_ack_timeout(u8 ca_ack_delay, u8 packet_life_time)
9321d846126SSean Hefty {
9331d846126SSean Hefty int ack_timeout = packet_life_time + 1;
9341d846126SSean Hefty
9351d846126SSean Hefty if (ack_timeout >= ca_ack_delay)
9361d846126SSean Hefty ack_timeout += (ca_ack_delay >= (ack_timeout - 1));
9371d846126SSean Hefty else
9381d846126SSean Hefty ack_timeout = ca_ack_delay +
9391d846126SSean Hefty (ack_timeout >= (ca_ack_delay - 1));
9401d846126SSean Hefty
9411d846126SSean Hefty return min(31, ack_timeout);
9421d846126SSean Hefty }
9431d846126SSean Hefty
cm_remove_remote(struct cm_id_private * cm_id_priv)9449767a27eSJason Gunthorpe static void cm_remove_remote(struct cm_id_private *cm_id_priv)
945a977049dSHal Rosenstock {
9469767a27eSJason Gunthorpe struct cm_timewait_info *timewait_info = cm_id_priv->timewait_info;
9479767a27eSJason Gunthorpe
948a977049dSHal Rosenstock if (timewait_info->inserted_remote_id) {
949a977049dSHal Rosenstock rb_erase(&timewait_info->remote_id_node, &cm.remote_id_table);
950a977049dSHal Rosenstock timewait_info->inserted_remote_id = 0;
951a977049dSHal Rosenstock }
952a977049dSHal Rosenstock
953a977049dSHal Rosenstock if (timewait_info->inserted_remote_qp) {
954a977049dSHal Rosenstock rb_erase(&timewait_info->remote_qp_node, &cm.remote_qp_table);
955a977049dSHal Rosenstock timewait_info->inserted_remote_qp = 0;
956a977049dSHal Rosenstock }
957a977049dSHal Rosenstock }
958a977049dSHal Rosenstock
cm_create_timewait_info(__be32 local_id)95997f52eb4SSean Hefty static struct cm_timewait_info *cm_create_timewait_info(__be32 local_id)
960a977049dSHal Rosenstock {
961a977049dSHal Rosenstock struct cm_timewait_info *timewait_info;
962a977049dSHal Rosenstock
963de6eb66bSRoland Dreier timewait_info = kzalloc(sizeof *timewait_info, GFP_KERNEL);
964a977049dSHal Rosenstock if (!timewait_info)
965a977049dSHal Rosenstock return ERR_PTR(-ENOMEM);
966a977049dSHal Rosenstock
967a977049dSHal Rosenstock timewait_info->work.local_id = local_id;
968c4028958SDavid Howells INIT_DELAYED_WORK(&timewait_info->work.work, cm_work_handler);
969a977049dSHal Rosenstock timewait_info->work.cm_event.event = IB_CM_TIMEWAIT_EXIT;
970a977049dSHal Rosenstock return timewait_info;
971a977049dSHal Rosenstock }
972a977049dSHal Rosenstock
cm_enter_timewait(struct cm_id_private * cm_id_priv)973a977049dSHal Rosenstock static void cm_enter_timewait(struct cm_id_private *cm_id_priv)
974a977049dSHal Rosenstock {
975a977049dSHal Rosenstock int wait_time;
9768575329dSSean Hefty unsigned long flags;
977be4b4993SErez Shitrit struct cm_device *cm_dev;
978be4b4993SErez Shitrit
97900777a68SJason Gunthorpe lockdep_assert_held(&cm_id_priv->lock);
98000777a68SJason Gunthorpe
981be4b4993SErez Shitrit cm_dev = ib_get_client_data(cm_id_priv->id.device, &cm_client);
982be4b4993SErez Shitrit if (!cm_dev)
983be4b4993SErez Shitrit return;
984a977049dSHal Rosenstock
9858575329dSSean Hefty spin_lock_irqsave(&cm.lock, flags);
9869767a27eSJason Gunthorpe cm_remove_remote(cm_id_priv);
9878575329dSSean Hefty list_add_tail(&cm_id_priv->timewait_info->list, &cm.timewait_list);
9888575329dSSean Hefty spin_unlock_irqrestore(&cm.lock, flags);
989a70d0590SMichael S. Tsirkin
990a977049dSHal Rosenstock /*
991a977049dSHal Rosenstock * The cm_id could be destroyed by the user before we exit timewait.
992a977049dSHal Rosenstock * To protect against this, we search for the cm_id after exiting
993a977049dSHal Rosenstock * timewait before notifying the user that we've exited timewait.
994a977049dSHal Rosenstock */
995a977049dSHal Rosenstock cm_id_priv->id.state = IB_CM_TIMEWAIT;
9961d846126SSean Hefty wait_time = cm_convert_to_ms(cm_id_priv->av.timeout);
997be4b4993SErez Shitrit
998be4b4993SErez Shitrit /* Check if the device started its remove_one */
9994bfdf635SBart Van Assche spin_lock_irqsave(&cm.lock, flags);
1000be4b4993SErez Shitrit if (!cm_dev->going_down)
1001a977049dSHal Rosenstock queue_delayed_work(cm.wq, &cm_id_priv->timewait_info->work.work,
1002a977049dSHal Rosenstock msecs_to_jiffies(wait_time));
10034bfdf635SBart Van Assche spin_unlock_irqrestore(&cm.lock, flags);
1004be4b4993SErez Shitrit
100509fb406aSJason Gunthorpe /*
100609fb406aSJason Gunthorpe * The timewait_info is converted into a work and gets freed during
100709fb406aSJason Gunthorpe * cm_free_work() in cm_timewait_handler().
100809fb406aSJason Gunthorpe */
100909fb406aSJason Gunthorpe BUILD_BUG_ON(offsetof(struct cm_timewait_info, work) != 0);
1010a977049dSHal Rosenstock cm_id_priv->timewait_info = NULL;
1011a977049dSHal Rosenstock }
1012a977049dSHal Rosenstock
cm_reset_to_idle(struct cm_id_private * cm_id_priv)1013a977049dSHal Rosenstock static void cm_reset_to_idle(struct cm_id_private *cm_id_priv)
1014a977049dSHal Rosenstock {
10158575329dSSean Hefty unsigned long flags;
10168575329dSSean Hefty
101700777a68SJason Gunthorpe lockdep_assert_held(&cm_id_priv->lock);
101800777a68SJason Gunthorpe
1019a977049dSHal Rosenstock cm_id_priv->id.state = IB_CM_IDLE;
1020a977049dSHal Rosenstock if (cm_id_priv->timewait_info) {
10218575329dSSean Hefty spin_lock_irqsave(&cm.lock, flags);
10229767a27eSJason Gunthorpe cm_remove_remote(cm_id_priv);
10238575329dSSean Hefty spin_unlock_irqrestore(&cm.lock, flags);
1024a977049dSHal Rosenstock kfree(cm_id_priv->timewait_info);
1025a977049dSHal Rosenstock cm_id_priv->timewait_info = NULL;
1026a977049dSHal Rosenstock }
1027a977049dSHal Rosenstock }
1028a977049dSHal Rosenstock
cm_destroy_id_wait_timeout(struct ib_cm_id * cm_id,enum ib_cm_state old_state)1029*b4285282SMark Zhang static noinline void cm_destroy_id_wait_timeout(struct ib_cm_id *cm_id,
1030*b4285282SMark Zhang enum ib_cm_state old_state)
10312e90774fSManjunath Patil {
10322e90774fSManjunath Patil struct cm_id_private *cm_id_priv;
10332e90774fSManjunath Patil
10342e90774fSManjunath Patil cm_id_priv = container_of(cm_id, struct cm_id_private, id);
1035*b4285282SMark Zhang pr_err("%s: cm_id=%p timed out. state %d -> %d, refcnt=%d\n", __func__,
1036*b4285282SMark Zhang cm_id, old_state, cm_id->state, refcount_read(&cm_id_priv->refcount));
10372e90774fSManjunath Patil }
10382e90774fSManjunath Patil
cm_destroy_id(struct ib_cm_id * cm_id,int err)103904c33543SMichael S. Tsirkin static void cm_destroy_id(struct ib_cm_id *cm_id, int err)
1040a977049dSHal Rosenstock {
1041a977049dSHal Rosenstock struct cm_id_private *cm_id_priv;
1042*b4285282SMark Zhang enum ib_cm_state old_state;
1043a977049dSHal Rosenstock struct cm_work *work;
10442e90774fSManjunath Patil int ret;
1045a977049dSHal Rosenstock
1046a977049dSHal Rosenstock cm_id_priv = container_of(cm_id, struct cm_id_private, id);
104724be6e81SSean Hefty spin_lock_irq(&cm_id_priv->lock);
1048*b4285282SMark Zhang old_state = cm_id->state;
104967b3c8dcSJason Gunthorpe retest:
1050a977049dSHal Rosenstock switch (cm_id->state) {
1051a977049dSHal Rosenstock case IB_CM_LISTEN:
105267b3c8dcSJason Gunthorpe spin_lock(&cm.lock);
1053067b171bSHaggai Eran if (--cm_id_priv->listen_sharecount > 0) {
1054067b171bSHaggai Eran /* The id is still shared. */
10552305d686SJason Gunthorpe WARN_ON(refcount_read(&cm_id_priv->refcount) == 1);
105667b3c8dcSJason Gunthorpe spin_unlock(&cm.lock);
105767b3c8dcSJason Gunthorpe spin_unlock_irq(&cm_id_priv->lock);
1058067b171bSHaggai Eran cm_deref_id(cm_id_priv);
1059067b171bSHaggai Eran return;
1060067b171bSHaggai Eran }
106167b3c8dcSJason Gunthorpe cm_id->state = IB_CM_IDLE;
1062a977049dSHal Rosenstock rb_erase(&cm_id_priv->service_node, &cm.listen_service_table);
10632305d686SJason Gunthorpe RB_CLEAR_NODE(&cm_id_priv->service_node);
106467b3c8dcSJason Gunthorpe spin_unlock(&cm.lock);
1065a977049dSHal Rosenstock break;
1066a977049dSHal Rosenstock case IB_CM_SIDR_REQ_SENT:
1067a977049dSHal Rosenstock cm_id->state = IB_CM_IDLE;
106870076a41SMark Zhang ib_cancel_mad(cm_id_priv->msg);
1069a977049dSHal Rosenstock break;
1070a977049dSHal Rosenstock case IB_CM_SIDR_REQ_RCVD:
10716a8824a7SJason Gunthorpe cm_send_sidr_rep_locked(cm_id_priv,
10726a8824a7SJason Gunthorpe &(struct ib_cm_sidr_rep_param){
10736a8824a7SJason Gunthorpe .status = IB_SIDR_REJECT });
107467b3c8dcSJason Gunthorpe /* cm_send_sidr_rep_locked will not move to IDLE if it fails */
107567b3c8dcSJason Gunthorpe cm_id->state = IB_CM_IDLE;
1076a977049dSHal Rosenstock break;
1077a977049dSHal Rosenstock case IB_CM_REQ_SENT:
1078c29ed5a4STed Kim case IB_CM_MRA_REQ_RCVD:
107970076a41SMark Zhang ib_cancel_mad(cm_id_priv->msg);
108081ddb41fSJason Gunthorpe cm_send_rej_locked(cm_id_priv, IB_CM_REJ_TIMEOUT,
1081e971b8cdSSean Hefty &cm_id_priv->id.device->node_guid,
108281ddb41fSJason Gunthorpe sizeof(cm_id_priv->id.device->node_guid),
1083227eca83SSean Hefty NULL, 0);
1084227eca83SSean Hefty break;
108504c33543SMichael S. Tsirkin case IB_CM_REQ_RCVD:
108604c33543SMichael S. Tsirkin if (err == -ENOMEM) {
108704c33543SMichael S. Tsirkin /* Do not reject to allow future retries. */
108804c33543SMichael S. Tsirkin cm_reset_to_idle(cm_id_priv);
108904c33543SMichael S. Tsirkin } else {
109081ddb41fSJason Gunthorpe cm_send_rej_locked(cm_id_priv,
109181ddb41fSJason Gunthorpe IB_CM_REJ_CONSUMER_DEFINED, NULL, 0,
109281ddb41fSJason Gunthorpe NULL, 0);
109304c33543SMichael S. Tsirkin }
109404c33543SMichael S. Tsirkin break;
1095a977049dSHal Rosenstock case IB_CM_REP_SENT:
1096a977049dSHal Rosenstock case IB_CM_MRA_REP_RCVD:
109770076a41SMark Zhang ib_cancel_mad(cm_id_priv->msg);
1098fba97dc7SKa-Cheong Poon cm_send_rej_locked(cm_id_priv, IB_CM_REJ_CONSUMER_DEFINED, NULL,
1099fba97dc7SKa-Cheong Poon 0, NULL, 0);
1100fba97dc7SKa-Cheong Poon goto retest;
1101a977049dSHal Rosenstock case IB_CM_MRA_REQ_SENT:
1102a977049dSHal Rosenstock case IB_CM_REP_RCVD:
1103a977049dSHal Rosenstock case IB_CM_MRA_REP_SENT:
110481ddb41fSJason Gunthorpe cm_send_rej_locked(cm_id_priv, IB_CM_REJ_CONSUMER_DEFINED, NULL,
110581ddb41fSJason Gunthorpe 0, NULL, 0);
1106a977049dSHal Rosenstock break;
1107a977049dSHal Rosenstock case IB_CM_ESTABLISHED:
1108e029fdc0SJason Gunthorpe if (cm_id_priv->qp_type == IB_QPT_XRC_TGT) {
110967b3c8dcSJason Gunthorpe cm_id->state = IB_CM_IDLE;
11102622e18eSSean Hefty break;
1111e029fdc0SJason Gunthorpe }
1112e029fdc0SJason Gunthorpe cm_send_dreq_locked(cm_id_priv, NULL, 0);
1113a977049dSHal Rosenstock goto retest;
1114a977049dSHal Rosenstock case IB_CM_DREQ_SENT:
111570076a41SMark Zhang ib_cancel_mad(cm_id_priv->msg);
1116a977049dSHal Rosenstock cm_enter_timewait(cm_id_priv);
111767b3c8dcSJason Gunthorpe goto retest;
1118a977049dSHal Rosenstock case IB_CM_DREQ_RCVD:
111987cabf3eSJason Gunthorpe cm_send_drep_locked(cm_id_priv, NULL, 0);
112067b3c8dcSJason Gunthorpe WARN_ON(cm_id->state != IB_CM_TIMEWAIT);
112167b3c8dcSJason Gunthorpe goto retest;
112267b3c8dcSJason Gunthorpe case IB_CM_TIMEWAIT:
112367b3c8dcSJason Gunthorpe /*
112467b3c8dcSJason Gunthorpe * The cm_acquire_id in cm_timewait_handler will stop working
11251cc44279SJason Gunthorpe * once we do xa_erase below, so just move to idle here for
112667b3c8dcSJason Gunthorpe * consistency.
112767b3c8dcSJason Gunthorpe */
112867b3c8dcSJason Gunthorpe cm_id->state = IB_CM_IDLE;
1129a977049dSHal Rosenstock break;
113067b3c8dcSJason Gunthorpe case IB_CM_IDLE:
1131a977049dSHal Rosenstock break;
1132a977049dSHal Rosenstock }
113367b3c8dcSJason Gunthorpe WARN_ON(cm_id->state != IB_CM_IDLE);
1134a977049dSHal Rosenstock
1135bede86a3SJason Gunthorpe spin_lock(&cm.lock);
1136bede86a3SJason Gunthorpe /* Required for cleanup paths related cm_req_handler() */
1137bede86a3SJason Gunthorpe if (cm_id_priv->timewait_info) {
11389767a27eSJason Gunthorpe cm_remove_remote(cm_id_priv);
1139bede86a3SJason Gunthorpe kfree(cm_id_priv->timewait_info);
1140bede86a3SJason Gunthorpe cm_id_priv->timewait_info = NULL;
1141bede86a3SJason Gunthorpe }
11423595c398SMark Zhang
11432305d686SJason Gunthorpe WARN_ON(cm_id_priv->listen_sharecount);
11442305d686SJason Gunthorpe WARN_ON(!RB_EMPTY_NODE(&cm_id_priv->service_node));
11452305d686SJason Gunthorpe if (!RB_EMPTY_NODE(&cm_id_priv->sidr_id_node))
11462305d686SJason Gunthorpe rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table);
1147bede86a3SJason Gunthorpe spin_unlock(&cm.lock);
1148bede86a3SJason Gunthorpe spin_unlock_irq(&cm_id_priv->lock);
11499db0ff53SMark Bloch
1150eb73060bSJason Gunthorpe xa_erase(&cm.local_id_table, cm_local_id(cm_id->local_id));
11511b52fa98SSean Hefty cm_deref_id(cm_id_priv);
11522e90774fSManjunath Patil do {
11532e90774fSManjunath Patil ret = wait_for_completion_timeout(&cm_id_priv->comp,
11542e90774fSManjunath Patil msecs_to_jiffies(
11552e90774fSManjunath Patil CM_DESTROY_ID_WAIT_TIMEOUT));
11562e90774fSManjunath Patil if (!ret) /* timeout happened */
1157*b4285282SMark Zhang cm_destroy_id_wait_timeout(cm_id, old_state);
11582e90774fSManjunath Patil } while (!ret);
11592e90774fSManjunath Patil
1160a977049dSHal Rosenstock while ((work = cm_dequeue_work(cm_id_priv)) != NULL)
1161a977049dSHal Rosenstock cm_free_work(work);
1162b7403217SParav Pandit
11637345201cSMark Zhang cm_destroy_av(&cm_id_priv->av);
11647345201cSMark Zhang cm_destroy_av(&cm_id_priv->alt_av);
1165a977049dSHal Rosenstock kfree(cm_id_priv->private_data);
11664d6e8a03SDanit Goldberg kfree_rcu(cm_id_priv, rcu);
1167a977049dSHal Rosenstock }
116804c33543SMichael S. Tsirkin
ib_destroy_cm_id(struct ib_cm_id * cm_id)116904c33543SMichael S. Tsirkin void ib_destroy_cm_id(struct ib_cm_id *cm_id)
117004c33543SMichael S. Tsirkin {
117104c33543SMichael S. Tsirkin cm_destroy_id(cm_id, 0);
117204c33543SMichael S. Tsirkin }
1173a977049dSHal Rosenstock EXPORT_SYMBOL(ib_destroy_cm_id);
1174a977049dSHal Rosenstock
cm_init_listen(struct cm_id_private * cm_id_priv,__be64 service_id)1175a461b746SMark Zhang static int cm_init_listen(struct cm_id_private *cm_id_priv, __be64 service_id)
117698f67156SJason Gunthorpe {
117798f67156SJason Gunthorpe if ((service_id & IB_SERVICE_ID_AGN_MASK) == IB_CM_ASSIGN_SERVICE_ID &&
117898f67156SJason Gunthorpe (service_id != IB_CM_ASSIGN_SERVICE_ID))
117998f67156SJason Gunthorpe return -EINVAL;
118098f67156SJason Gunthorpe
1181a461b746SMark Zhang if (service_id == IB_CM_ASSIGN_SERVICE_ID)
118298f67156SJason Gunthorpe cm_id_priv->id.service_id = cpu_to_be64(cm.listen_service_id++);
1183a461b746SMark Zhang else
118498f67156SJason Gunthorpe cm_id_priv->id.service_id = service_id;
1185a461b746SMark Zhang
118698f67156SJason Gunthorpe return 0;
118798f67156SJason Gunthorpe }
118898f67156SJason Gunthorpe
1189067b171bSHaggai Eran /**
119098f67156SJason Gunthorpe * ib_cm_listen - Initiates listening on the specified service ID for
1191067b171bSHaggai Eran * connection and service ID resolution requests.
1192067b171bSHaggai Eran * @cm_id: Connection identifier associated with the listen request.
1193067b171bSHaggai Eran * @service_id: Service identifier matched against incoming connection
1194067b171bSHaggai Eran * and service ID resolution requests. The service ID should be specified
1195067b171bSHaggai Eran * network-byte order. If set to IB_CM_ASSIGN_SERVICE_ID, the CM will
1196067b171bSHaggai Eran * assign a service ID to the caller.
1197067b171bSHaggai Eran */
ib_cm_listen(struct ib_cm_id * cm_id,__be64 service_id)119891a3f14eSMark Zhang int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id)
1199067b171bSHaggai Eran {
120098f67156SJason Gunthorpe struct cm_id_private *cm_id_priv =
120198f67156SJason Gunthorpe container_of(cm_id, struct cm_id_private, id);
120273fec7fdSHaggai Eran unsigned long flags;
120373fec7fdSHaggai Eran int ret;
120473fec7fdSHaggai Eran
120598f67156SJason Gunthorpe spin_lock_irqsave(&cm_id_priv->lock, flags);
120698f67156SJason Gunthorpe if (cm_id_priv->id.state != IB_CM_IDLE) {
120798f67156SJason Gunthorpe ret = -EINVAL;
120898f67156SJason Gunthorpe goto out;
120998f67156SJason Gunthorpe }
121073fec7fdSHaggai Eran
1211a461b746SMark Zhang ret = cm_init_listen(cm_id_priv, service_id);
121298f67156SJason Gunthorpe if (ret)
121398f67156SJason Gunthorpe goto out;
121498f67156SJason Gunthorpe
121598f67156SJason Gunthorpe if (!cm_insert_listen(cm_id_priv, NULL)) {
121698f67156SJason Gunthorpe ret = -EBUSY;
121798f67156SJason Gunthorpe goto out;
121898f67156SJason Gunthorpe }
121998f67156SJason Gunthorpe
122098f67156SJason Gunthorpe cm_id_priv->id.state = IB_CM_LISTEN;
122198f67156SJason Gunthorpe ret = 0;
122298f67156SJason Gunthorpe
122398f67156SJason Gunthorpe out:
122498f67156SJason Gunthorpe spin_unlock_irqrestore(&cm_id_priv->lock, flags);
122573fec7fdSHaggai Eran return ret;
1226067b171bSHaggai Eran }
1227a977049dSHal Rosenstock EXPORT_SYMBOL(ib_cm_listen);
1228a977049dSHal Rosenstock
1229067b171bSHaggai Eran /**
12302988ca08SMauro Carvalho Chehab * ib_cm_insert_listen - Create a new listening ib_cm_id and listen on
12312988ca08SMauro Carvalho Chehab * the given service ID.
1232067b171bSHaggai Eran *
1233067b171bSHaggai Eran * If there's an existing ID listening on that same device and service ID,
1234067b171bSHaggai Eran * return it.
1235067b171bSHaggai Eran *
1236067b171bSHaggai Eran * @device: Device associated with the cm_id. All related communication will
1237067b171bSHaggai Eran * be associated with the specified device.
1238067b171bSHaggai Eran * @cm_handler: Callback invoked to notify the user of CM events.
1239067b171bSHaggai Eran * @service_id: Service identifier matched against incoming connection
1240067b171bSHaggai Eran * and service ID resolution requests. The service ID should be specified
1241067b171bSHaggai Eran * network-byte order. If set to IB_CM_ASSIGN_SERVICE_ID, the CM will
1242067b171bSHaggai Eran * assign a service ID to the caller.
1243067b171bSHaggai Eran *
1244067b171bSHaggai Eran * Callers should call ib_destroy_cm_id when done with the listener ID.
1245067b171bSHaggai Eran */
ib_cm_insert_listen(struct ib_device * device,ib_cm_handler cm_handler,__be64 service_id)1246067b171bSHaggai Eran struct ib_cm_id *ib_cm_insert_listen(struct ib_device *device,
1247067b171bSHaggai Eran ib_cm_handler cm_handler,
1248067b171bSHaggai Eran __be64 service_id)
1249067b171bSHaggai Eran {
125098f67156SJason Gunthorpe struct cm_id_private *listen_id_priv;
1251067b171bSHaggai Eran struct cm_id_private *cm_id_priv;
1252067b171bSHaggai Eran int err = 0;
1253067b171bSHaggai Eran
1254067b171bSHaggai Eran /* Create an ID in advance, since the creation may sleep */
125598f67156SJason Gunthorpe cm_id_priv = cm_alloc_id_priv(device, cm_handler, NULL);
125698f67156SJason Gunthorpe if (IS_ERR(cm_id_priv))
125798f67156SJason Gunthorpe return ERR_CAST(cm_id_priv);
1258067b171bSHaggai Eran
1259a461b746SMark Zhang err = cm_init_listen(cm_id_priv, service_id);
12602990f223SMiaoqian Lin if (err) {
12612990f223SMiaoqian Lin ib_destroy_cm_id(&cm_id_priv->id);
1262067b171bSHaggai Eran return ERR_PTR(err);
12632990f223SMiaoqian Lin }
126498f67156SJason Gunthorpe
126598f67156SJason Gunthorpe spin_lock_irq(&cm_id_priv->lock);
126698f67156SJason Gunthorpe listen_id_priv = cm_insert_listen(cm_id_priv, cm_handler);
126798f67156SJason Gunthorpe if (listen_id_priv != cm_id_priv) {
126898f67156SJason Gunthorpe spin_unlock_irq(&cm_id_priv->lock);
126998f67156SJason Gunthorpe ib_destroy_cm_id(&cm_id_priv->id);
127098f67156SJason Gunthorpe if (!listen_id_priv)
127198f67156SJason Gunthorpe return ERR_PTR(-EINVAL);
127298f67156SJason Gunthorpe return &listen_id_priv->id;
1273067b171bSHaggai Eran }
127498f67156SJason Gunthorpe cm_id_priv->id.state = IB_CM_LISTEN;
127598f67156SJason Gunthorpe spin_unlock_irq(&cm_id_priv->lock);
127698f67156SJason Gunthorpe
127798f67156SJason Gunthorpe /*
127898f67156SJason Gunthorpe * A listen ID does not need to be in the xarray since it does not
127998f67156SJason Gunthorpe * receive mads, is not placed in the remote_id or remote_qpn rbtree,
128098f67156SJason Gunthorpe * and does not enter timewait.
128198f67156SJason Gunthorpe */
128298f67156SJason Gunthorpe
128398f67156SJason Gunthorpe return &cm_id_priv->id;
1284067b171bSHaggai Eran }
1285067b171bSHaggai Eran EXPORT_SYMBOL(ib_cm_insert_listen);
1286067b171bSHaggai Eran
cm_form_tid(struct cm_id_private * cm_id_priv)128787a37ce9SHåkon Bugge static __be64 cm_form_tid(struct cm_id_private *cm_id_priv)
1288a977049dSHal Rosenstock {
128976039ac9SMark Zhang u64 hi_tid = 0, low_tid;
1290a977049dSHal Rosenstock
129176039ac9SMark Zhang lockdep_assert_held(&cm_id_priv->lock);
129276039ac9SMark Zhang
129387a37ce9SHåkon Bugge low_tid = (u64)cm_id_priv->id.local_id;
129476039ac9SMark Zhang if (!cm_id_priv->av.port)
129576039ac9SMark Zhang return cpu_to_be64(low_tid);
129676039ac9SMark Zhang
129776039ac9SMark Zhang spin_lock(&cm_id_priv->av.port->cm_dev->mad_agent_lock);
129876039ac9SMark Zhang if (cm_id_priv->av.port->mad_agent)
129976039ac9SMark Zhang hi_tid = ((u64)cm_id_priv->av.port->mad_agent->hi_tid) << 32;
130076039ac9SMark Zhang spin_unlock(&cm_id_priv->av.port->cm_dev->mad_agent_lock);
1301a977049dSHal Rosenstock return cpu_to_be64(hi_tid | low_tid);
1302a977049dSHal Rosenstock }
1303a977049dSHal Rosenstock
cm_format_mad_hdr(struct ib_mad_hdr * hdr,__be16 attr_id,__be64 tid)1304a977049dSHal Rosenstock static void cm_format_mad_hdr(struct ib_mad_hdr *hdr,
130597f52eb4SSean Hefty __be16 attr_id, __be64 tid)
1306a977049dSHal Rosenstock {
1307a977049dSHal Rosenstock hdr->base_version = IB_MGMT_BASE_VERSION;
1308a977049dSHal Rosenstock hdr->mgmt_class = IB_MGMT_CLASS_CM;
1309a977049dSHal Rosenstock hdr->class_version = IB_CM_CLASS_VERSION;
1310a977049dSHal Rosenstock hdr->method = IB_MGMT_METHOD_SEND;
1311a977049dSHal Rosenstock hdr->attr_id = attr_id;
1312a977049dSHal Rosenstock hdr->tid = tid;
1313a977049dSHal Rosenstock }
1314a977049dSHal Rosenstock
cm_format_mad_ece_hdr(struct ib_mad_hdr * hdr,__be16 attr_id,__be64 tid,u32 attr_mod)1315a20652e1SLeon Romanovsky static void cm_format_mad_ece_hdr(struct ib_mad_hdr *hdr, __be16 attr_id,
1316a20652e1SLeon Romanovsky __be64 tid, u32 attr_mod)
1317a20652e1SLeon Romanovsky {
1318a20652e1SLeon Romanovsky cm_format_mad_hdr(hdr, attr_id, tid);
1319a20652e1SLeon Romanovsky hdr->attr_mod = cpu_to_be32(attr_mod);
1320a20652e1SLeon Romanovsky }
1321a20652e1SLeon Romanovsky
cm_format_req(struct cm_req_msg * req_msg,struct cm_id_private * cm_id_priv,struct ib_cm_req_param * param)1322a977049dSHal Rosenstock static void cm_format_req(struct cm_req_msg *req_msg,
1323a977049dSHal Rosenstock struct cm_id_private *cm_id_priv,
1324a977049dSHal Rosenstock struct ib_cm_req_param *param)
1325a977049dSHal Rosenstock {
1326c2f8fc4eSDasaratharaman Chandramouli struct sa_path_rec *pri_path = param->primary_path;
1327c2f8fc4eSDasaratharaman Chandramouli struct sa_path_rec *alt_path = param->alternate_path;
1328e92aa00aSHiatt, Don bool pri_ext = false;
1329eb8336dbSMark Zhang __be16 lid;
1330e92aa00aSHiatt, Don
1331e92aa00aSHiatt, Don if (pri_path->rec_type == SA_PATH_REC_TYPE_OPA)
1332e92aa00aSHiatt, Don pri_ext = opa_is_extended_lid(pri_path->opa.dlid,
1333e92aa00aSHiatt, Don pri_path->opa.slid);
13343971c9f6SSean Hefty
1335a20652e1SLeon Romanovsky cm_format_mad_ece_hdr(&req_msg->hdr, CM_REQ_ATTR_ID,
1336a20652e1SLeon Romanovsky cm_form_tid(cm_id_priv), param->ece.attr_mod);
1337a977049dSHal Rosenstock
133891b60a71SJason Gunthorpe IBA_SET(CM_REQ_LOCAL_COMM_ID, req_msg,
133991b60a71SJason Gunthorpe be32_to_cpu(cm_id_priv->id.local_id));
134091b60a71SJason Gunthorpe IBA_SET(CM_REQ_SERVICE_ID, req_msg, be64_to_cpu(param->service_id));
134191b60a71SJason Gunthorpe IBA_SET(CM_REQ_LOCAL_CA_GUID, req_msg,
134291b60a71SJason Gunthorpe be64_to_cpu(cm_id_priv->id.device->node_guid));
134301adb7f4SJason Gunthorpe IBA_SET(CM_REQ_LOCAL_QPN, req_msg, param->qp_num);
1344b6bbee68SJason Gunthorpe IBA_SET(CM_REQ_INITIATOR_DEPTH, req_msg, param->initiator_depth);
1345b6bbee68SJason Gunthorpe IBA_SET(CM_REQ_REMOTE_CM_RESPONSE_TIMEOUT, req_msg,
1346a977049dSHal Rosenstock param->remote_cm_response_timeout);
1347a977049dSHal Rosenstock cm_req_set_qp_type(req_msg, param->qp_type);
1348b6bbee68SJason Gunthorpe IBA_SET(CM_REQ_END_TO_END_FLOW_CONTROL, req_msg, param->flow_control);
134901adb7f4SJason Gunthorpe IBA_SET(CM_REQ_STARTING_PSN, req_msg, param->starting_psn);
1350b6bbee68SJason Gunthorpe IBA_SET(CM_REQ_LOCAL_CM_RESPONSE_TIMEOUT, req_msg,
1351a977049dSHal Rosenstock param->local_cm_response_timeout);
135291b60a71SJason Gunthorpe IBA_SET(CM_REQ_PARTITION_KEY, req_msg,
135391b60a71SJason Gunthorpe be16_to_cpu(param->primary_path->pkey));
1354b6bbee68SJason Gunthorpe IBA_SET(CM_REQ_PATH_PACKET_PAYLOAD_MTU, req_msg,
1355b6bbee68SJason Gunthorpe param->primary_path->mtu);
1356b6bbee68SJason Gunthorpe IBA_SET(CM_REQ_MAX_CM_RETRIES, req_msg, param->max_cm_retries);
1357d26a360bSSean Hefty
1358d26a360bSSean Hefty if (param->qp_type != IB_QPT_XRC_INI) {
1359b6bbee68SJason Gunthorpe IBA_SET(CM_REQ_RESPONDER_RESOURCES, req_msg,
1360b6bbee68SJason Gunthorpe param->responder_resources);
1361b6bbee68SJason Gunthorpe IBA_SET(CM_REQ_RETRY_COUNT, req_msg, param->retry_count);
1362b6bbee68SJason Gunthorpe IBA_SET(CM_REQ_RNR_RETRY_COUNT, req_msg,
1363b6bbee68SJason Gunthorpe param->rnr_retry_count);
1364b6bbee68SJason Gunthorpe IBA_SET(CM_REQ_SRQ, req_msg, param->srq);
1365d26a360bSSean Hefty }
1366a977049dSHal Rosenstock
13674ca662a3SJason Gunthorpe *IBA_GET_MEM_PTR(CM_REQ_PRIMARY_LOCAL_PORT_GID, req_msg) =
13684ca662a3SJason Gunthorpe pri_path->sgid;
13694ca662a3SJason Gunthorpe *IBA_GET_MEM_PTR(CM_REQ_PRIMARY_REMOTE_PORT_GID, req_msg) =
13704ca662a3SJason Gunthorpe pri_path->dgid;
1371e92aa00aSHiatt, Don if (pri_ext) {
13724ca662a3SJason Gunthorpe IBA_GET_MEM_PTR(CM_REQ_PRIMARY_LOCAL_PORT_GID, req_msg)
13734ca662a3SJason Gunthorpe ->global.interface_id =
13744ca662a3SJason Gunthorpe OPA_MAKE_ID(be32_to_cpu(pri_path->opa.slid));
13754ca662a3SJason Gunthorpe IBA_GET_MEM_PTR(CM_REQ_PRIMARY_REMOTE_PORT_GID, req_msg)
13764ca662a3SJason Gunthorpe ->global.interface_id =
13774ca662a3SJason Gunthorpe OPA_MAKE_ID(be32_to_cpu(pri_path->opa.dlid));
1378e92aa00aSHiatt, Don }
13793971c9f6SSean Hefty if (pri_path->hop_limit <= 1) {
138091b60a71SJason Gunthorpe IBA_SET(CM_REQ_PRIMARY_LOCAL_PORT_LID, req_msg,
138191b60a71SJason Gunthorpe be16_to_cpu(pri_ext ? 0 :
138291b60a71SJason Gunthorpe htons(ntohl(sa_path_get_slid(
138391b60a71SJason Gunthorpe pri_path)))));
138491b60a71SJason Gunthorpe IBA_SET(CM_REQ_PRIMARY_REMOTE_PORT_LID, req_msg,
138591b60a71SJason Gunthorpe be16_to_cpu(pri_ext ? 0 :
138691b60a71SJason Gunthorpe htons(ntohl(sa_path_get_dlid(
138791b60a71SJason Gunthorpe pri_path)))));
13883971c9f6SSean Hefty } else {
1389eb8336dbSMark Zhang
1390eb8336dbSMark Zhang if (param->primary_path_inbound) {
1391eb8336dbSMark Zhang lid = param->primary_path_inbound->ib.dlid;
1392eb8336dbSMark Zhang IBA_SET(CM_REQ_PRIMARY_LOCAL_PORT_LID, req_msg,
1393eb8336dbSMark Zhang be16_to_cpu(lid));
1394eb8336dbSMark Zhang } else
139591b60a71SJason Gunthorpe IBA_SET(CM_REQ_PRIMARY_LOCAL_PORT_LID, req_msg,
139691b60a71SJason Gunthorpe be16_to_cpu(IB_LID_PERMISSIVE));
1397eb8336dbSMark Zhang
1398eb8336dbSMark Zhang /* Work-around until there's a way to obtain remote LID info */
139991b60a71SJason Gunthorpe IBA_SET(CM_REQ_PRIMARY_REMOTE_PORT_LID, req_msg,
140091b60a71SJason Gunthorpe be16_to_cpu(IB_LID_PERMISSIVE));
14013971c9f6SSean Hefty }
140201adb7f4SJason Gunthorpe IBA_SET(CM_REQ_PRIMARY_FLOW_LABEL, req_msg,
140301adb7f4SJason Gunthorpe be32_to_cpu(pri_path->flow_label));
1404b6bbee68SJason Gunthorpe IBA_SET(CM_REQ_PRIMARY_PACKET_RATE, req_msg, pri_path->rate);
140591b60a71SJason Gunthorpe IBA_SET(CM_REQ_PRIMARY_TRAFFIC_CLASS, req_msg, pri_path->traffic_class);
140691b60a71SJason Gunthorpe IBA_SET(CM_REQ_PRIMARY_HOP_LIMIT, req_msg, pri_path->hop_limit);
1407b6bbee68SJason Gunthorpe IBA_SET(CM_REQ_PRIMARY_SL, req_msg, pri_path->sl);
1408b6bbee68SJason Gunthorpe IBA_SET(CM_REQ_PRIMARY_SUBNET_LOCAL, req_msg,
1409b6bbee68SJason Gunthorpe (pri_path->hop_limit <= 1));
1410b6bbee68SJason Gunthorpe IBA_SET(CM_REQ_PRIMARY_LOCAL_ACK_TIMEOUT, req_msg,
14111d846126SSean Hefty cm_ack_timeout(cm_id_priv->av.port->cm_dev->ack_delay,
14123971c9f6SSean Hefty pri_path->packet_life_time));
1413a977049dSHal Rosenstock
14143971c9f6SSean Hefty if (alt_path) {
1415e92aa00aSHiatt, Don bool alt_ext = false;
1416e92aa00aSHiatt, Don
1417e92aa00aSHiatt, Don if (alt_path->rec_type == SA_PATH_REC_TYPE_OPA)
1418e92aa00aSHiatt, Don alt_ext = opa_is_extended_lid(alt_path->opa.dlid,
1419e92aa00aSHiatt, Don alt_path->opa.slid);
1420e92aa00aSHiatt, Don
14214ca662a3SJason Gunthorpe *IBA_GET_MEM_PTR(CM_REQ_ALTERNATE_LOCAL_PORT_GID, req_msg) =
14224ca662a3SJason Gunthorpe alt_path->sgid;
14234ca662a3SJason Gunthorpe *IBA_GET_MEM_PTR(CM_REQ_ALTERNATE_REMOTE_PORT_GID, req_msg) =
14244ca662a3SJason Gunthorpe alt_path->dgid;
1425e92aa00aSHiatt, Don if (alt_ext) {
14264ca662a3SJason Gunthorpe IBA_GET_MEM_PTR(CM_REQ_ALTERNATE_LOCAL_PORT_GID,
14274ca662a3SJason Gunthorpe req_msg)
14284ca662a3SJason Gunthorpe ->global.interface_id =
14294ca662a3SJason Gunthorpe OPA_MAKE_ID(be32_to_cpu(alt_path->opa.slid));
14304ca662a3SJason Gunthorpe IBA_GET_MEM_PTR(CM_REQ_ALTERNATE_REMOTE_PORT_GID,
14314ca662a3SJason Gunthorpe req_msg)
14324ca662a3SJason Gunthorpe ->global.interface_id =
14334ca662a3SJason Gunthorpe OPA_MAKE_ID(be32_to_cpu(alt_path->opa.dlid));
1434e92aa00aSHiatt, Don }
14353971c9f6SSean Hefty if (alt_path->hop_limit <= 1) {
143691b60a71SJason Gunthorpe IBA_SET(CM_REQ_ALTERNATE_LOCAL_PORT_LID, req_msg,
143791b60a71SJason Gunthorpe be16_to_cpu(
143891b60a71SJason Gunthorpe alt_ext ? 0 :
143991b60a71SJason Gunthorpe htons(ntohl(sa_path_get_slid(
144091b60a71SJason Gunthorpe alt_path)))));
144191b60a71SJason Gunthorpe IBA_SET(CM_REQ_ALTERNATE_REMOTE_PORT_LID, req_msg,
144291b60a71SJason Gunthorpe be16_to_cpu(
144391b60a71SJason Gunthorpe alt_ext ? 0 :
144491b60a71SJason Gunthorpe htons(ntohl(sa_path_get_dlid(
144591b60a71SJason Gunthorpe alt_path)))));
14463971c9f6SSean Hefty } else {
144791b60a71SJason Gunthorpe IBA_SET(CM_REQ_ALTERNATE_LOCAL_PORT_LID, req_msg,
144891b60a71SJason Gunthorpe be16_to_cpu(IB_LID_PERMISSIVE));
144991b60a71SJason Gunthorpe IBA_SET(CM_REQ_ALTERNATE_REMOTE_PORT_LID, req_msg,
145091b60a71SJason Gunthorpe be16_to_cpu(IB_LID_PERMISSIVE));
14513971c9f6SSean Hefty }
145201adb7f4SJason Gunthorpe IBA_SET(CM_REQ_ALTERNATE_FLOW_LABEL, req_msg,
145301adb7f4SJason Gunthorpe be32_to_cpu(alt_path->flow_label));
1454b6bbee68SJason Gunthorpe IBA_SET(CM_REQ_ALTERNATE_PACKET_RATE, req_msg, alt_path->rate);
145591b60a71SJason Gunthorpe IBA_SET(CM_REQ_ALTERNATE_TRAFFIC_CLASS, req_msg,
145691b60a71SJason Gunthorpe alt_path->traffic_class);
145791b60a71SJason Gunthorpe IBA_SET(CM_REQ_ALTERNATE_HOP_LIMIT, req_msg,
145891b60a71SJason Gunthorpe alt_path->hop_limit);
1459b6bbee68SJason Gunthorpe IBA_SET(CM_REQ_ALTERNATE_SL, req_msg, alt_path->sl);
1460b6bbee68SJason Gunthorpe IBA_SET(CM_REQ_ALTERNATE_SUBNET_LOCAL, req_msg,
1461b6bbee68SJason Gunthorpe (alt_path->hop_limit <= 1));
1462b6bbee68SJason Gunthorpe IBA_SET(CM_REQ_ALTERNATE_LOCAL_ACK_TIMEOUT, req_msg,
14631d846126SSean Hefty cm_ack_timeout(cm_id_priv->av.port->cm_dev->ack_delay,
14643971c9f6SSean Hefty alt_path->packet_life_time));
1465a977049dSHal Rosenstock }
1466a20652e1SLeon Romanovsky IBA_SET(CM_REQ_VENDOR_ID, req_msg, param->ece.vendor_id);
1467a977049dSHal Rosenstock
1468a977049dSHal Rosenstock if (param->private_data && param->private_data_len)
14694ca662a3SJason Gunthorpe IBA_SET_MEM(CM_REQ_PRIVATE_DATA, req_msg, param->private_data,
1470a977049dSHal Rosenstock param->private_data_len);
1471a977049dSHal Rosenstock }
1472a977049dSHal Rosenstock
cm_validate_req_param(struct ib_cm_req_param * param)1473858119e1SArjan van de Ven static int cm_validate_req_param(struct ib_cm_req_param *param)
1474a977049dSHal Rosenstock {
1475a977049dSHal Rosenstock if (!param->primary_path)
1476a977049dSHal Rosenstock return -EINVAL;
1477a977049dSHal Rosenstock
1478d26a360bSSean Hefty if (param->qp_type != IB_QPT_RC && param->qp_type != IB_QPT_UC &&
1479d26a360bSSean Hefty param->qp_type != IB_QPT_XRC_INI)
1480a977049dSHal Rosenstock return -EINVAL;
1481a977049dSHal Rosenstock
1482a977049dSHal Rosenstock if (param->private_data &&
1483a977049dSHal Rosenstock param->private_data_len > IB_CM_REQ_PRIVATE_DATA_SIZE)
1484a977049dSHal Rosenstock return -EINVAL;
1485a977049dSHal Rosenstock
1486a977049dSHal Rosenstock if (param->alternate_path &&
1487a977049dSHal Rosenstock (param->alternate_path->pkey != param->primary_path->pkey ||
1488a977049dSHal Rosenstock param->alternate_path->mtu != param->primary_path->mtu))
1489a977049dSHal Rosenstock return -EINVAL;
1490a977049dSHal Rosenstock
1491a977049dSHal Rosenstock return 0;
1492a977049dSHal Rosenstock }
1493a977049dSHal Rosenstock
ib_send_cm_req(struct ib_cm_id * cm_id,struct ib_cm_req_param * param)1494a977049dSHal Rosenstock int ib_send_cm_req(struct ib_cm_id *cm_id,
1495a977049dSHal Rosenstock struct ib_cm_req_param *param)
1496a977049dSHal Rosenstock {
14977345201cSMark Zhang struct cm_av av = {}, alt_av = {};
1498a977049dSHal Rosenstock struct cm_id_private *cm_id_priv;
14994b4e586eSJason Gunthorpe struct ib_mad_send_buf *msg;
1500a977049dSHal Rosenstock struct cm_req_msg *req_msg;
1501a977049dSHal Rosenstock unsigned long flags;
1502a977049dSHal Rosenstock int ret;
1503a977049dSHal Rosenstock
1504a977049dSHal Rosenstock ret = cm_validate_req_param(param);
1505a977049dSHal Rosenstock if (ret)
1506a977049dSHal Rosenstock return ret;
1507a977049dSHal Rosenstock
1508a977049dSHal Rosenstock /* Verify that we're not in timewait. */
1509a977049dSHal Rosenstock cm_id_priv = container_of(cm_id, struct cm_id_private, id);
1510a977049dSHal Rosenstock spin_lock_irqsave(&cm_id_priv->lock, flags);
1511bede86a3SJason Gunthorpe if (cm_id->state != IB_CM_IDLE || WARN_ON(cm_id_priv->timewait_info)) {
1512a977049dSHal Rosenstock spin_unlock_irqrestore(&cm_id_priv->lock, flags);
15137345201cSMark Zhang return -EINVAL;
1514a977049dSHal Rosenstock }
1515a977049dSHal Rosenstock spin_unlock_irqrestore(&cm_id_priv->lock, flags);
1516a977049dSHal Rosenstock
1517a977049dSHal Rosenstock cm_id_priv->timewait_info = cm_create_timewait_info(cm_id_priv->
1518a977049dSHal Rosenstock id.local_id);
151975df23e2SSean Hefty if (IS_ERR(cm_id_priv->timewait_info)) {
152075df23e2SSean Hefty ret = PTR_ERR(cm_id_priv->timewait_info);
1521340b940eSLeon Romanovsky cm_id_priv->timewait_info = NULL;
15227345201cSMark Zhang return ret;
152375df23e2SSean Hefty }
1524a977049dSHal Rosenstock
152539839107SParav Pandit ret = cm_init_av_by_path(param->primary_path,
15267345201cSMark Zhang param->ppath_sgid_attr, &av);
1527a977049dSHal Rosenstock if (ret)
15287345201cSMark Zhang return ret;
1529a977049dSHal Rosenstock if (param->alternate_path) {
153039839107SParav Pandit ret = cm_init_av_by_path(param->alternate_path, NULL,
15317345201cSMark Zhang &alt_av);
15327345201cSMark Zhang if (ret) {
15337345201cSMark Zhang cm_destroy_av(&av);
15347345201cSMark Zhang return ret;
15357345201cSMark Zhang }
1536a977049dSHal Rosenstock }
1537a977049dSHal Rosenstock cm_id->service_id = param->service_id;
1538a977049dSHal Rosenstock cm_id_priv->timeout_ms = cm_convert_to_ms(
1539a977049dSHal Rosenstock param->primary_path->packet_life_time) * 2 +
1540a977049dSHal Rosenstock cm_convert_to_ms(
1541a977049dSHal Rosenstock param->remote_cm_response_timeout);
1542a977049dSHal Rosenstock cm_id_priv->max_cm_retries = param->max_cm_retries;
1543a977049dSHal Rosenstock cm_id_priv->initiator_depth = param->initiator_depth;
1544a977049dSHal Rosenstock cm_id_priv->responder_resources = param->responder_resources;
1545a977049dSHal Rosenstock cm_id_priv->retry_count = param->retry_count;
1546a977049dSHal Rosenstock cm_id_priv->path_mtu = param->primary_path->mtu;
1547e1444b5aSSean Hefty cm_id_priv->pkey = param->primary_path->pkey;
1548ae7971a7SSean Hefty cm_id_priv->qp_type = param->qp_type;
1549a977049dSHal Rosenstock
15504b4e586eSJason Gunthorpe spin_lock_irqsave(&cm_id_priv->lock, flags);
15517345201cSMark Zhang
15527345201cSMark Zhang cm_move_av_from_path(&cm_id_priv->av, &av);
1553eb8336dbSMark Zhang if (param->primary_path_outbound)
1554eb8336dbSMark Zhang cm_id_priv->av.dlid_datapath =
1555eb8336dbSMark Zhang be16_to_cpu(param->primary_path_outbound->ib.dlid);
1556eb8336dbSMark Zhang
15577345201cSMark Zhang if (param->alternate_path)
15587345201cSMark Zhang cm_move_av_from_path(&cm_id_priv->alt_av, &alt_av);
15597345201cSMark Zhang
15604b4e586eSJason Gunthorpe msg = cm_alloc_priv_msg(cm_id_priv);
15614b4e586eSJason Gunthorpe if (IS_ERR(msg)) {
15624b4e586eSJason Gunthorpe ret = PTR_ERR(msg);
15634b4e586eSJason Gunthorpe goto out_unlock;
15644b4e586eSJason Gunthorpe }
1565a977049dSHal Rosenstock
15664b4e586eSJason Gunthorpe req_msg = (struct cm_req_msg *)msg->mad;
1567a977049dSHal Rosenstock cm_format_req(req_msg, cm_id_priv, param);
1568a977049dSHal Rosenstock cm_id_priv->tid = req_msg->hdr.tid;
15694b4e586eSJason Gunthorpe msg->timeout_ms = cm_id_priv->timeout_ms;
15704b4e586eSJason Gunthorpe msg->context[1] = (void *)(unsigned long)IB_CM_REQ_SENT;
1571a977049dSHal Rosenstock
157201adb7f4SJason Gunthorpe cm_id_priv->local_qpn = cpu_to_be32(IBA_GET(CM_REQ_LOCAL_QPN, req_msg));
157301adb7f4SJason Gunthorpe cm_id_priv->rq_psn = cpu_to_be32(IBA_GET(CM_REQ_STARTING_PSN, req_msg));
1574a977049dSHal Rosenstock
15758dc105beSChuck Lever trace_icm_send_req(&cm_id_priv->id);
15764b4e586eSJason Gunthorpe ret = ib_post_send_mad(msg, NULL);
15774b4e586eSJason Gunthorpe if (ret)
15784b4e586eSJason Gunthorpe goto out_free;
1579a977049dSHal Rosenstock BUG_ON(cm_id->state != IB_CM_IDLE);
1580a977049dSHal Rosenstock cm_id->state = IB_CM_REQ_SENT;
1581a977049dSHal Rosenstock spin_unlock_irqrestore(&cm_id_priv->lock, flags);
1582a977049dSHal Rosenstock return 0;
15834b4e586eSJason Gunthorpe out_free:
15844b4e586eSJason Gunthorpe cm_free_priv_msg(msg);
15854b4e586eSJason Gunthorpe out_unlock:
15864b4e586eSJason Gunthorpe spin_unlock_irqrestore(&cm_id_priv->lock, flags);
158796376a40SJason Gunthorpe return ret;
1588a977049dSHal Rosenstock }
1589a977049dSHal Rosenstock EXPORT_SYMBOL(ib_send_cm_req);
1590a977049dSHal Rosenstock
cm_issue_rej(struct cm_port * port,struct ib_mad_recv_wc * mad_recv_wc,enum ib_cm_rej_reason reason,enum cm_msg_response msg_rejected,void * ari,u8 ari_length)1591a977049dSHal Rosenstock static int cm_issue_rej(struct cm_port *port,
1592a977049dSHal Rosenstock struct ib_mad_recv_wc *mad_recv_wc,
1593a977049dSHal Rosenstock enum ib_cm_rej_reason reason,
1594a977049dSHal Rosenstock enum cm_msg_response msg_rejected,
1595a977049dSHal Rosenstock void *ari, u8 ari_length)
1596a977049dSHal Rosenstock {
1597a977049dSHal Rosenstock struct ib_mad_send_buf *msg = NULL;
1598a977049dSHal Rosenstock struct cm_rej_msg *rej_msg, *rcv_msg;
1599a977049dSHal Rosenstock int ret;
1600a977049dSHal Rosenstock
1601a977049dSHal Rosenstock ret = cm_alloc_response_msg(port, mad_recv_wc, &msg);
1602a977049dSHal Rosenstock if (ret)
1603a977049dSHal Rosenstock return ret;
1604a977049dSHal Rosenstock
1605a977049dSHal Rosenstock /* We just need common CM header information. Cast to any message. */
1606a977049dSHal Rosenstock rcv_msg = (struct cm_rej_msg *) mad_recv_wc->recv_buf.mad;
1607a977049dSHal Rosenstock rej_msg = (struct cm_rej_msg *) msg->mad;
1608a977049dSHal Rosenstock
1609a977049dSHal Rosenstock cm_format_mad_hdr(&rej_msg->hdr, CM_REJ_ATTR_ID, rcv_msg->hdr.tid);
161091b60a71SJason Gunthorpe IBA_SET(CM_REJ_REMOTE_COMM_ID, rej_msg,
161191b60a71SJason Gunthorpe IBA_GET(CM_REJ_LOCAL_COMM_ID, rcv_msg));
161291b60a71SJason Gunthorpe IBA_SET(CM_REJ_LOCAL_COMM_ID, rej_msg,
161391b60a71SJason Gunthorpe IBA_GET(CM_REJ_REMOTE_COMM_ID, rcv_msg));
1614b6bbee68SJason Gunthorpe IBA_SET(CM_REJ_MESSAGE_REJECTED, rej_msg, msg_rejected);
161591b60a71SJason Gunthorpe IBA_SET(CM_REJ_REASON, rej_msg, reason);
1616a977049dSHal Rosenstock
1617a977049dSHal Rosenstock if (ari && ari_length) {
1618b6bbee68SJason Gunthorpe IBA_SET(CM_REJ_REJECTED_INFO_LENGTH, rej_msg, ari_length);
16194ca662a3SJason Gunthorpe IBA_SET_MEM(CM_REJ_ARI, rej_msg, ari, ari_length);
1620a977049dSHal Rosenstock }
1621a977049dSHal Rosenstock
16228dc105beSChuck Lever trace_icm_issue_rej(
16238dc105beSChuck Lever IBA_GET(CM_REJ_LOCAL_COMM_ID, rcv_msg),
16248dc105beSChuck Lever IBA_GET(CM_REJ_REMOTE_COMM_ID, rcv_msg));
162534816ad9SSean Hefty ret = ib_post_send_mad(msg, NULL);
1626a977049dSHal Rosenstock if (ret)
162796376a40SJason Gunthorpe cm_free_response_msg(msg);
1628a977049dSHal Rosenstock
1629a977049dSHal Rosenstock return ret;
1630a977049dSHal Rosenstock }
1631a977049dSHal Rosenstock
cm_req_has_alt_path(struct cm_req_msg * req_msg)16326b3c0e6eSDasaratharaman Chandramouli static bool cm_req_has_alt_path(struct cm_req_msg *req_msg)
16336b3c0e6eSDasaratharaman Chandramouli {
163491b60a71SJason Gunthorpe return ((cpu_to_be16(
163591b60a71SJason Gunthorpe IBA_GET(CM_REQ_ALTERNATE_LOCAL_PORT_LID, req_msg))) ||
16364ca662a3SJason Gunthorpe (ib_is_opa_gid(IBA_GET_MEM_PTR(CM_REQ_ALTERNATE_LOCAL_PORT_GID,
16374ca662a3SJason Gunthorpe req_msg))));
16386b3c0e6eSDasaratharaman Chandramouli }
16396b3c0e6eSDasaratharaman Chandramouli
cm_path_set_rec_type(struct ib_device * ib_device,u32 port_num,struct sa_path_rec * path,union ib_gid * gid)16401fb7f897SMark Bloch static void cm_path_set_rec_type(struct ib_device *ib_device, u32 port_num,
16416b3c0e6eSDasaratharaman Chandramouli struct sa_path_rec *path, union ib_gid *gid)
16426b3c0e6eSDasaratharaman Chandramouli {
16436b3c0e6eSDasaratharaman Chandramouli if (ib_is_opa_gid(gid) && rdma_cap_opa_ah(ib_device, port_num))
16446b3c0e6eSDasaratharaman Chandramouli path->rec_type = SA_PATH_REC_TYPE_OPA;
16456b3c0e6eSDasaratharaman Chandramouli else
16466b3c0e6eSDasaratharaman Chandramouli path->rec_type = SA_PATH_REC_TYPE_IB;
16476b3c0e6eSDasaratharaman Chandramouli }
16486b3c0e6eSDasaratharaman Chandramouli
cm_format_path_lid_from_req(struct cm_req_msg * req_msg,struct sa_path_rec * primary_path,struct sa_path_rec * alt_path,struct ib_wc * wc)1649ac3a949fSDasaratharaman Chandramouli static void cm_format_path_lid_from_req(struct cm_req_msg *req_msg,
1650ac3a949fSDasaratharaman Chandramouli struct sa_path_rec *primary_path,
1651b7d95040SMark Zhang struct sa_path_rec *alt_path,
1652b7d95040SMark Zhang struct ib_wc *wc)
1653ac3a949fSDasaratharaman Chandramouli {
1654ac3a949fSDasaratharaman Chandramouli u32 lid;
1655ac3a949fSDasaratharaman Chandramouli
1656ac3a949fSDasaratharaman Chandramouli if (primary_path->rec_type != SA_PATH_REC_TYPE_OPA) {
1657b7d95040SMark Zhang sa_path_set_dlid(primary_path, wc->slid);
1658ac3a949fSDasaratharaman Chandramouli sa_path_set_slid(primary_path,
165991b60a71SJason Gunthorpe IBA_GET(CM_REQ_PRIMARY_REMOTE_PORT_LID,
166091b60a71SJason Gunthorpe req_msg));
1661ac3a949fSDasaratharaman Chandramouli } else {
16624ca662a3SJason Gunthorpe lid = opa_get_lid_from_gid(IBA_GET_MEM_PTR(
16634ca662a3SJason Gunthorpe CM_REQ_PRIMARY_LOCAL_PORT_GID, req_msg));
16649d187177SBart Van Assche sa_path_set_dlid(primary_path, lid);
1665ac3a949fSDasaratharaman Chandramouli
16664ca662a3SJason Gunthorpe lid = opa_get_lid_from_gid(IBA_GET_MEM_PTR(
16674ca662a3SJason Gunthorpe CM_REQ_PRIMARY_REMOTE_PORT_GID, req_msg));
16689d187177SBart Van Assche sa_path_set_slid(primary_path, lid);
1669ac3a949fSDasaratharaman Chandramouli }
1670ac3a949fSDasaratharaman Chandramouli
1671ac3a949fSDasaratharaman Chandramouli if (!cm_req_has_alt_path(req_msg))
1672ac3a949fSDasaratharaman Chandramouli return;
1673ac3a949fSDasaratharaman Chandramouli
1674ac3a949fSDasaratharaman Chandramouli if (alt_path->rec_type != SA_PATH_REC_TYPE_OPA) {
167591b60a71SJason Gunthorpe sa_path_set_dlid(alt_path,
167691b60a71SJason Gunthorpe IBA_GET(CM_REQ_ALTERNATE_LOCAL_PORT_LID,
167791b60a71SJason Gunthorpe req_msg));
167891b60a71SJason Gunthorpe sa_path_set_slid(alt_path,
167991b60a71SJason Gunthorpe IBA_GET(CM_REQ_ALTERNATE_REMOTE_PORT_LID,
168091b60a71SJason Gunthorpe req_msg));
1681ac3a949fSDasaratharaman Chandramouli } else {
16824ca662a3SJason Gunthorpe lid = opa_get_lid_from_gid(IBA_GET_MEM_PTR(
16834ca662a3SJason Gunthorpe CM_REQ_ALTERNATE_LOCAL_PORT_GID, req_msg));
16849d187177SBart Van Assche sa_path_set_dlid(alt_path, lid);
1685ac3a949fSDasaratharaman Chandramouli
16864ca662a3SJason Gunthorpe lid = opa_get_lid_from_gid(IBA_GET_MEM_PTR(
16874ca662a3SJason Gunthorpe CM_REQ_ALTERNATE_REMOTE_PORT_GID, req_msg));
16889d187177SBart Van Assche sa_path_set_slid(alt_path, lid);
1689ac3a949fSDasaratharaman Chandramouli }
1690ac3a949fSDasaratharaman Chandramouli }
1691ac3a949fSDasaratharaman Chandramouli
cm_format_paths_from_req(struct cm_req_msg * req_msg,struct sa_path_rec * primary_path,struct sa_path_rec * alt_path,struct ib_wc * wc)1692858119e1SArjan van de Ven static void cm_format_paths_from_req(struct cm_req_msg *req_msg,
1693c2f8fc4eSDasaratharaman Chandramouli struct sa_path_rec *primary_path,
1694b7d95040SMark Zhang struct sa_path_rec *alt_path,
1695b7d95040SMark Zhang struct ib_wc *wc)
1696a977049dSHal Rosenstock {
16974ca662a3SJason Gunthorpe primary_path->dgid =
16984ca662a3SJason Gunthorpe *IBA_GET_MEM_PTR(CM_REQ_PRIMARY_LOCAL_PORT_GID, req_msg);
16994ca662a3SJason Gunthorpe primary_path->sgid =
17004ca662a3SJason Gunthorpe *IBA_GET_MEM_PTR(CM_REQ_PRIMARY_REMOTE_PORT_GID, req_msg);
170101adb7f4SJason Gunthorpe primary_path->flow_label =
170201adb7f4SJason Gunthorpe cpu_to_be32(IBA_GET(CM_REQ_PRIMARY_FLOW_LABEL, req_msg));
170391b60a71SJason Gunthorpe primary_path->hop_limit = IBA_GET(CM_REQ_PRIMARY_HOP_LIMIT, req_msg);
170491b60a71SJason Gunthorpe primary_path->traffic_class =
170591b60a71SJason Gunthorpe IBA_GET(CM_REQ_PRIMARY_TRAFFIC_CLASS, req_msg);
1706a977049dSHal Rosenstock primary_path->reversible = 1;
170791b60a71SJason Gunthorpe primary_path->pkey =
170891b60a71SJason Gunthorpe cpu_to_be16(IBA_GET(CM_REQ_PARTITION_KEY, req_msg));
1709b6bbee68SJason Gunthorpe primary_path->sl = IBA_GET(CM_REQ_PRIMARY_SL, req_msg);
1710a977049dSHal Rosenstock primary_path->mtu_selector = IB_SA_EQ;
1711b6bbee68SJason Gunthorpe primary_path->mtu = IBA_GET(CM_REQ_PATH_PACKET_PAYLOAD_MTU, req_msg);
1712a977049dSHal Rosenstock primary_path->rate_selector = IB_SA_EQ;
1713b6bbee68SJason Gunthorpe primary_path->rate = IBA_GET(CM_REQ_PRIMARY_PACKET_RATE, req_msg);
1714a977049dSHal Rosenstock primary_path->packet_life_time_selector = IB_SA_EQ;
1715a977049dSHal Rosenstock primary_path->packet_life_time =
1716b6bbee68SJason Gunthorpe IBA_GET(CM_REQ_PRIMARY_LOCAL_ACK_TIMEOUT, req_msg);
1717a977049dSHal Rosenstock primary_path->packet_life_time -= (primary_path->packet_life_time > 0);
171891b60a71SJason Gunthorpe primary_path->service_id =
171991b60a71SJason Gunthorpe cpu_to_be64(IBA_GET(CM_REQ_SERVICE_ID, req_msg));
1720114cc9c4SParav Pandit if (sa_path_is_roce(primary_path))
1721114cc9c4SParav Pandit primary_path->roce.route_resolved = false;
1722a977049dSHal Rosenstock
1723ac3a949fSDasaratharaman Chandramouli if (cm_req_has_alt_path(req_msg)) {
17244ca662a3SJason Gunthorpe alt_path->dgid = *IBA_GET_MEM_PTR(
17254ca662a3SJason Gunthorpe CM_REQ_ALTERNATE_LOCAL_PORT_GID, req_msg);
17264ca662a3SJason Gunthorpe alt_path->sgid = *IBA_GET_MEM_PTR(
17274ca662a3SJason Gunthorpe CM_REQ_ALTERNATE_REMOTE_PORT_GID, req_msg);
172801adb7f4SJason Gunthorpe alt_path->flow_label = cpu_to_be32(
172901adb7f4SJason Gunthorpe IBA_GET(CM_REQ_ALTERNATE_FLOW_LABEL, req_msg));
173091b60a71SJason Gunthorpe alt_path->hop_limit =
173191b60a71SJason Gunthorpe IBA_GET(CM_REQ_ALTERNATE_HOP_LIMIT, req_msg);
173291b60a71SJason Gunthorpe alt_path->traffic_class =
173391b60a71SJason Gunthorpe IBA_GET(CM_REQ_ALTERNATE_TRAFFIC_CLASS, req_msg);
1734a977049dSHal Rosenstock alt_path->reversible = 1;
173591b60a71SJason Gunthorpe alt_path->pkey =
173691b60a71SJason Gunthorpe cpu_to_be16(IBA_GET(CM_REQ_PARTITION_KEY, req_msg));
1737b6bbee68SJason Gunthorpe alt_path->sl = IBA_GET(CM_REQ_ALTERNATE_SL, req_msg);
1738a977049dSHal Rosenstock alt_path->mtu_selector = IB_SA_EQ;
1739b6bbee68SJason Gunthorpe alt_path->mtu =
1740b6bbee68SJason Gunthorpe IBA_GET(CM_REQ_PATH_PACKET_PAYLOAD_MTU, req_msg);
1741a977049dSHal Rosenstock alt_path->rate_selector = IB_SA_EQ;
1742b6bbee68SJason Gunthorpe alt_path->rate = IBA_GET(CM_REQ_ALTERNATE_PACKET_RATE, req_msg);
1743a977049dSHal Rosenstock alt_path->packet_life_time_selector = IB_SA_EQ;
1744a977049dSHal Rosenstock alt_path->packet_life_time =
1745b6bbee68SJason Gunthorpe IBA_GET(CM_REQ_ALTERNATE_LOCAL_ACK_TIMEOUT, req_msg);
1746a977049dSHal Rosenstock alt_path->packet_life_time -= (alt_path->packet_life_time > 0);
174791b60a71SJason Gunthorpe alt_path->service_id =
174891b60a71SJason Gunthorpe cpu_to_be64(IBA_GET(CM_REQ_SERVICE_ID, req_msg));
1749114cc9c4SParav Pandit
1750114cc9c4SParav Pandit if (sa_path_is_roce(alt_path))
1751114cc9c4SParav Pandit alt_path->roce.route_resolved = false;
1752a977049dSHal Rosenstock }
1753b7d95040SMark Zhang cm_format_path_lid_from_req(req_msg, primary_path, alt_path, wc);
1754a977049dSHal Rosenstock }
1755a977049dSHal Rosenstock
cm_get_bth_pkey(struct cm_work * work)175624cad9a7SHaggai Eran static u16 cm_get_bth_pkey(struct cm_work *work)
175724cad9a7SHaggai Eran {
175824cad9a7SHaggai Eran struct ib_device *ib_dev = work->port->cm_dev->ib_device;
17591fb7f897SMark Bloch u32 port_num = work->port->port_num;
176024cad9a7SHaggai Eran u16 pkey_index = work->mad_recv_wc->wc->pkey_index;
176124cad9a7SHaggai Eran u16 pkey;
176224cad9a7SHaggai Eran int ret;
176324cad9a7SHaggai Eran
176424cad9a7SHaggai Eran ret = ib_get_cached_pkey(ib_dev, port_num, pkey_index, &pkey);
176524cad9a7SHaggai Eran if (ret) {
17663cea7b4aSWenpeng Liang dev_warn_ratelimited(&ib_dev->dev, "ib_cm: Couldn't retrieve pkey for incoming request (port %u, pkey index %u). %d\n",
176724cad9a7SHaggai Eran port_num, pkey_index, ret);
176824cad9a7SHaggai Eran return 0;
176924cad9a7SHaggai Eran }
177024cad9a7SHaggai Eran
177124cad9a7SHaggai Eran return pkey;
177224cad9a7SHaggai Eran }
177324cad9a7SHaggai Eran
1774c5c4e40eSDon Hiatt /**
17752988ca08SMauro Carvalho Chehab * cm_opa_to_ib_sgid - Convert OPA SGID to IB SGID
1776c5c4e40eSDon Hiatt * ULPs (such as IPoIB) do not understand OPA GIDs and will
1777c5c4e40eSDon Hiatt * reject them as the local_gid will not match the sgid. Therefore,
1778c5c4e40eSDon Hiatt * change the pathrec's SGID to an IB SGID.
1779c5c4e40eSDon Hiatt *
1780c5c4e40eSDon Hiatt * @work: Work completion
1781c5c4e40eSDon Hiatt * @path: Path record
1782c5c4e40eSDon Hiatt */
cm_opa_to_ib_sgid(struct cm_work * work,struct sa_path_rec * path)1783c5c4e40eSDon Hiatt static void cm_opa_to_ib_sgid(struct cm_work *work,
1784c5c4e40eSDon Hiatt struct sa_path_rec *path)
1785c5c4e40eSDon Hiatt {
1786c5c4e40eSDon Hiatt struct ib_device *dev = work->port->cm_dev->ib_device;
17871fb7f897SMark Bloch u32 port_num = work->port->port_num;
1788c5c4e40eSDon Hiatt
1789c5c4e40eSDon Hiatt if (rdma_cap_opa_ah(dev, port_num) &&
1790c5c4e40eSDon Hiatt (ib_is_opa_gid(&path->sgid))) {
1791c5c4e40eSDon Hiatt union ib_gid sgid;
1792c5c4e40eSDon Hiatt
17931dfce294SParav Pandit if (rdma_query_gid(dev, port_num, 0, &sgid)) {
1794c5c4e40eSDon Hiatt dev_warn(&dev->dev,
1795c5c4e40eSDon Hiatt "Error updating sgid in CM request\n");
1796c5c4e40eSDon Hiatt return;
1797c5c4e40eSDon Hiatt }
1798c5c4e40eSDon Hiatt
1799c5c4e40eSDon Hiatt path->sgid = sgid;
1800c5c4e40eSDon Hiatt }
1801c5c4e40eSDon Hiatt }
1802c5c4e40eSDon Hiatt
cm_format_req_event(struct cm_work * work,struct cm_id_private * cm_id_priv,struct ib_cm_id * listen_id)1803a977049dSHal Rosenstock static void cm_format_req_event(struct cm_work *work,
1804a977049dSHal Rosenstock struct cm_id_private *cm_id_priv,
1805a977049dSHal Rosenstock struct ib_cm_id *listen_id)
1806a977049dSHal Rosenstock {
1807a977049dSHal Rosenstock struct cm_req_msg *req_msg;
1808a977049dSHal Rosenstock struct ib_cm_req_event_param *param;
1809a977049dSHal Rosenstock
1810a977049dSHal Rosenstock req_msg = (struct cm_req_msg *)work->mad_recv_wc->recv_buf.mad;
1811a977049dSHal Rosenstock param = &work->cm_event.param.req_rcvd;
1812a977049dSHal Rosenstock param->listen_id = listen_id;
181324cad9a7SHaggai Eran param->bth_pkey = cm_get_bth_pkey(work);
1814a977049dSHal Rosenstock param->port = cm_id_priv->av.port->port_num;
1815a977049dSHal Rosenstock param->primary_path = &work->path[0];
1816c5c4e40eSDon Hiatt cm_opa_to_ib_sgid(work, param->primary_path);
1817c5c4e40eSDon Hiatt if (cm_req_has_alt_path(req_msg)) {
1818a977049dSHal Rosenstock param->alternate_path = &work->path[1];
1819c5c4e40eSDon Hiatt cm_opa_to_ib_sgid(work, param->alternate_path);
1820c5c4e40eSDon Hiatt } else {
1821a977049dSHal Rosenstock param->alternate_path = NULL;
1822c5c4e40eSDon Hiatt }
182391b60a71SJason Gunthorpe param->remote_ca_guid =
182491b60a71SJason Gunthorpe cpu_to_be64(IBA_GET(CM_REQ_LOCAL_CA_GUID, req_msg));
182591b60a71SJason Gunthorpe param->remote_qkey = IBA_GET(CM_REQ_LOCAL_Q_KEY, req_msg);
182601adb7f4SJason Gunthorpe param->remote_qpn = IBA_GET(CM_REQ_LOCAL_QPN, req_msg);
1827a977049dSHal Rosenstock param->qp_type = cm_req_get_qp_type(req_msg);
182801adb7f4SJason Gunthorpe param->starting_psn = IBA_GET(CM_REQ_STARTING_PSN, req_msg);
1829b6bbee68SJason Gunthorpe param->responder_resources = IBA_GET(CM_REQ_INITIATOR_DEPTH, req_msg);
1830b6bbee68SJason Gunthorpe param->initiator_depth = IBA_GET(CM_REQ_RESPONDER_RESOURCES, req_msg);
1831a977049dSHal Rosenstock param->local_cm_response_timeout =
1832b6bbee68SJason Gunthorpe IBA_GET(CM_REQ_REMOTE_CM_RESPONSE_TIMEOUT, req_msg);
1833b6bbee68SJason Gunthorpe param->flow_control = IBA_GET(CM_REQ_END_TO_END_FLOW_CONTROL, req_msg);
1834a977049dSHal Rosenstock param->remote_cm_response_timeout =
1835b6bbee68SJason Gunthorpe IBA_GET(CM_REQ_LOCAL_CM_RESPONSE_TIMEOUT, req_msg);
1836b6bbee68SJason Gunthorpe param->retry_count = IBA_GET(CM_REQ_RETRY_COUNT, req_msg);
1837b6bbee68SJason Gunthorpe param->rnr_retry_count = IBA_GET(CM_REQ_RNR_RETRY_COUNT, req_msg);
1838b6bbee68SJason Gunthorpe param->srq = IBA_GET(CM_REQ_SRQ, req_msg);
1839cee10433SParav Pandit param->ppath_sgid_attr = cm_id_priv->av.ah_attr.grh.sgid_attr;
1840a20652e1SLeon Romanovsky param->ece.vendor_id = IBA_GET(CM_REQ_VENDOR_ID, req_msg);
1841a20652e1SLeon Romanovsky param->ece.attr_mod = be32_to_cpu(req_msg->hdr.attr_mod);
1842a20652e1SLeon Romanovsky
18434ca662a3SJason Gunthorpe work->cm_event.private_data =
18444ca662a3SJason Gunthorpe IBA_GET_MEM_PTR(CM_REQ_PRIVATE_DATA, req_msg);
1845a977049dSHal Rosenstock }
1846a977049dSHal Rosenstock
cm_process_work(struct cm_id_private * cm_id_priv,struct cm_work * work)1847a977049dSHal Rosenstock static void cm_process_work(struct cm_id_private *cm_id_priv,
1848a977049dSHal Rosenstock struct cm_work *work)
1849a977049dSHal Rosenstock {
1850a977049dSHal Rosenstock int ret;
1851a977049dSHal Rosenstock
1852a977049dSHal Rosenstock /* We will typically only have the current event to report. */
1853a977049dSHal Rosenstock ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, &work->cm_event);
1854a977049dSHal Rosenstock cm_free_work(work);
1855a977049dSHal Rosenstock
1856a977049dSHal Rosenstock while (!ret && !atomic_add_negative(-1, &cm_id_priv->work_count)) {
185724be6e81SSean Hefty spin_lock_irq(&cm_id_priv->lock);
1858a977049dSHal Rosenstock work = cm_dequeue_work(cm_id_priv);
185924be6e81SSean Hefty spin_unlock_irq(&cm_id_priv->lock);
18602f5059a7SLeon Romanovsky if (!work)
18612f5059a7SLeon Romanovsky return;
18622f5059a7SLeon Romanovsky
1863a977049dSHal Rosenstock ret = cm_id_priv->id.cm_handler(&cm_id_priv->id,
1864a977049dSHal Rosenstock &work->cm_event);
1865a977049dSHal Rosenstock cm_free_work(work);
1866a977049dSHal Rosenstock }
1867a977049dSHal Rosenstock cm_deref_id(cm_id_priv);
1868a977049dSHal Rosenstock if (ret)
186904c33543SMichael S. Tsirkin cm_destroy_id(&cm_id_priv->id, ret);
1870a977049dSHal Rosenstock }
1871a977049dSHal Rosenstock
cm_format_mra(struct cm_mra_msg * mra_msg,struct cm_id_private * cm_id_priv,enum cm_msg_response msg_mraed,u8 service_timeout,const void * private_data,u8 private_data_len)1872a977049dSHal Rosenstock static void cm_format_mra(struct cm_mra_msg *mra_msg,
1873a977049dSHal Rosenstock struct cm_id_private *cm_id_priv,
1874a977049dSHal Rosenstock enum cm_msg_response msg_mraed, u8 service_timeout,
1875a977049dSHal Rosenstock const void *private_data, u8 private_data_len)
1876a977049dSHal Rosenstock {
1877a977049dSHal Rosenstock cm_format_mad_hdr(&mra_msg->hdr, CM_MRA_ATTR_ID, cm_id_priv->tid);
1878b6bbee68SJason Gunthorpe IBA_SET(CM_MRA_MESSAGE_MRAED, mra_msg, msg_mraed);
187991b60a71SJason Gunthorpe IBA_SET(CM_MRA_LOCAL_COMM_ID, mra_msg,
188091b60a71SJason Gunthorpe be32_to_cpu(cm_id_priv->id.local_id));
188191b60a71SJason Gunthorpe IBA_SET(CM_MRA_REMOTE_COMM_ID, mra_msg,
188291b60a71SJason Gunthorpe be32_to_cpu(cm_id_priv->id.remote_id));
1883b6bbee68SJason Gunthorpe IBA_SET(CM_MRA_SERVICE_TIMEOUT, mra_msg, service_timeout);
1884a977049dSHal Rosenstock
1885a977049dSHal Rosenstock if (private_data && private_data_len)
18864ca662a3SJason Gunthorpe IBA_SET_MEM(CM_MRA_PRIVATE_DATA, mra_msg, private_data,
18874ca662a3SJason Gunthorpe private_data_len);
1888a977049dSHal Rosenstock }
1889a977049dSHal Rosenstock
cm_format_rej(struct cm_rej_msg * rej_msg,struct cm_id_private * cm_id_priv,enum ib_cm_rej_reason reason,void * ari,u8 ari_length,const void * private_data,u8 private_data_len,enum ib_cm_state state)1890a977049dSHal Rosenstock static void cm_format_rej(struct cm_rej_msg *rej_msg,
1891a977049dSHal Rosenstock struct cm_id_private *cm_id_priv,
18920c6949c3SLeon Romanovsky enum ib_cm_rej_reason reason, void *ari,
18930c6949c3SLeon Romanovsky u8 ari_length, const void *private_data,
18940c6949c3SLeon Romanovsky u8 private_data_len, enum ib_cm_state state)
1895a977049dSHal Rosenstock {
189600777a68SJason Gunthorpe lockdep_assert_held(&cm_id_priv->lock);
189700777a68SJason Gunthorpe
1898a977049dSHal Rosenstock cm_format_mad_hdr(&rej_msg->hdr, CM_REJ_ATTR_ID, cm_id_priv->tid);
189991b60a71SJason Gunthorpe IBA_SET(CM_REJ_REMOTE_COMM_ID, rej_msg,
190091b60a71SJason Gunthorpe be32_to_cpu(cm_id_priv->id.remote_id));
1901a977049dSHal Rosenstock
19020c6949c3SLeon Romanovsky switch (state) {
1903a977049dSHal Rosenstock case IB_CM_REQ_RCVD:
190491b60a71SJason Gunthorpe IBA_SET(CM_REJ_LOCAL_COMM_ID, rej_msg, be32_to_cpu(0));
1905b6bbee68SJason Gunthorpe IBA_SET(CM_REJ_MESSAGE_REJECTED, rej_msg, CM_MSG_RESPONSE_REQ);
1906a977049dSHal Rosenstock break;
1907a977049dSHal Rosenstock case IB_CM_MRA_REQ_SENT:
190891b60a71SJason Gunthorpe IBA_SET(CM_REJ_LOCAL_COMM_ID, rej_msg,
190991b60a71SJason Gunthorpe be32_to_cpu(cm_id_priv->id.local_id));
1910b6bbee68SJason Gunthorpe IBA_SET(CM_REJ_MESSAGE_REJECTED, rej_msg, CM_MSG_RESPONSE_REQ);
1911a977049dSHal Rosenstock break;
1912a977049dSHal Rosenstock case IB_CM_REP_RCVD:
1913a977049dSHal Rosenstock case IB_CM_MRA_REP_SENT:
191491b60a71SJason Gunthorpe IBA_SET(CM_REJ_LOCAL_COMM_ID, rej_msg,
191591b60a71SJason Gunthorpe be32_to_cpu(cm_id_priv->id.local_id));
1916b6bbee68SJason Gunthorpe IBA_SET(CM_REJ_MESSAGE_REJECTED, rej_msg, CM_MSG_RESPONSE_REP);
1917a977049dSHal Rosenstock break;
1918a977049dSHal Rosenstock default:
191991b60a71SJason Gunthorpe IBA_SET(CM_REJ_LOCAL_COMM_ID, rej_msg,
192091b60a71SJason Gunthorpe be32_to_cpu(cm_id_priv->id.local_id));
1921b6bbee68SJason Gunthorpe IBA_SET(CM_REJ_MESSAGE_REJECTED, rej_msg,
1922b6bbee68SJason Gunthorpe CM_MSG_RESPONSE_OTHER);
1923a977049dSHal Rosenstock break;
1924a977049dSHal Rosenstock }
1925a977049dSHal Rosenstock
192691b60a71SJason Gunthorpe IBA_SET(CM_REJ_REASON, rej_msg, reason);
1927a977049dSHal Rosenstock if (ari && ari_length) {
1928b6bbee68SJason Gunthorpe IBA_SET(CM_REJ_REJECTED_INFO_LENGTH, rej_msg, ari_length);
19294ca662a3SJason Gunthorpe IBA_SET_MEM(CM_REJ_ARI, rej_msg, ari, ari_length);
1930a977049dSHal Rosenstock }
1931a977049dSHal Rosenstock
1932a977049dSHal Rosenstock if (private_data && private_data_len)
19334ca662a3SJason Gunthorpe IBA_SET_MEM(CM_REJ_PRIVATE_DATA, rej_msg, private_data,
19344ca662a3SJason Gunthorpe private_data_len);
1935a977049dSHal Rosenstock }
1936a977049dSHal Rosenstock
cm_dup_req_handler(struct cm_work * work,struct cm_id_private * cm_id_priv)1937a977049dSHal Rosenstock static void cm_dup_req_handler(struct cm_work *work,
1938a977049dSHal Rosenstock struct cm_id_private *cm_id_priv)
1939a977049dSHal Rosenstock {
1940a977049dSHal Rosenstock struct ib_mad_send_buf *msg = NULL;
1941a977049dSHal Rosenstock int ret;
1942a977049dSHal Rosenstock
1943526a12c8SJason Gunthorpe atomic_long_inc(
1944526a12c8SJason Gunthorpe &work->port->counters[CM_RECV_DUPLICATES][CM_REQ_COUNTER]);
19459af57b7aSSean Hefty
1946a977049dSHal Rosenstock /* Quick state check to discard duplicate REQs. */
1947d1de9a88SJason Gunthorpe spin_lock_irq(&cm_id_priv->lock);
1948d1de9a88SJason Gunthorpe if (cm_id_priv->id.state == IB_CM_REQ_RCVD) {
1949d1de9a88SJason Gunthorpe spin_unlock_irq(&cm_id_priv->lock);
1950a977049dSHal Rosenstock return;
1951d1de9a88SJason Gunthorpe }
1952d1de9a88SJason Gunthorpe spin_unlock_irq(&cm_id_priv->lock);
1953a977049dSHal Rosenstock
1954a977049dSHal Rosenstock ret = cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg);
1955a977049dSHal Rosenstock if (ret)
1956a977049dSHal Rosenstock return;
1957a977049dSHal Rosenstock
195824be6e81SSean Hefty spin_lock_irq(&cm_id_priv->lock);
1959a977049dSHal Rosenstock switch (cm_id_priv->id.state) {
1960a977049dSHal Rosenstock case IB_CM_MRA_REQ_SENT:
1961a977049dSHal Rosenstock cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
1962a977049dSHal Rosenstock CM_MSG_RESPONSE_REQ, cm_id_priv->service_timeout,
1963a977049dSHal Rosenstock cm_id_priv->private_data,
1964a977049dSHal Rosenstock cm_id_priv->private_data_len);
1965a977049dSHal Rosenstock break;
1966a977049dSHal Rosenstock case IB_CM_TIMEWAIT:
1967a977049dSHal Rosenstock cm_format_rej((struct cm_rej_msg *)msg->mad, cm_id_priv,
19680c6949c3SLeon Romanovsky IB_CM_REJ_STALE_CONN, NULL, 0, NULL, 0,
19690c6949c3SLeon Romanovsky IB_CM_TIMEWAIT);
1970a977049dSHal Rosenstock break;
1971a977049dSHal Rosenstock default:
1972a977049dSHal Rosenstock goto unlock;
1973a977049dSHal Rosenstock }
197424be6e81SSean Hefty spin_unlock_irq(&cm_id_priv->lock);
1975a977049dSHal Rosenstock
19768dc105beSChuck Lever trace_icm_send_dup_req(&cm_id_priv->id);
197734816ad9SSean Hefty ret = ib_post_send_mad(msg, NULL);
1978a977049dSHal Rosenstock if (ret)
1979a977049dSHal Rosenstock goto free;
1980a977049dSHal Rosenstock return;
1981a977049dSHal Rosenstock
198224be6e81SSean Hefty unlock: spin_unlock_irq(&cm_id_priv->lock);
198396376a40SJason Gunthorpe free: cm_free_response_msg(msg);
1984a977049dSHal Rosenstock }
1985a977049dSHal Rosenstock
cm_match_req(struct cm_work * work,struct cm_id_private * cm_id_priv)1986a977049dSHal Rosenstock static struct cm_id_private *cm_match_req(struct cm_work *work,
1987a977049dSHal Rosenstock struct cm_id_private *cm_id_priv)
1988a977049dSHal Rosenstock {
1989a977049dSHal Rosenstock struct cm_id_private *listen_cm_id_priv, *cur_cm_id_priv;
1990a977049dSHal Rosenstock struct cm_timewait_info *timewait_info;
1991a977049dSHal Rosenstock struct cm_req_msg *req_msg;
1992a977049dSHal Rosenstock
1993a977049dSHal Rosenstock req_msg = (struct cm_req_msg *)work->mad_recv_wc->recv_buf.mad;
1994a977049dSHal Rosenstock
1995d998ccceSSean Hefty /* Check for possible duplicate REQ. */
199624be6e81SSean Hefty spin_lock_irq(&cm.lock);
1997a977049dSHal Rosenstock timewait_info = cm_insert_remote_id(cm_id_priv->timewait_info);
1998a977049dSHal Rosenstock if (timewait_info) {
19994d6e8a03SDanit Goldberg cur_cm_id_priv = cm_acquire_id(timewait_info->work.local_id,
2000a977049dSHal Rosenstock timewait_info->work.remote_id);
200124be6e81SSean Hefty spin_unlock_irq(&cm.lock);
2002a977049dSHal Rosenstock if (cur_cm_id_priv) {
2003a977049dSHal Rosenstock cm_dup_req_handler(work, cur_cm_id_priv);
2004a977049dSHal Rosenstock cm_deref_id(cur_cm_id_priv);
2005d998ccceSSean Hefty }
2006d998ccceSSean Hefty return NULL;
2007d998ccceSSean Hefty }
2008d998ccceSSean Hefty
2009d998ccceSSean Hefty /* Check for stale connections. */
2010d998ccceSSean Hefty timewait_info = cm_insert_remote_qpn(cm_id_priv->timewait_info);
2011d998ccceSSean Hefty if (timewait_info) {
20129767a27eSJason Gunthorpe cm_remove_remote(cm_id_priv);
20134d6e8a03SDanit Goldberg cur_cm_id_priv = cm_acquire_id(timewait_info->work.local_id,
20149315bc9aSHans Westgaard Ry timewait_info->work.remote_id);
20159315bc9aSHans Westgaard Ry
201624be6e81SSean Hefty spin_unlock_irq(&cm.lock);
2017a977049dSHal Rosenstock cm_issue_rej(work->port, work->mad_recv_wc,
2018a977049dSHal Rosenstock IB_CM_REJ_STALE_CONN, CM_MSG_RESPONSE_REQ,
2019a977049dSHal Rosenstock NULL, 0);
20209315bc9aSHans Westgaard Ry if (cur_cm_id_priv) {
202151e8463cSJason Gunthorpe ib_send_cm_dreq(&cur_cm_id_priv->id, NULL, 0);
20229315bc9aSHans Westgaard Ry cm_deref_id(cur_cm_id_priv);
20239315bc9aSHans Westgaard Ry }
2024d998ccceSSean Hefty return NULL;
2025a977049dSHal Rosenstock }
2026a977049dSHal Rosenstock
2027a977049dSHal Rosenstock /* Find matching listen request. */
202891b60a71SJason Gunthorpe listen_cm_id_priv = cm_find_listen(
202991b60a71SJason Gunthorpe cm_id_priv->id.device,
203091b60a71SJason Gunthorpe cpu_to_be64(IBA_GET(CM_REQ_SERVICE_ID, req_msg)));
2031a977049dSHal Rosenstock if (!listen_cm_id_priv) {
20329767a27eSJason Gunthorpe cm_remove_remote(cm_id_priv);
203324be6e81SSean Hefty spin_unlock_irq(&cm.lock);
2034a977049dSHal Rosenstock cm_issue_rej(work->port, work->mad_recv_wc,
2035a977049dSHal Rosenstock IB_CM_REJ_INVALID_SERVICE_ID, CM_MSG_RESPONSE_REQ,
2036a977049dSHal Rosenstock NULL, 0);
2037c206f8baSJason Gunthorpe return NULL;
2038a977049dSHal Rosenstock }
203924be6e81SSean Hefty spin_unlock_irq(&cm.lock);
2040a977049dSHal Rosenstock return listen_cm_id_priv;
2041a977049dSHal Rosenstock }
2042a977049dSHal Rosenstock
20433971c9f6SSean Hefty /*
20443971c9f6SSean Hefty * Work-around for inter-subnet connections. If the LIDs are permissive,
20453971c9f6SSean Hefty * we need to override the LID/SL data in the REQ with the LID information
20463971c9f6SSean Hefty * in the work completion.
20473971c9f6SSean Hefty */
cm_process_routed_req(struct cm_req_msg * req_msg,struct ib_wc * wc)20483971c9f6SSean Hefty static void cm_process_routed_req(struct cm_req_msg *req_msg, struct ib_wc *wc)
20493971c9f6SSean Hefty {
2050b6bbee68SJason Gunthorpe if (!IBA_GET(CM_REQ_PRIMARY_SUBNET_LOCAL, req_msg)) {
205191b60a71SJason Gunthorpe if (cpu_to_be16(IBA_GET(CM_REQ_PRIMARY_LOCAL_PORT_LID,
205291b60a71SJason Gunthorpe req_msg)) == IB_LID_PERMISSIVE) {
205391b60a71SJason Gunthorpe IBA_SET(CM_REQ_PRIMARY_LOCAL_PORT_LID, req_msg,
205491b60a71SJason Gunthorpe be16_to_cpu(ib_lid_be16(wc->slid)));
2055b6bbee68SJason Gunthorpe IBA_SET(CM_REQ_PRIMARY_SL, req_msg, wc->sl);
20563971c9f6SSean Hefty }
20573971c9f6SSean Hefty
205891b60a71SJason Gunthorpe if (cpu_to_be16(IBA_GET(CM_REQ_PRIMARY_REMOTE_PORT_LID,
205991b60a71SJason Gunthorpe req_msg)) == IB_LID_PERMISSIVE)
206091b60a71SJason Gunthorpe IBA_SET(CM_REQ_PRIMARY_REMOTE_PORT_LID, req_msg,
206191b60a71SJason Gunthorpe wc->dlid_path_bits);
20623971c9f6SSean Hefty }
20633971c9f6SSean Hefty
2064b6bbee68SJason Gunthorpe if (!IBA_GET(CM_REQ_ALTERNATE_SUBNET_LOCAL, req_msg)) {
206591b60a71SJason Gunthorpe if (cpu_to_be16(IBA_GET(CM_REQ_ALTERNATE_LOCAL_PORT_LID,
206691b60a71SJason Gunthorpe req_msg)) == IB_LID_PERMISSIVE) {
206791b60a71SJason Gunthorpe IBA_SET(CM_REQ_ALTERNATE_LOCAL_PORT_LID, req_msg,
206891b60a71SJason Gunthorpe be16_to_cpu(ib_lid_be16(wc->slid)));
2069b6bbee68SJason Gunthorpe IBA_SET(CM_REQ_ALTERNATE_SL, req_msg, wc->sl);
20703971c9f6SSean Hefty }
20713971c9f6SSean Hefty
207291b60a71SJason Gunthorpe if (cpu_to_be16(IBA_GET(CM_REQ_ALTERNATE_REMOTE_PORT_LID,
207391b60a71SJason Gunthorpe req_msg)) == IB_LID_PERMISSIVE)
207491b60a71SJason Gunthorpe IBA_SET(CM_REQ_ALTERNATE_REMOTE_PORT_LID, req_msg,
207591b60a71SJason Gunthorpe wc->dlid_path_bits);
20763971c9f6SSean Hefty }
20773971c9f6SSean Hefty }
20783971c9f6SSean Hefty
cm_req_handler(struct cm_work * work)2079a977049dSHal Rosenstock static int cm_req_handler(struct cm_work *work)
2080a977049dSHal Rosenstock {
2081a977049dSHal Rosenstock struct cm_id_private *cm_id_priv, *listen_cm_id_priv;
2082a977049dSHal Rosenstock struct cm_req_msg *req_msg;
2083d8966fcdSDasaratharaman Chandramouli const struct ib_global_route *grh;
2084a8872d53SParav Pandit const struct ib_gid_attr *gid_attr;
2085a977049dSHal Rosenstock int ret;
2086a977049dSHal Rosenstock
2087a977049dSHal Rosenstock req_msg = (struct cm_req_msg *)work->mad_recv_wc->recv_buf.mad;
2088a977049dSHal Rosenstock
2089c206f8baSJason Gunthorpe cm_id_priv =
2090c206f8baSJason Gunthorpe cm_alloc_id_priv(work->port->cm_dev->ib_device, NULL, NULL);
2091c206f8baSJason Gunthorpe if (IS_ERR(cm_id_priv))
2092c206f8baSJason Gunthorpe return PTR_ERR(cm_id_priv);
2093a977049dSHal Rosenstock
209491b60a71SJason Gunthorpe cm_id_priv->id.remote_id =
209591b60a71SJason Gunthorpe cpu_to_be32(IBA_GET(CM_REQ_LOCAL_COMM_ID, req_msg));
2096c206f8baSJason Gunthorpe cm_id_priv->id.service_id =
2097c206f8baSJason Gunthorpe cpu_to_be64(IBA_GET(CM_REQ_SERVICE_ID, req_msg));
2098c206f8baSJason Gunthorpe cm_id_priv->tid = req_msg->hdr.tid;
2099c206f8baSJason Gunthorpe cm_id_priv->timeout_ms = cm_convert_to_ms(
2100c206f8baSJason Gunthorpe IBA_GET(CM_REQ_LOCAL_CM_RESPONSE_TIMEOUT, req_msg));
2101c206f8baSJason Gunthorpe cm_id_priv->max_cm_retries = IBA_GET(CM_REQ_MAX_CM_RETRIES, req_msg);
2102c206f8baSJason Gunthorpe cm_id_priv->remote_qpn =
2103c206f8baSJason Gunthorpe cpu_to_be32(IBA_GET(CM_REQ_LOCAL_QPN, req_msg));
2104c206f8baSJason Gunthorpe cm_id_priv->initiator_depth =
2105c206f8baSJason Gunthorpe IBA_GET(CM_REQ_RESPONDER_RESOURCES, req_msg);
2106c206f8baSJason Gunthorpe cm_id_priv->responder_resources =
2107c206f8baSJason Gunthorpe IBA_GET(CM_REQ_INITIATOR_DEPTH, req_msg);
2108c206f8baSJason Gunthorpe cm_id_priv->path_mtu = IBA_GET(CM_REQ_PATH_PACKET_PAYLOAD_MTU, req_msg);
2109c206f8baSJason Gunthorpe cm_id_priv->pkey = cpu_to_be16(IBA_GET(CM_REQ_PARTITION_KEY, req_msg));
2110c206f8baSJason Gunthorpe cm_id_priv->sq_psn = cpu_to_be32(IBA_GET(CM_REQ_STARTING_PSN, req_msg));
2111c206f8baSJason Gunthorpe cm_id_priv->retry_count = IBA_GET(CM_REQ_RETRY_COUNT, req_msg);
2112c206f8baSJason Gunthorpe cm_id_priv->rnr_retry_count = IBA_GET(CM_REQ_RNR_RETRY_COUNT, req_msg);
2113c206f8baSJason Gunthorpe cm_id_priv->qp_type = cm_req_get_qp_type(req_msg);
2114c206f8baSJason Gunthorpe
21150c4386ecSParav Pandit ret = cm_init_av_for_response(work->port, work->mad_recv_wc->wc,
2116ca222c6bSSean Hefty work->mad_recv_wc->recv_buf.grh,
2117a977049dSHal Rosenstock &cm_id_priv->av);
21180c4386ecSParav Pandit if (ret)
21190c4386ecSParav Pandit goto destroy;
2120a977049dSHal Rosenstock cm_id_priv->timewait_info = cm_create_timewait_info(cm_id_priv->
2121a977049dSHal Rosenstock id.local_id);
2122a977049dSHal Rosenstock if (IS_ERR(cm_id_priv->timewait_info)) {
2123a977049dSHal Rosenstock ret = PTR_ERR(cm_id_priv->timewait_info);
2124340b940eSLeon Romanovsky cm_id_priv->timewait_info = NULL;
212576842405SSean Hefty goto destroy;
2126a977049dSHal Rosenstock }
2127c206f8baSJason Gunthorpe cm_id_priv->timewait_info->work.remote_id = cm_id_priv->id.remote_id;
212891b60a71SJason Gunthorpe cm_id_priv->timewait_info->remote_ca_guid =
212991b60a71SJason Gunthorpe cpu_to_be64(IBA_GET(CM_REQ_LOCAL_CA_GUID, req_msg));
2130c206f8baSJason Gunthorpe cm_id_priv->timewait_info->remote_qpn = cm_id_priv->remote_qpn;
2131c206f8baSJason Gunthorpe
2132c206f8baSJason Gunthorpe /*
2133c206f8baSJason Gunthorpe * Note that the ID pointer is not in the xarray at this point,
2134c206f8baSJason Gunthorpe * so this set is only visible to the local thread.
2135c206f8baSJason Gunthorpe */
2136c206f8baSJason Gunthorpe cm_id_priv->id.state = IB_CM_REQ_RCVD;
2137a977049dSHal Rosenstock
2138a977049dSHal Rosenstock listen_cm_id_priv = cm_match_req(work, cm_id_priv);
2139a977049dSHal Rosenstock if (!listen_cm_id_priv) {
214075874b3dSChuck Lever trace_icm_no_listener_err(&cm_id_priv->id);
2141c206f8baSJason Gunthorpe cm_id_priv->id.state = IB_CM_IDLE;
2142a977049dSHal Rosenstock ret = -EINVAL;
2143bede86a3SJason Gunthorpe goto destroy;
2144a977049dSHal Rosenstock }
2145a977049dSHal Rosenstock
21469fdca4daSDasaratharaman Chandramouli memset(&work->path[0], 0, sizeof(work->path[0]));
21475a3dc323SParav Pandit if (cm_req_has_alt_path(req_msg))
21489fdca4daSDasaratharaman Chandramouli memset(&work->path[1], 0, sizeof(work->path[1]));
2149d8966fcdSDasaratharaman Chandramouli grh = rdma_ah_read_grh(&cm_id_priv->av.ah_attr);
2150a8872d53SParav Pandit gid_attr = grh->sgid_attr;
215116c72e40SParav Pandit
215265d4801aSHåkon Bugge if (cm_id_priv->av.ah_attr.type == RDMA_AH_ATTR_TYPE_ROCE) {
2153dfa834e1SDasaratharaman Chandramouli work->path[0].rec_type =
2154a8872d53SParav Pandit sa_conv_gid_to_pathrec_type(gid_attr->gid_type);
2155dfa834e1SDasaratharaman Chandramouli } else {
215665d4801aSHåkon Bugge cm_process_routed_req(req_msg, work->mad_recv_wc->wc);
21574ca662a3SJason Gunthorpe cm_path_set_rec_type(
21584ca662a3SJason Gunthorpe work->port->cm_dev->ib_device, work->port->port_num,
21596b3c0e6eSDasaratharaman Chandramouli &work->path[0],
21604ca662a3SJason Gunthorpe IBA_GET_MEM_PTR(CM_REQ_PRIMARY_LOCAL_PORT_GID,
21614ca662a3SJason Gunthorpe req_msg));
216220029832SMatan Barak }
21636b3c0e6eSDasaratharaman Chandramouli if (cm_req_has_alt_path(req_msg))
21649fdca4daSDasaratharaman Chandramouli work->path[1].rec_type = work->path[0].rec_type;
21659fdca4daSDasaratharaman Chandramouli cm_format_paths_from_req(req_msg, &work->path[0],
2166b7d95040SMark Zhang &work->path[1], work->mad_recv_wc->wc);
21679fdca4daSDasaratharaman Chandramouli if (cm_id_priv->av.ah_attr.type == RDMA_AH_ATTR_TYPE_ROCE)
21689fdca4daSDasaratharaman Chandramouli sa_path_set_dmac(&work->path[0],
21699fdca4daSDasaratharaman Chandramouli cm_id_priv->av.ah_attr.roce.dmac);
21709fdca4daSDasaratharaman Chandramouli work->path[0].hop_limit = grh->hop_limit;
217176039ac9SMark Zhang
217276039ac9SMark Zhang /* This destroy call is needed to pair with cm_init_av_for_response */
217376039ac9SMark Zhang cm_destroy_av(&cm_id_priv->av);
21743595c398SMark Zhang ret = cm_init_av_by_path(&work->path[0], gid_attr, &cm_id_priv->av);
217576842405SSean Hefty if (ret) {
217616c72e40SParav Pandit int err;
217716c72e40SParav Pandit
21781dfce294SParav Pandit err = rdma_query_gid(work->port->cm_dev->ib_device,
2179cb57bb84SMatan Barak work->port->port_num, 0,
21801dfce294SParav Pandit &work->path[0].sgid);
218116c72e40SParav Pandit if (err)
2182c206f8baSJason Gunthorpe ib_send_cm_rej(&cm_id_priv->id, IB_CM_REJ_INVALID_GID,
218316c72e40SParav Pandit NULL, 0, NULL, 0);
218416c72e40SParav Pandit else
2185c206f8baSJason Gunthorpe ib_send_cm_rej(&cm_id_priv->id, IB_CM_REJ_INVALID_GID,
218616c72e40SParav Pandit &work->path[0].sgid,
218716c72e40SParav Pandit sizeof(work->path[0].sgid),
218876842405SSean Hefty NULL, 0);
218976842405SSean Hefty goto rejected;
219076842405SSean Hefty }
2191eb8336dbSMark Zhang if (cm_id_priv->av.ah_attr.type == RDMA_AH_ATTR_TYPE_IB)
2192eb8336dbSMark Zhang cm_id_priv->av.dlid_datapath =
2193eb8336dbSMark Zhang IBA_GET(CM_REQ_PRIMARY_LOCAL_PORT_LID, req_msg);
2194eb8336dbSMark Zhang
21956b3c0e6eSDasaratharaman Chandramouli if (cm_req_has_alt_path(req_msg)) {
219639839107SParav Pandit ret = cm_init_av_by_path(&work->path[1], NULL,
21973595c398SMark Zhang &cm_id_priv->alt_av);
219876842405SSean Hefty if (ret) {
2199c206f8baSJason Gunthorpe ib_send_cm_rej(&cm_id_priv->id,
2200c206f8baSJason Gunthorpe IB_CM_REJ_INVALID_ALT_GID,
220176842405SSean Hefty &work->path[0].sgid,
220216c72e40SParav Pandit sizeof(work->path[0].sgid), NULL, 0);
220376842405SSean Hefty goto rejected;
220476842405SSean Hefty }
2205a977049dSHal Rosenstock }
2206a977049dSHal Rosenstock
2207c206f8baSJason Gunthorpe cm_id_priv->id.cm_handler = listen_cm_id_priv->id.cm_handler;
2208c206f8baSJason Gunthorpe cm_id_priv->id.context = listen_cm_id_priv->id.context;
2209a977049dSHal Rosenstock cm_format_req_event(work, cm_id_priv, &listen_cm_id_priv->id);
2210c206f8baSJason Gunthorpe
2211c206f8baSJason Gunthorpe /* Now MAD handlers can see the new ID */
2212c206f8baSJason Gunthorpe spin_lock_irq(&cm_id_priv->lock);
2213c206f8baSJason Gunthorpe cm_finalize_id(cm_id_priv);
2214c206f8baSJason Gunthorpe
2215c206f8baSJason Gunthorpe /* Refcount belongs to the event, pairs with cm_process_work() */
2216c206f8baSJason Gunthorpe refcount_inc(&cm_id_priv->refcount);
2217e83f195aSJason Gunthorpe cm_queue_work_unlock(cm_id_priv, work);
2218c206f8baSJason Gunthorpe /*
2219c206f8baSJason Gunthorpe * Since this ID was just created and was not made visible to other MAD
2220c206f8baSJason Gunthorpe * handlers until the cm_finalize_id() above we know that the
2221c206f8baSJason Gunthorpe * cm_process_work() will deliver the event and the listen_cm_id
2222c206f8baSJason Gunthorpe * embedded in the event can be derefed here.
2223c206f8baSJason Gunthorpe */
2224a977049dSHal Rosenstock cm_deref_id(listen_cm_id_priv);
2225a977049dSHal Rosenstock return 0;
2226a977049dSHal Rosenstock
222776842405SSean Hefty rejected:
2228a977049dSHal Rosenstock cm_deref_id(listen_cm_id_priv);
222976842405SSean Hefty destroy:
2230c206f8baSJason Gunthorpe ib_destroy_cm_id(&cm_id_priv->id);
2231a977049dSHal Rosenstock return ret;
2232a977049dSHal Rosenstock }
2233a977049dSHal Rosenstock
cm_format_rep(struct cm_rep_msg * rep_msg,struct cm_id_private * cm_id_priv,struct ib_cm_rep_param * param)2234a977049dSHal Rosenstock static void cm_format_rep(struct cm_rep_msg *rep_msg,
2235a977049dSHal Rosenstock struct cm_id_private *cm_id_priv,
2236a977049dSHal Rosenstock struct ib_cm_rep_param *param)
2237a977049dSHal Rosenstock {
2238a20652e1SLeon Romanovsky cm_format_mad_ece_hdr(&rep_msg->hdr, CM_REP_ATTR_ID, cm_id_priv->tid,
2239a20652e1SLeon Romanovsky param->ece.attr_mod);
224091b60a71SJason Gunthorpe IBA_SET(CM_REP_LOCAL_COMM_ID, rep_msg,
224191b60a71SJason Gunthorpe be32_to_cpu(cm_id_priv->id.local_id));
224291b60a71SJason Gunthorpe IBA_SET(CM_REP_REMOTE_COMM_ID, rep_msg,
224391b60a71SJason Gunthorpe be32_to_cpu(cm_id_priv->id.remote_id));
224401adb7f4SJason Gunthorpe IBA_SET(CM_REP_STARTING_PSN, rep_msg, param->starting_psn);
224591b60a71SJason Gunthorpe IBA_SET(CM_REP_RESPONDER_RESOURCES, rep_msg,
224691b60a71SJason Gunthorpe param->responder_resources);
2247b6bbee68SJason Gunthorpe IBA_SET(CM_REP_TARGET_ACK_DELAY, rep_msg,
22481d846126SSean Hefty cm_id_priv->av.port->cm_dev->ack_delay);
2249b6bbee68SJason Gunthorpe IBA_SET(CM_REP_FAILOVER_ACCEPTED, rep_msg, param->failover_accepted);
2250b6bbee68SJason Gunthorpe IBA_SET(CM_REP_RNR_RETRY_COUNT, rep_msg, param->rnr_retry_count);
225191b60a71SJason Gunthorpe IBA_SET(CM_REP_LOCAL_CA_GUID, rep_msg,
225291b60a71SJason Gunthorpe be64_to_cpu(cm_id_priv->id.device->node_guid));
2253a977049dSHal Rosenstock
2254d26a360bSSean Hefty if (cm_id_priv->qp_type != IB_QPT_XRC_TGT) {
225591b60a71SJason Gunthorpe IBA_SET(CM_REP_INITIATOR_DEPTH, rep_msg,
225691b60a71SJason Gunthorpe param->initiator_depth);
2257b6bbee68SJason Gunthorpe IBA_SET(CM_REP_END_TO_END_FLOW_CONTROL, rep_msg,
2258b6bbee68SJason Gunthorpe param->flow_control);
2259b6bbee68SJason Gunthorpe IBA_SET(CM_REP_SRQ, rep_msg, param->srq);
226001adb7f4SJason Gunthorpe IBA_SET(CM_REP_LOCAL_QPN, rep_msg, param->qp_num);
2261d26a360bSSean Hefty } else {
2262b6bbee68SJason Gunthorpe IBA_SET(CM_REP_SRQ, rep_msg, 1);
226301adb7f4SJason Gunthorpe IBA_SET(CM_REP_LOCAL_EE_CONTEXT_NUMBER, rep_msg, param->qp_num);
2264d26a360bSSean Hefty }
2265d26a360bSSean Hefty
2266a20652e1SLeon Romanovsky IBA_SET(CM_REP_VENDOR_ID_L, rep_msg, param->ece.vendor_id);
2267a20652e1SLeon Romanovsky IBA_SET(CM_REP_VENDOR_ID_M, rep_msg, param->ece.vendor_id >> 8);
2268a20652e1SLeon Romanovsky IBA_SET(CM_REP_VENDOR_ID_H, rep_msg, param->ece.vendor_id >> 16);
2269a20652e1SLeon Romanovsky
2270a977049dSHal Rosenstock if (param->private_data && param->private_data_len)
22714ca662a3SJason Gunthorpe IBA_SET_MEM(CM_REP_PRIVATE_DATA, rep_msg, param->private_data,
2272a977049dSHal Rosenstock param->private_data_len);
2273a977049dSHal Rosenstock }
2274a977049dSHal Rosenstock
ib_send_cm_rep(struct ib_cm_id * cm_id,struct ib_cm_rep_param * param)2275a977049dSHal Rosenstock int ib_send_cm_rep(struct ib_cm_id *cm_id,
2276a977049dSHal Rosenstock struct ib_cm_rep_param *param)
2277a977049dSHal Rosenstock {
2278a977049dSHal Rosenstock struct cm_id_private *cm_id_priv;
2279a977049dSHal Rosenstock struct ib_mad_send_buf *msg;
2280a977049dSHal Rosenstock struct cm_rep_msg *rep_msg;
2281a977049dSHal Rosenstock unsigned long flags;
2282a977049dSHal Rosenstock int ret;
2283a977049dSHal Rosenstock
2284a977049dSHal Rosenstock if (param->private_data &&
2285a977049dSHal Rosenstock param->private_data_len > IB_CM_REP_PRIVATE_DATA_SIZE)
2286a977049dSHal Rosenstock return -EINVAL;
2287a977049dSHal Rosenstock
2288a977049dSHal Rosenstock cm_id_priv = container_of(cm_id, struct cm_id_private, id);
2289a977049dSHal Rosenstock spin_lock_irqsave(&cm_id_priv->lock, flags);
2290a977049dSHal Rosenstock if (cm_id->state != IB_CM_REQ_RCVD &&
2291a977049dSHal Rosenstock cm_id->state != IB_CM_MRA_REQ_SENT) {
229275874b3dSChuck Lever trace_icm_send_rep_err(cm_id_priv->id.local_id, cm_id->state);
2293a977049dSHal Rosenstock ret = -EINVAL;
2294a977049dSHal Rosenstock goto out;
2295a977049dSHal Rosenstock }
2296a977049dSHal Rosenstock
22974b4e586eSJason Gunthorpe msg = cm_alloc_priv_msg(cm_id_priv);
22984b4e586eSJason Gunthorpe if (IS_ERR(msg)) {
22994b4e586eSJason Gunthorpe ret = PTR_ERR(msg);
2300a977049dSHal Rosenstock goto out;
23014b4e586eSJason Gunthorpe }
2302a977049dSHal Rosenstock
2303a977049dSHal Rosenstock rep_msg = (struct cm_rep_msg *) msg->mad;
2304a977049dSHal Rosenstock cm_format_rep(rep_msg, cm_id_priv, param);
230534816ad9SSean Hefty msg->timeout_ms = cm_id_priv->timeout_ms;
2306a977049dSHal Rosenstock msg->context[1] = (void *) (unsigned long) IB_CM_REP_SENT;
2307a977049dSHal Rosenstock
23088dc105beSChuck Lever trace_icm_send_rep(cm_id);
230934816ad9SSean Hefty ret = ib_post_send_mad(msg, NULL);
23104b4e586eSJason Gunthorpe if (ret)
23114b4e586eSJason Gunthorpe goto out_free;
2312a977049dSHal Rosenstock
2313a977049dSHal Rosenstock cm_id->state = IB_CM_REP_SENT;
2314a977049dSHal Rosenstock cm_id_priv->initiator_depth = param->initiator_depth;
2315a977049dSHal Rosenstock cm_id_priv->responder_resources = param->responder_resources;
231601adb7f4SJason Gunthorpe cm_id_priv->rq_psn = cpu_to_be32(IBA_GET(CM_REP_STARTING_PSN, rep_msg));
2317ca750d4aSLeon Romanovsky WARN_ONCE(param->qp_num & 0xFF000000,
2318ca750d4aSLeon Romanovsky "IBTA declares QPN to be 24 bits, but it is 0x%X\n",
2319ca750d4aSLeon Romanovsky param->qp_num);
2320ef700446SSean Hefty cm_id_priv->local_qpn = cpu_to_be32(param->qp_num & 0xFFFFFF);
23214b4e586eSJason Gunthorpe spin_unlock_irqrestore(&cm_id_priv->lock, flags);
23224b4e586eSJason Gunthorpe return 0;
2323a977049dSHal Rosenstock
23244b4e586eSJason Gunthorpe out_free:
23254b4e586eSJason Gunthorpe cm_free_priv_msg(msg);
23264b4e586eSJason Gunthorpe out:
23274b4e586eSJason Gunthorpe spin_unlock_irqrestore(&cm_id_priv->lock, flags);
2328a977049dSHal Rosenstock return ret;
2329a977049dSHal Rosenstock }
2330a977049dSHal Rosenstock EXPORT_SYMBOL(ib_send_cm_rep);
2331a977049dSHal Rosenstock
cm_format_rtu(struct cm_rtu_msg * rtu_msg,struct cm_id_private * cm_id_priv,const void * private_data,u8 private_data_len)2332a977049dSHal Rosenstock static void cm_format_rtu(struct cm_rtu_msg *rtu_msg,
2333a977049dSHal Rosenstock struct cm_id_private *cm_id_priv,
2334a977049dSHal Rosenstock const void *private_data,
2335a977049dSHal Rosenstock u8 private_data_len)
2336a977049dSHal Rosenstock {
2337a977049dSHal Rosenstock cm_format_mad_hdr(&rtu_msg->hdr, CM_RTU_ATTR_ID, cm_id_priv->tid);
233891b60a71SJason Gunthorpe IBA_SET(CM_RTU_LOCAL_COMM_ID, rtu_msg,
233991b60a71SJason Gunthorpe be32_to_cpu(cm_id_priv->id.local_id));
234091b60a71SJason Gunthorpe IBA_SET(CM_RTU_REMOTE_COMM_ID, rtu_msg,
234191b60a71SJason Gunthorpe be32_to_cpu(cm_id_priv->id.remote_id));
2342a977049dSHal Rosenstock
2343a977049dSHal Rosenstock if (private_data && private_data_len)
23444ca662a3SJason Gunthorpe IBA_SET_MEM(CM_RTU_PRIVATE_DATA, rtu_msg, private_data,
23454ca662a3SJason Gunthorpe private_data_len);
2346a977049dSHal Rosenstock }
2347a977049dSHal Rosenstock
ib_send_cm_rtu(struct ib_cm_id * cm_id,const void * private_data,u8 private_data_len)2348a977049dSHal Rosenstock int ib_send_cm_rtu(struct ib_cm_id *cm_id,
2349a977049dSHal Rosenstock const void *private_data,
2350a977049dSHal Rosenstock u8 private_data_len)
2351a977049dSHal Rosenstock {
2352a977049dSHal Rosenstock struct cm_id_private *cm_id_priv;
2353a977049dSHal Rosenstock struct ib_mad_send_buf *msg;
2354a977049dSHal Rosenstock unsigned long flags;
2355a977049dSHal Rosenstock void *data;
2356a977049dSHal Rosenstock int ret;
2357a977049dSHal Rosenstock
2358a977049dSHal Rosenstock if (private_data && private_data_len > IB_CM_RTU_PRIVATE_DATA_SIZE)
2359a977049dSHal Rosenstock return -EINVAL;
2360a977049dSHal Rosenstock
2361a977049dSHal Rosenstock data = cm_copy_private_data(private_data, private_data_len);
2362a977049dSHal Rosenstock if (IS_ERR(data))
2363a977049dSHal Rosenstock return PTR_ERR(data);
2364a977049dSHal Rosenstock
2365a977049dSHal Rosenstock cm_id_priv = container_of(cm_id, struct cm_id_private, id);
2366a977049dSHal Rosenstock spin_lock_irqsave(&cm_id_priv->lock, flags);
2367a977049dSHal Rosenstock if (cm_id->state != IB_CM_REP_RCVD &&
2368a977049dSHal Rosenstock cm_id->state != IB_CM_MRA_REP_SENT) {
236975874b3dSChuck Lever trace_icm_send_cm_rtu_err(cm_id);
2370a977049dSHal Rosenstock ret = -EINVAL;
2371a977049dSHal Rosenstock goto error;
2372a977049dSHal Rosenstock }
2373a977049dSHal Rosenstock
23744b4e586eSJason Gunthorpe msg = cm_alloc_msg(cm_id_priv);
23754b4e586eSJason Gunthorpe if (IS_ERR(msg)) {
23764b4e586eSJason Gunthorpe ret = PTR_ERR(msg);
2377a977049dSHal Rosenstock goto error;
23784b4e586eSJason Gunthorpe }
2379a977049dSHal Rosenstock
2380a977049dSHal Rosenstock cm_format_rtu((struct cm_rtu_msg *) msg->mad, cm_id_priv,
2381a977049dSHal Rosenstock private_data, private_data_len);
2382a977049dSHal Rosenstock
23838dc105beSChuck Lever trace_icm_send_rtu(cm_id);
238434816ad9SSean Hefty ret = ib_post_send_mad(msg, NULL);
2385a977049dSHal Rosenstock if (ret) {
2386a977049dSHal Rosenstock spin_unlock_irqrestore(&cm_id_priv->lock, flags);
2387a977049dSHal Rosenstock cm_free_msg(msg);
2388a977049dSHal Rosenstock kfree(data);
2389a977049dSHal Rosenstock return ret;
2390a977049dSHal Rosenstock }
2391a977049dSHal Rosenstock
2392a977049dSHal Rosenstock cm_id->state = IB_CM_ESTABLISHED;
2393a977049dSHal Rosenstock cm_set_private_data(cm_id_priv, data, private_data_len);
2394a977049dSHal Rosenstock spin_unlock_irqrestore(&cm_id_priv->lock, flags);
2395a977049dSHal Rosenstock return 0;
2396a977049dSHal Rosenstock
2397a977049dSHal Rosenstock error: spin_unlock_irqrestore(&cm_id_priv->lock, flags);
2398a977049dSHal Rosenstock kfree(data);
2399a977049dSHal Rosenstock return ret;
2400a977049dSHal Rosenstock }
2401a977049dSHal Rosenstock EXPORT_SYMBOL(ib_send_cm_rtu);
2402a977049dSHal Rosenstock
cm_format_rep_event(struct cm_work * work,enum ib_qp_type qp_type)2403ef700446SSean Hefty static void cm_format_rep_event(struct cm_work *work, enum ib_qp_type qp_type)
2404a977049dSHal Rosenstock {
2405a977049dSHal Rosenstock struct cm_rep_msg *rep_msg;
2406a977049dSHal Rosenstock struct ib_cm_rep_event_param *param;
2407a977049dSHal Rosenstock
2408a977049dSHal Rosenstock rep_msg = (struct cm_rep_msg *)work->mad_recv_wc->recv_buf.mad;
2409a977049dSHal Rosenstock param = &work->cm_event.param.rep_rcvd;
241091b60a71SJason Gunthorpe param->remote_ca_guid =
241191b60a71SJason Gunthorpe cpu_to_be64(IBA_GET(CM_REP_LOCAL_CA_GUID, rep_msg));
241291b60a71SJason Gunthorpe param->remote_qkey = IBA_GET(CM_REP_LOCAL_Q_KEY, rep_msg);
2413ef700446SSean Hefty param->remote_qpn = be32_to_cpu(cm_rep_get_qpn(rep_msg, qp_type));
241401adb7f4SJason Gunthorpe param->starting_psn = IBA_GET(CM_REP_STARTING_PSN, rep_msg);
241591b60a71SJason Gunthorpe param->responder_resources = IBA_GET(CM_REP_INITIATOR_DEPTH, rep_msg);
241691b60a71SJason Gunthorpe param->initiator_depth = IBA_GET(CM_REP_RESPONDER_RESOURCES, rep_msg);
2417b6bbee68SJason Gunthorpe param->target_ack_delay = IBA_GET(CM_REP_TARGET_ACK_DELAY, rep_msg);
2418b6bbee68SJason Gunthorpe param->failover_accepted = IBA_GET(CM_REP_FAILOVER_ACCEPTED, rep_msg);
2419b6bbee68SJason Gunthorpe param->flow_control = IBA_GET(CM_REP_END_TO_END_FLOW_CONTROL, rep_msg);
2420b6bbee68SJason Gunthorpe param->rnr_retry_count = IBA_GET(CM_REP_RNR_RETRY_COUNT, rep_msg);
2421b6bbee68SJason Gunthorpe param->srq = IBA_GET(CM_REP_SRQ, rep_msg);
2422a20652e1SLeon Romanovsky param->ece.vendor_id = IBA_GET(CM_REP_VENDOR_ID_H, rep_msg) << 16;
2423a20652e1SLeon Romanovsky param->ece.vendor_id |= IBA_GET(CM_REP_VENDOR_ID_M, rep_msg) << 8;
2424a20652e1SLeon Romanovsky param->ece.vendor_id |= IBA_GET(CM_REP_VENDOR_ID_L, rep_msg);
2425a20652e1SLeon Romanovsky param->ece.attr_mod = be32_to_cpu(rep_msg->hdr.attr_mod);
2426a20652e1SLeon Romanovsky
24274ca662a3SJason Gunthorpe work->cm_event.private_data =
24284ca662a3SJason Gunthorpe IBA_GET_MEM_PTR(CM_REP_PRIVATE_DATA, rep_msg);
2429a977049dSHal Rosenstock }
2430a977049dSHal Rosenstock
cm_dup_rep_handler(struct cm_work * work)2431a977049dSHal Rosenstock static void cm_dup_rep_handler(struct cm_work *work)
2432a977049dSHal Rosenstock {
2433a977049dSHal Rosenstock struct cm_id_private *cm_id_priv;
2434a977049dSHal Rosenstock struct cm_rep_msg *rep_msg;
2435a977049dSHal Rosenstock struct ib_mad_send_buf *msg = NULL;
2436a977049dSHal Rosenstock int ret;
2437a977049dSHal Rosenstock
2438a977049dSHal Rosenstock rep_msg = (struct cm_rep_msg *) work->mad_recv_wc->recv_buf.mad;
243991b60a71SJason Gunthorpe cm_id_priv = cm_acquire_id(
244091b60a71SJason Gunthorpe cpu_to_be32(IBA_GET(CM_REP_REMOTE_COMM_ID, rep_msg)),
244191b60a71SJason Gunthorpe cpu_to_be32(IBA_GET(CM_REP_LOCAL_COMM_ID, rep_msg)));
2442a977049dSHal Rosenstock if (!cm_id_priv)
2443a977049dSHal Rosenstock return;
2444a977049dSHal Rosenstock
2445526a12c8SJason Gunthorpe atomic_long_inc(
2446526a12c8SJason Gunthorpe &work->port->counters[CM_RECV_DUPLICATES][CM_REP_COUNTER]);
2447a977049dSHal Rosenstock ret = cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg);
2448a977049dSHal Rosenstock if (ret)
2449a977049dSHal Rosenstock goto deref;
2450a977049dSHal Rosenstock
245124be6e81SSean Hefty spin_lock_irq(&cm_id_priv->lock);
2452a977049dSHal Rosenstock if (cm_id_priv->id.state == IB_CM_ESTABLISHED)
2453a977049dSHal Rosenstock cm_format_rtu((struct cm_rtu_msg *) msg->mad, cm_id_priv,
2454a977049dSHal Rosenstock cm_id_priv->private_data,
2455a977049dSHal Rosenstock cm_id_priv->private_data_len);
2456a977049dSHal Rosenstock else if (cm_id_priv->id.state == IB_CM_MRA_REP_SENT)
2457a977049dSHal Rosenstock cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
2458a977049dSHal Rosenstock CM_MSG_RESPONSE_REP, cm_id_priv->service_timeout,
2459a977049dSHal Rosenstock cm_id_priv->private_data,
2460a977049dSHal Rosenstock cm_id_priv->private_data_len);
2461a977049dSHal Rosenstock else
2462a977049dSHal Rosenstock goto unlock;
246324be6e81SSean Hefty spin_unlock_irq(&cm_id_priv->lock);
2464a977049dSHal Rosenstock
24658dc105beSChuck Lever trace_icm_send_dup_rep(&cm_id_priv->id);
246634816ad9SSean Hefty ret = ib_post_send_mad(msg, NULL);
2467a977049dSHal Rosenstock if (ret)
2468a977049dSHal Rosenstock goto free;
2469a977049dSHal Rosenstock goto deref;
2470a977049dSHal Rosenstock
247124be6e81SSean Hefty unlock: spin_unlock_irq(&cm_id_priv->lock);
247296376a40SJason Gunthorpe free: cm_free_response_msg(msg);
2473a977049dSHal Rosenstock deref: cm_deref_id(cm_id_priv);
2474a977049dSHal Rosenstock }
2475a977049dSHal Rosenstock
cm_rep_handler(struct cm_work * work)2476a977049dSHal Rosenstock static int cm_rep_handler(struct cm_work *work)
2477a977049dSHal Rosenstock {
2478a977049dSHal Rosenstock struct cm_id_private *cm_id_priv;
2479a977049dSHal Rosenstock struct cm_rep_msg *rep_msg;
2480a977049dSHal Rosenstock int ret;
24819315bc9aSHans Westgaard Ry struct cm_id_private *cur_cm_id_priv;
24829315bc9aSHans Westgaard Ry struct cm_timewait_info *timewait_info;
2483a977049dSHal Rosenstock
2484a977049dSHal Rosenstock rep_msg = (struct cm_rep_msg *)work->mad_recv_wc->recv_buf.mad;
248591b60a71SJason Gunthorpe cm_id_priv = cm_acquire_id(
248691b60a71SJason Gunthorpe cpu_to_be32(IBA_GET(CM_REP_REMOTE_COMM_ID, rep_msg)), 0);
2487a977049dSHal Rosenstock if (!cm_id_priv) {
2488a977049dSHal Rosenstock cm_dup_rep_handler(work);
248975874b3dSChuck Lever trace_icm_remote_no_priv_err(
249091b60a71SJason Gunthorpe IBA_GET(CM_REP_REMOTE_COMM_ID, rep_msg));
2491a977049dSHal Rosenstock return -EINVAL;
2492a977049dSHal Rosenstock }
2493a977049dSHal Rosenstock
2494ef700446SSean Hefty cm_format_rep_event(work, cm_id_priv->qp_type);
2495a977049dSHal Rosenstock
249624be6e81SSean Hefty spin_lock_irq(&cm_id_priv->lock);
2497a977049dSHal Rosenstock switch (cm_id_priv->id.state) {
2498a977049dSHal Rosenstock case IB_CM_REQ_SENT:
2499a977049dSHal Rosenstock case IB_CM_MRA_REQ_RCVD:
2500a977049dSHal Rosenstock break;
2501a977049dSHal Rosenstock default:
2502a977049dSHal Rosenstock ret = -EINVAL;
250375874b3dSChuck Lever trace_icm_rep_unknown_err(
250491b60a71SJason Gunthorpe IBA_GET(CM_REP_LOCAL_COMM_ID, rep_msg),
250575874b3dSChuck Lever IBA_GET(CM_REP_REMOTE_COMM_ID, rep_msg),
250675874b3dSChuck Lever cm_id_priv->id.state);
2507153a2e43SJason Gunthorpe spin_unlock_irq(&cm_id_priv->lock);
2508a977049dSHal Rosenstock goto error;
2509a977049dSHal Rosenstock }
251087fd1a11SSean Hefty
251191b60a71SJason Gunthorpe cm_id_priv->timewait_info->work.remote_id =
251291b60a71SJason Gunthorpe cpu_to_be32(IBA_GET(CM_REP_LOCAL_COMM_ID, rep_msg));
251391b60a71SJason Gunthorpe cm_id_priv->timewait_info->remote_ca_guid =
251491b60a71SJason Gunthorpe cpu_to_be64(IBA_GET(CM_REP_LOCAL_CA_GUID, rep_msg));
2515ef700446SSean Hefty cm_id_priv->timewait_info->remote_qpn = cm_rep_get_qpn(rep_msg, cm_id_priv->qp_type);
251687fd1a11SSean Hefty
251787fd1a11SSean Hefty spin_lock(&cm.lock);
251887fd1a11SSean Hefty /* Check for duplicate REP. */
251987fd1a11SSean Hefty if (cm_insert_remote_id(cm_id_priv->timewait_info)) {
252087fd1a11SSean Hefty spin_unlock(&cm.lock);
252124be6e81SSean Hefty spin_unlock_irq(&cm_id_priv->lock);
252287fd1a11SSean Hefty ret = -EINVAL;
252375874b3dSChuck Lever trace_icm_insert_failed_err(
252491b60a71SJason Gunthorpe IBA_GET(CM_REP_REMOTE_COMM_ID, rep_msg));
252587fd1a11SSean Hefty goto error;
252687fd1a11SSean Hefty }
252787fd1a11SSean Hefty /* Check for a stale connection. */
25289315bc9aSHans Westgaard Ry timewait_info = cm_insert_remote_qpn(cm_id_priv->timewait_info);
25299315bc9aSHans Westgaard Ry if (timewait_info) {
25309767a27eSJason Gunthorpe cm_remove_remote(cm_id_priv);
25314d6e8a03SDanit Goldberg cur_cm_id_priv = cm_acquire_id(timewait_info->work.local_id,
25329315bc9aSHans Westgaard Ry timewait_info->work.remote_id);
25339315bc9aSHans Westgaard Ry
253487fd1a11SSean Hefty spin_unlock(&cm.lock);
253524be6e81SSean Hefty spin_unlock_irq(&cm_id_priv->lock);
253687fd1a11SSean Hefty cm_issue_rej(work->port, work->mad_recv_wc,
253787fd1a11SSean Hefty IB_CM_REJ_STALE_CONN, CM_MSG_RESPONSE_REP,
253887fd1a11SSean Hefty NULL, 0);
253987fd1a11SSean Hefty ret = -EINVAL;
254075874b3dSChuck Lever trace_icm_staleconn_err(
254175874b3dSChuck Lever IBA_GET(CM_REP_LOCAL_COMM_ID, rep_msg),
254291b60a71SJason Gunthorpe IBA_GET(CM_REP_REMOTE_COMM_ID, rep_msg));
2543119bf817SDaniel Jurgens
25449315bc9aSHans Westgaard Ry if (cur_cm_id_priv) {
254551e8463cSJason Gunthorpe ib_send_cm_dreq(&cur_cm_id_priv->id, NULL, 0);
25469315bc9aSHans Westgaard Ry cm_deref_id(cur_cm_id_priv);
25479315bc9aSHans Westgaard Ry }
25489315bc9aSHans Westgaard Ry
254987fd1a11SSean Hefty goto error;
255087fd1a11SSean Hefty }
255187fd1a11SSean Hefty spin_unlock(&cm.lock);
255287fd1a11SSean Hefty
2553a977049dSHal Rosenstock cm_id_priv->id.state = IB_CM_REP_RCVD;
255491b60a71SJason Gunthorpe cm_id_priv->id.remote_id =
255591b60a71SJason Gunthorpe cpu_to_be32(IBA_GET(CM_REP_LOCAL_COMM_ID, rep_msg));
2556ef700446SSean Hefty cm_id_priv->remote_qpn = cm_rep_get_qpn(rep_msg, cm_id_priv->qp_type);
255791b60a71SJason Gunthorpe cm_id_priv->initiator_depth =
255891b60a71SJason Gunthorpe IBA_GET(CM_REP_RESPONDER_RESOURCES, rep_msg);
255991b60a71SJason Gunthorpe cm_id_priv->responder_resources =
256091b60a71SJason Gunthorpe IBA_GET(CM_REP_INITIATOR_DEPTH, rep_msg);
256101adb7f4SJason Gunthorpe cm_id_priv->sq_psn = cpu_to_be32(IBA_GET(CM_REP_STARTING_PSN, rep_msg));
2562b6bbee68SJason Gunthorpe cm_id_priv->rnr_retry_count = IBA_GET(CM_REP_RNR_RETRY_COUNT, rep_msg);
2563b6bbee68SJason Gunthorpe cm_id_priv->target_ack_delay =
2564b6bbee68SJason Gunthorpe IBA_GET(CM_REP_TARGET_ACK_DELAY, rep_msg);
25651d846126SSean Hefty cm_id_priv->av.timeout =
25661d846126SSean Hefty cm_ack_timeout(cm_id_priv->target_ack_delay,
25671d846126SSean Hefty cm_id_priv->av.timeout - 1);
25681d846126SSean Hefty cm_id_priv->alt_av.timeout =
25691d846126SSean Hefty cm_ack_timeout(cm_id_priv->target_ack_delay,
25701d846126SSean Hefty cm_id_priv->alt_av.timeout - 1);
2571a977049dSHal Rosenstock
257270076a41SMark Zhang ib_cancel_mad(cm_id_priv->msg);
2573e83f195aSJason Gunthorpe cm_queue_work_unlock(cm_id_priv, work);
2574a977049dSHal Rosenstock return 0;
2575a977049dSHal Rosenstock
257687fd1a11SSean Hefty error:
2577a977049dSHal Rosenstock cm_deref_id(cm_id_priv);
2578a977049dSHal Rosenstock return ret;
2579a977049dSHal Rosenstock }
2580a977049dSHal Rosenstock
cm_establish_handler(struct cm_work * work)2581a977049dSHal Rosenstock static int cm_establish_handler(struct cm_work *work)
2582a977049dSHal Rosenstock {
2583a977049dSHal Rosenstock struct cm_id_private *cm_id_priv;
2584a977049dSHal Rosenstock
2585e1444b5aSSean Hefty /* See comment in cm_establish about lookup. */
2586a977049dSHal Rosenstock cm_id_priv = cm_acquire_id(work->local_id, work->remote_id);
2587a977049dSHal Rosenstock if (!cm_id_priv)
2588a977049dSHal Rosenstock return -EINVAL;
2589a977049dSHal Rosenstock
259024be6e81SSean Hefty spin_lock_irq(&cm_id_priv->lock);
2591a977049dSHal Rosenstock if (cm_id_priv->id.state != IB_CM_ESTABLISHED) {
259224be6e81SSean Hefty spin_unlock_irq(&cm_id_priv->lock);
2593a977049dSHal Rosenstock goto out;
2594a977049dSHal Rosenstock }
2595a977049dSHal Rosenstock
259670076a41SMark Zhang ib_cancel_mad(cm_id_priv->msg);
2597e83f195aSJason Gunthorpe cm_queue_work_unlock(cm_id_priv, work);
2598a977049dSHal Rosenstock return 0;
2599a977049dSHal Rosenstock out:
2600a977049dSHal Rosenstock cm_deref_id(cm_id_priv);
2601a977049dSHal Rosenstock return -EINVAL;
2602a977049dSHal Rosenstock }
2603a977049dSHal Rosenstock
cm_rtu_handler(struct cm_work * work)2604a977049dSHal Rosenstock static int cm_rtu_handler(struct cm_work *work)
2605a977049dSHal Rosenstock {
2606a977049dSHal Rosenstock struct cm_id_private *cm_id_priv;
2607a977049dSHal Rosenstock struct cm_rtu_msg *rtu_msg;
2608a977049dSHal Rosenstock
2609a977049dSHal Rosenstock rtu_msg = (struct cm_rtu_msg *)work->mad_recv_wc->recv_buf.mad;
261091b60a71SJason Gunthorpe cm_id_priv = cm_acquire_id(
261191b60a71SJason Gunthorpe cpu_to_be32(IBA_GET(CM_RTU_REMOTE_COMM_ID, rtu_msg)),
261291b60a71SJason Gunthorpe cpu_to_be32(IBA_GET(CM_RTU_LOCAL_COMM_ID, rtu_msg)));
2613a977049dSHal Rosenstock if (!cm_id_priv)
2614a977049dSHal Rosenstock return -EINVAL;
2615a977049dSHal Rosenstock
26164ca662a3SJason Gunthorpe work->cm_event.private_data =
26174ca662a3SJason Gunthorpe IBA_GET_MEM_PTR(CM_RTU_PRIVATE_DATA, rtu_msg);
2618a977049dSHal Rosenstock
261924be6e81SSean Hefty spin_lock_irq(&cm_id_priv->lock);
2620a977049dSHal Rosenstock if (cm_id_priv->id.state != IB_CM_REP_SENT &&
2621a977049dSHal Rosenstock cm_id_priv->id.state != IB_CM_MRA_REP_RCVD) {
262224be6e81SSean Hefty spin_unlock_irq(&cm_id_priv->lock);
2623526a12c8SJason Gunthorpe atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES]
2624526a12c8SJason Gunthorpe [CM_RTU_COUNTER]);
2625a977049dSHal Rosenstock goto out;
2626a977049dSHal Rosenstock }
2627a977049dSHal Rosenstock cm_id_priv->id.state = IB_CM_ESTABLISHED;
2628a977049dSHal Rosenstock
262970076a41SMark Zhang ib_cancel_mad(cm_id_priv->msg);
2630e83f195aSJason Gunthorpe cm_queue_work_unlock(cm_id_priv, work);
2631a977049dSHal Rosenstock return 0;
2632a977049dSHal Rosenstock out:
2633a977049dSHal Rosenstock cm_deref_id(cm_id_priv);
2634a977049dSHal Rosenstock return -EINVAL;
2635a977049dSHal Rosenstock }
2636a977049dSHal Rosenstock
cm_format_dreq(struct cm_dreq_msg * dreq_msg,struct cm_id_private * cm_id_priv,const void * private_data,u8 private_data_len)2637a977049dSHal Rosenstock static void cm_format_dreq(struct cm_dreq_msg *dreq_msg,
2638a977049dSHal Rosenstock struct cm_id_private *cm_id_priv,
2639a977049dSHal Rosenstock const void *private_data,
2640a977049dSHal Rosenstock u8 private_data_len)
2641a977049dSHal Rosenstock {
2642a977049dSHal Rosenstock cm_format_mad_hdr(&dreq_msg->hdr, CM_DREQ_ATTR_ID,
264387a37ce9SHåkon Bugge cm_form_tid(cm_id_priv));
264491b60a71SJason Gunthorpe IBA_SET(CM_DREQ_LOCAL_COMM_ID, dreq_msg,
264591b60a71SJason Gunthorpe be32_to_cpu(cm_id_priv->id.local_id));
264691b60a71SJason Gunthorpe IBA_SET(CM_DREQ_REMOTE_COMM_ID, dreq_msg,
264791b60a71SJason Gunthorpe be32_to_cpu(cm_id_priv->id.remote_id));
264801adb7f4SJason Gunthorpe IBA_SET(CM_DREQ_REMOTE_QPN_EECN, dreq_msg,
264901adb7f4SJason Gunthorpe be32_to_cpu(cm_id_priv->remote_qpn));
2650a977049dSHal Rosenstock
2651a977049dSHal Rosenstock if (private_data && private_data_len)
26524ca662a3SJason Gunthorpe IBA_SET_MEM(CM_DREQ_PRIVATE_DATA, dreq_msg, private_data,
26534ca662a3SJason Gunthorpe private_data_len);
2654a977049dSHal Rosenstock }
2655a977049dSHal Rosenstock
cm_send_dreq_locked(struct cm_id_private * cm_id_priv,const void * private_data,u8 private_data_len)2656e029fdc0SJason Gunthorpe static int cm_send_dreq_locked(struct cm_id_private *cm_id_priv,
2657e029fdc0SJason Gunthorpe const void *private_data, u8 private_data_len)
2658a977049dSHal Rosenstock {
2659a977049dSHal Rosenstock struct ib_mad_send_buf *msg;
2660a977049dSHal Rosenstock int ret;
2661a977049dSHal Rosenstock
2662e029fdc0SJason Gunthorpe lockdep_assert_held(&cm_id_priv->lock);
2663e029fdc0SJason Gunthorpe
2664a977049dSHal Rosenstock if (private_data && private_data_len > IB_CM_DREQ_PRIVATE_DATA_SIZE)
2665a977049dSHal Rosenstock return -EINVAL;
2666a977049dSHal Rosenstock
2667e029fdc0SJason Gunthorpe if (cm_id_priv->id.state != IB_CM_ESTABLISHED) {
266875874b3dSChuck Lever trace_icm_dreq_skipped(&cm_id_priv->id);
2669e029fdc0SJason Gunthorpe return -EINVAL;
2670a977049dSHal Rosenstock }
2671a977049dSHal Rosenstock
2672e029fdc0SJason Gunthorpe if (cm_id_priv->id.lap_state == IB_CM_LAP_SENT ||
2673e029fdc0SJason Gunthorpe cm_id_priv->id.lap_state == IB_CM_MRA_LAP_RCVD)
267470076a41SMark Zhang ib_cancel_mad(cm_id_priv->msg);
26758d8ac865SSean Hefty
26764b4e586eSJason Gunthorpe msg = cm_alloc_priv_msg(cm_id_priv);
26774b4e586eSJason Gunthorpe if (IS_ERR(msg)) {
2678a977049dSHal Rosenstock cm_enter_timewait(cm_id_priv);
26794b4e586eSJason Gunthorpe return PTR_ERR(msg);
2680a977049dSHal Rosenstock }
2681a977049dSHal Rosenstock
2682a977049dSHal Rosenstock cm_format_dreq((struct cm_dreq_msg *) msg->mad, cm_id_priv,
2683a977049dSHal Rosenstock private_data, private_data_len);
268434816ad9SSean Hefty msg->timeout_ms = cm_id_priv->timeout_ms;
2685a977049dSHal Rosenstock msg->context[1] = (void *) (unsigned long) IB_CM_DREQ_SENT;
2686a977049dSHal Rosenstock
26878dc105beSChuck Lever trace_icm_send_dreq(&cm_id_priv->id);
268834816ad9SSean Hefty ret = ib_post_send_mad(msg, NULL);
2689a977049dSHal Rosenstock if (ret) {
2690a977049dSHal Rosenstock cm_enter_timewait(cm_id_priv);
26914b4e586eSJason Gunthorpe cm_free_priv_msg(msg);
2692a977049dSHal Rosenstock return ret;
2693a977049dSHal Rosenstock }
2694a977049dSHal Rosenstock
2695e029fdc0SJason Gunthorpe cm_id_priv->id.state = IB_CM_DREQ_SENT;
2696e029fdc0SJason Gunthorpe return 0;
2697e029fdc0SJason Gunthorpe }
2698e029fdc0SJason Gunthorpe
ib_send_cm_dreq(struct ib_cm_id * cm_id,const void * private_data,u8 private_data_len)2699e029fdc0SJason Gunthorpe int ib_send_cm_dreq(struct ib_cm_id *cm_id, const void *private_data,
2700e029fdc0SJason Gunthorpe u8 private_data_len)
2701e029fdc0SJason Gunthorpe {
2702e029fdc0SJason Gunthorpe struct cm_id_private *cm_id_priv =
2703e029fdc0SJason Gunthorpe container_of(cm_id, struct cm_id_private, id);
2704e029fdc0SJason Gunthorpe unsigned long flags;
2705e029fdc0SJason Gunthorpe int ret;
2706e029fdc0SJason Gunthorpe
2707e029fdc0SJason Gunthorpe spin_lock_irqsave(&cm_id_priv->lock, flags);
2708e029fdc0SJason Gunthorpe ret = cm_send_dreq_locked(cm_id_priv, private_data, private_data_len);
2709e029fdc0SJason Gunthorpe spin_unlock_irqrestore(&cm_id_priv->lock, flags);
2710a977049dSHal Rosenstock return ret;
2711a977049dSHal Rosenstock }
2712a977049dSHal Rosenstock EXPORT_SYMBOL(ib_send_cm_dreq);
2713a977049dSHal Rosenstock
cm_format_drep(struct cm_drep_msg * drep_msg,struct cm_id_private * cm_id_priv,const void * private_data,u8 private_data_len)2714a977049dSHal Rosenstock static void cm_format_drep(struct cm_drep_msg *drep_msg,
2715a977049dSHal Rosenstock struct cm_id_private *cm_id_priv,
2716a977049dSHal Rosenstock const void *private_data,
2717a977049dSHal Rosenstock u8 private_data_len)
2718a977049dSHal Rosenstock {
2719a977049dSHal Rosenstock cm_format_mad_hdr(&drep_msg->hdr, CM_DREP_ATTR_ID, cm_id_priv->tid);
272091b60a71SJason Gunthorpe IBA_SET(CM_DREP_LOCAL_COMM_ID, drep_msg,
272191b60a71SJason Gunthorpe be32_to_cpu(cm_id_priv->id.local_id));
272291b60a71SJason Gunthorpe IBA_SET(CM_DREP_REMOTE_COMM_ID, drep_msg,
272391b60a71SJason Gunthorpe be32_to_cpu(cm_id_priv->id.remote_id));
2724a977049dSHal Rosenstock
2725a977049dSHal Rosenstock if (private_data && private_data_len)
27264ca662a3SJason Gunthorpe IBA_SET_MEM(CM_DREP_PRIVATE_DATA, drep_msg, private_data,
27274ca662a3SJason Gunthorpe private_data_len);
2728a977049dSHal Rosenstock }
2729a977049dSHal Rosenstock
cm_send_drep_locked(struct cm_id_private * cm_id_priv,void * private_data,u8 private_data_len)273087cabf3eSJason Gunthorpe static int cm_send_drep_locked(struct cm_id_private *cm_id_priv,
273187cabf3eSJason Gunthorpe void *private_data, u8 private_data_len)
2732a977049dSHal Rosenstock {
2733a977049dSHal Rosenstock struct ib_mad_send_buf *msg;
2734a977049dSHal Rosenstock int ret;
2735a977049dSHal Rosenstock
273687cabf3eSJason Gunthorpe lockdep_assert_held(&cm_id_priv->lock);
273787cabf3eSJason Gunthorpe
2738a977049dSHal Rosenstock if (private_data && private_data_len > IB_CM_DREP_PRIVATE_DATA_SIZE)
2739a977049dSHal Rosenstock return -EINVAL;
2740a977049dSHal Rosenstock
274187cabf3eSJason Gunthorpe if (cm_id_priv->id.state != IB_CM_DREQ_RCVD) {
274275874b3dSChuck Lever trace_icm_send_drep_err(&cm_id_priv->id);
274387cabf3eSJason Gunthorpe kfree(private_data);
2744a977049dSHal Rosenstock return -EINVAL;
2745a977049dSHal Rosenstock }
2746a977049dSHal Rosenstock
274787cabf3eSJason Gunthorpe cm_set_private_data(cm_id_priv, private_data, private_data_len);
2748a977049dSHal Rosenstock cm_enter_timewait(cm_id_priv);
2749a977049dSHal Rosenstock
27504b4e586eSJason Gunthorpe msg = cm_alloc_msg(cm_id_priv);
27514b4e586eSJason Gunthorpe if (IS_ERR(msg))
27524b4e586eSJason Gunthorpe return PTR_ERR(msg);
2753a977049dSHal Rosenstock
2754a977049dSHal Rosenstock cm_format_drep((struct cm_drep_msg *) msg->mad, cm_id_priv,
2755a977049dSHal Rosenstock private_data, private_data_len);
2756a977049dSHal Rosenstock
27578dc105beSChuck Lever trace_icm_send_drep(&cm_id_priv->id);
275834816ad9SSean Hefty ret = ib_post_send_mad(msg, NULL);
2759a977049dSHal Rosenstock if (ret) {
2760a977049dSHal Rosenstock cm_free_msg(msg);
2761a977049dSHal Rosenstock return ret;
2762a977049dSHal Rosenstock }
276387cabf3eSJason Gunthorpe return 0;
276487cabf3eSJason Gunthorpe }
2765a977049dSHal Rosenstock
ib_send_cm_drep(struct ib_cm_id * cm_id,const void * private_data,u8 private_data_len)276687cabf3eSJason Gunthorpe int ib_send_cm_drep(struct ib_cm_id *cm_id, const void *private_data,
276787cabf3eSJason Gunthorpe u8 private_data_len)
276887cabf3eSJason Gunthorpe {
276987cabf3eSJason Gunthorpe struct cm_id_private *cm_id_priv =
277087cabf3eSJason Gunthorpe container_of(cm_id, struct cm_id_private, id);
277187cabf3eSJason Gunthorpe unsigned long flags;
277287cabf3eSJason Gunthorpe void *data;
277387cabf3eSJason Gunthorpe int ret;
277487cabf3eSJason Gunthorpe
277587cabf3eSJason Gunthorpe data = cm_copy_private_data(private_data, private_data_len);
277687cabf3eSJason Gunthorpe if (IS_ERR(data))
277787cabf3eSJason Gunthorpe return PTR_ERR(data);
277887cabf3eSJason Gunthorpe
277987cabf3eSJason Gunthorpe spin_lock_irqsave(&cm_id_priv->lock, flags);
278087cabf3eSJason Gunthorpe ret = cm_send_drep_locked(cm_id_priv, data, private_data_len);
278187cabf3eSJason Gunthorpe spin_unlock_irqrestore(&cm_id_priv->lock, flags);
2782a977049dSHal Rosenstock return ret;
2783a977049dSHal Rosenstock }
2784a977049dSHal Rosenstock EXPORT_SYMBOL(ib_send_cm_drep);
2785a977049dSHal Rosenstock
cm_issue_drep(struct cm_port * port,struct ib_mad_recv_wc * mad_recv_wc)278682a9c16aSSean Hefty static int cm_issue_drep(struct cm_port *port,
278782a9c16aSSean Hefty struct ib_mad_recv_wc *mad_recv_wc)
278882a9c16aSSean Hefty {
278982a9c16aSSean Hefty struct ib_mad_send_buf *msg = NULL;
279082a9c16aSSean Hefty struct cm_dreq_msg *dreq_msg;
279182a9c16aSSean Hefty struct cm_drep_msg *drep_msg;
279282a9c16aSSean Hefty int ret;
279382a9c16aSSean Hefty
279482a9c16aSSean Hefty ret = cm_alloc_response_msg(port, mad_recv_wc, &msg);
279582a9c16aSSean Hefty if (ret)
279682a9c16aSSean Hefty return ret;
279782a9c16aSSean Hefty
279882a9c16aSSean Hefty dreq_msg = (struct cm_dreq_msg *) mad_recv_wc->recv_buf.mad;
279982a9c16aSSean Hefty drep_msg = (struct cm_drep_msg *) msg->mad;
280082a9c16aSSean Hefty
280182a9c16aSSean Hefty cm_format_mad_hdr(&drep_msg->hdr, CM_DREP_ATTR_ID, dreq_msg->hdr.tid);
280291b60a71SJason Gunthorpe IBA_SET(CM_DREP_REMOTE_COMM_ID, drep_msg,
280391b60a71SJason Gunthorpe IBA_GET(CM_DREQ_LOCAL_COMM_ID, dreq_msg));
280491b60a71SJason Gunthorpe IBA_SET(CM_DREP_LOCAL_COMM_ID, drep_msg,
280591b60a71SJason Gunthorpe IBA_GET(CM_DREQ_REMOTE_COMM_ID, dreq_msg));
280682a9c16aSSean Hefty
28078dc105beSChuck Lever trace_icm_issue_drep(
28088dc105beSChuck Lever IBA_GET(CM_DREQ_LOCAL_COMM_ID, dreq_msg),
28098dc105beSChuck Lever IBA_GET(CM_DREQ_REMOTE_COMM_ID, dreq_msg));
281082a9c16aSSean Hefty ret = ib_post_send_mad(msg, NULL);
281182a9c16aSSean Hefty if (ret)
281296376a40SJason Gunthorpe cm_free_response_msg(msg);
281382a9c16aSSean Hefty
281482a9c16aSSean Hefty return ret;
281582a9c16aSSean Hefty }
281682a9c16aSSean Hefty
cm_dreq_handler(struct cm_work * work)2817a977049dSHal Rosenstock static int cm_dreq_handler(struct cm_work *work)
2818a977049dSHal Rosenstock {
2819a977049dSHal Rosenstock struct cm_id_private *cm_id_priv;
2820a977049dSHal Rosenstock struct cm_dreq_msg *dreq_msg;
2821a977049dSHal Rosenstock struct ib_mad_send_buf *msg = NULL;
2822a977049dSHal Rosenstock
2823a977049dSHal Rosenstock dreq_msg = (struct cm_dreq_msg *)work->mad_recv_wc->recv_buf.mad;
282491b60a71SJason Gunthorpe cm_id_priv = cm_acquire_id(
282591b60a71SJason Gunthorpe cpu_to_be32(IBA_GET(CM_DREQ_REMOTE_COMM_ID, dreq_msg)),
282691b60a71SJason Gunthorpe cpu_to_be32(IBA_GET(CM_DREQ_LOCAL_COMM_ID, dreq_msg)));
282782a9c16aSSean Hefty if (!cm_id_priv) {
2828526a12c8SJason Gunthorpe atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES]
2829526a12c8SJason Gunthorpe [CM_DREQ_COUNTER]);
283082a9c16aSSean Hefty cm_issue_drep(work->port, work->mad_recv_wc);
283175874b3dSChuck Lever trace_icm_no_priv_err(
283275874b3dSChuck Lever IBA_GET(CM_DREQ_LOCAL_COMM_ID, dreq_msg),
283391b60a71SJason Gunthorpe IBA_GET(CM_DREQ_REMOTE_COMM_ID, dreq_msg));
2834a977049dSHal Rosenstock return -EINVAL;
283582a9c16aSSean Hefty }
2836a977049dSHal Rosenstock
28374ca662a3SJason Gunthorpe work->cm_event.private_data =
28384ca662a3SJason Gunthorpe IBA_GET_MEM_PTR(CM_DREQ_PRIVATE_DATA, dreq_msg);
2839a977049dSHal Rosenstock
284024be6e81SSean Hefty spin_lock_irq(&cm_id_priv->lock);
284101adb7f4SJason Gunthorpe if (cm_id_priv->local_qpn !=
284201adb7f4SJason Gunthorpe cpu_to_be32(IBA_GET(CM_DREQ_REMOTE_QPN_EECN, dreq_msg)))
2843a977049dSHal Rosenstock goto unlock;
2844a977049dSHal Rosenstock
2845a977049dSHal Rosenstock switch (cm_id_priv->id.state) {
2846a977049dSHal Rosenstock case IB_CM_REP_SENT:
2847a977049dSHal Rosenstock case IB_CM_DREQ_SENT:
2848107dd7beSMark Zhang case IB_CM_MRA_REP_RCVD:
284970076a41SMark Zhang ib_cancel_mad(cm_id_priv->msg);
2850a977049dSHal Rosenstock break;
2851a977049dSHal Rosenstock case IB_CM_ESTABLISHED:
28528d8ac865SSean Hefty if (cm_id_priv->id.lap_state == IB_CM_LAP_SENT ||
28538d8ac865SSean Hefty cm_id_priv->id.lap_state == IB_CM_MRA_LAP_RCVD)
285470076a41SMark Zhang ib_cancel_mad(cm_id_priv->msg);
28558d8ac865SSean Hefty break;
2856a977049dSHal Rosenstock case IB_CM_TIMEWAIT:
2857526a12c8SJason Gunthorpe atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES]
2858526a12c8SJason Gunthorpe [CM_DREQ_COUNTER]);
2859c7616118SRoland Dreier msg = cm_alloc_response_msg_no_ah(work->port, work->mad_recv_wc);
2860c7616118SRoland Dreier if (IS_ERR(msg))
2861a977049dSHal Rosenstock goto unlock;
2862a977049dSHal Rosenstock
2863a977049dSHal Rosenstock cm_format_drep((struct cm_drep_msg *) msg->mad, cm_id_priv,
2864a977049dSHal Rosenstock cm_id_priv->private_data,
2865a977049dSHal Rosenstock cm_id_priv->private_data_len);
286624be6e81SSean Hefty spin_unlock_irq(&cm_id_priv->lock);
2867a977049dSHal Rosenstock
2868c7616118SRoland Dreier if (cm_create_response_msg_ah(work->port, work->mad_recv_wc, msg) ||
2869c7616118SRoland Dreier ib_post_send_mad(msg, NULL))
287096376a40SJason Gunthorpe cm_free_response_msg(msg);
2871a977049dSHal Rosenstock goto deref;
28729af57b7aSSean Hefty case IB_CM_DREQ_RCVD:
2873526a12c8SJason Gunthorpe atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES]
2874526a12c8SJason Gunthorpe [CM_DREQ_COUNTER]);
28759af57b7aSSean Hefty goto unlock;
2876a977049dSHal Rosenstock default:
287775874b3dSChuck Lever trace_icm_dreq_unknown_err(&cm_id_priv->id);
2878a977049dSHal Rosenstock goto unlock;
2879a977049dSHal Rosenstock }
2880a977049dSHal Rosenstock cm_id_priv->id.state = IB_CM_DREQ_RCVD;
2881a977049dSHal Rosenstock cm_id_priv->tid = dreq_msg->hdr.tid;
2882e83f195aSJason Gunthorpe cm_queue_work_unlock(cm_id_priv, work);
2883a977049dSHal Rosenstock return 0;
2884a977049dSHal Rosenstock
288524be6e81SSean Hefty unlock: spin_unlock_irq(&cm_id_priv->lock);
2886a977049dSHal Rosenstock deref: cm_deref_id(cm_id_priv);
2887a977049dSHal Rosenstock return -EINVAL;
2888a977049dSHal Rosenstock }
2889a977049dSHal Rosenstock
cm_drep_handler(struct cm_work * work)2890a977049dSHal Rosenstock static int cm_drep_handler(struct cm_work *work)
2891a977049dSHal Rosenstock {
2892a977049dSHal Rosenstock struct cm_id_private *cm_id_priv;
2893a977049dSHal Rosenstock struct cm_drep_msg *drep_msg;
2894a977049dSHal Rosenstock
2895a977049dSHal Rosenstock drep_msg = (struct cm_drep_msg *)work->mad_recv_wc->recv_buf.mad;
289691b60a71SJason Gunthorpe cm_id_priv = cm_acquire_id(
289791b60a71SJason Gunthorpe cpu_to_be32(IBA_GET(CM_DREP_REMOTE_COMM_ID, drep_msg)),
289891b60a71SJason Gunthorpe cpu_to_be32(IBA_GET(CM_DREP_LOCAL_COMM_ID, drep_msg)));
2899a977049dSHal Rosenstock if (!cm_id_priv)
2900a977049dSHal Rosenstock return -EINVAL;
2901a977049dSHal Rosenstock
29024ca662a3SJason Gunthorpe work->cm_event.private_data =
29034ca662a3SJason Gunthorpe IBA_GET_MEM_PTR(CM_DREP_PRIVATE_DATA, drep_msg);
2904a977049dSHal Rosenstock
290524be6e81SSean Hefty spin_lock_irq(&cm_id_priv->lock);
2906a977049dSHal Rosenstock if (cm_id_priv->id.state != IB_CM_DREQ_SENT &&
2907a977049dSHal Rosenstock cm_id_priv->id.state != IB_CM_DREQ_RCVD) {
290824be6e81SSean Hefty spin_unlock_irq(&cm_id_priv->lock);
2909a977049dSHal Rosenstock goto out;
2910a977049dSHal Rosenstock }
2911a977049dSHal Rosenstock cm_enter_timewait(cm_id_priv);
2912a977049dSHal Rosenstock
291370076a41SMark Zhang ib_cancel_mad(cm_id_priv->msg);
2914e83f195aSJason Gunthorpe cm_queue_work_unlock(cm_id_priv, work);
2915a977049dSHal Rosenstock return 0;
2916a977049dSHal Rosenstock out:
2917a977049dSHal Rosenstock cm_deref_id(cm_id_priv);
2918a977049dSHal Rosenstock return -EINVAL;
2919a977049dSHal Rosenstock }
2920a977049dSHal Rosenstock
cm_send_rej_locked(struct cm_id_private * cm_id_priv,enum ib_cm_rej_reason reason,void * ari,u8 ari_length,const void * private_data,u8 private_data_len)292181ddb41fSJason Gunthorpe static int cm_send_rej_locked(struct cm_id_private *cm_id_priv,
292281ddb41fSJason Gunthorpe enum ib_cm_rej_reason reason, void *ari,
292381ddb41fSJason Gunthorpe u8 ari_length, const void *private_data,
2924a977049dSHal Rosenstock u8 private_data_len)
2925a977049dSHal Rosenstock {
29260c6949c3SLeon Romanovsky enum ib_cm_state state = cm_id_priv->id.state;
2927a977049dSHal Rosenstock struct ib_mad_send_buf *msg;
2928a977049dSHal Rosenstock int ret;
2929a977049dSHal Rosenstock
293081ddb41fSJason Gunthorpe lockdep_assert_held(&cm_id_priv->lock);
293181ddb41fSJason Gunthorpe
2932a977049dSHal Rosenstock if ((private_data && private_data_len > IB_CM_REJ_PRIVATE_DATA_SIZE) ||
2933a977049dSHal Rosenstock (ari && ari_length > IB_CM_REJ_ARI_LENGTH))
2934a977049dSHal Rosenstock return -EINVAL;
2935a977049dSHal Rosenstock
2936bd9de1baSMark Zhang trace_icm_send_rej(&cm_id_priv->id, reason);
2937bd9de1baSMark Zhang
29380c6949c3SLeon Romanovsky switch (state) {
2939a977049dSHal Rosenstock case IB_CM_REQ_SENT:
2940a977049dSHal Rosenstock case IB_CM_MRA_REQ_RCVD:
2941a977049dSHal Rosenstock case IB_CM_REQ_RCVD:
2942a977049dSHal Rosenstock case IB_CM_MRA_REQ_SENT:
2943a977049dSHal Rosenstock case IB_CM_REP_RCVD:
2944a977049dSHal Rosenstock case IB_CM_MRA_REP_SENT:
2945a977049dSHal Rosenstock cm_reset_to_idle(cm_id_priv);
29464b4e586eSJason Gunthorpe msg = cm_alloc_msg(cm_id_priv);
29474b4e586eSJason Gunthorpe if (IS_ERR(msg))
29484b4e586eSJason Gunthorpe return PTR_ERR(msg);
294981ddb41fSJason Gunthorpe cm_format_rej((struct cm_rej_msg *)msg->mad, cm_id_priv, reason,
29500c6949c3SLeon Romanovsky ari, ari_length, private_data, private_data_len,
29510c6949c3SLeon Romanovsky state);
2952a977049dSHal Rosenstock break;
2953a977049dSHal Rosenstock case IB_CM_REP_SENT:
2954a977049dSHal Rosenstock case IB_CM_MRA_REP_RCVD:
2955a977049dSHal Rosenstock cm_enter_timewait(cm_id_priv);
29564b4e586eSJason Gunthorpe msg = cm_alloc_msg(cm_id_priv);
29574b4e586eSJason Gunthorpe if (IS_ERR(msg))
29584b4e586eSJason Gunthorpe return PTR_ERR(msg);
295981ddb41fSJason Gunthorpe cm_format_rej((struct cm_rej_msg *)msg->mad, cm_id_priv, reason,
29600c6949c3SLeon Romanovsky ari, ari_length, private_data, private_data_len,
29610c6949c3SLeon Romanovsky state);
2962a977049dSHal Rosenstock break;
2963a977049dSHal Rosenstock default:
296475874b3dSChuck Lever trace_icm_send_unknown_rej_err(&cm_id_priv->id);
296581ddb41fSJason Gunthorpe return -EINVAL;
2966a977049dSHal Rosenstock }
2967a977049dSHal Rosenstock
296834816ad9SSean Hefty ret = ib_post_send_mad(msg, NULL);
296981ddb41fSJason Gunthorpe if (ret) {
2970a977049dSHal Rosenstock cm_free_msg(msg);
297181ddb41fSJason Gunthorpe return ret;
297281ddb41fSJason Gunthorpe }
2973a977049dSHal Rosenstock
297481ddb41fSJason Gunthorpe return 0;
297581ddb41fSJason Gunthorpe }
297681ddb41fSJason Gunthorpe
ib_send_cm_rej(struct ib_cm_id * cm_id,enum ib_cm_rej_reason reason,void * ari,u8 ari_length,const void * private_data,u8 private_data_len)297781ddb41fSJason Gunthorpe int ib_send_cm_rej(struct ib_cm_id *cm_id, enum ib_cm_rej_reason reason,
297881ddb41fSJason Gunthorpe void *ari, u8 ari_length, const void *private_data,
297981ddb41fSJason Gunthorpe u8 private_data_len)
298081ddb41fSJason Gunthorpe {
298181ddb41fSJason Gunthorpe struct cm_id_private *cm_id_priv =
298281ddb41fSJason Gunthorpe container_of(cm_id, struct cm_id_private, id);
298381ddb41fSJason Gunthorpe unsigned long flags;
298481ddb41fSJason Gunthorpe int ret;
298581ddb41fSJason Gunthorpe
298681ddb41fSJason Gunthorpe spin_lock_irqsave(&cm_id_priv->lock, flags);
298781ddb41fSJason Gunthorpe ret = cm_send_rej_locked(cm_id_priv, reason, ari, ari_length,
298881ddb41fSJason Gunthorpe private_data, private_data_len);
298981ddb41fSJason Gunthorpe spin_unlock_irqrestore(&cm_id_priv->lock, flags);
2990a977049dSHal Rosenstock return ret;
2991a977049dSHal Rosenstock }
2992a977049dSHal Rosenstock EXPORT_SYMBOL(ib_send_cm_rej);
2993a977049dSHal Rosenstock
cm_format_rej_event(struct cm_work * work)2994a977049dSHal Rosenstock static void cm_format_rej_event(struct cm_work *work)
2995a977049dSHal Rosenstock {
2996a977049dSHal Rosenstock struct cm_rej_msg *rej_msg;
2997a977049dSHal Rosenstock struct ib_cm_rej_event_param *param;
2998a977049dSHal Rosenstock
2999a977049dSHal Rosenstock rej_msg = (struct cm_rej_msg *)work->mad_recv_wc->recv_buf.mad;
3000a977049dSHal Rosenstock param = &work->cm_event.param.rej_rcvd;
30014ca662a3SJason Gunthorpe param->ari = IBA_GET_MEM_PTR(CM_REJ_ARI, rej_msg);
3002b6bbee68SJason Gunthorpe param->ari_length = IBA_GET(CM_REJ_REJECTED_INFO_LENGTH, rej_msg);
300391b60a71SJason Gunthorpe param->reason = IBA_GET(CM_REJ_REASON, rej_msg);
30044ca662a3SJason Gunthorpe work->cm_event.private_data =
30054ca662a3SJason Gunthorpe IBA_GET_MEM_PTR(CM_REJ_PRIVATE_DATA, rej_msg);
3006a977049dSHal Rosenstock }
3007a977049dSHal Rosenstock
cm_acquire_rejected_id(struct cm_rej_msg * rej_msg)3008a977049dSHal Rosenstock static struct cm_id_private *cm_acquire_rejected_id(struct cm_rej_msg *rej_msg)
3009a977049dSHal Rosenstock {
3010a977049dSHal Rosenstock struct cm_id_private *cm_id_priv;
301197f52eb4SSean Hefty __be32 remote_id;
3012a977049dSHal Rosenstock
301391b60a71SJason Gunthorpe remote_id = cpu_to_be32(IBA_GET(CM_REJ_LOCAL_COMM_ID, rej_msg));
3014a977049dSHal Rosenstock
301591b60a71SJason Gunthorpe if (IBA_GET(CM_REJ_REASON, rej_msg) == IB_CM_REJ_TIMEOUT) {
3016cfa68b0dSJason Gunthorpe cm_id_priv = cm_find_remote_id(
30174ca662a3SJason Gunthorpe *((__be64 *)IBA_GET_MEM_PTR(CM_REJ_ARI, rej_msg)),
3018a977049dSHal Rosenstock remote_id);
3019b6bbee68SJason Gunthorpe } else if (IBA_GET(CM_REJ_MESSAGE_REJECTED, rej_msg) ==
3020b6bbee68SJason Gunthorpe CM_MSG_RESPONSE_REQ)
302191b60a71SJason Gunthorpe cm_id_priv = cm_acquire_id(
302291b60a71SJason Gunthorpe cpu_to_be32(IBA_GET(CM_REJ_REMOTE_COMM_ID, rej_msg)),
302391b60a71SJason Gunthorpe 0);
3024a977049dSHal Rosenstock else
302591b60a71SJason Gunthorpe cm_id_priv = cm_acquire_id(
302691b60a71SJason Gunthorpe cpu_to_be32(IBA_GET(CM_REJ_REMOTE_COMM_ID, rej_msg)),
302791b60a71SJason Gunthorpe remote_id);
3028a977049dSHal Rosenstock
3029a977049dSHal Rosenstock return cm_id_priv;
3030a977049dSHal Rosenstock }
3031a977049dSHal Rosenstock
cm_rej_handler(struct cm_work * work)3032a977049dSHal Rosenstock static int cm_rej_handler(struct cm_work *work)
3033a977049dSHal Rosenstock {
3034a977049dSHal Rosenstock struct cm_id_private *cm_id_priv;
3035a977049dSHal Rosenstock struct cm_rej_msg *rej_msg;
3036a977049dSHal Rosenstock
3037a977049dSHal Rosenstock rej_msg = (struct cm_rej_msg *)work->mad_recv_wc->recv_buf.mad;
3038a977049dSHal Rosenstock cm_id_priv = cm_acquire_rejected_id(rej_msg);
3039a977049dSHal Rosenstock if (!cm_id_priv)
3040a977049dSHal Rosenstock return -EINVAL;
3041a977049dSHal Rosenstock
3042a977049dSHal Rosenstock cm_format_rej_event(work);
3043a977049dSHal Rosenstock
304424be6e81SSean Hefty spin_lock_irq(&cm_id_priv->lock);
3045a977049dSHal Rosenstock switch (cm_id_priv->id.state) {
3046a977049dSHal Rosenstock case IB_CM_REQ_SENT:
3047a977049dSHal Rosenstock case IB_CM_MRA_REQ_RCVD:
3048a977049dSHal Rosenstock case IB_CM_REP_SENT:
3049a977049dSHal Rosenstock case IB_CM_MRA_REP_RCVD:
305070076a41SMark Zhang ib_cancel_mad(cm_id_priv->msg);
3051df561f66SGustavo A. R. Silva fallthrough;
3052a977049dSHal Rosenstock case IB_CM_REQ_RCVD:
3053a977049dSHal Rosenstock case IB_CM_MRA_REQ_SENT:
305491b60a71SJason Gunthorpe if (IBA_GET(CM_REJ_REASON, rej_msg) == IB_CM_REJ_STALE_CONN)
3055a977049dSHal Rosenstock cm_enter_timewait(cm_id_priv);
3056a977049dSHal Rosenstock else
3057a977049dSHal Rosenstock cm_reset_to_idle(cm_id_priv);
3058a977049dSHal Rosenstock break;
3059a977049dSHal Rosenstock case IB_CM_DREQ_SENT:
306070076a41SMark Zhang ib_cancel_mad(cm_id_priv->msg);
3061df561f66SGustavo A. R. Silva fallthrough;
3062a977049dSHal Rosenstock case IB_CM_REP_RCVD:
3063a977049dSHal Rosenstock case IB_CM_MRA_REP_SENT:
3064a977049dSHal Rosenstock cm_enter_timewait(cm_id_priv);
3065a977049dSHal Rosenstock break;
30668d8ac865SSean Hefty case IB_CM_ESTABLISHED:
30678d8ac865SSean Hefty if (cm_id_priv->id.lap_state == IB_CM_LAP_UNINIT ||
30688d8ac865SSean Hefty cm_id_priv->id.lap_state == IB_CM_LAP_SENT) {
30698d8ac865SSean Hefty if (cm_id_priv->id.lap_state == IB_CM_LAP_SENT)
307070076a41SMark Zhang ib_cancel_mad(cm_id_priv->msg);
30718d8ac865SSean Hefty cm_enter_timewait(cm_id_priv);
30728d8ac865SSean Hefty break;
30738d8ac865SSean Hefty }
3074df561f66SGustavo A. R. Silva fallthrough;
3075a977049dSHal Rosenstock default:
307675874b3dSChuck Lever trace_icm_rej_unknown_err(&cm_id_priv->id);
3077153a2e43SJason Gunthorpe spin_unlock_irq(&cm_id_priv->lock);
3078a977049dSHal Rosenstock goto out;
3079a977049dSHal Rosenstock }
3080a977049dSHal Rosenstock
3081e83f195aSJason Gunthorpe cm_queue_work_unlock(cm_id_priv, work);
3082a977049dSHal Rosenstock return 0;
3083a977049dSHal Rosenstock out:
3084a977049dSHal Rosenstock cm_deref_id(cm_id_priv);
3085a977049dSHal Rosenstock return -EINVAL;
3086a977049dSHal Rosenstock }
3087a977049dSHal Rosenstock
ib_send_cm_mra(struct ib_cm_id * cm_id,u8 service_timeout,const void * private_data,u8 private_data_len)3088a977049dSHal Rosenstock int ib_send_cm_mra(struct ib_cm_id *cm_id,
3089a977049dSHal Rosenstock u8 service_timeout,
3090a977049dSHal Rosenstock const void *private_data,
3091a977049dSHal Rosenstock u8 private_data_len)
3092a977049dSHal Rosenstock {
3093a977049dSHal Rosenstock struct cm_id_private *cm_id_priv;
3094a977049dSHal Rosenstock struct ib_mad_send_buf *msg;
3095de98b693SSean Hefty enum ib_cm_state cm_state;
3096de98b693SSean Hefty enum ib_cm_lap_state lap_state;
3097de98b693SSean Hefty enum cm_msg_response msg_response;
3098a977049dSHal Rosenstock void *data;
3099a977049dSHal Rosenstock unsigned long flags;
3100a977049dSHal Rosenstock int ret;
3101a977049dSHal Rosenstock
3102a977049dSHal Rosenstock if (private_data && private_data_len > IB_CM_MRA_PRIVATE_DATA_SIZE)
3103a977049dSHal Rosenstock return -EINVAL;
3104a977049dSHal Rosenstock
3105a977049dSHal Rosenstock data = cm_copy_private_data(private_data, private_data_len);
3106a977049dSHal Rosenstock if (IS_ERR(data))
3107a977049dSHal Rosenstock return PTR_ERR(data);
3108a977049dSHal Rosenstock
3109a977049dSHal Rosenstock cm_id_priv = container_of(cm_id, struct cm_id_private, id);
3110a977049dSHal Rosenstock
3111a977049dSHal Rosenstock spin_lock_irqsave(&cm_id_priv->lock, flags);
3112a977049dSHal Rosenstock switch (cm_id_priv->id.state) {
3113a977049dSHal Rosenstock case IB_CM_REQ_RCVD:
3114de98b693SSean Hefty cm_state = IB_CM_MRA_REQ_SENT;
3115de98b693SSean Hefty lap_state = cm_id->lap_state;
3116de98b693SSean Hefty msg_response = CM_MSG_RESPONSE_REQ;
3117a977049dSHal Rosenstock break;
3118a977049dSHal Rosenstock case IB_CM_REP_RCVD:
3119de98b693SSean Hefty cm_state = IB_CM_MRA_REP_SENT;
3120de98b693SSean Hefty lap_state = cm_id->lap_state;
3121de98b693SSean Hefty msg_response = CM_MSG_RESPONSE_REP;
3122a977049dSHal Rosenstock break;
3123a977049dSHal Rosenstock case IB_CM_ESTABLISHED:
312450a025c6SSean Hefty if (cm_id->lap_state == IB_CM_LAP_RCVD) {
3125de98b693SSean Hefty cm_state = cm_id->state;
3126de98b693SSean Hefty lap_state = IB_CM_MRA_LAP_SENT;
3127de98b693SSean Hefty msg_response = CM_MSG_RESPONSE_OTHER;
3128a977049dSHal Rosenstock break;
312950a025c6SSean Hefty }
3130df561f66SGustavo A. R. Silva fallthrough;
3131a977049dSHal Rosenstock default:
313275874b3dSChuck Lever trace_icm_send_mra_unknown_err(&cm_id_priv->id);
3133a977049dSHal Rosenstock ret = -EINVAL;
31344b4e586eSJason Gunthorpe goto error_unlock;
3135a977049dSHal Rosenstock }
3136de98b693SSean Hefty
3137de98b693SSean Hefty if (!(service_timeout & IB_CM_MRA_FLAG_DELAY)) {
31384b4e586eSJason Gunthorpe msg = cm_alloc_msg(cm_id_priv);
31394b4e586eSJason Gunthorpe if (IS_ERR(msg)) {
31404b4e586eSJason Gunthorpe ret = PTR_ERR(msg);
31414b4e586eSJason Gunthorpe goto error_unlock;
31424b4e586eSJason Gunthorpe }
3143de98b693SSean Hefty
3144de98b693SSean Hefty cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
3145de98b693SSean Hefty msg_response, service_timeout,
3146de98b693SSean Hefty private_data, private_data_len);
31478dc105beSChuck Lever trace_icm_send_mra(cm_id);
3148de98b693SSean Hefty ret = ib_post_send_mad(msg, NULL);
3149de98b693SSean Hefty if (ret)
31504b4e586eSJason Gunthorpe goto error_free_msg;
3151de98b693SSean Hefty }
3152de98b693SSean Hefty
3153de98b693SSean Hefty cm_id->state = cm_state;
3154de98b693SSean Hefty cm_id->lap_state = lap_state;
3155a977049dSHal Rosenstock cm_id_priv->service_timeout = service_timeout;
3156a977049dSHal Rosenstock cm_set_private_data(cm_id_priv, data, private_data_len);
3157a977049dSHal Rosenstock spin_unlock_irqrestore(&cm_id_priv->lock, flags);
3158a977049dSHal Rosenstock return 0;
3159a977049dSHal Rosenstock
31604b4e586eSJason Gunthorpe error_free_msg:
3161a977049dSHal Rosenstock cm_free_msg(msg);
31624b4e586eSJason Gunthorpe error_unlock:
31634b4e586eSJason Gunthorpe spin_unlock_irqrestore(&cm_id_priv->lock, flags);
31644b4e586eSJason Gunthorpe kfree(data);
3165a977049dSHal Rosenstock return ret;
3166a977049dSHal Rosenstock }
3167a977049dSHal Rosenstock EXPORT_SYMBOL(ib_send_cm_mra);
3168a977049dSHal Rosenstock
cm_acquire_mraed_id(struct cm_mra_msg * mra_msg)3169a977049dSHal Rosenstock static struct cm_id_private *cm_acquire_mraed_id(struct cm_mra_msg *mra_msg)
3170a977049dSHal Rosenstock {
3171b6bbee68SJason Gunthorpe switch (IBA_GET(CM_MRA_MESSAGE_MRAED, mra_msg)) {
3172a977049dSHal Rosenstock case CM_MSG_RESPONSE_REQ:
317391b60a71SJason Gunthorpe return cm_acquire_id(
317491b60a71SJason Gunthorpe cpu_to_be32(IBA_GET(CM_MRA_REMOTE_COMM_ID, mra_msg)),
317591b60a71SJason Gunthorpe 0);
3176a977049dSHal Rosenstock case CM_MSG_RESPONSE_REP:
3177a977049dSHal Rosenstock case CM_MSG_RESPONSE_OTHER:
317891b60a71SJason Gunthorpe return cm_acquire_id(
317991b60a71SJason Gunthorpe cpu_to_be32(IBA_GET(CM_MRA_REMOTE_COMM_ID, mra_msg)),
318091b60a71SJason Gunthorpe cpu_to_be32(IBA_GET(CM_MRA_LOCAL_COMM_ID, mra_msg)));
3181a977049dSHal Rosenstock default:
3182a977049dSHal Rosenstock return NULL;
3183a977049dSHal Rosenstock }
3184a977049dSHal Rosenstock }
3185a977049dSHal Rosenstock
cm_mra_handler(struct cm_work * work)3186a977049dSHal Rosenstock static int cm_mra_handler(struct cm_work *work)
3187a977049dSHal Rosenstock {
3188a977049dSHal Rosenstock struct cm_id_private *cm_id_priv;
3189a977049dSHal Rosenstock struct cm_mra_msg *mra_msg;
3190e83f195aSJason Gunthorpe int timeout;
3191a977049dSHal Rosenstock
3192a977049dSHal Rosenstock mra_msg = (struct cm_mra_msg *)work->mad_recv_wc->recv_buf.mad;
3193a977049dSHal Rosenstock cm_id_priv = cm_acquire_mraed_id(mra_msg);
3194a977049dSHal Rosenstock if (!cm_id_priv)
3195a977049dSHal Rosenstock return -EINVAL;
3196a977049dSHal Rosenstock
31974ca662a3SJason Gunthorpe work->cm_event.private_data =
31984ca662a3SJason Gunthorpe IBA_GET_MEM_PTR(CM_MRA_PRIVATE_DATA, mra_msg);
3199a977049dSHal Rosenstock work->cm_event.param.mra_rcvd.service_timeout =
3200b6bbee68SJason Gunthorpe IBA_GET(CM_MRA_SERVICE_TIMEOUT, mra_msg);
3201b6bbee68SJason Gunthorpe timeout = cm_convert_to_ms(IBA_GET(CM_MRA_SERVICE_TIMEOUT, mra_msg)) +
32021d846126SSean Hefty cm_convert_to_ms(cm_id_priv->av.timeout);
3203a977049dSHal Rosenstock
320424be6e81SSean Hefty spin_lock_irq(&cm_id_priv->lock);
3205a977049dSHal Rosenstock switch (cm_id_priv->id.state) {
3206a977049dSHal Rosenstock case IB_CM_REQ_SENT:
3207b6bbee68SJason Gunthorpe if (IBA_GET(CM_MRA_MESSAGE_MRAED, mra_msg) !=
3208b6bbee68SJason Gunthorpe CM_MSG_RESPONSE_REQ ||
320970076a41SMark Zhang ib_modify_mad(cm_id_priv->msg, timeout))
3210a977049dSHal Rosenstock goto out;
3211a977049dSHal Rosenstock cm_id_priv->id.state = IB_CM_MRA_REQ_RCVD;
3212a977049dSHal Rosenstock break;
3213a977049dSHal Rosenstock case IB_CM_REP_SENT:
3214b6bbee68SJason Gunthorpe if (IBA_GET(CM_MRA_MESSAGE_MRAED, mra_msg) !=
3215b6bbee68SJason Gunthorpe CM_MSG_RESPONSE_REP ||
321670076a41SMark Zhang ib_modify_mad(cm_id_priv->msg, timeout))
3217a977049dSHal Rosenstock goto out;
3218a977049dSHal Rosenstock cm_id_priv->id.state = IB_CM_MRA_REP_RCVD;
3219a977049dSHal Rosenstock break;
3220a977049dSHal Rosenstock case IB_CM_ESTABLISHED:
3221b6bbee68SJason Gunthorpe if (IBA_GET(CM_MRA_MESSAGE_MRAED, mra_msg) !=
3222b6bbee68SJason Gunthorpe CM_MSG_RESPONSE_OTHER ||
3223a977049dSHal Rosenstock cm_id_priv->id.lap_state != IB_CM_LAP_SENT ||
322470076a41SMark Zhang ib_modify_mad(cm_id_priv->msg, timeout)) {
32259af57b7aSSean Hefty if (cm_id_priv->id.lap_state == IB_CM_MRA_LAP_RCVD)
3226526a12c8SJason Gunthorpe atomic_long_inc(
3227526a12c8SJason Gunthorpe &work->port->counters[CM_RECV_DUPLICATES]
3228526a12c8SJason Gunthorpe [CM_MRA_COUNTER]);
3229a977049dSHal Rosenstock goto out;
32309af57b7aSSean Hefty }
3231a977049dSHal Rosenstock cm_id_priv->id.lap_state = IB_CM_MRA_LAP_RCVD;
3232a977049dSHal Rosenstock break;
32339af57b7aSSean Hefty case IB_CM_MRA_REQ_RCVD:
32349af57b7aSSean Hefty case IB_CM_MRA_REP_RCVD:
3235526a12c8SJason Gunthorpe atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES]
3236526a12c8SJason Gunthorpe [CM_MRA_COUNTER]);
3237df561f66SGustavo A. R. Silva fallthrough;
3238a977049dSHal Rosenstock default:
323975874b3dSChuck Lever trace_icm_mra_unknown_err(&cm_id_priv->id);
3240a977049dSHal Rosenstock goto out;
3241a977049dSHal Rosenstock }
3242a977049dSHal Rosenstock
3243a977049dSHal Rosenstock cm_id_priv->msg->context[1] = (void *) (unsigned long)
3244a977049dSHal Rosenstock cm_id_priv->id.state;
3245e83f195aSJason Gunthorpe cm_queue_work_unlock(cm_id_priv, work);
3246a977049dSHal Rosenstock return 0;
3247a977049dSHal Rosenstock out:
324824be6e81SSean Hefty spin_unlock_irq(&cm_id_priv->lock);
3249a977049dSHal Rosenstock cm_deref_id(cm_id_priv);
3250a977049dSHal Rosenstock return -EINVAL;
3251a977049dSHal Rosenstock }
3252a977049dSHal Rosenstock
cm_format_path_lid_from_lap(struct cm_lap_msg * lap_msg,struct sa_path_rec * path)3253ac3a949fSDasaratharaman Chandramouli static void cm_format_path_lid_from_lap(struct cm_lap_msg *lap_msg,
3254ac3a949fSDasaratharaman Chandramouli struct sa_path_rec *path)
3255ac3a949fSDasaratharaman Chandramouli {
3256ac3a949fSDasaratharaman Chandramouli u32 lid;
3257ac3a949fSDasaratharaman Chandramouli
3258ac3a949fSDasaratharaman Chandramouli if (path->rec_type != SA_PATH_REC_TYPE_OPA) {
325991b60a71SJason Gunthorpe sa_path_set_dlid(path, IBA_GET(CM_LAP_ALTERNATE_LOCAL_PORT_LID,
326091b60a71SJason Gunthorpe lap_msg));
326191b60a71SJason Gunthorpe sa_path_set_slid(path, IBA_GET(CM_LAP_ALTERNATE_REMOTE_PORT_LID,
326291b60a71SJason Gunthorpe lap_msg));
3263ac3a949fSDasaratharaman Chandramouli } else {
32644ca662a3SJason Gunthorpe lid = opa_get_lid_from_gid(IBA_GET_MEM_PTR(
32654ca662a3SJason Gunthorpe CM_LAP_ALTERNATE_LOCAL_PORT_GID, lap_msg));
32669d187177SBart Van Assche sa_path_set_dlid(path, lid);
3267ac3a949fSDasaratharaman Chandramouli
32684ca662a3SJason Gunthorpe lid = opa_get_lid_from_gid(IBA_GET_MEM_PTR(
32694ca662a3SJason Gunthorpe CM_LAP_ALTERNATE_REMOTE_PORT_GID, lap_msg));
32709d187177SBart Van Assche sa_path_set_slid(path, lid);
3271ac3a949fSDasaratharaman Chandramouli }
3272ac3a949fSDasaratharaman Chandramouli }
3273ac3a949fSDasaratharaman Chandramouli
cm_format_path_from_lap(struct cm_id_private * cm_id_priv,struct sa_path_rec * path,struct cm_lap_msg * lap_msg)3274e1444b5aSSean Hefty static void cm_format_path_from_lap(struct cm_id_private *cm_id_priv,
3275c2f8fc4eSDasaratharaman Chandramouli struct sa_path_rec *path,
3276a977049dSHal Rosenstock struct cm_lap_msg *lap_msg)
3277a977049dSHal Rosenstock {
32784ca662a3SJason Gunthorpe path->dgid = *IBA_GET_MEM_PTR(CM_LAP_ALTERNATE_LOCAL_PORT_GID, lap_msg);
32794ca662a3SJason Gunthorpe path->sgid =
32804ca662a3SJason Gunthorpe *IBA_GET_MEM_PTR(CM_LAP_ALTERNATE_REMOTE_PORT_GID, lap_msg);
328101adb7f4SJason Gunthorpe path->flow_label =
328201adb7f4SJason Gunthorpe cpu_to_be32(IBA_GET(CM_LAP_ALTERNATE_FLOW_LABEL, lap_msg));
328391b60a71SJason Gunthorpe path->hop_limit = IBA_GET(CM_LAP_ALTERNATE_HOP_LIMIT, lap_msg);
3284b6bbee68SJason Gunthorpe path->traffic_class = IBA_GET(CM_LAP_ALTERNATE_TRAFFIC_CLASS, lap_msg);
3285a977049dSHal Rosenstock path->reversible = 1;
3286e1444b5aSSean Hefty path->pkey = cm_id_priv->pkey;
3287b6bbee68SJason Gunthorpe path->sl = IBA_GET(CM_LAP_ALTERNATE_SL, lap_msg);
3288a977049dSHal Rosenstock path->mtu_selector = IB_SA_EQ;
3289e1444b5aSSean Hefty path->mtu = cm_id_priv->path_mtu;
3290a977049dSHal Rosenstock path->rate_selector = IB_SA_EQ;
3291b6bbee68SJason Gunthorpe path->rate = IBA_GET(CM_LAP_ALTERNATE_PACKET_RATE, lap_msg);
3292a977049dSHal Rosenstock path->packet_life_time_selector = IB_SA_EQ;
3293b6bbee68SJason Gunthorpe path->packet_life_time =
3294b6bbee68SJason Gunthorpe IBA_GET(CM_LAP_ALTERNATE_LOCAL_ACK_TIMEOUT, lap_msg);
3295a977049dSHal Rosenstock path->packet_life_time -= (path->packet_life_time > 0);
3296ac3a949fSDasaratharaman Chandramouli cm_format_path_lid_from_lap(lap_msg, path);
3297a977049dSHal Rosenstock }
3298a977049dSHal Rosenstock
cm_lap_handler(struct cm_work * work)3299a977049dSHal Rosenstock static int cm_lap_handler(struct cm_work *work)
3300a977049dSHal Rosenstock {
3301a977049dSHal Rosenstock struct cm_id_private *cm_id_priv;
3302a977049dSHal Rosenstock struct cm_lap_msg *lap_msg;
3303a977049dSHal Rosenstock struct ib_cm_lap_event_param *param;
3304a977049dSHal Rosenstock struct ib_mad_send_buf *msg = NULL;
33057345201cSMark Zhang struct rdma_ah_attr ah_attr;
33067345201cSMark Zhang struct cm_av alt_av = {};
3307a977049dSHal Rosenstock int ret;
3308a977049dSHal Rosenstock
330997c45c2cSParav Pandit /* Currently Alternate path messages are not supported for
331097c45c2cSParav Pandit * RoCE link layer.
331197c45c2cSParav Pandit */
331297c45c2cSParav Pandit if (rdma_protocol_roce(work->port->cm_dev->ib_device,
331397c45c2cSParav Pandit work->port->port_num))
331497c45c2cSParav Pandit return -EINVAL;
331597c45c2cSParav Pandit
3316a977049dSHal Rosenstock /* todo: verify LAP request and send reject APR if invalid. */
3317a977049dSHal Rosenstock lap_msg = (struct cm_lap_msg *)work->mad_recv_wc->recv_buf.mad;
331891b60a71SJason Gunthorpe cm_id_priv = cm_acquire_id(
331991b60a71SJason Gunthorpe cpu_to_be32(IBA_GET(CM_LAP_REMOTE_COMM_ID, lap_msg)),
332091b60a71SJason Gunthorpe cpu_to_be32(IBA_GET(CM_LAP_LOCAL_COMM_ID, lap_msg)));
3321a977049dSHal Rosenstock if (!cm_id_priv)
3322a977049dSHal Rosenstock return -EINVAL;
3323a977049dSHal Rosenstock
3324a977049dSHal Rosenstock param = &work->cm_event.param.lap_rcvd;
33256b3c0e6eSDasaratharaman Chandramouli memset(&work->path[0], 0, sizeof(work->path[1]));
33266b3c0e6eSDasaratharaman Chandramouli cm_path_set_rec_type(work->port->cm_dev->ib_device,
33274ca662a3SJason Gunthorpe work->port->port_num, &work->path[0],
33284ca662a3SJason Gunthorpe IBA_GET_MEM_PTR(CM_LAP_ALTERNATE_LOCAL_PORT_GID,
33294ca662a3SJason Gunthorpe lap_msg));
3330a977049dSHal Rosenstock param->alternate_path = &work->path[0];
3331e1444b5aSSean Hefty cm_format_path_from_lap(cm_id_priv, param->alternate_path, lap_msg);
33324ca662a3SJason Gunthorpe work->cm_event.private_data =
33334ca662a3SJason Gunthorpe IBA_GET_MEM_PTR(CM_LAP_PRIVATE_DATA, lap_msg);
3334a977049dSHal Rosenstock
33357345201cSMark Zhang ret = ib_init_ah_attr_from_wc(work->port->cm_dev->ib_device,
33367345201cSMark Zhang work->port->port_num,
33377345201cSMark Zhang work->mad_recv_wc->wc,
33387345201cSMark Zhang work->mad_recv_wc->recv_buf.grh,
33397345201cSMark Zhang &ah_attr);
33407345201cSMark Zhang if (ret)
33417345201cSMark Zhang goto deref;
33427345201cSMark Zhang
33437345201cSMark Zhang ret = cm_init_av_by_path(param->alternate_path, NULL, &alt_av);
33447345201cSMark Zhang if (ret) {
33457345201cSMark Zhang rdma_destroy_ah_attr(&ah_attr);
3346b856101aSMark Zhang goto deref;
33477345201cSMark Zhang }
33487345201cSMark Zhang
334924be6e81SSean Hefty spin_lock_irq(&cm_id_priv->lock);
33507345201cSMark Zhang cm_init_av_for_lap(work->port, work->mad_recv_wc->wc,
33517345201cSMark Zhang &ah_attr, &cm_id_priv->av);
33527345201cSMark Zhang cm_move_av_from_path(&cm_id_priv->alt_av, &alt_av);
33537345201cSMark Zhang
3354a977049dSHal Rosenstock if (cm_id_priv->id.state != IB_CM_ESTABLISHED)
3355a977049dSHal Rosenstock goto unlock;
3356a977049dSHal Rosenstock
3357a977049dSHal Rosenstock switch (cm_id_priv->id.lap_state) {
3358e1444b5aSSean Hefty case IB_CM_LAP_UNINIT:
3359a977049dSHal Rosenstock case IB_CM_LAP_IDLE:
3360a977049dSHal Rosenstock break;
3361a977049dSHal Rosenstock case IB_CM_MRA_LAP_SENT:
3362526a12c8SJason Gunthorpe atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES]
3363526a12c8SJason Gunthorpe [CM_LAP_COUNTER]);
3364c7616118SRoland Dreier msg = cm_alloc_response_msg_no_ah(work->port, work->mad_recv_wc);
3365c7616118SRoland Dreier if (IS_ERR(msg))
3366a977049dSHal Rosenstock goto unlock;
3367a977049dSHal Rosenstock
3368a977049dSHal Rosenstock cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
3369a977049dSHal Rosenstock CM_MSG_RESPONSE_OTHER,
3370a977049dSHal Rosenstock cm_id_priv->service_timeout,
3371a977049dSHal Rosenstock cm_id_priv->private_data,
3372a977049dSHal Rosenstock cm_id_priv->private_data_len);
337324be6e81SSean Hefty spin_unlock_irq(&cm_id_priv->lock);
3374a977049dSHal Rosenstock
3375c7616118SRoland Dreier if (cm_create_response_msg_ah(work->port, work->mad_recv_wc, msg) ||
3376c7616118SRoland Dreier ib_post_send_mad(msg, NULL))
337796376a40SJason Gunthorpe cm_free_response_msg(msg);
3378a977049dSHal Rosenstock goto deref;
33799af57b7aSSean Hefty case IB_CM_LAP_RCVD:
3380526a12c8SJason Gunthorpe atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES]
3381526a12c8SJason Gunthorpe [CM_LAP_COUNTER]);
33829af57b7aSSean Hefty goto unlock;
3383a977049dSHal Rosenstock default:
3384a977049dSHal Rosenstock goto unlock;
3385a977049dSHal Rosenstock }
3386a977049dSHal Rosenstock
3387a5c57d32SParav Pandit cm_id_priv->id.lap_state = IB_CM_LAP_RCVD;
3388a5c57d32SParav Pandit cm_id_priv->tid = lap_msg->hdr.tid;
3389e83f195aSJason Gunthorpe cm_queue_work_unlock(cm_id_priv, work);
3390a977049dSHal Rosenstock return 0;
3391a977049dSHal Rosenstock
339224be6e81SSean Hefty unlock: spin_unlock_irq(&cm_id_priv->lock);
3393a977049dSHal Rosenstock deref: cm_deref_id(cm_id_priv);
3394a977049dSHal Rosenstock return -EINVAL;
3395a977049dSHal Rosenstock }
3396a977049dSHal Rosenstock
cm_apr_handler(struct cm_work * work)3397a977049dSHal Rosenstock static int cm_apr_handler(struct cm_work *work)
3398a977049dSHal Rosenstock {
3399a977049dSHal Rosenstock struct cm_id_private *cm_id_priv;
3400a977049dSHal Rosenstock struct cm_apr_msg *apr_msg;
3401a977049dSHal Rosenstock
340297c45c2cSParav Pandit /* Currently Alternate path messages are not supported for
340397c45c2cSParav Pandit * RoCE link layer.
340497c45c2cSParav Pandit */
340597c45c2cSParav Pandit if (rdma_protocol_roce(work->port->cm_dev->ib_device,
340697c45c2cSParav Pandit work->port->port_num))
340797c45c2cSParav Pandit return -EINVAL;
340897c45c2cSParav Pandit
3409a977049dSHal Rosenstock apr_msg = (struct cm_apr_msg *)work->mad_recv_wc->recv_buf.mad;
341091b60a71SJason Gunthorpe cm_id_priv = cm_acquire_id(
341191b60a71SJason Gunthorpe cpu_to_be32(IBA_GET(CM_APR_REMOTE_COMM_ID, apr_msg)),
341291b60a71SJason Gunthorpe cpu_to_be32(IBA_GET(CM_APR_LOCAL_COMM_ID, apr_msg)));
3413a977049dSHal Rosenstock if (!cm_id_priv)
3414a977049dSHal Rosenstock return -EINVAL; /* Unmatched reply. */
3415a977049dSHal Rosenstock
341691b60a71SJason Gunthorpe work->cm_event.param.apr_rcvd.ap_status =
341791b60a71SJason Gunthorpe IBA_GET(CM_APR_AR_STATUS, apr_msg);
34184ca662a3SJason Gunthorpe work->cm_event.param.apr_rcvd.apr_info =
34194ca662a3SJason Gunthorpe IBA_GET_MEM_PTR(CM_APR_ADDITIONAL_INFORMATION, apr_msg);
342091b60a71SJason Gunthorpe work->cm_event.param.apr_rcvd.info_len =
342191b60a71SJason Gunthorpe IBA_GET(CM_APR_ADDITIONAL_INFORMATION_LENGTH, apr_msg);
34224ca662a3SJason Gunthorpe work->cm_event.private_data =
34234ca662a3SJason Gunthorpe IBA_GET_MEM_PTR(CM_APR_PRIVATE_DATA, apr_msg);
3424a977049dSHal Rosenstock
342524be6e81SSean Hefty spin_lock_irq(&cm_id_priv->lock);
3426a977049dSHal Rosenstock if (cm_id_priv->id.state != IB_CM_ESTABLISHED ||
3427a977049dSHal Rosenstock (cm_id_priv->id.lap_state != IB_CM_LAP_SENT &&
3428a977049dSHal Rosenstock cm_id_priv->id.lap_state != IB_CM_MRA_LAP_RCVD)) {
342924be6e81SSean Hefty spin_unlock_irq(&cm_id_priv->lock);
3430a977049dSHal Rosenstock goto out;
3431a977049dSHal Rosenstock }
3432a977049dSHal Rosenstock cm_id_priv->id.lap_state = IB_CM_LAP_IDLE;
343370076a41SMark Zhang ib_cancel_mad(cm_id_priv->msg);
3434e83f195aSJason Gunthorpe cm_queue_work_unlock(cm_id_priv, work);
3435a977049dSHal Rosenstock return 0;
3436a977049dSHal Rosenstock out:
3437a977049dSHal Rosenstock cm_deref_id(cm_id_priv);
3438a977049dSHal Rosenstock return -EINVAL;
3439a977049dSHal Rosenstock }
3440a977049dSHal Rosenstock
cm_timewait_handler(struct cm_work * work)3441a977049dSHal Rosenstock static int cm_timewait_handler(struct cm_work *work)
3442a977049dSHal Rosenstock {
3443a977049dSHal Rosenstock struct cm_timewait_info *timewait_info;
3444a977049dSHal Rosenstock struct cm_id_private *cm_id_priv;
3445a977049dSHal Rosenstock
3446909624d8SParav Pandit timewait_info = container_of(work, struct cm_timewait_info, work);
34478575329dSSean Hefty spin_lock_irq(&cm.lock);
34488575329dSSean Hefty list_del(&timewait_info->list);
34498575329dSSean Hefty spin_unlock_irq(&cm.lock);
3450a977049dSHal Rosenstock
3451a977049dSHal Rosenstock cm_id_priv = cm_acquire_id(timewait_info->work.local_id,
3452a977049dSHal Rosenstock timewait_info->work.remote_id);
3453a977049dSHal Rosenstock if (!cm_id_priv)
3454a977049dSHal Rosenstock return -EINVAL;
3455a977049dSHal Rosenstock
34568575329dSSean Hefty spin_lock_irq(&cm_id_priv->lock);
3457a977049dSHal Rosenstock if (cm_id_priv->id.state != IB_CM_TIMEWAIT ||
3458a977049dSHal Rosenstock cm_id_priv->remote_qpn != timewait_info->remote_qpn) {
34598575329dSSean Hefty spin_unlock_irq(&cm_id_priv->lock);
3460a977049dSHal Rosenstock goto out;
3461a977049dSHal Rosenstock }
3462a977049dSHal Rosenstock cm_id_priv->id.state = IB_CM_IDLE;
3463e83f195aSJason Gunthorpe cm_queue_work_unlock(cm_id_priv, work);
3464a977049dSHal Rosenstock return 0;
3465a977049dSHal Rosenstock out:
3466a977049dSHal Rosenstock cm_deref_id(cm_id_priv);
3467a977049dSHal Rosenstock return -EINVAL;
3468a977049dSHal Rosenstock }
3469a977049dSHal Rosenstock
cm_format_sidr_req(struct cm_sidr_req_msg * sidr_req_msg,struct cm_id_private * cm_id_priv,struct ib_cm_sidr_req_param * param)3470a977049dSHal Rosenstock static void cm_format_sidr_req(struct cm_sidr_req_msg *sidr_req_msg,
3471a977049dSHal Rosenstock struct cm_id_private *cm_id_priv,
3472a977049dSHal Rosenstock struct ib_cm_sidr_req_param *param)
3473a977049dSHal Rosenstock {
3474a977049dSHal Rosenstock cm_format_mad_hdr(&sidr_req_msg->hdr, CM_SIDR_REQ_ATTR_ID,
347587a37ce9SHåkon Bugge cm_form_tid(cm_id_priv));
347691b60a71SJason Gunthorpe IBA_SET(CM_SIDR_REQ_REQUESTID, sidr_req_msg,
347791b60a71SJason Gunthorpe be32_to_cpu(cm_id_priv->id.local_id));
347891b60a71SJason Gunthorpe IBA_SET(CM_SIDR_REQ_PARTITION_KEY, sidr_req_msg,
347991b60a71SJason Gunthorpe be16_to_cpu(param->path->pkey));
348091b60a71SJason Gunthorpe IBA_SET(CM_SIDR_REQ_SERVICEID, sidr_req_msg,
348191b60a71SJason Gunthorpe be64_to_cpu(param->service_id));
3482a977049dSHal Rosenstock
3483a977049dSHal Rosenstock if (param->private_data && param->private_data_len)
34844ca662a3SJason Gunthorpe IBA_SET_MEM(CM_SIDR_REQ_PRIVATE_DATA, sidr_req_msg,
34854ca662a3SJason Gunthorpe param->private_data, param->private_data_len);
3486a977049dSHal Rosenstock }
3487a977049dSHal Rosenstock
ib_send_cm_sidr_req(struct ib_cm_id * cm_id,struct ib_cm_sidr_req_param * param)3488a977049dSHal Rosenstock int ib_send_cm_sidr_req(struct ib_cm_id *cm_id,
3489a977049dSHal Rosenstock struct ib_cm_sidr_req_param *param)
3490a977049dSHal Rosenstock {
3491a977049dSHal Rosenstock struct cm_id_private *cm_id_priv;
3492a977049dSHal Rosenstock struct ib_mad_send_buf *msg;
34937345201cSMark Zhang struct cm_av av = {};
3494a977049dSHal Rosenstock unsigned long flags;
3495a977049dSHal Rosenstock int ret;
3496a977049dSHal Rosenstock
3497a977049dSHal Rosenstock if (!param->path || (param->private_data &&
3498a977049dSHal Rosenstock param->private_data_len > IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE))
3499a977049dSHal Rosenstock return -EINVAL;
3500a977049dSHal Rosenstock
3501a977049dSHal Rosenstock cm_id_priv = container_of(cm_id, struct cm_id_private, id);
35027345201cSMark Zhang ret = cm_init_av_by_path(param->path, param->sgid_attr, &av);
3503a977049dSHal Rosenstock if (ret)
35044b4e586eSJason Gunthorpe return ret;
3505a977049dSHal Rosenstock
35067345201cSMark Zhang spin_lock_irqsave(&cm_id_priv->lock, flags);
35077345201cSMark Zhang cm_move_av_from_path(&cm_id_priv->av, &av);
3508a977049dSHal Rosenstock cm_id->service_id = param->service_id;
3509a977049dSHal Rosenstock cm_id_priv->timeout_ms = param->timeout_ms;
3510a977049dSHal Rosenstock cm_id_priv->max_cm_retries = param->max_cm_retries;
35114b4e586eSJason Gunthorpe if (cm_id->state != IB_CM_IDLE) {
35124b4e586eSJason Gunthorpe ret = -EINVAL;
35134b4e586eSJason Gunthorpe goto out_unlock;
35144b4e586eSJason Gunthorpe }
35154b4e586eSJason Gunthorpe
35164b4e586eSJason Gunthorpe msg = cm_alloc_priv_msg(cm_id_priv);
35174b4e586eSJason Gunthorpe if (IS_ERR(msg)) {
35184b4e586eSJason Gunthorpe ret = PTR_ERR(msg);
35194b4e586eSJason Gunthorpe goto out_unlock;
35204b4e586eSJason Gunthorpe }
3521a977049dSHal Rosenstock
3522a977049dSHal Rosenstock cm_format_sidr_req((struct cm_sidr_req_msg *)msg->mad, cm_id_priv,
3523a977049dSHal Rosenstock param);
352434816ad9SSean Hefty msg->timeout_ms = cm_id_priv->timeout_ms;
3525a977049dSHal Rosenstock msg->context[1] = (void *)(unsigned long)IB_CM_SIDR_REQ_SENT;
3526a977049dSHal Rosenstock
35278dc105beSChuck Lever trace_icm_send_sidr_req(&cm_id_priv->id);
352834816ad9SSean Hefty ret = ib_post_send_mad(msg, NULL);
35294b4e586eSJason Gunthorpe if (ret)
35304b4e586eSJason Gunthorpe goto out_free;
3531a977049dSHal Rosenstock cm_id->state = IB_CM_SIDR_REQ_SENT;
3532a977049dSHal Rosenstock spin_unlock_irqrestore(&cm_id_priv->lock, flags);
35334b4e586eSJason Gunthorpe return 0;
35344b4e586eSJason Gunthorpe out_free:
35354b4e586eSJason Gunthorpe cm_free_priv_msg(msg);
35364b4e586eSJason Gunthorpe out_unlock:
35374b4e586eSJason Gunthorpe spin_unlock_irqrestore(&cm_id_priv->lock, flags);
3538a977049dSHal Rosenstock return ret;
3539a977049dSHal Rosenstock }
3540a977049dSHal Rosenstock EXPORT_SYMBOL(ib_send_cm_sidr_req);
3541a977049dSHal Rosenstock
cm_format_sidr_req_event(struct cm_work * work,const struct cm_id_private * rx_cm_id,struct ib_cm_id * listen_id)3542a977049dSHal Rosenstock static void cm_format_sidr_req_event(struct cm_work *work,
3543cee10433SParav Pandit const struct cm_id_private *rx_cm_id,
3544a977049dSHal Rosenstock struct ib_cm_id *listen_id)
3545a977049dSHal Rosenstock {
3546a977049dSHal Rosenstock struct cm_sidr_req_msg *sidr_req_msg;
3547a977049dSHal Rosenstock struct ib_cm_sidr_req_event_param *param;
3548a977049dSHal Rosenstock
3549a977049dSHal Rosenstock sidr_req_msg = (struct cm_sidr_req_msg *)
3550a977049dSHal Rosenstock work->mad_recv_wc->recv_buf.mad;
3551a977049dSHal Rosenstock param = &work->cm_event.param.sidr_req_rcvd;
355291b60a71SJason Gunthorpe param->pkey = IBA_GET(CM_SIDR_REQ_PARTITION_KEY, sidr_req_msg);
3553a977049dSHal Rosenstock param->listen_id = listen_id;
355491b60a71SJason Gunthorpe param->service_id =
355591b60a71SJason Gunthorpe cpu_to_be64(IBA_GET(CM_SIDR_REQ_SERVICEID, sidr_req_msg));
355624cad9a7SHaggai Eran param->bth_pkey = cm_get_bth_pkey(work);
3557a977049dSHal Rosenstock param->port = work->port->port_num;
3558cee10433SParav Pandit param->sgid_attr = rx_cm_id->av.ah_attr.grh.sgid_attr;
35594ca662a3SJason Gunthorpe work->cm_event.private_data =
35604ca662a3SJason Gunthorpe IBA_GET_MEM_PTR(CM_SIDR_REQ_PRIVATE_DATA, sidr_req_msg);
3561a977049dSHal Rosenstock }
3562a977049dSHal Rosenstock
cm_sidr_req_handler(struct cm_work * work)3563a977049dSHal Rosenstock static int cm_sidr_req_handler(struct cm_work *work)
3564a977049dSHal Rosenstock {
3565083bfdbfSJason Gunthorpe struct cm_id_private *cm_id_priv, *listen_cm_id_priv;
3566a977049dSHal Rosenstock struct cm_sidr_req_msg *sidr_req_msg;
3567a977049dSHal Rosenstock struct ib_wc *wc;
35680c4386ecSParav Pandit int ret;
3569a977049dSHal Rosenstock
3570083bfdbfSJason Gunthorpe cm_id_priv =
3571083bfdbfSJason Gunthorpe cm_alloc_id_priv(work->port->cm_dev->ib_device, NULL, NULL);
3572083bfdbfSJason Gunthorpe if (IS_ERR(cm_id_priv))
3573083bfdbfSJason Gunthorpe return PTR_ERR(cm_id_priv);
3574a977049dSHal Rosenstock
3575a977049dSHal Rosenstock /* Record SGID/SLID and request ID for lookup. */
3576a977049dSHal Rosenstock sidr_req_msg = (struct cm_sidr_req_msg *)
3577a977049dSHal Rosenstock work->mad_recv_wc->recv_buf.mad;
3578083bfdbfSJason Gunthorpe
3579083bfdbfSJason Gunthorpe cm_id_priv->id.remote_id =
3580083bfdbfSJason Gunthorpe cpu_to_be32(IBA_GET(CM_SIDR_REQ_REQUESTID, sidr_req_msg));
3581083bfdbfSJason Gunthorpe cm_id_priv->id.service_id =
3582083bfdbfSJason Gunthorpe cpu_to_be64(IBA_GET(CM_SIDR_REQ_SERVICEID, sidr_req_msg));
3583083bfdbfSJason Gunthorpe cm_id_priv->tid = sidr_req_msg->hdr.tid;
3584083bfdbfSJason Gunthorpe
3585a977049dSHal Rosenstock wc = work->mad_recv_wc->wc;
3586bf0480a2SJason Gunthorpe cm_id_priv->sidr_slid = wc->slid;
35870c4386ecSParav Pandit ret = cm_init_av_for_response(work->port, work->mad_recv_wc->wc,
3588ca222c6bSSean Hefty work->mad_recv_wc->recv_buf.grh,
3589a977049dSHal Rosenstock &cm_id_priv->av);
35900c4386ecSParav Pandit if (ret)
35910c4386ecSParav Pandit goto out;
35920c4386ecSParav Pandit
359324be6e81SSean Hefty spin_lock_irq(&cm.lock);
3594083bfdbfSJason Gunthorpe listen_cm_id_priv = cm_insert_remote_sidr(cm_id_priv);
3595083bfdbfSJason Gunthorpe if (listen_cm_id_priv) {
359624be6e81SSean Hefty spin_unlock_irq(&cm.lock);
3597526a12c8SJason Gunthorpe atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES]
3598526a12c8SJason Gunthorpe [CM_SIDR_REQ_COUNTER]);
3599a977049dSHal Rosenstock goto out; /* Duplicate message. */
3600a977049dSHal Rosenstock }
360129c2731cSSean Hefty cm_id_priv->id.state = IB_CM_SIDR_REQ_RCVD;
3602083bfdbfSJason Gunthorpe listen_cm_id_priv = cm_find_listen(cm_id_priv->id.device,
3603083bfdbfSJason Gunthorpe cm_id_priv->id.service_id);
3604083bfdbfSJason Gunthorpe if (!listen_cm_id_priv) {
360524be6e81SSean Hefty spin_unlock_irq(&cm.lock);
36066a8824a7SJason Gunthorpe ib_send_cm_sidr_rep(&cm_id_priv->id,
36076a8824a7SJason Gunthorpe &(struct ib_cm_sidr_rep_param){
36086a8824a7SJason Gunthorpe .status = IB_SIDR_UNSUPPORTED });
3609a977049dSHal Rosenstock goto out; /* No match. */
3610a977049dSHal Rosenstock }
361124be6e81SSean Hefty spin_unlock_irq(&cm.lock);
3612a977049dSHal Rosenstock
3613083bfdbfSJason Gunthorpe cm_id_priv->id.cm_handler = listen_cm_id_priv->id.cm_handler;
3614083bfdbfSJason Gunthorpe cm_id_priv->id.context = listen_cm_id_priv->id.context;
3615a977049dSHal Rosenstock
3616083bfdbfSJason Gunthorpe /*
3617083bfdbfSJason Gunthorpe * A SIDR ID does not need to be in the xarray since it does not receive
3618083bfdbfSJason Gunthorpe * mads, is not placed in the remote_id or remote_qpn rbtree, and does
3619083bfdbfSJason Gunthorpe * not enter timewait.
3620083bfdbfSJason Gunthorpe */
3621083bfdbfSJason Gunthorpe
3622083bfdbfSJason Gunthorpe cm_format_sidr_req_event(work, cm_id_priv, &listen_cm_id_priv->id);
3623083bfdbfSJason Gunthorpe ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, &work->cm_event);
3624083bfdbfSJason Gunthorpe cm_free_work(work);
3625083bfdbfSJason Gunthorpe /*
3626083bfdbfSJason Gunthorpe * A pointer to the listen_cm_id is held in the event, so this deref
3627083bfdbfSJason Gunthorpe * must be after the event is delivered above.
3628083bfdbfSJason Gunthorpe */
3629083bfdbfSJason Gunthorpe cm_deref_id(listen_cm_id_priv);
3630083bfdbfSJason Gunthorpe if (ret)
3631083bfdbfSJason Gunthorpe cm_destroy_id(&cm_id_priv->id, ret);
3632a977049dSHal Rosenstock return 0;
3633a977049dSHal Rosenstock out:
3634a977049dSHal Rosenstock ib_destroy_cm_id(&cm_id_priv->id);
3635a977049dSHal Rosenstock return -EINVAL;
3636a977049dSHal Rosenstock }
3637a977049dSHal Rosenstock
cm_format_sidr_rep(struct cm_sidr_rep_msg * sidr_rep_msg,struct cm_id_private * cm_id_priv,struct ib_cm_sidr_rep_param * param)3638a977049dSHal Rosenstock static void cm_format_sidr_rep(struct cm_sidr_rep_msg *sidr_rep_msg,
3639a977049dSHal Rosenstock struct cm_id_private *cm_id_priv,
3640a977049dSHal Rosenstock struct ib_cm_sidr_rep_param *param)
3641a977049dSHal Rosenstock {
3642a20652e1SLeon Romanovsky cm_format_mad_ece_hdr(&sidr_rep_msg->hdr, CM_SIDR_REP_ATTR_ID,
3643a20652e1SLeon Romanovsky cm_id_priv->tid, param->ece.attr_mod);
364491b60a71SJason Gunthorpe IBA_SET(CM_SIDR_REP_REQUESTID, sidr_rep_msg,
364591b60a71SJason Gunthorpe be32_to_cpu(cm_id_priv->id.remote_id));
364691b60a71SJason Gunthorpe IBA_SET(CM_SIDR_REP_STATUS, sidr_rep_msg, param->status);
364701adb7f4SJason Gunthorpe IBA_SET(CM_SIDR_REP_QPN, sidr_rep_msg, param->qp_num);
364891b60a71SJason Gunthorpe IBA_SET(CM_SIDR_REP_SERVICEID, sidr_rep_msg,
364991b60a71SJason Gunthorpe be64_to_cpu(cm_id_priv->id.service_id));
365091b60a71SJason Gunthorpe IBA_SET(CM_SIDR_REP_Q_KEY, sidr_rep_msg, param->qkey);
3651a20652e1SLeon Romanovsky IBA_SET(CM_SIDR_REP_VENDOR_ID_L, sidr_rep_msg,
3652a20652e1SLeon Romanovsky param->ece.vendor_id & 0xFF);
3653a20652e1SLeon Romanovsky IBA_SET(CM_SIDR_REP_VENDOR_ID_H, sidr_rep_msg,
3654a20652e1SLeon Romanovsky (param->ece.vendor_id >> 8) & 0xFF);
3655a977049dSHal Rosenstock
3656a977049dSHal Rosenstock if (param->info && param->info_length)
36574ca662a3SJason Gunthorpe IBA_SET_MEM(CM_SIDR_REP_ADDITIONAL_INFORMATION, sidr_rep_msg,
36584ca662a3SJason Gunthorpe param->info, param->info_length);
3659a977049dSHal Rosenstock
3660a977049dSHal Rosenstock if (param->private_data && param->private_data_len)
36614ca662a3SJason Gunthorpe IBA_SET_MEM(CM_SIDR_REP_PRIVATE_DATA, sidr_rep_msg,
36624ca662a3SJason Gunthorpe param->private_data, param->private_data_len);
3663a977049dSHal Rosenstock }
3664a977049dSHal Rosenstock
cm_send_sidr_rep_locked(struct cm_id_private * cm_id_priv,struct ib_cm_sidr_rep_param * param)36656a8824a7SJason Gunthorpe static int cm_send_sidr_rep_locked(struct cm_id_private *cm_id_priv,
3666a977049dSHal Rosenstock struct ib_cm_sidr_rep_param *param)
3667a977049dSHal Rosenstock {
3668a977049dSHal Rosenstock struct ib_mad_send_buf *msg;
3669221384dfSSaeed Mahameed unsigned long flags;
3670a977049dSHal Rosenstock int ret;
3671a977049dSHal Rosenstock
36726a8824a7SJason Gunthorpe lockdep_assert_held(&cm_id_priv->lock);
36736a8824a7SJason Gunthorpe
3674a977049dSHal Rosenstock if ((param->info && param->info_length > IB_CM_SIDR_REP_INFO_LENGTH) ||
3675a977049dSHal Rosenstock (param->private_data &&
3676a977049dSHal Rosenstock param->private_data_len > IB_CM_SIDR_REP_PRIVATE_DATA_SIZE))
3677a977049dSHal Rosenstock return -EINVAL;
3678a977049dSHal Rosenstock
36796a8824a7SJason Gunthorpe if (cm_id_priv->id.state != IB_CM_SIDR_REQ_RCVD)
36806a8824a7SJason Gunthorpe return -EINVAL;
3681a977049dSHal Rosenstock
36824b4e586eSJason Gunthorpe msg = cm_alloc_msg(cm_id_priv);
36834b4e586eSJason Gunthorpe if (IS_ERR(msg))
36844b4e586eSJason Gunthorpe return PTR_ERR(msg);
3685a977049dSHal Rosenstock
3686a977049dSHal Rosenstock cm_format_sidr_rep((struct cm_sidr_rep_msg *) msg->mad, cm_id_priv,
3687a977049dSHal Rosenstock param);
36888dc105beSChuck Lever trace_icm_send_sidr_rep(&cm_id_priv->id);
368934816ad9SSean Hefty ret = ib_post_send_mad(msg, NULL);
3690a977049dSHal Rosenstock if (ret) {
3691a977049dSHal Rosenstock cm_free_msg(msg);
3692a977049dSHal Rosenstock return ret;
3693a977049dSHal Rosenstock }
36946a8824a7SJason Gunthorpe cm_id_priv->id.state = IB_CM_IDLE;
3695221384dfSSaeed Mahameed spin_lock_irqsave(&cm.lock, flags);
36960ca81a28SDoron Tsur if (!RB_EMPTY_NODE(&cm_id_priv->sidr_id_node)) {
3697a977049dSHal Rosenstock rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table);
36980ca81a28SDoron Tsur RB_CLEAR_NODE(&cm_id_priv->sidr_id_node);
36990ca81a28SDoron Tsur }
3700221384dfSSaeed Mahameed spin_unlock_irqrestore(&cm.lock, flags);
3701a977049dSHal Rosenstock return 0;
37026a8824a7SJason Gunthorpe }
3703a977049dSHal Rosenstock
ib_send_cm_sidr_rep(struct ib_cm_id * cm_id,struct ib_cm_sidr_rep_param * param)37046a8824a7SJason Gunthorpe int ib_send_cm_sidr_rep(struct ib_cm_id *cm_id,
37056a8824a7SJason Gunthorpe struct ib_cm_sidr_rep_param *param)
37066a8824a7SJason Gunthorpe {
37076a8824a7SJason Gunthorpe struct cm_id_private *cm_id_priv =
37086a8824a7SJason Gunthorpe container_of(cm_id, struct cm_id_private, id);
37096a8824a7SJason Gunthorpe unsigned long flags;
37106a8824a7SJason Gunthorpe int ret;
37116a8824a7SJason Gunthorpe
37126a8824a7SJason Gunthorpe spin_lock_irqsave(&cm_id_priv->lock, flags);
37136a8824a7SJason Gunthorpe ret = cm_send_sidr_rep_locked(cm_id_priv, param);
37146a8824a7SJason Gunthorpe spin_unlock_irqrestore(&cm_id_priv->lock, flags);
3715a977049dSHal Rosenstock return ret;
3716a977049dSHal Rosenstock }
3717a977049dSHal Rosenstock EXPORT_SYMBOL(ib_send_cm_sidr_rep);
3718a977049dSHal Rosenstock
cm_format_sidr_rep_event(struct cm_work * work,const struct cm_id_private * cm_id_priv)3719815d456eSParav Pandit static void cm_format_sidr_rep_event(struct cm_work *work,
3720815d456eSParav Pandit const struct cm_id_private *cm_id_priv)
3721a977049dSHal Rosenstock {
3722a977049dSHal Rosenstock struct cm_sidr_rep_msg *sidr_rep_msg;
3723a977049dSHal Rosenstock struct ib_cm_sidr_rep_event_param *param;
3724a977049dSHal Rosenstock
3725a977049dSHal Rosenstock sidr_rep_msg = (struct cm_sidr_rep_msg *)
3726a977049dSHal Rosenstock work->mad_recv_wc->recv_buf.mad;
3727a977049dSHal Rosenstock param = &work->cm_event.param.sidr_rep_rcvd;
372891b60a71SJason Gunthorpe param->status = IBA_GET(CM_SIDR_REP_STATUS, sidr_rep_msg);
372991b60a71SJason Gunthorpe param->qkey = IBA_GET(CM_SIDR_REP_Q_KEY, sidr_rep_msg);
373001adb7f4SJason Gunthorpe param->qpn = IBA_GET(CM_SIDR_REP_QPN, sidr_rep_msg);
37314ca662a3SJason Gunthorpe param->info = IBA_GET_MEM_PTR(CM_SIDR_REP_ADDITIONAL_INFORMATION,
37324ca662a3SJason Gunthorpe sidr_rep_msg);
373391b60a71SJason Gunthorpe param->info_len = IBA_GET(CM_SIDR_REP_ADDITIONAL_INFORMATION_LENGTH,
373491b60a71SJason Gunthorpe sidr_rep_msg);
3735815d456eSParav Pandit param->sgid_attr = cm_id_priv->av.ah_attr.grh.sgid_attr;
37364ca662a3SJason Gunthorpe work->cm_event.private_data =
37374ca662a3SJason Gunthorpe IBA_GET_MEM_PTR(CM_SIDR_REP_PRIVATE_DATA, sidr_rep_msg);
3738a977049dSHal Rosenstock }
3739a977049dSHal Rosenstock
cm_sidr_rep_handler(struct cm_work * work)3740a977049dSHal Rosenstock static int cm_sidr_rep_handler(struct cm_work *work)
3741a977049dSHal Rosenstock {
3742a977049dSHal Rosenstock struct cm_sidr_rep_msg *sidr_rep_msg;
3743a977049dSHal Rosenstock struct cm_id_private *cm_id_priv;
3744a977049dSHal Rosenstock
3745a977049dSHal Rosenstock sidr_rep_msg = (struct cm_sidr_rep_msg *)
3746a977049dSHal Rosenstock work->mad_recv_wc->recv_buf.mad;
374791b60a71SJason Gunthorpe cm_id_priv = cm_acquire_id(
374891b60a71SJason Gunthorpe cpu_to_be32(IBA_GET(CM_SIDR_REP_REQUESTID, sidr_rep_msg)), 0);
3749a977049dSHal Rosenstock if (!cm_id_priv)
3750a977049dSHal Rosenstock return -EINVAL; /* Unmatched reply. */
3751a977049dSHal Rosenstock
375224be6e81SSean Hefty spin_lock_irq(&cm_id_priv->lock);
3753a977049dSHal Rosenstock if (cm_id_priv->id.state != IB_CM_SIDR_REQ_SENT) {
375424be6e81SSean Hefty spin_unlock_irq(&cm_id_priv->lock);
3755a977049dSHal Rosenstock goto out;
3756a977049dSHal Rosenstock }
3757a977049dSHal Rosenstock cm_id_priv->id.state = IB_CM_IDLE;
375870076a41SMark Zhang ib_cancel_mad(cm_id_priv->msg);
375924be6e81SSean Hefty spin_unlock_irq(&cm_id_priv->lock);
3760a977049dSHal Rosenstock
3761815d456eSParav Pandit cm_format_sidr_rep_event(work, cm_id_priv);
3762a977049dSHal Rosenstock cm_process_work(cm_id_priv, work);
3763a977049dSHal Rosenstock return 0;
3764a977049dSHal Rosenstock out:
3765a977049dSHal Rosenstock cm_deref_id(cm_id_priv);
3766a977049dSHal Rosenstock return -EINVAL;
3767a977049dSHal Rosenstock }
3768a977049dSHal Rosenstock
cm_process_send_error(struct cm_id_private * cm_id_priv,struct ib_mad_send_buf * msg,enum ib_cm_state state,enum ib_wc_status wc_status)3769c1cf6d9fSJason Gunthorpe static void cm_process_send_error(struct cm_id_private *cm_id_priv,
3770c1cf6d9fSJason Gunthorpe struct ib_mad_send_buf *msg,
3771c1cf6d9fSJason Gunthorpe enum ib_cm_state state,
3772a977049dSHal Rosenstock enum ib_wc_status wc_status)
3773a977049dSHal Rosenstock {
3774c1cf6d9fSJason Gunthorpe struct ib_cm_event cm_event = {};
3775a977049dSHal Rosenstock int ret;
3776a977049dSHal Rosenstock
3777a977049dSHal Rosenstock /* Discard old sends or ones without a response. */
377824be6e81SSean Hefty spin_lock_irq(&cm_id_priv->lock);
3779c1cf6d9fSJason Gunthorpe if (msg != cm_id_priv->msg) {
3780c1cf6d9fSJason Gunthorpe spin_unlock_irq(&cm_id_priv->lock);
3781c1cf6d9fSJason Gunthorpe cm_free_msg(msg);
3782c1cf6d9fSJason Gunthorpe return;
3783c1cf6d9fSJason Gunthorpe }
3784c1cf6d9fSJason Gunthorpe cm_free_priv_msg(msg);
3785c1cf6d9fSJason Gunthorpe
3786c1cf6d9fSJason Gunthorpe if (state != cm_id_priv->id.state || wc_status == IB_WC_SUCCESS ||
3787c1cf6d9fSJason Gunthorpe wc_status == IB_WC_WR_FLUSH_ERR)
3788c1cf6d9fSJason Gunthorpe goto out_unlock;
3789a977049dSHal Rosenstock
379075874b3dSChuck Lever trace_icm_mad_send_err(state, wc_status);
3791a977049dSHal Rosenstock switch (state) {
3792a977049dSHal Rosenstock case IB_CM_REQ_SENT:
3793a977049dSHal Rosenstock case IB_CM_MRA_REQ_RCVD:
3794a977049dSHal Rosenstock cm_reset_to_idle(cm_id_priv);
3795a977049dSHal Rosenstock cm_event.event = IB_CM_REQ_ERROR;
3796a977049dSHal Rosenstock break;
3797a977049dSHal Rosenstock case IB_CM_REP_SENT:
3798a977049dSHal Rosenstock case IB_CM_MRA_REP_RCVD:
3799a977049dSHal Rosenstock cm_reset_to_idle(cm_id_priv);
3800a977049dSHal Rosenstock cm_event.event = IB_CM_REP_ERROR;
3801a977049dSHal Rosenstock break;
3802a977049dSHal Rosenstock case IB_CM_DREQ_SENT:
3803a977049dSHal Rosenstock cm_enter_timewait(cm_id_priv);
3804a977049dSHal Rosenstock cm_event.event = IB_CM_DREQ_ERROR;
3805a977049dSHal Rosenstock break;
3806a977049dSHal Rosenstock case IB_CM_SIDR_REQ_SENT:
3807a977049dSHal Rosenstock cm_id_priv->id.state = IB_CM_IDLE;
3808a977049dSHal Rosenstock cm_event.event = IB_CM_SIDR_REQ_ERROR;
3809a977049dSHal Rosenstock break;
3810a977049dSHal Rosenstock default:
3811c1cf6d9fSJason Gunthorpe goto out_unlock;
3812a977049dSHal Rosenstock }
381324be6e81SSean Hefty spin_unlock_irq(&cm_id_priv->lock);
3814a977049dSHal Rosenstock cm_event.param.send_status = wc_status;
3815a977049dSHal Rosenstock
3816a977049dSHal Rosenstock /* No other events can occur on the cm_id at this point. */
3817a977049dSHal Rosenstock ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, &cm_event);
3818a977049dSHal Rosenstock if (ret)
3819a977049dSHal Rosenstock ib_destroy_cm_id(&cm_id_priv->id);
3820a977049dSHal Rosenstock return;
3821c1cf6d9fSJason Gunthorpe out_unlock:
382224be6e81SSean Hefty spin_unlock_irq(&cm_id_priv->lock);
3823a977049dSHal Rosenstock }
3824a977049dSHal Rosenstock
cm_send_handler(struct ib_mad_agent * mad_agent,struct ib_mad_send_wc * mad_send_wc)3825a977049dSHal Rosenstock static void cm_send_handler(struct ib_mad_agent *mad_agent,
3826a977049dSHal Rosenstock struct ib_mad_send_wc *mad_send_wc)
3827a977049dSHal Rosenstock {
382834816ad9SSean Hefty struct ib_mad_send_buf *msg = mad_send_wc->send_buf;
3829c1cf6d9fSJason Gunthorpe struct cm_id_private *cm_id_priv = msg->context[0];
3830c1cf6d9fSJason Gunthorpe enum ib_cm_state state =
3831c1cf6d9fSJason Gunthorpe (enum ib_cm_state)(unsigned long)msg->context[1];
38329af57b7aSSean Hefty struct cm_port *port;
38339af57b7aSSean Hefty u16 attr_index;
38349af57b7aSSean Hefty
38359af57b7aSSean Hefty port = mad_agent->context;
38369af57b7aSSean Hefty attr_index = be16_to_cpu(((struct ib_mad_hdr *)
38379af57b7aSSean Hefty msg->mad)->attr_id) - CM_ATTR_ID_OFFSET;
38389af57b7aSSean Hefty
38399af57b7aSSean Hefty /*
38409af57b7aSSean Hefty * If the send was in response to a received message (context[0] is not
38419af57b7aSSean Hefty * set to a cm_id), and is not a REJ, then it is a send that was
38429af57b7aSSean Hefty * manually retried.
38439af57b7aSSean Hefty */
3844c1cf6d9fSJason Gunthorpe if (!cm_id_priv && (attr_index != CM_REJ_COUNTER))
38459af57b7aSSean Hefty msg->retries = 1;
38469af57b7aSSean Hefty
3847526a12c8SJason Gunthorpe atomic_long_add(1 + msg->retries, &port->counters[CM_XMIT][attr_index]);
38489af57b7aSSean Hefty if (msg->retries)
38499af57b7aSSean Hefty atomic_long_add(msg->retries,
3850526a12c8SJason Gunthorpe &port->counters[CM_XMIT_RETRIES][attr_index]);
3851a977049dSHal Rosenstock
3852c1cf6d9fSJason Gunthorpe if (cm_id_priv)
3853c1cf6d9fSJason Gunthorpe cm_process_send_error(cm_id_priv, msg, state,
3854c1cf6d9fSJason Gunthorpe mad_send_wc->status);
3855a977049dSHal Rosenstock else
3856c1cf6d9fSJason Gunthorpe cm_free_response_msg(msg);
3857a977049dSHal Rosenstock }
3858a977049dSHal Rosenstock
cm_work_handler(struct work_struct * _work)3859c4028958SDavid Howells static void cm_work_handler(struct work_struct *_work)
3860a977049dSHal Rosenstock {
3861c4028958SDavid Howells struct cm_work *work = container_of(_work, struct cm_work, work.work);
3862a977049dSHal Rosenstock int ret;
3863a977049dSHal Rosenstock
3864a977049dSHal Rosenstock switch (work->cm_event.event) {
3865a977049dSHal Rosenstock case IB_CM_REQ_RECEIVED:
3866a977049dSHal Rosenstock ret = cm_req_handler(work);
3867a977049dSHal Rosenstock break;
3868a977049dSHal Rosenstock case IB_CM_MRA_RECEIVED:
3869a977049dSHal Rosenstock ret = cm_mra_handler(work);
3870a977049dSHal Rosenstock break;
3871a977049dSHal Rosenstock case IB_CM_REJ_RECEIVED:
3872a977049dSHal Rosenstock ret = cm_rej_handler(work);
3873a977049dSHal Rosenstock break;
3874a977049dSHal Rosenstock case IB_CM_REP_RECEIVED:
3875a977049dSHal Rosenstock ret = cm_rep_handler(work);
3876a977049dSHal Rosenstock break;
3877a977049dSHal Rosenstock case IB_CM_RTU_RECEIVED:
3878a977049dSHal Rosenstock ret = cm_rtu_handler(work);
3879a977049dSHal Rosenstock break;
3880a977049dSHal Rosenstock case IB_CM_USER_ESTABLISHED:
3881a977049dSHal Rosenstock ret = cm_establish_handler(work);
3882a977049dSHal Rosenstock break;
3883a977049dSHal Rosenstock case IB_CM_DREQ_RECEIVED:
3884a977049dSHal Rosenstock ret = cm_dreq_handler(work);
3885a977049dSHal Rosenstock break;
3886a977049dSHal Rosenstock case IB_CM_DREP_RECEIVED:
3887a977049dSHal Rosenstock ret = cm_drep_handler(work);
3888a977049dSHal Rosenstock break;
3889a977049dSHal Rosenstock case IB_CM_SIDR_REQ_RECEIVED:
3890a977049dSHal Rosenstock ret = cm_sidr_req_handler(work);
3891a977049dSHal Rosenstock break;
3892a977049dSHal Rosenstock case IB_CM_SIDR_REP_RECEIVED:
3893a977049dSHal Rosenstock ret = cm_sidr_rep_handler(work);
3894a977049dSHal Rosenstock break;
3895a977049dSHal Rosenstock case IB_CM_LAP_RECEIVED:
3896a977049dSHal Rosenstock ret = cm_lap_handler(work);
3897a977049dSHal Rosenstock break;
3898a977049dSHal Rosenstock case IB_CM_APR_RECEIVED:
3899a977049dSHal Rosenstock ret = cm_apr_handler(work);
3900a977049dSHal Rosenstock break;
3901a977049dSHal Rosenstock case IB_CM_TIMEWAIT_EXIT:
3902a977049dSHal Rosenstock ret = cm_timewait_handler(work);
3903a977049dSHal Rosenstock break;
3904a977049dSHal Rosenstock default:
390575874b3dSChuck Lever trace_icm_handler_err(work->cm_event.event);
3906a977049dSHal Rosenstock ret = -EINVAL;
3907a977049dSHal Rosenstock break;
3908a977049dSHal Rosenstock }
3909a977049dSHal Rosenstock if (ret)
3910a977049dSHal Rosenstock cm_free_work(work);
3911a977049dSHal Rosenstock }
3912a977049dSHal Rosenstock
cm_establish(struct ib_cm_id * cm_id)3913e1444b5aSSean Hefty static int cm_establish(struct ib_cm_id *cm_id)
3914a977049dSHal Rosenstock {
3915a977049dSHal Rosenstock struct cm_id_private *cm_id_priv;
3916a977049dSHal Rosenstock struct cm_work *work;
3917a977049dSHal Rosenstock unsigned long flags;
3918a977049dSHal Rosenstock int ret = 0;
3919be4b4993SErez Shitrit struct cm_device *cm_dev;
3920be4b4993SErez Shitrit
3921be4b4993SErez Shitrit cm_dev = ib_get_client_data(cm_id->device, &cm_client);
3922be4b4993SErez Shitrit if (!cm_dev)
3923be4b4993SErez Shitrit return -ENODEV;
3924a977049dSHal Rosenstock
3925a977049dSHal Rosenstock work = kmalloc(sizeof *work, GFP_ATOMIC);
3926a977049dSHal Rosenstock if (!work)
3927a977049dSHal Rosenstock return -ENOMEM;
3928a977049dSHal Rosenstock
3929a977049dSHal Rosenstock cm_id_priv = container_of(cm_id, struct cm_id_private, id);
3930a977049dSHal Rosenstock spin_lock_irqsave(&cm_id_priv->lock, flags);
3931b6eb7011SWenpeng Liang switch (cm_id->state) {
3932a977049dSHal Rosenstock case IB_CM_REP_SENT:
3933a977049dSHal Rosenstock case IB_CM_MRA_REP_RCVD:
3934a977049dSHal Rosenstock cm_id->state = IB_CM_ESTABLISHED;
3935a977049dSHal Rosenstock break;
3936a977049dSHal Rosenstock case IB_CM_ESTABLISHED:
3937a977049dSHal Rosenstock ret = -EISCONN;
3938a977049dSHal Rosenstock break;
3939a977049dSHal Rosenstock default:
394075874b3dSChuck Lever trace_icm_establish_err(cm_id);
3941a977049dSHal Rosenstock ret = -EINVAL;
3942a977049dSHal Rosenstock break;
3943a977049dSHal Rosenstock }
3944a977049dSHal Rosenstock spin_unlock_irqrestore(&cm_id_priv->lock, flags);
3945a977049dSHal Rosenstock
3946a977049dSHal Rosenstock if (ret) {
3947a977049dSHal Rosenstock kfree(work);
3948a977049dSHal Rosenstock goto out;
3949a977049dSHal Rosenstock }
3950a977049dSHal Rosenstock
3951a977049dSHal Rosenstock /*
3952a977049dSHal Rosenstock * The CM worker thread may try to destroy the cm_id before it
3953a977049dSHal Rosenstock * can execute this work item. To prevent potential deadlock,
3954a977049dSHal Rosenstock * we need to find the cm_id once we're in the context of the
3955a977049dSHal Rosenstock * worker thread, rather than holding a reference on it.
3956a977049dSHal Rosenstock */
3957c4028958SDavid Howells INIT_DELAYED_WORK(&work->work, cm_work_handler);
3958a977049dSHal Rosenstock work->local_id = cm_id->local_id;
3959a977049dSHal Rosenstock work->remote_id = cm_id->remote_id;
3960a977049dSHal Rosenstock work->mad_recv_wc = NULL;
3961a977049dSHal Rosenstock work->cm_event.event = IB_CM_USER_ESTABLISHED;
3962be4b4993SErez Shitrit
3963be4b4993SErez Shitrit /* Check if the device started its remove_one */
3964943f44d9SBart Van Assche spin_lock_irqsave(&cm.lock, flags);
3965be4b4993SErez Shitrit if (!cm_dev->going_down) {
3966c4028958SDavid Howells queue_delayed_work(cm.wq, &work->work, 0);
3967be4b4993SErez Shitrit } else {
3968be4b4993SErez Shitrit kfree(work);
3969be4b4993SErez Shitrit ret = -ENODEV;
3970be4b4993SErez Shitrit }
3971943f44d9SBart Van Assche spin_unlock_irqrestore(&cm.lock, flags);
3972be4b4993SErez Shitrit
3973a977049dSHal Rosenstock out:
3974a977049dSHal Rosenstock return ret;
3975a977049dSHal Rosenstock }
3976e1444b5aSSean Hefty
cm_migrate(struct ib_cm_id * cm_id)3977e1444b5aSSean Hefty static int cm_migrate(struct ib_cm_id *cm_id)
3978e1444b5aSSean Hefty {
3979e1444b5aSSean Hefty struct cm_id_private *cm_id_priv;
3980e1444b5aSSean Hefty unsigned long flags;
3981e1444b5aSSean Hefty int ret = 0;
3982e1444b5aSSean Hefty
3983e1444b5aSSean Hefty cm_id_priv = container_of(cm_id, struct cm_id_private, id);
3984e1444b5aSSean Hefty spin_lock_irqsave(&cm_id_priv->lock, flags);
3985e1444b5aSSean Hefty if (cm_id->state == IB_CM_ESTABLISHED &&
3986e1444b5aSSean Hefty (cm_id->lap_state == IB_CM_LAP_UNINIT ||
3987e1444b5aSSean Hefty cm_id->lap_state == IB_CM_LAP_IDLE)) {
3988e1444b5aSSean Hefty cm_id->lap_state = IB_CM_LAP_IDLE;
3989e1444b5aSSean Hefty cm_id_priv->av = cm_id_priv->alt_av;
3990e1444b5aSSean Hefty } else
3991e1444b5aSSean Hefty ret = -EINVAL;
3992e1444b5aSSean Hefty spin_unlock_irqrestore(&cm_id_priv->lock, flags);
3993e1444b5aSSean Hefty
3994e1444b5aSSean Hefty return ret;
3995e1444b5aSSean Hefty }
3996e1444b5aSSean Hefty
ib_cm_notify(struct ib_cm_id * cm_id,enum ib_event_type event)3997e1444b5aSSean Hefty int ib_cm_notify(struct ib_cm_id *cm_id, enum ib_event_type event)
3998e1444b5aSSean Hefty {
3999e1444b5aSSean Hefty int ret;
4000e1444b5aSSean Hefty
4001e1444b5aSSean Hefty switch (event) {
4002e1444b5aSSean Hefty case IB_EVENT_COMM_EST:
4003e1444b5aSSean Hefty ret = cm_establish(cm_id);
4004e1444b5aSSean Hefty break;
4005e1444b5aSSean Hefty case IB_EVENT_PATH_MIG:
4006e1444b5aSSean Hefty ret = cm_migrate(cm_id);
4007e1444b5aSSean Hefty break;
4008e1444b5aSSean Hefty default:
4009e1444b5aSSean Hefty ret = -EINVAL;
4010e1444b5aSSean Hefty }
4011e1444b5aSSean Hefty return ret;
4012e1444b5aSSean Hefty }
4013e1444b5aSSean Hefty EXPORT_SYMBOL(ib_cm_notify);
4014a977049dSHal Rosenstock
cm_recv_handler(struct ib_mad_agent * mad_agent,struct ib_mad_send_buf * send_buf,struct ib_mad_recv_wc * mad_recv_wc)4015a977049dSHal Rosenstock static void cm_recv_handler(struct ib_mad_agent *mad_agent,
4016ca281265SChristoph Hellwig struct ib_mad_send_buf *send_buf,
4017a977049dSHal Rosenstock struct ib_mad_recv_wc *mad_recv_wc)
4018a977049dSHal Rosenstock {
40199af57b7aSSean Hefty struct cm_port *port = mad_agent->context;
4020a977049dSHal Rosenstock struct cm_work *work;
4021a977049dSHal Rosenstock enum ib_cm_event_type event;
40225a3dc323SParav Pandit bool alt_path = false;
40239af57b7aSSean Hefty u16 attr_id;
4024a977049dSHal Rosenstock int paths = 0;
4025be4b4993SErez Shitrit int going_down = 0;
4026a977049dSHal Rosenstock
4027a977049dSHal Rosenstock switch (mad_recv_wc->recv_buf.mad->mad_hdr.attr_id) {
4028a977049dSHal Rosenstock case CM_REQ_ATTR_ID:
40295a3dc323SParav Pandit alt_path = cm_req_has_alt_path((struct cm_req_msg *)
40305a3dc323SParav Pandit mad_recv_wc->recv_buf.mad);
40315a3dc323SParav Pandit paths = 1 + (alt_path != 0);
4032a977049dSHal Rosenstock event = IB_CM_REQ_RECEIVED;
4033a977049dSHal Rosenstock break;
4034a977049dSHal Rosenstock case CM_MRA_ATTR_ID:
4035a977049dSHal Rosenstock event = IB_CM_MRA_RECEIVED;
4036a977049dSHal Rosenstock break;
4037a977049dSHal Rosenstock case CM_REJ_ATTR_ID:
4038a977049dSHal Rosenstock event = IB_CM_REJ_RECEIVED;
4039a977049dSHal Rosenstock break;
4040a977049dSHal Rosenstock case CM_REP_ATTR_ID:
4041a977049dSHal Rosenstock event = IB_CM_REP_RECEIVED;
4042a977049dSHal Rosenstock break;
4043a977049dSHal Rosenstock case CM_RTU_ATTR_ID:
4044a977049dSHal Rosenstock event = IB_CM_RTU_RECEIVED;
4045a977049dSHal Rosenstock break;
4046a977049dSHal Rosenstock case CM_DREQ_ATTR_ID:
4047a977049dSHal Rosenstock event = IB_CM_DREQ_RECEIVED;
4048a977049dSHal Rosenstock break;
4049a977049dSHal Rosenstock case CM_DREP_ATTR_ID:
4050a977049dSHal Rosenstock event = IB_CM_DREP_RECEIVED;
4051a977049dSHal Rosenstock break;
4052a977049dSHal Rosenstock case CM_SIDR_REQ_ATTR_ID:
4053a977049dSHal Rosenstock event = IB_CM_SIDR_REQ_RECEIVED;
4054a977049dSHal Rosenstock break;
4055a977049dSHal Rosenstock case CM_SIDR_REP_ATTR_ID:
4056a977049dSHal Rosenstock event = IB_CM_SIDR_REP_RECEIVED;
4057a977049dSHal Rosenstock break;
4058a977049dSHal Rosenstock case CM_LAP_ATTR_ID:
4059a977049dSHal Rosenstock paths = 1;
4060a977049dSHal Rosenstock event = IB_CM_LAP_RECEIVED;
4061a977049dSHal Rosenstock break;
4062a977049dSHal Rosenstock case CM_APR_ATTR_ID:
4063a977049dSHal Rosenstock event = IB_CM_APR_RECEIVED;
4064a977049dSHal Rosenstock break;
4065a977049dSHal Rosenstock default:
4066a977049dSHal Rosenstock ib_free_recv_mad(mad_recv_wc);
4067a977049dSHal Rosenstock return;
4068a977049dSHal Rosenstock }
4069a977049dSHal Rosenstock
40709af57b7aSSean Hefty attr_id = be16_to_cpu(mad_recv_wc->recv_buf.mad->mad_hdr.attr_id);
4071526a12c8SJason Gunthorpe atomic_long_inc(&port->counters[CM_RECV][attr_id - CM_ATTR_ID_OFFSET]);
40729af57b7aSSean Hefty
4073b5c61b96SGustavo A. R. Silva work = kmalloc(struct_size(work, path, paths), GFP_KERNEL);
4074a977049dSHal Rosenstock if (!work) {
4075a977049dSHal Rosenstock ib_free_recv_mad(mad_recv_wc);
4076a977049dSHal Rosenstock return;
4077a977049dSHal Rosenstock }
4078a977049dSHal Rosenstock
4079c4028958SDavid Howells INIT_DELAYED_WORK(&work->work, cm_work_handler);
4080a977049dSHal Rosenstock work->cm_event.event = event;
4081a977049dSHal Rosenstock work->mad_recv_wc = mad_recv_wc;
40829af57b7aSSean Hefty work->port = port;
4083be4b4993SErez Shitrit
4084be4b4993SErez Shitrit /* Check if the device started its remove_one */
4085be4b4993SErez Shitrit spin_lock_irq(&cm.lock);
4086be4b4993SErez Shitrit if (!port->cm_dev->going_down)
4087c4028958SDavid Howells queue_delayed_work(cm.wq, &work->work, 0);
4088be4b4993SErez Shitrit else
4089be4b4993SErez Shitrit going_down = 1;
4090be4b4993SErez Shitrit spin_unlock_irq(&cm.lock);
4091be4b4993SErez Shitrit
4092be4b4993SErez Shitrit if (going_down) {
4093be4b4993SErez Shitrit kfree(work);
4094be4b4993SErez Shitrit ib_free_recv_mad(mad_recv_wc);
4095be4b4993SErez Shitrit }
4096a977049dSHal Rosenstock }
4097a977049dSHal Rosenstock
cm_init_qp_init_attr(struct cm_id_private * cm_id_priv,struct ib_qp_attr * qp_attr,int * qp_attr_mask)4098a977049dSHal Rosenstock static int cm_init_qp_init_attr(struct cm_id_private *cm_id_priv,
4099a977049dSHal Rosenstock struct ib_qp_attr *qp_attr,
4100a977049dSHal Rosenstock int *qp_attr_mask)
4101a977049dSHal Rosenstock {
4102a977049dSHal Rosenstock unsigned long flags;
4103a977049dSHal Rosenstock int ret;
4104a977049dSHal Rosenstock
4105a977049dSHal Rosenstock spin_lock_irqsave(&cm_id_priv->lock, flags);
4106a977049dSHal Rosenstock switch (cm_id_priv->id.state) {
4107a977049dSHal Rosenstock case IB_CM_REQ_SENT:
4108a977049dSHal Rosenstock case IB_CM_MRA_REQ_RCVD:
4109a977049dSHal Rosenstock case IB_CM_REQ_RCVD:
4110a977049dSHal Rosenstock case IB_CM_MRA_REQ_SENT:
4111a977049dSHal Rosenstock case IB_CM_REP_RCVD:
4112a977049dSHal Rosenstock case IB_CM_MRA_REP_SENT:
4113a977049dSHal Rosenstock case IB_CM_REP_SENT:
4114a977049dSHal Rosenstock case IB_CM_MRA_REP_RCVD:
4115a977049dSHal Rosenstock case IB_CM_ESTABLISHED:
4116a977049dSHal Rosenstock *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS |
4117a977049dSHal Rosenstock IB_QP_PKEY_INDEX | IB_QP_PORT;
4118e31353eaSDotan Barak qp_attr->qp_access_flags = IB_ACCESS_REMOTE_WRITE;
41198b4d379bSLi Zhijian if (cm_id_priv->responder_resources) {
41208b4d379bSLi Zhijian struct ib_device *ib_dev = cm_id_priv->id.device;
41218b4d379bSLi Zhijian u64 support_flush = ib_dev->attrs.device_cap_flags &
41228b4d379bSLi Zhijian (IB_DEVICE_FLUSH_GLOBAL | IB_DEVICE_FLUSH_PERSISTENT);
41238b4d379bSLi Zhijian u32 flushable = support_flush ?
41248b4d379bSLi Zhijian (IB_ACCESS_FLUSH_GLOBAL |
41258b4d379bSLi Zhijian IB_ACCESS_FLUSH_PERSISTENT) : 0;
41268b4d379bSLi Zhijian
4127c1f250c0SSean Hefty qp_attr->qp_access_flags |= IB_ACCESS_REMOTE_READ |
41288b4d379bSLi Zhijian IB_ACCESS_REMOTE_ATOMIC |
41298b4d379bSLi Zhijian flushable;
41308b4d379bSLi Zhijian }
4131a977049dSHal Rosenstock qp_attr->pkey_index = cm_id_priv->av.pkey_index;
413276039ac9SMark Zhang if (cm_id_priv->av.port)
4133a977049dSHal Rosenstock qp_attr->port_num = cm_id_priv->av.port->port_num;
4134a977049dSHal Rosenstock ret = 0;
4135a977049dSHal Rosenstock break;
4136a977049dSHal Rosenstock default:
413775874b3dSChuck Lever trace_icm_qp_init_err(&cm_id_priv->id);
4138a977049dSHal Rosenstock ret = -EINVAL;
4139a977049dSHal Rosenstock break;
4140a977049dSHal Rosenstock }
4141a977049dSHal Rosenstock spin_unlock_irqrestore(&cm_id_priv->lock, flags);
4142a977049dSHal Rosenstock return ret;
4143a977049dSHal Rosenstock }
4144a977049dSHal Rosenstock
cm_init_qp_rtr_attr(struct cm_id_private * cm_id_priv,struct ib_qp_attr * qp_attr,int * qp_attr_mask)4145a977049dSHal Rosenstock static int cm_init_qp_rtr_attr(struct cm_id_private *cm_id_priv,
4146a977049dSHal Rosenstock struct ib_qp_attr *qp_attr,
4147a977049dSHal Rosenstock int *qp_attr_mask)
4148a977049dSHal Rosenstock {
4149a977049dSHal Rosenstock unsigned long flags;
4150a977049dSHal Rosenstock int ret;
4151a977049dSHal Rosenstock
4152a977049dSHal Rosenstock spin_lock_irqsave(&cm_id_priv->lock, flags);
4153a977049dSHal Rosenstock switch (cm_id_priv->id.state) {
4154a977049dSHal Rosenstock case IB_CM_REQ_RCVD:
4155a977049dSHal Rosenstock case IB_CM_MRA_REQ_SENT:
4156a977049dSHal Rosenstock case IB_CM_REP_RCVD:
4157a977049dSHal Rosenstock case IB_CM_MRA_REP_SENT:
4158a977049dSHal Rosenstock case IB_CM_REP_SENT:
4159a977049dSHal Rosenstock case IB_CM_MRA_REP_RCVD:
4160a977049dSHal Rosenstock case IB_CM_ESTABLISHED:
4161a977049dSHal Rosenstock *qp_attr_mask = IB_QP_STATE | IB_QP_AV | IB_QP_PATH_MTU |
4162ae7971a7SSean Hefty IB_QP_DEST_QPN | IB_QP_RQ_PSN;
4163a977049dSHal Rosenstock qp_attr->ah_attr = cm_id_priv->av.ah_attr;
4164eb8336dbSMark Zhang if ((qp_attr->ah_attr.type == RDMA_AH_ATTR_TYPE_IB) &&
4165eb8336dbSMark Zhang cm_id_priv->av.dlid_datapath &&
4166eb8336dbSMark Zhang (cm_id_priv->av.dlid_datapath != 0xffff))
4167eb8336dbSMark Zhang qp_attr->ah_attr.ib.dlid = cm_id_priv->av.dlid_datapath;
4168a977049dSHal Rosenstock qp_attr->path_mtu = cm_id_priv->path_mtu;
4169a977049dSHal Rosenstock qp_attr->dest_qp_num = be32_to_cpu(cm_id_priv->remote_qpn);
4170a977049dSHal Rosenstock qp_attr->rq_psn = be32_to_cpu(cm_id_priv->rq_psn);
4171d26a360bSSean Hefty if (cm_id_priv->qp_type == IB_QPT_RC ||
4172d26a360bSSean Hefty cm_id_priv->qp_type == IB_QPT_XRC_TGT) {
4173ae7971a7SSean Hefty *qp_attr_mask |= IB_QP_MAX_DEST_RD_ATOMIC |
4174ae7971a7SSean Hefty IB_QP_MIN_RNR_TIMER;
4175ae7971a7SSean Hefty qp_attr->max_dest_rd_atomic =
4176ae7971a7SSean Hefty cm_id_priv->responder_resources;
4177a977049dSHal Rosenstock qp_attr->min_rnr_timer = 0;
4178ae7971a7SSean Hefty }
417976039ac9SMark Zhang if (rdma_ah_get_dlid(&cm_id_priv->alt_av.ah_attr) &&
418076039ac9SMark Zhang cm_id_priv->alt_av.port) {
4181a977049dSHal Rosenstock *qp_attr_mask |= IB_QP_ALT_PATH;
41820d8fdfd7SSean Hefty qp_attr->alt_port_num = cm_id_priv->alt_av.port->port_num;
4183e1444b5aSSean Hefty qp_attr->alt_pkey_index = cm_id_priv->alt_av.pkey_index;
41841d846126SSean Hefty qp_attr->alt_timeout = cm_id_priv->alt_av.timeout;
4185a977049dSHal Rosenstock qp_attr->alt_ah_attr = cm_id_priv->alt_av.ah_attr;
4186a977049dSHal Rosenstock }
4187a977049dSHal Rosenstock ret = 0;
4188a977049dSHal Rosenstock break;
4189a977049dSHal Rosenstock default:
419075874b3dSChuck Lever trace_icm_qp_rtr_err(&cm_id_priv->id);
4191a977049dSHal Rosenstock ret = -EINVAL;
4192a977049dSHal Rosenstock break;
4193a977049dSHal Rosenstock }
4194a977049dSHal Rosenstock spin_unlock_irqrestore(&cm_id_priv->lock, flags);
4195a977049dSHal Rosenstock return ret;
4196a977049dSHal Rosenstock }
4197a977049dSHal Rosenstock
cm_init_qp_rts_attr(struct cm_id_private * cm_id_priv,struct ib_qp_attr * qp_attr,int * qp_attr_mask)4198a977049dSHal Rosenstock static int cm_init_qp_rts_attr(struct cm_id_private *cm_id_priv,
4199a977049dSHal Rosenstock struct ib_qp_attr *qp_attr,
4200a977049dSHal Rosenstock int *qp_attr_mask)
4201a977049dSHal Rosenstock {
4202a977049dSHal Rosenstock unsigned long flags;
4203a977049dSHal Rosenstock int ret;
4204a977049dSHal Rosenstock
4205a977049dSHal Rosenstock spin_lock_irqsave(&cm_id_priv->lock, flags);
4206a977049dSHal Rosenstock switch (cm_id_priv->id.state) {
42070fe313b0SSean Hefty /* Allow transition to RTS before sending REP */
42080fe313b0SSean Hefty case IB_CM_REQ_RCVD:
42090fe313b0SSean Hefty case IB_CM_MRA_REQ_SENT:
42100fe313b0SSean Hefty
4211a977049dSHal Rosenstock case IB_CM_REP_RCVD:
4212a977049dSHal Rosenstock case IB_CM_MRA_REP_SENT:
4213a977049dSHal Rosenstock case IB_CM_REP_SENT:
4214a977049dSHal Rosenstock case IB_CM_MRA_REP_RCVD:
4215a977049dSHal Rosenstock case IB_CM_ESTABLISHED:
4216e1444b5aSSean Hefty if (cm_id_priv->id.lap_state == IB_CM_LAP_UNINIT) {
4217ae7971a7SSean Hefty *qp_attr_mask = IB_QP_STATE | IB_QP_SQ_PSN;
4218ae7971a7SSean Hefty qp_attr->sq_psn = be32_to_cpu(cm_id_priv->sq_psn);
4219d26a360bSSean Hefty switch (cm_id_priv->qp_type) {
4220d26a360bSSean Hefty case IB_QPT_RC:
4221d26a360bSSean Hefty case IB_QPT_XRC_INI:
4222d26a360bSSean Hefty *qp_attr_mask |= IB_QP_RETRY_CNT | IB_QP_RNR_RETRY |
4223a977049dSHal Rosenstock IB_QP_MAX_QP_RD_ATOMIC;
4224a977049dSHal Rosenstock qp_attr->retry_cnt = cm_id_priv->retry_count;
4225a977049dSHal Rosenstock qp_attr->rnr_retry = cm_id_priv->rnr_retry_count;
4226d26a360bSSean Hefty qp_attr->max_rd_atomic = cm_id_priv->initiator_depth;
4227df561f66SGustavo A. R. Silva fallthrough;
4228d26a360bSSean Hefty case IB_QPT_XRC_TGT:
4229d26a360bSSean Hefty *qp_attr_mask |= IB_QP_TIMEOUT;
4230d26a360bSSean Hefty qp_attr->timeout = cm_id_priv->av.timeout;
4231d26a360bSSean Hefty break;
4232d26a360bSSean Hefty default:
4233d26a360bSSean Hefty break;
4234ae7971a7SSean Hefty }
4235d8966fcdSDasaratharaman Chandramouli if (rdma_ah_get_dlid(&cm_id_priv->alt_av.ah_attr)) {
4236a977049dSHal Rosenstock *qp_attr_mask |= IB_QP_PATH_MIG_STATE;
4237a977049dSHal Rosenstock qp_attr->path_mig_state = IB_MIG_REARM;
4238a977049dSHal Rosenstock }
4239e1444b5aSSean Hefty } else {
4240e1444b5aSSean Hefty *qp_attr_mask = IB_QP_ALT_PATH | IB_QP_PATH_MIG_STATE;
424176039ac9SMark Zhang if (cm_id_priv->alt_av.port)
424276039ac9SMark Zhang qp_attr->alt_port_num =
424376039ac9SMark Zhang cm_id_priv->alt_av.port->port_num;
4244e1444b5aSSean Hefty qp_attr->alt_pkey_index = cm_id_priv->alt_av.pkey_index;
42451d846126SSean Hefty qp_attr->alt_timeout = cm_id_priv->alt_av.timeout;
4246e1444b5aSSean Hefty qp_attr->alt_ah_attr = cm_id_priv->alt_av.ah_attr;
4247e1444b5aSSean Hefty qp_attr->path_mig_state = IB_MIG_REARM;
4248e1444b5aSSean Hefty }
4249a977049dSHal Rosenstock ret = 0;
4250a977049dSHal Rosenstock break;
4251a977049dSHal Rosenstock default:
425275874b3dSChuck Lever trace_icm_qp_rts_err(&cm_id_priv->id);
4253a977049dSHal Rosenstock ret = -EINVAL;
4254a977049dSHal Rosenstock break;
4255a977049dSHal Rosenstock }
4256a977049dSHal Rosenstock spin_unlock_irqrestore(&cm_id_priv->lock, flags);
4257a977049dSHal Rosenstock return ret;
4258a977049dSHal Rosenstock }
4259a977049dSHal Rosenstock
ib_cm_init_qp_attr(struct ib_cm_id * cm_id,struct ib_qp_attr * qp_attr,int * qp_attr_mask)4260a977049dSHal Rosenstock int ib_cm_init_qp_attr(struct ib_cm_id *cm_id,
4261a977049dSHal Rosenstock struct ib_qp_attr *qp_attr,
4262a977049dSHal Rosenstock int *qp_attr_mask)
4263a977049dSHal Rosenstock {
4264a977049dSHal Rosenstock struct cm_id_private *cm_id_priv;
4265a977049dSHal Rosenstock int ret;
4266a977049dSHal Rosenstock
4267a977049dSHal Rosenstock cm_id_priv = container_of(cm_id, struct cm_id_private, id);
4268a977049dSHal Rosenstock switch (qp_attr->qp_state) {
4269a977049dSHal Rosenstock case IB_QPS_INIT:
4270a977049dSHal Rosenstock ret = cm_init_qp_init_attr(cm_id_priv, qp_attr, qp_attr_mask);
4271a977049dSHal Rosenstock break;
4272a977049dSHal Rosenstock case IB_QPS_RTR:
4273a977049dSHal Rosenstock ret = cm_init_qp_rtr_attr(cm_id_priv, qp_attr, qp_attr_mask);
4274a977049dSHal Rosenstock break;
4275a977049dSHal Rosenstock case IB_QPS_RTS:
4276a977049dSHal Rosenstock ret = cm_init_qp_rts_attr(cm_id_priv, qp_attr, qp_attr_mask);
4277a977049dSHal Rosenstock break;
4278a977049dSHal Rosenstock default:
4279a977049dSHal Rosenstock ret = -EINVAL;
4280a977049dSHal Rosenstock break;
4281a977049dSHal Rosenstock }
4282a977049dSHal Rosenstock return ret;
4283a977049dSHal Rosenstock }
4284a977049dSHal Rosenstock EXPORT_SYMBOL(ib_cm_init_qp_attr);
4285a977049dSHal Rosenstock
cm_show_counter(struct ib_device * ibdev,u32 port_num,struct ib_port_attribute * attr,char * buf)4286526a12c8SJason Gunthorpe static ssize_t cm_show_counter(struct ib_device *ibdev, u32 port_num,
4287526a12c8SJason Gunthorpe struct ib_port_attribute *attr, char *buf)
42889af57b7aSSean Hefty {
4289526a12c8SJason Gunthorpe struct cm_counter_attribute *cm_attr =
4290526a12c8SJason Gunthorpe container_of(attr, struct cm_counter_attribute, attr);
4291526a12c8SJason Gunthorpe struct cm_device *cm_dev = ib_get_client_data(ibdev, &cm_client);
42929af57b7aSSean Hefty
4293526a12c8SJason Gunthorpe if (WARN_ON(!cm_dev))
4294526a12c8SJason Gunthorpe return -EINVAL;
42959af57b7aSSean Hefty
4296526a12c8SJason Gunthorpe return sysfs_emit(
4297526a12c8SJason Gunthorpe buf, "%ld\n",
4298526a12c8SJason Gunthorpe atomic_long_read(
4299526a12c8SJason Gunthorpe &cm_dev->port[port_num - 1]
4300526a12c8SJason Gunthorpe ->counters[cm_attr->group][cm_attr->index]));
43019af57b7aSSean Hefty }
43029af57b7aSSean Hefty
4303526a12c8SJason Gunthorpe #define CM_COUNTER_ATTR(_name, _group, _index) \
4304526a12c8SJason Gunthorpe { \
4305526a12c8SJason Gunthorpe .attr = __ATTR(_name, 0444, cm_show_counter, NULL), \
4306526a12c8SJason Gunthorpe .group = _group, .index = _index \
4307526a12c8SJason Gunthorpe }
4308526a12c8SJason Gunthorpe
4309526a12c8SJason Gunthorpe #define CM_COUNTER_GROUP(_group, _name) \
4310526a12c8SJason Gunthorpe static struct cm_counter_attribute cm_counter_attr_##_group[] = { \
4311526a12c8SJason Gunthorpe CM_COUNTER_ATTR(req, _group, CM_REQ_COUNTER), \
4312526a12c8SJason Gunthorpe CM_COUNTER_ATTR(mra, _group, CM_MRA_COUNTER), \
4313526a12c8SJason Gunthorpe CM_COUNTER_ATTR(rej, _group, CM_REJ_COUNTER), \
4314526a12c8SJason Gunthorpe CM_COUNTER_ATTR(rep, _group, CM_REP_COUNTER), \
4315526a12c8SJason Gunthorpe CM_COUNTER_ATTR(rtu, _group, CM_RTU_COUNTER), \
4316526a12c8SJason Gunthorpe CM_COUNTER_ATTR(dreq, _group, CM_DREQ_COUNTER), \
4317526a12c8SJason Gunthorpe CM_COUNTER_ATTR(drep, _group, CM_DREP_COUNTER), \
4318526a12c8SJason Gunthorpe CM_COUNTER_ATTR(sidr_req, _group, CM_SIDR_REQ_COUNTER), \
4319526a12c8SJason Gunthorpe CM_COUNTER_ATTR(sidr_rep, _group, CM_SIDR_REP_COUNTER), \
4320526a12c8SJason Gunthorpe CM_COUNTER_ATTR(lap, _group, CM_LAP_COUNTER), \
4321526a12c8SJason Gunthorpe CM_COUNTER_ATTR(apr, _group, CM_APR_COUNTER), \
4322526a12c8SJason Gunthorpe }; \
4323526a12c8SJason Gunthorpe static struct attribute *cm_counter_attrs_##_group[] = { \
4324526a12c8SJason Gunthorpe &cm_counter_attr_##_group[0].attr.attr, \
4325526a12c8SJason Gunthorpe &cm_counter_attr_##_group[1].attr.attr, \
4326526a12c8SJason Gunthorpe &cm_counter_attr_##_group[2].attr.attr, \
4327526a12c8SJason Gunthorpe &cm_counter_attr_##_group[3].attr.attr, \
4328526a12c8SJason Gunthorpe &cm_counter_attr_##_group[4].attr.attr, \
4329526a12c8SJason Gunthorpe &cm_counter_attr_##_group[5].attr.attr, \
4330526a12c8SJason Gunthorpe &cm_counter_attr_##_group[6].attr.attr, \
4331526a12c8SJason Gunthorpe &cm_counter_attr_##_group[7].attr.attr, \
4332526a12c8SJason Gunthorpe &cm_counter_attr_##_group[8].attr.attr, \
4333526a12c8SJason Gunthorpe &cm_counter_attr_##_group[9].attr.attr, \
4334526a12c8SJason Gunthorpe &cm_counter_attr_##_group[10].attr.attr, \
4335526a12c8SJason Gunthorpe NULL, \
4336526a12c8SJason Gunthorpe }; \
4337526a12c8SJason Gunthorpe static const struct attribute_group cm_counter_group_##_group = { \
4338526a12c8SJason Gunthorpe .name = _name, \
4339526a12c8SJason Gunthorpe .attrs = cm_counter_attrs_##_group, \
43409af57b7aSSean Hefty };
43419af57b7aSSean Hefty
4342526a12c8SJason Gunthorpe CM_COUNTER_GROUP(CM_XMIT, "cm_tx_msgs")
4343526a12c8SJason Gunthorpe CM_COUNTER_GROUP(CM_XMIT_RETRIES, "cm_tx_retries")
4344526a12c8SJason Gunthorpe CM_COUNTER_GROUP(CM_RECV, "cm_rx_msgs")
4345526a12c8SJason Gunthorpe CM_COUNTER_GROUP(CM_RECV_DUPLICATES, "cm_rx_duplicates")
4346526a12c8SJason Gunthorpe
4347526a12c8SJason Gunthorpe static const struct attribute_group *cm_counter_groups[] = {
4348526a12c8SJason Gunthorpe &cm_counter_group_CM_XMIT,
4349526a12c8SJason Gunthorpe &cm_counter_group_CM_XMIT_RETRIES,
4350526a12c8SJason Gunthorpe &cm_counter_group_CM_RECV,
4351526a12c8SJason Gunthorpe &cm_counter_group_CM_RECV_DUPLICATES,
4352526a12c8SJason Gunthorpe NULL,
43539af57b7aSSean Hefty };
43549af57b7aSSean Hefty
cm_add_one(struct ib_device * ib_device)435511a0ae4cSJason Gunthorpe static int cm_add_one(struct ib_device *ib_device)
4356a977049dSHal Rosenstock {
4357a977049dSHal Rosenstock struct cm_device *cm_dev;
4358a977049dSHal Rosenstock struct cm_port *port;
4359a977049dSHal Rosenstock struct ib_mad_reg_req reg_req = {
4360a977049dSHal Rosenstock .mgmt_class = IB_MGMT_CLASS_CM,
43610f29b46dSIra Weiny .mgmt_class_version = IB_CM_CLASS_VERSION,
4362a977049dSHal Rosenstock };
4363a977049dSHal Rosenstock struct ib_port_modify port_modify = {
4364a977049dSHal Rosenstock .set_port_cap_mask = IB_PORT_CM_SUP
4365a977049dSHal Rosenstock };
4366a977049dSHal Rosenstock unsigned long flags;
4367a977049dSHal Rosenstock int ret;
4368091e6a4cSMichael Wang int count = 0;
43691fb7f897SMark Bloch u32 i;
4370a977049dSHal Rosenstock
4371acafe7e3SKees Cook cm_dev = kzalloc(struct_size(cm_dev, port, ib_device->phys_port_cnt),
4372acafe7e3SKees Cook GFP_KERNEL);
4373a977049dSHal Rosenstock if (!cm_dev)
437411a0ae4cSJason Gunthorpe return -ENOMEM;
4375a977049dSHal Rosenstock
437676039ac9SMark Zhang kref_init(&cm_dev->kref);
437776039ac9SMark Zhang spin_lock_init(&cm_dev->mad_agent_lock);
4378d4c4196fSGreg Kroah-Hartman cm_dev->ib_device = ib_device;
437986bee4c9SOr Gerlitz cm_dev->ack_delay = ib_device->attrs.local_ca_ack_delay;
4380be4b4993SErez Shitrit cm_dev->going_down = 0;
43819af57b7aSSean Hefty
4382526a12c8SJason Gunthorpe ib_set_client_data(ib_device, &cm_client, cm_dev);
4383526a12c8SJason Gunthorpe
4384a977049dSHal Rosenstock set_bit(IB_MGMT_METHOD_SEND, reg_req.method_mask);
4385131be267SParav Pandit rdma_for_each_port (ib_device, i) {
438672219ceaSMichael Wang if (!rdma_cap_ib_cm(ib_device, i))
4387091e6a4cSMichael Wang continue;
4388091e6a4cSMichael Wang
43899af57b7aSSean Hefty port = kzalloc(sizeof *port, GFP_KERNEL);
439011a0ae4cSJason Gunthorpe if (!port) {
439111a0ae4cSJason Gunthorpe ret = -ENOMEM;
43929af57b7aSSean Hefty goto error1;
439311a0ae4cSJason Gunthorpe }
43949af57b7aSSean Hefty
43959af57b7aSSean Hefty cm_dev->port[i-1] = port;
4396a977049dSHal Rosenstock port->cm_dev = cm_dev;
4397a977049dSHal Rosenstock port->port_num = i;
43989af57b7aSSean Hefty
4399526a12c8SJason Gunthorpe ret = ib_port_register_client_groups(ib_device, i,
4400526a12c8SJason Gunthorpe cm_counter_groups);
44019af57b7aSSean Hefty if (ret)
44029af57b7aSSean Hefty goto error1;
44039af57b7aSSean Hefty
4404d4c4196fSGreg Kroah-Hartman port->mad_agent = ib_register_mad_agent(ib_device, i,
4405a977049dSHal Rosenstock IB_QPT_GSI,
4406a977049dSHal Rosenstock ®_req,
4407a977049dSHal Rosenstock 0,
4408a977049dSHal Rosenstock cm_send_handler,
4409a977049dSHal Rosenstock cm_recv_handler,
44100f29b46dSIra Weiny port,
44110f29b46dSIra Weiny 0);
441211a0ae4cSJason Gunthorpe if (IS_ERR(port->mad_agent)) {
441311a0ae4cSJason Gunthorpe ret = PTR_ERR(port->mad_agent);
44149af57b7aSSean Hefty goto error2;
441511a0ae4cSJason Gunthorpe }
4416a977049dSHal Rosenstock
4417d4c4196fSGreg Kroah-Hartman ret = ib_modify_port(ib_device, i, 0, &port_modify);
4418a977049dSHal Rosenstock if (ret)
44199af57b7aSSean Hefty goto error3;
4420091e6a4cSMichael Wang
4421091e6a4cSMichael Wang count++;
4422a977049dSHal Rosenstock }
4423091e6a4cSMichael Wang
442411a0ae4cSJason Gunthorpe if (!count) {
442511a0ae4cSJason Gunthorpe ret = -EOPNOTSUPP;
4426091e6a4cSMichael Wang goto free;
442711a0ae4cSJason Gunthorpe }
4428091e6a4cSMichael Wang
4429a977049dSHal Rosenstock write_lock_irqsave(&cm.device_lock, flags);
4430a977049dSHal Rosenstock list_add_tail(&cm_dev->list, &cm.device_list);
4431a977049dSHal Rosenstock write_unlock_irqrestore(&cm.device_lock, flags);
443211a0ae4cSJason Gunthorpe return 0;
4433a977049dSHal Rosenstock
44349af57b7aSSean Hefty error3:
4435cf311cd4SSean Hefty ib_unregister_mad_agent(port->mad_agent);
44369af57b7aSSean Hefty error2:
4437526a12c8SJason Gunthorpe ib_port_unregister_client_groups(ib_device, i, cm_counter_groups);
4438cf311cd4SSean Hefty error1:
4439a977049dSHal Rosenstock port_modify.set_port_cap_mask = 0;
4440a977049dSHal Rosenstock port_modify.clr_port_cap_mask = IB_PORT_CM_SUP;
4441a977049dSHal Rosenstock while (--i) {
444272219ceaSMichael Wang if (!rdma_cap_ib_cm(ib_device, i))
4443091e6a4cSMichael Wang continue;
4444091e6a4cSMichael Wang
44459af57b7aSSean Hefty port = cm_dev->port[i-1];
4446d4c4196fSGreg Kroah-Hartman ib_modify_port(ib_device, port->port_num, 0, &port_modify);
4447a977049dSHal Rosenstock ib_unregister_mad_agent(port->mad_agent);
4448526a12c8SJason Gunthorpe ib_port_unregister_client_groups(ib_device, i,
4449526a12c8SJason Gunthorpe cm_counter_groups);
4450a977049dSHal Rosenstock }
4451091e6a4cSMichael Wang free:
445276039ac9SMark Zhang cm_device_put(cm_dev);
445311a0ae4cSJason Gunthorpe return ret;
4454a977049dSHal Rosenstock }
4455a977049dSHal Rosenstock
cm_remove_one(struct ib_device * ib_device,void * client_data)44567c1eb45aSHaggai Eran static void cm_remove_one(struct ib_device *ib_device, void *client_data)
4457a977049dSHal Rosenstock {
44587c1eb45aSHaggai Eran struct cm_device *cm_dev = client_data;
4459a977049dSHal Rosenstock struct cm_port *port;
4460a977049dSHal Rosenstock struct ib_port_modify port_modify = {
4461a977049dSHal Rosenstock .clr_port_cap_mask = IB_PORT_CM_SUP
4462a977049dSHal Rosenstock };
4463a977049dSHal Rosenstock unsigned long flags;
44641fb7f897SMark Bloch u32 i;
4465a977049dSHal Rosenstock
4466a977049dSHal Rosenstock write_lock_irqsave(&cm.device_lock, flags);
4467a977049dSHal Rosenstock list_del(&cm_dev->list);
4468a977049dSHal Rosenstock write_unlock_irqrestore(&cm.device_lock, flags);
4469a977049dSHal Rosenstock
4470be4b4993SErez Shitrit spin_lock_irq(&cm.lock);
4471be4b4993SErez Shitrit cm_dev->going_down = 1;
4472be4b4993SErez Shitrit spin_unlock_irq(&cm.lock);
4473be4b4993SErez Shitrit
4474131be267SParav Pandit rdma_for_each_port (ib_device, i) {
447576039ac9SMark Zhang struct ib_mad_agent *mad_agent;
447676039ac9SMark Zhang
447772219ceaSMichael Wang if (!rdma_cap_ib_cm(ib_device, i))
4478091e6a4cSMichael Wang continue;
4479091e6a4cSMichael Wang
44809af57b7aSSean Hefty port = cm_dev->port[i-1];
448176039ac9SMark Zhang mad_agent = port->mad_agent;
4482d4c4196fSGreg Kroah-Hartman ib_modify_port(ib_device, port->port_num, 0, &port_modify);
4483be4b4993SErez Shitrit /*
4484be4b4993SErez Shitrit * We flush the queue here after the going_down set, this
4485be4b4993SErez Shitrit * verify that no new works will be queued in the recv handler,
4486be4b4993SErez Shitrit * after that we can call the unregister_mad_agent
4487be4b4993SErez Shitrit */
448884ba284cSSean Hefty flush_workqueue(cm.wq);
448976039ac9SMark Zhang /*
449076039ac9SMark Zhang * The above ensures no call paths from the work are running,
449176039ac9SMark Zhang * the remaining paths all take the mad_agent_lock.
449276039ac9SMark Zhang */
449376039ac9SMark Zhang spin_lock(&cm_dev->mad_agent_lock);
449476039ac9SMark Zhang port->mad_agent = NULL;
449576039ac9SMark Zhang spin_unlock(&cm_dev->mad_agent_lock);
449676039ac9SMark Zhang ib_unregister_mad_agent(mad_agent);
4497526a12c8SJason Gunthorpe ib_port_unregister_client_groups(ib_device, i,
4498526a12c8SJason Gunthorpe cm_counter_groups);
4499a977049dSHal Rosenstock }
45009db0ff53SMark Bloch
450176039ac9SMark Zhang cm_device_put(cm_dev);
4502a977049dSHal Rosenstock }
4503a977049dSHal Rosenstock
ib_cm_init(void)4504a977049dSHal Rosenstock static int __init ib_cm_init(void)
4505a977049dSHal Rosenstock {
4506a977049dSHal Rosenstock int ret;
4507a977049dSHal Rosenstock
4508a977049dSHal Rosenstock INIT_LIST_HEAD(&cm.device_list);
4509a977049dSHal Rosenstock rwlock_init(&cm.device_lock);
4510a977049dSHal Rosenstock spin_lock_init(&cm.lock);
4511a977049dSHal Rosenstock cm.listen_service_table = RB_ROOT;
45129c3da099SHarvey Harrison cm.listen_service_id = be64_to_cpu(IB_CM_ASSIGN_SERVICE_ID);
4513a977049dSHal Rosenstock cm.remote_id_table = RB_ROOT;
4514a977049dSHal Rosenstock cm.remote_qp_table = RB_ROOT;
4515a977049dSHal Rosenstock cm.remote_sidr_table = RB_ROOT;
4516eb73060bSJason Gunthorpe xa_init_flags(&cm.local_id_table, XA_FLAGS_ALLOC);
4517f06d2653SSean Hefty get_random_bytes(&cm.random_id_operand, sizeof cm.random_id_operand);
45188575329dSSean Hefty INIT_LIST_HEAD(&cm.timewait_list);
4519a977049dSHal Rosenstock
4520cb93e597SSagi Grimberg cm.wq = alloc_workqueue("ib_cm", 0, 1);
452187d4abdaSDotan Barak if (!cm.wq) {
452287d4abdaSDotan Barak ret = -ENOMEM;
452387d4abdaSDotan Barak goto error2;
452487d4abdaSDotan Barak }
452587d4abdaSDotan Barak
4526a977049dSHal Rosenstock ret = ib_register_client(&cm_client);
4527a977049dSHal Rosenstock if (ret)
452887d4abdaSDotan Barak goto error3;
4529a977049dSHal Rosenstock
4530a977049dSHal Rosenstock return 0;
453187d4abdaSDotan Barak error3:
4532a977049dSHal Rosenstock destroy_workqueue(cm.wq);
453387d4abdaSDotan Barak error2:
4534a977049dSHal Rosenstock return ret;
4535a977049dSHal Rosenstock }
4536a977049dSHal Rosenstock
ib_cm_cleanup(void)4537a977049dSHal Rosenstock static void __exit ib_cm_cleanup(void)
4538a977049dSHal Rosenstock {
45398575329dSSean Hefty struct cm_timewait_info *timewait_info, *tmp;
45408575329dSSean Hefty
45418575329dSSean Hefty spin_lock_irq(&cm.lock);
45428575329dSSean Hefty list_for_each_entry(timewait_info, &cm.timewait_list, list)
45438575329dSSean Hefty cancel_delayed_work(&timewait_info->work.work);
45448575329dSSean Hefty spin_unlock_irq(&cm.lock);
45458575329dSSean Hefty
454684ba284cSSean Hefty ib_unregister_client(&cm_client);
4547a977049dSHal Rosenstock destroy_workqueue(cm.wq);
45488575329dSSean Hefty
45498575329dSSean Hefty list_for_each_entry_safe(timewait_info, tmp, &cm.timewait_list, list) {
45508575329dSSean Hefty list_del(&timewait_info->list);
45518575329dSSean Hefty kfree(timewait_info);
45528575329dSSean Hefty }
45538575329dSSean Hefty
4554ae78ff3aSMatthew Wilcox WARN_ON(!xa_empty(&cm.local_id_table));
4555a977049dSHal Rosenstock }
4556a977049dSHal Rosenstock
4557a977049dSHal Rosenstock module_init(ib_cm_init);
4558a977049dSHal Rosenstock module_exit(ib_cm_cleanup);
4559