xref: /openbmc/linux/drivers/infiniband/hw/qedr/qedr_iw_cm.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
1de0089e6SKalderon, Michal /* QLogic qedr NIC Driver
2de0089e6SKalderon, Michal  * Copyright (c) 2015-2017  QLogic Corporation
3de0089e6SKalderon, Michal  *
4de0089e6SKalderon, Michal  * This software is available to you under a choice of one of two
5de0089e6SKalderon, Michal  * licenses.  You may choose to be licensed under the terms of the GNU
6de0089e6SKalderon, Michal  * General Public License (GPL) Version 2, available from the file
7de0089e6SKalderon, Michal  * COPYING in the main directory of this source tree, or the
8de0089e6SKalderon, Michal  * OpenIB.org BSD license below:
9de0089e6SKalderon, Michal  *
10de0089e6SKalderon, Michal  *     Redistribution and use in source and binary forms, with or
11de0089e6SKalderon, Michal  *     without modification, are permitted provided that the following
12de0089e6SKalderon, Michal  *     conditions are met:
13de0089e6SKalderon, Michal  *
14de0089e6SKalderon, Michal  *      - Redistributions of source code must retain the above
15de0089e6SKalderon, Michal  *        copyright notice, this list of conditions and the following
16de0089e6SKalderon, Michal  *        disclaimer.
17de0089e6SKalderon, Michal  *
18de0089e6SKalderon, Michal  *      - Redistributions in binary form must reproduce the above
19de0089e6SKalderon, Michal  *        copyright notice, this list of conditions and the following
20de0089e6SKalderon, Michal  *        disclaimer in the documentation and /or other materials
21de0089e6SKalderon, Michal  *        provided with the distribution.
22de0089e6SKalderon, Michal  *
23de0089e6SKalderon, Michal  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24de0089e6SKalderon, Michal  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25de0089e6SKalderon, Michal  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26de0089e6SKalderon, Michal  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27de0089e6SKalderon, Michal  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28de0089e6SKalderon, Michal  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29de0089e6SKalderon, Michal  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30de0089e6SKalderon, Michal  * SOFTWARE.
31de0089e6SKalderon, Michal  */
32e411e058SKalderon, Michal #include <net/ip.h>
33e411e058SKalderon, Michal #include <net/ipv6.h>
34e411e058SKalderon, Michal #include <net/udp.h>
35e411e058SKalderon, Michal #include <net/addrconf.h>
36e411e058SKalderon, Michal #include <net/route.h>
37e411e058SKalderon, Michal #include <net/ip6_route.h>
38e411e058SKalderon, Michal #include <net/flow.h>
39de0089e6SKalderon, Michal #include "qedr.h"
40e411e058SKalderon, Michal #include "qedr_iw_cm.h"
41e411e058SKalderon, Michal 
42e411e058SKalderon, Michal static inline void
qedr_fill_sockaddr4(const struct qed_iwarp_cm_info * cm_info,struct iw_cm_event * event)43e411e058SKalderon, Michal qedr_fill_sockaddr4(const struct qed_iwarp_cm_info *cm_info,
44e411e058SKalderon, Michal 		    struct iw_cm_event *event)
45e411e058SKalderon, Michal {
46e411e058SKalderon, Michal 	struct sockaddr_in *laddr = (struct sockaddr_in *)&event->local_addr;
47e411e058SKalderon, Michal 	struct sockaddr_in *raddr = (struct sockaddr_in *)&event->remote_addr;
48e411e058SKalderon, Michal 
49e411e058SKalderon, Michal 	laddr->sin_family = AF_INET;
50e411e058SKalderon, Michal 	raddr->sin_family = AF_INET;
51e411e058SKalderon, Michal 
52e411e058SKalderon, Michal 	laddr->sin_port = htons(cm_info->local_port);
53e411e058SKalderon, Michal 	raddr->sin_port = htons(cm_info->remote_port);
54e411e058SKalderon, Michal 
55e411e058SKalderon, Michal 	laddr->sin_addr.s_addr = htonl(cm_info->local_ip[0]);
56e411e058SKalderon, Michal 	raddr->sin_addr.s_addr = htonl(cm_info->remote_ip[0]);
57e411e058SKalderon, Michal }
58e411e058SKalderon, Michal 
59e411e058SKalderon, Michal static inline void
qedr_fill_sockaddr6(const struct qed_iwarp_cm_info * cm_info,struct iw_cm_event * event)60e411e058SKalderon, Michal qedr_fill_sockaddr6(const struct qed_iwarp_cm_info *cm_info,
61e411e058SKalderon, Michal 		    struct iw_cm_event *event)
62e411e058SKalderon, Michal {
63e411e058SKalderon, Michal 	struct sockaddr_in6 *laddr6 = (struct sockaddr_in6 *)&event->local_addr;
64e411e058SKalderon, Michal 	struct sockaddr_in6 *raddr6 =
65e411e058SKalderon, Michal 	    (struct sockaddr_in6 *)&event->remote_addr;
66e411e058SKalderon, Michal 	int i;
67e411e058SKalderon, Michal 
68e411e058SKalderon, Michal 	laddr6->sin6_family = AF_INET6;
69e411e058SKalderon, Michal 	raddr6->sin6_family = AF_INET6;
70e411e058SKalderon, Michal 
71e411e058SKalderon, Michal 	laddr6->sin6_port = htons(cm_info->local_port);
72e411e058SKalderon, Michal 	raddr6->sin6_port = htons(cm_info->remote_port);
73e411e058SKalderon, Michal 
74e411e058SKalderon, Michal 	for (i = 0; i < 4; i++) {
75e411e058SKalderon, Michal 		laddr6->sin6_addr.in6_u.u6_addr32[i] =
76e411e058SKalderon, Michal 		    htonl(cm_info->local_ip[i]);
77e411e058SKalderon, Michal 		raddr6->sin6_addr.in6_u.u6_addr32[i] =
78e411e058SKalderon, Michal 		    htonl(cm_info->remote_ip[i]);
79e411e058SKalderon, Michal 	}
80e411e058SKalderon, Michal }
81e411e058SKalderon, Michal 
qedr_iw_free_qp(struct kref * ref)8282af6d19SMichal Kalderon static void qedr_iw_free_qp(struct kref *ref)
8382af6d19SMichal Kalderon {
8482af6d19SMichal Kalderon 	struct qedr_qp *qp = container_of(ref, struct qedr_qp, refcnt);
8582af6d19SMichal Kalderon 
86*60fab107SPrabhakar Kushwaha 	complete(&qp->qp_rel_comp);
8782af6d19SMichal Kalderon }
8882af6d19SMichal Kalderon 
8982af6d19SMichal Kalderon static void
qedr_iw_free_ep(struct kref * ref)9082af6d19SMichal Kalderon qedr_iw_free_ep(struct kref *ref)
9182af6d19SMichal Kalderon {
9282af6d19SMichal Kalderon 	struct qedr_iw_ep *ep = container_of(ref, struct qedr_iw_ep, refcnt);
9382af6d19SMichal Kalderon 
9482af6d19SMichal Kalderon 	if (ep->qp)
9582af6d19SMichal Kalderon 		kref_put(&ep->qp->refcnt, qedr_iw_free_qp);
9682af6d19SMichal Kalderon 
9782af6d19SMichal Kalderon 	if (ep->cm_id)
9882af6d19SMichal Kalderon 		ep->cm_id->rem_ref(ep->cm_id);
9982af6d19SMichal Kalderon 
10082af6d19SMichal Kalderon 	kfree(ep);
10182af6d19SMichal Kalderon }
10282af6d19SMichal Kalderon 
1030089985eSBart Van Assche static void
qedr_iw_mpa_request(void * context,struct qed_iwarp_cm_event_params * params)104e411e058SKalderon, Michal qedr_iw_mpa_request(void *context, struct qed_iwarp_cm_event_params *params)
105e411e058SKalderon, Michal {
106e411e058SKalderon, Michal 	struct qedr_iw_listener *listener = (struct qedr_iw_listener *)context;
107e411e058SKalderon, Michal 	struct qedr_dev *dev = listener->dev;
108e411e058SKalderon, Michal 	struct iw_cm_event event;
109e411e058SKalderon, Michal 	struct qedr_iw_ep *ep;
110e411e058SKalderon, Michal 
111e411e058SKalderon, Michal 	ep = kzalloc(sizeof(*ep), GFP_ATOMIC);
112e411e058SKalderon, Michal 	if (!ep)
113e411e058SKalderon, Michal 		return;
114e411e058SKalderon, Michal 
115e411e058SKalderon, Michal 	ep->dev = dev;
116e411e058SKalderon, Michal 	ep->qed_context = params->ep_context;
11782af6d19SMichal Kalderon 	kref_init(&ep->refcnt);
118e411e058SKalderon, Michal 
119e411e058SKalderon, Michal 	memset(&event, 0, sizeof(event));
120e411e058SKalderon, Michal 	event.event = IW_CM_EVENT_CONNECT_REQUEST;
121e411e058SKalderon, Michal 	event.status = params->status;
122e411e058SKalderon, Michal 
123bd491d2aSArnd Bergmann 	if (!IS_ENABLED(CONFIG_IPV6) ||
124bd491d2aSArnd Bergmann 	    params->cm_info->ip_version == QED_TCP_IPV4)
125e411e058SKalderon, Michal 		qedr_fill_sockaddr4(params->cm_info, &event);
126e411e058SKalderon, Michal 	else
127e411e058SKalderon, Michal 		qedr_fill_sockaddr6(params->cm_info, &event);
128e411e058SKalderon, Michal 
129e411e058SKalderon, Michal 	event.provider_data = (void *)ep;
130e411e058SKalderon, Michal 	event.private_data = (void *)params->cm_info->private_data;
131e411e058SKalderon, Michal 	event.private_data_len = (u8)params->cm_info->private_data_len;
132e411e058SKalderon, Michal 	event.ord = params->cm_info->ord;
133e411e058SKalderon, Michal 	event.ird = params->cm_info->ird;
134e411e058SKalderon, Michal 
135e411e058SKalderon, Michal 	listener->cm_id->event_handler(listener->cm_id, &event);
136e411e058SKalderon, Michal }
137e411e058SKalderon, Michal 
1380089985eSBart Van Assche static void
qedr_iw_issue_event(void * context,struct qed_iwarp_cm_event_params * params,enum iw_cm_event_type event_type)139e411e058SKalderon, Michal qedr_iw_issue_event(void *context,
140e411e058SKalderon, Michal 		    struct qed_iwarp_cm_event_params *params,
141e411e058SKalderon, Michal 		    enum iw_cm_event_type event_type)
142e411e058SKalderon, Michal {
143e411e058SKalderon, Michal 	struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;
144e411e058SKalderon, Michal 	struct iw_cm_event event;
145e411e058SKalderon, Michal 
146e411e058SKalderon, Michal 	memset(&event, 0, sizeof(event));
147e411e058SKalderon, Michal 	event.status = params->status;
148e411e058SKalderon, Michal 	event.event = event_type;
149e411e058SKalderon, Michal 
150e411e058SKalderon, Michal 	if (params->cm_info) {
151e411e058SKalderon, Michal 		event.ird = params->cm_info->ird;
152e411e058SKalderon, Michal 		event.ord = params->cm_info->ord;
1530dfbd5ecSMichal Kalderon 		/* Only connect_request and reply have valid private data
1540dfbd5ecSMichal Kalderon 		 * the rest of the events this may be left overs from
1550dfbd5ecSMichal Kalderon 		 * connection establishment. CONNECT_REQUEST is issued via
1560dfbd5ecSMichal Kalderon 		 * qedr_iw_mpa_request
1570dfbd5ecSMichal Kalderon 		 */
1580dfbd5ecSMichal Kalderon 		if (event_type == IW_CM_EVENT_CONNECT_REPLY) {
1590dfbd5ecSMichal Kalderon 			event.private_data_len =
1600dfbd5ecSMichal Kalderon 				params->cm_info->private_data_len;
1610dfbd5ecSMichal Kalderon 			event.private_data =
1620dfbd5ecSMichal Kalderon 				(void *)params->cm_info->private_data;
1630dfbd5ecSMichal Kalderon 		}
164e411e058SKalderon, Michal 	}
165e411e058SKalderon, Michal 
166e411e058SKalderon, Michal 	if (ep->cm_id)
167e411e058SKalderon, Michal 		ep->cm_id->event_handler(ep->cm_id, &event);
168e411e058SKalderon, Michal }
169e411e058SKalderon, Michal 
1700089985eSBart Van Assche static void
qedr_iw_close_event(void * context,struct qed_iwarp_cm_event_params * params)171e411e058SKalderon, Michal qedr_iw_close_event(void *context, struct qed_iwarp_cm_event_params *params)
172e411e058SKalderon, Michal {
173e411e058SKalderon, Michal 	struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;
174e411e058SKalderon, Michal 
17582af6d19SMichal Kalderon 	if (ep->cm_id)
176e411e058SKalderon, Michal 		qedr_iw_issue_event(context, params, IW_CM_EVENT_CLOSE);
177e411e058SKalderon, Michal 
17882af6d19SMichal Kalderon 	kref_put(&ep->refcnt, qedr_iw_free_ep);
179e411e058SKalderon, Michal }
180e411e058SKalderon, Michal 
1810089985eSBart Van Assche static void
qedr_iw_qp_event(void * context,struct qed_iwarp_cm_event_params * params,enum ib_event_type ib_event,char * str)182e411e058SKalderon, Michal qedr_iw_qp_event(void *context,
183e411e058SKalderon, Michal 		 struct qed_iwarp_cm_event_params *params,
184e411e058SKalderon, Michal 		 enum ib_event_type ib_event, char *str)
185e411e058SKalderon, Michal {
186e411e058SKalderon, Michal 	struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;
187e411e058SKalderon, Michal 	struct qedr_dev *dev = ep->dev;
188e411e058SKalderon, Michal 	struct ib_qp *ibqp = &ep->qp->ibqp;
189e411e058SKalderon, Michal 	struct ib_event event;
190e411e058SKalderon, Michal 
191e411e058SKalderon, Michal 	DP_NOTICE(dev, "QP error received: %s\n", str);
192e411e058SKalderon, Michal 
193e411e058SKalderon, Michal 	if (ibqp->event_handler) {
194e411e058SKalderon, Michal 		event.event = ib_event;
195e411e058SKalderon, Michal 		event.device = ibqp->device;
196e411e058SKalderon, Michal 		event.element.qp = ibqp;
197e411e058SKalderon, Michal 		ibqp->event_handler(&event, ibqp->qp_context);
198e411e058SKalderon, Michal 	}
199e411e058SKalderon, Michal }
200e411e058SKalderon, Michal 
201e411e058SKalderon, Michal struct qedr_discon_work {
202e411e058SKalderon, Michal 	struct work_struct		work;
203e411e058SKalderon, Michal 	struct qedr_iw_ep		*ep;
204e411e058SKalderon, Michal 	enum qed_iwarp_event_type	event;
205e411e058SKalderon, Michal 	int				status;
206e411e058SKalderon, Michal };
207e411e058SKalderon, Michal 
qedr_iw_disconnect_worker(struct work_struct * work)208e411e058SKalderon, Michal static void qedr_iw_disconnect_worker(struct work_struct *work)
209e411e058SKalderon, Michal {
210e411e058SKalderon, Michal 	struct qedr_discon_work *dwork =
211e411e058SKalderon, Michal 	    container_of(work, struct qedr_discon_work, work);
212e411e058SKalderon, Michal 	struct qed_rdma_modify_qp_in_params qp_params = { 0 };
213e411e058SKalderon, Michal 	struct qedr_iw_ep *ep = dwork->ep;
214e411e058SKalderon, Michal 	struct qedr_dev *dev = ep->dev;
215e411e058SKalderon, Michal 	struct qedr_qp *qp = ep->qp;
216e411e058SKalderon, Michal 	struct iw_cm_event event;
217e411e058SKalderon, Michal 
21882af6d19SMichal Kalderon 	/* The qp won't be released until we release the ep.
21982af6d19SMichal Kalderon 	 * the ep's refcnt was increased before calling this
22082af6d19SMichal Kalderon 	 * function, therefore it is safe to access qp
22182af6d19SMichal Kalderon 	 */
22282af6d19SMichal Kalderon 	if (test_and_set_bit(QEDR_IWARP_CM_WAIT_FOR_DISCONNECT,
22382af6d19SMichal Kalderon 			     &qp->iwarp_cm_flags))
22482af6d19SMichal Kalderon 		goto out;
225e411e058SKalderon, Michal 
226e411e058SKalderon, Michal 	memset(&event, 0, sizeof(event));
227e411e058SKalderon, Michal 	event.status = dwork->status;
228e411e058SKalderon, Michal 	event.event = IW_CM_EVENT_DISCONNECT;
229e411e058SKalderon, Michal 
230e411e058SKalderon, Michal 	/* Success means graceful disconnect was requested. modifying
231e411e058SKalderon, Michal 	 * to SQD is translated to graceful disconnect. O/w reset is sent
232e411e058SKalderon, Michal 	 */
233e411e058SKalderon, Michal 	if (dwork->status)
234e411e058SKalderon, Michal 		qp_params.new_state = QED_ROCE_QP_STATE_ERR;
235e411e058SKalderon, Michal 	else
236e411e058SKalderon, Michal 		qp_params.new_state = QED_ROCE_QP_STATE_SQD;
237e411e058SKalderon, Michal 
238e411e058SKalderon, Michal 
239e411e058SKalderon, Michal 	if (ep->cm_id)
240e411e058SKalderon, Michal 		ep->cm_id->event_handler(ep->cm_id, &event);
241e411e058SKalderon, Michal 
242e411e058SKalderon, Michal 	SET_FIELD(qp_params.modify_flags,
243e411e058SKalderon, Michal 		  QED_RDMA_MODIFY_QP_VALID_NEW_STATE, 1);
244e411e058SKalderon, Michal 
245e411e058SKalderon, Michal 	dev->ops->rdma_modify_qp(dev->rdma_ctx, qp->qed_qp, &qp_params);
246e411e058SKalderon, Michal 
24782af6d19SMichal Kalderon 	complete(&ep->qp->iwarp_cm_comp);
24882af6d19SMichal Kalderon out:
24982af6d19SMichal Kalderon 	kfree(dwork);
25082af6d19SMichal Kalderon 	kref_put(&ep->refcnt, qedr_iw_free_ep);
251e411e058SKalderon, Michal }
252e411e058SKalderon, Michal 
2530089985eSBart Van Assche static void
qedr_iw_disconnect_event(void * context,struct qed_iwarp_cm_event_params * params)254e411e058SKalderon, Michal qedr_iw_disconnect_event(void *context,
255e411e058SKalderon, Michal 			 struct qed_iwarp_cm_event_params *params)
256e411e058SKalderon, Michal {
257e411e058SKalderon, Michal 	struct qedr_discon_work *work;
258e411e058SKalderon, Michal 	struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;
259e411e058SKalderon, Michal 	struct qedr_dev *dev = ep->dev;
260e411e058SKalderon, Michal 
261e411e058SKalderon, Michal 	work = kzalloc(sizeof(*work), GFP_ATOMIC);
262e411e058SKalderon, Michal 	if (!work)
263e411e058SKalderon, Michal 		return;
264e411e058SKalderon, Michal 
26582af6d19SMichal Kalderon 	/* We can't get a close event before disconnect, but since
26682af6d19SMichal Kalderon 	 * we're scheduling a work queue we need to make sure close
26782af6d19SMichal Kalderon 	 * won't delete the ep, so we increase the refcnt
26882af6d19SMichal Kalderon 	 */
26982af6d19SMichal Kalderon 	kref_get(&ep->refcnt);
27082af6d19SMichal Kalderon 
271e411e058SKalderon, Michal 	work->ep = ep;
272e411e058SKalderon, Michal 	work->event = params->event;
273e411e058SKalderon, Michal 	work->status = params->status;
274e411e058SKalderon, Michal 
275e411e058SKalderon, Michal 	INIT_WORK(&work->work, qedr_iw_disconnect_worker);
276e411e058SKalderon, Michal 	queue_work(dev->iwarp_wq, &work->work);
277e411e058SKalderon, Michal }
278e411e058SKalderon, Michal 
279e411e058SKalderon, Michal static void
qedr_iw_passive_complete(void * context,struct qed_iwarp_cm_event_params * params)280e411e058SKalderon, Michal qedr_iw_passive_complete(void *context,
281e411e058SKalderon, Michal 			 struct qed_iwarp_cm_event_params *params)
282e411e058SKalderon, Michal {
283e411e058SKalderon, Michal 	struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;
284e411e058SKalderon, Michal 	struct qedr_dev *dev = ep->dev;
285e411e058SKalderon, Michal 
286e411e058SKalderon, Michal 	/* We will only reach the following state if MPA_REJECT was called on
287e411e058SKalderon, Michal 	 * passive. In this case there will be no associated QP.
288e411e058SKalderon, Michal 	 */
289e411e058SKalderon, Michal 	if ((params->status == -ECONNREFUSED) && (!ep->qp)) {
290e411e058SKalderon, Michal 		DP_DEBUG(dev, QEDR_MSG_IWARP,
291e411e058SKalderon, Michal 			 "PASSIVE connection refused releasing ep...\n");
29282af6d19SMichal Kalderon 		kref_put(&ep->refcnt, qedr_iw_free_ep);
293e411e058SKalderon, Michal 		return;
294e411e058SKalderon, Michal 	}
295e411e058SKalderon, Michal 
29682af6d19SMichal Kalderon 	complete(&ep->qp->iwarp_cm_comp);
297e411e058SKalderon, Michal 	qedr_iw_issue_event(context, params, IW_CM_EVENT_ESTABLISHED);
298e411e058SKalderon, Michal 
299e411e058SKalderon, Michal 	if (params->status < 0)
300e411e058SKalderon, Michal 		qedr_iw_close_event(context, params);
301e411e058SKalderon, Michal }
302e411e058SKalderon, Michal 
30382af6d19SMichal Kalderon static void
qedr_iw_active_complete(void * context,struct qed_iwarp_cm_event_params * params)30482af6d19SMichal Kalderon qedr_iw_active_complete(void *context,
30582af6d19SMichal Kalderon 			struct qed_iwarp_cm_event_params *params)
30682af6d19SMichal Kalderon {
30782af6d19SMichal Kalderon 	struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;
30882af6d19SMichal Kalderon 
30982af6d19SMichal Kalderon 	complete(&ep->qp->iwarp_cm_comp);
31082af6d19SMichal Kalderon 	qedr_iw_issue_event(context, params, IW_CM_EVENT_CONNECT_REPLY);
31182af6d19SMichal Kalderon 
31282af6d19SMichal Kalderon 	if (params->status < 0)
31382af6d19SMichal Kalderon 		kref_put(&ep->refcnt, qedr_iw_free_ep);
31482af6d19SMichal Kalderon }
31582af6d19SMichal Kalderon 
3160089985eSBart Van Assche static int
qedr_iw_mpa_reply(void * context,struct qed_iwarp_cm_event_params * params)317e411e058SKalderon, Michal qedr_iw_mpa_reply(void *context, struct qed_iwarp_cm_event_params *params)
318e411e058SKalderon, Michal {
319e411e058SKalderon, Michal 	struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;
320e411e058SKalderon, Michal 	struct qedr_dev *dev = ep->dev;
321e411e058SKalderon, Michal 	struct qed_iwarp_send_rtr_in rtr_in;
322e411e058SKalderon, Michal 
323e411e058SKalderon, Michal 	rtr_in.ep_context = params->ep_context;
324e411e058SKalderon, Michal 
325e411e058SKalderon, Michal 	return dev->ops->iwarp_send_rtr(dev->rdma_ctx, &rtr_in);
326e411e058SKalderon, Michal }
327e411e058SKalderon, Michal 
3280089985eSBart Van Assche static int
qedr_iw_event_handler(void * context,struct qed_iwarp_cm_event_params * params)329e411e058SKalderon, Michal qedr_iw_event_handler(void *context, struct qed_iwarp_cm_event_params *params)
330e411e058SKalderon, Michal {
331e411e058SKalderon, Michal 	struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;
332e411e058SKalderon, Michal 	struct qedr_dev *dev = ep->dev;
333e411e058SKalderon, Michal 
334e411e058SKalderon, Michal 	switch (params->event) {
335e411e058SKalderon, Michal 	case QED_IWARP_EVENT_MPA_REQUEST:
336e411e058SKalderon, Michal 		qedr_iw_mpa_request(context, params);
337e411e058SKalderon, Michal 		break;
338e411e058SKalderon, Michal 	case QED_IWARP_EVENT_ACTIVE_MPA_REPLY:
339e411e058SKalderon, Michal 		qedr_iw_mpa_reply(context, params);
340e411e058SKalderon, Michal 		break;
341e411e058SKalderon, Michal 	case QED_IWARP_EVENT_PASSIVE_COMPLETE:
342e411e058SKalderon, Michal 		qedr_iw_passive_complete(context, params);
343e411e058SKalderon, Michal 		break;
344e411e058SKalderon, Michal 	case QED_IWARP_EVENT_ACTIVE_COMPLETE:
34582af6d19SMichal Kalderon 		qedr_iw_active_complete(context, params);
346e411e058SKalderon, Michal 		break;
347e411e058SKalderon, Michal 	case QED_IWARP_EVENT_DISCONNECT:
348e411e058SKalderon, Michal 		qedr_iw_disconnect_event(context, params);
349e411e058SKalderon, Michal 		break;
350e411e058SKalderon, Michal 	case QED_IWARP_EVENT_CLOSE:
351e411e058SKalderon, Michal 		qedr_iw_close_event(context, params);
352e411e058SKalderon, Michal 		break;
353e411e058SKalderon, Michal 	case QED_IWARP_EVENT_RQ_EMPTY:
354e411e058SKalderon, Michal 		qedr_iw_qp_event(context, params, IB_EVENT_QP_FATAL,
355e411e058SKalderon, Michal 				 "QED_IWARP_EVENT_RQ_EMPTY");
356e411e058SKalderon, Michal 		break;
357e411e058SKalderon, Michal 	case QED_IWARP_EVENT_IRQ_FULL:
358e411e058SKalderon, Michal 		qedr_iw_qp_event(context, params, IB_EVENT_QP_FATAL,
359e411e058SKalderon, Michal 				 "QED_IWARP_EVENT_IRQ_FULL");
360e411e058SKalderon, Michal 		break;
361e411e058SKalderon, Michal 	case QED_IWARP_EVENT_LLP_TIMEOUT:
362e411e058SKalderon, Michal 		qedr_iw_qp_event(context, params, IB_EVENT_QP_FATAL,
363e411e058SKalderon, Michal 				 "QED_IWARP_EVENT_LLP_TIMEOUT");
364e411e058SKalderon, Michal 		break;
365e411e058SKalderon, Michal 	case QED_IWARP_EVENT_REMOTE_PROTECTION_ERROR:
366e411e058SKalderon, Michal 		qedr_iw_qp_event(context, params, IB_EVENT_QP_ACCESS_ERR,
367e411e058SKalderon, Michal 				 "QED_IWARP_EVENT_REMOTE_PROTECTION_ERROR");
368e411e058SKalderon, Michal 		break;
369e411e058SKalderon, Michal 	case QED_IWARP_EVENT_CQ_OVERFLOW:
370e411e058SKalderon, Michal 		qedr_iw_qp_event(context, params, IB_EVENT_QP_FATAL,
371e411e058SKalderon, Michal 				 "QED_IWARP_EVENT_CQ_OVERFLOW");
372e411e058SKalderon, Michal 		break;
373e411e058SKalderon, Michal 	case QED_IWARP_EVENT_QP_CATASTROPHIC:
374e411e058SKalderon, Michal 		qedr_iw_qp_event(context, params, IB_EVENT_QP_FATAL,
375e411e058SKalderon, Michal 				 "QED_IWARP_EVENT_QP_CATASTROPHIC");
376e411e058SKalderon, Michal 		break;
377e411e058SKalderon, Michal 	case QED_IWARP_EVENT_LOCAL_ACCESS_ERROR:
378e411e058SKalderon, Michal 		qedr_iw_qp_event(context, params, IB_EVENT_QP_ACCESS_ERR,
379e411e058SKalderon, Michal 				 "QED_IWARP_EVENT_LOCAL_ACCESS_ERROR");
380e411e058SKalderon, Michal 		break;
381e411e058SKalderon, Michal 	case QED_IWARP_EVENT_REMOTE_OPERATION_ERROR:
382e411e058SKalderon, Michal 		qedr_iw_qp_event(context, params, IB_EVENT_QP_FATAL,
383e411e058SKalderon, Michal 				 "QED_IWARP_EVENT_REMOTE_OPERATION_ERROR");
384e411e058SKalderon, Michal 		break;
385e411e058SKalderon, Michal 	case QED_IWARP_EVENT_TERMINATE_RECEIVED:
386e411e058SKalderon, Michal 		DP_NOTICE(dev, "Got terminate message\n");
387e411e058SKalderon, Michal 		break;
388e411e058SKalderon, Michal 	default:
389e411e058SKalderon, Michal 		DP_NOTICE(dev, "Unknown event received %d\n", params->event);
390e411e058SKalderon, Michal 		break;
391790b57f6SYueHaibing 	}
392e411e058SKalderon, Michal 	return 0;
393e411e058SKalderon, Michal }
394e411e058SKalderon, Michal 
qedr_iw_get_vlan_ipv4(struct qedr_dev * dev,u32 * addr)395e411e058SKalderon, Michal static u16 qedr_iw_get_vlan_ipv4(struct qedr_dev *dev, u32 *addr)
396e411e058SKalderon, Michal {
397e411e058SKalderon, Michal 	struct net_device *ndev;
398e411e058SKalderon, Michal 	u16 vlan_id = 0;
399e411e058SKalderon, Michal 
400e411e058SKalderon, Michal 	ndev = ip_dev_find(&init_net, htonl(addr[0]));
401e411e058SKalderon, Michal 
402e411e058SKalderon, Michal 	if (ndev) {
403e411e058SKalderon, Michal 		vlan_id = rdma_vlan_dev_vlan_id(ndev);
404e411e058SKalderon, Michal 		dev_put(ndev);
405e411e058SKalderon, Michal 	}
406e411e058SKalderon, Michal 	if (vlan_id == 0xffff)
407e411e058SKalderon, Michal 		vlan_id = 0;
408e411e058SKalderon, Michal 	return vlan_id;
409e411e058SKalderon, Michal }
410e411e058SKalderon, Michal 
qedr_iw_get_vlan_ipv6(u32 * addr)411e411e058SKalderon, Michal static u16 qedr_iw_get_vlan_ipv6(u32 *addr)
412e411e058SKalderon, Michal {
413e411e058SKalderon, Michal 	struct net_device *ndev = NULL;
414e411e058SKalderon, Michal 	struct in6_addr laddr6;
415e411e058SKalderon, Michal 	u16 vlan_id = 0;
416e411e058SKalderon, Michal 	int i;
417e411e058SKalderon, Michal 
418e411e058SKalderon, Michal 	if (!IS_ENABLED(CONFIG_IPV6))
419e411e058SKalderon, Michal 		return vlan_id;
420e411e058SKalderon, Michal 
421e411e058SKalderon, Michal 	for (i = 0; i < 4; i++)
422e411e058SKalderon, Michal 		laddr6.in6_u.u6_addr32[i] = htonl(addr[i]);
423e411e058SKalderon, Michal 
424e411e058SKalderon, Michal 	rcu_read_lock();
425e411e058SKalderon, Michal 	for_each_netdev_rcu(&init_net, ndev) {
426e411e058SKalderon, Michal 		if (ipv6_chk_addr(&init_net, &laddr6, ndev, 1)) {
427e411e058SKalderon, Michal 			vlan_id = rdma_vlan_dev_vlan_id(ndev);
428e411e058SKalderon, Michal 			break;
429e411e058SKalderon, Michal 		}
430e411e058SKalderon, Michal 	}
431e411e058SKalderon, Michal 
432e411e058SKalderon, Michal 	rcu_read_unlock();
433e411e058SKalderon, Michal 	if (vlan_id == 0xffff)
434e411e058SKalderon, Michal 		vlan_id = 0;
435e411e058SKalderon, Michal 
436e411e058SKalderon, Michal 	return vlan_id;
437e411e058SKalderon, Michal }
438e411e058SKalderon, Michal 
439e411e058SKalderon, Michal static int
qedr_addr4_resolve(struct qedr_dev * dev,struct sockaddr_in * src_in,struct sockaddr_in * dst_in,u8 * dst_mac)440e411e058SKalderon, Michal qedr_addr4_resolve(struct qedr_dev *dev,
441e411e058SKalderon, Michal 		   struct sockaddr_in *src_in,
442e411e058SKalderon, Michal 		   struct sockaddr_in *dst_in, u8 *dst_mac)
443e411e058SKalderon, Michal {
444e411e058SKalderon, Michal 	__be32 src_ip = src_in->sin_addr.s_addr;
445e411e058SKalderon, Michal 	__be32 dst_ip = dst_in->sin_addr.s_addr;
446e411e058SKalderon, Michal 	struct neighbour *neigh = NULL;
447e411e058SKalderon, Michal 	struct rtable *rt = NULL;
448e411e058SKalderon, Michal 	int rc = 0;
449e411e058SKalderon, Michal 
450e411e058SKalderon, Michal 	rt = ip_route_output(&init_net, dst_ip, src_ip, 0, 0);
451e411e058SKalderon, Michal 	if (IS_ERR(rt)) {
452e411e058SKalderon, Michal 		DP_ERR(dev, "ip_route_output returned error\n");
453e411e058SKalderon, Michal 		return -EINVAL;
454e411e058SKalderon, Michal 	}
455e411e058SKalderon, Michal 
456e411e058SKalderon, Michal 	neigh = dst_neigh_lookup(&rt->dst, &dst_ip);
457e411e058SKalderon, Michal 
458e411e058SKalderon, Michal 	if (neigh) {
459e411e058SKalderon, Michal 		rcu_read_lock();
460e411e058SKalderon, Michal 		if (neigh->nud_state & NUD_VALID) {
461e411e058SKalderon, Michal 			ether_addr_copy(dst_mac, neigh->ha);
462e411e058SKalderon, Michal 			DP_DEBUG(dev, QEDR_MSG_QP, "mac_addr=[%pM]\n", dst_mac);
463e411e058SKalderon, Michal 		} else {
464e411e058SKalderon, Michal 			neigh_event_send(neigh, NULL);
465e411e058SKalderon, Michal 		}
466e411e058SKalderon, Michal 		rcu_read_unlock();
467e411e058SKalderon, Michal 		neigh_release(neigh);
468e411e058SKalderon, Michal 	}
469e411e058SKalderon, Michal 
470e411e058SKalderon, Michal 	ip_rt_put(rt);
471e411e058SKalderon, Michal 
472e411e058SKalderon, Michal 	return rc;
473e411e058SKalderon, Michal }
474e411e058SKalderon, Michal 
475e411e058SKalderon, Michal static int
qedr_addr6_resolve(struct qedr_dev * dev,struct sockaddr_in6 * src_in,struct sockaddr_in6 * dst_in,u8 * dst_mac)476e411e058SKalderon, Michal qedr_addr6_resolve(struct qedr_dev *dev,
477e411e058SKalderon, Michal 		   struct sockaddr_in6 *src_in,
478e411e058SKalderon, Michal 		   struct sockaddr_in6 *dst_in, u8 *dst_mac)
479e411e058SKalderon, Michal {
480e411e058SKalderon, Michal 	struct neighbour *neigh = NULL;
481e411e058SKalderon, Michal 	struct dst_entry *dst;
482e411e058SKalderon, Michal 	struct flowi6 fl6;
483e411e058SKalderon, Michal 	int rc = 0;
484e411e058SKalderon, Michal 
485e411e058SKalderon, Michal 	memset(&fl6, 0, sizeof(fl6));
486e411e058SKalderon, Michal 	fl6.daddr = dst_in->sin6_addr;
487e411e058SKalderon, Michal 	fl6.saddr = src_in->sin6_addr;
488e411e058SKalderon, Michal 
489e411e058SKalderon, Michal 	dst = ip6_route_output(&init_net, NULL, &fl6);
490e411e058SKalderon, Michal 
491e411e058SKalderon, Michal 	if ((!dst) || dst->error) {
492e411e058SKalderon, Michal 		if (dst) {
493e411e058SKalderon, Michal 			DP_ERR(dev,
494e411e058SKalderon, Michal 			       "ip6_route_output returned dst->error = %d\n",
495e411e058SKalderon, Michal 			       dst->error);
496960657b7SPan Bian 			dst_release(dst);
497e411e058SKalderon, Michal 		}
498e411e058SKalderon, Michal 		return -EINVAL;
499e411e058SKalderon, Michal 	}
50011052696SKalderon, Michal 	neigh = dst_neigh_lookup(dst, &fl6.daddr);
501e411e058SKalderon, Michal 	if (neigh) {
502e411e058SKalderon, Michal 		rcu_read_lock();
503e411e058SKalderon, Michal 		if (neigh->nud_state & NUD_VALID) {
504e411e058SKalderon, Michal 			ether_addr_copy(dst_mac, neigh->ha);
505e411e058SKalderon, Michal 			DP_DEBUG(dev, QEDR_MSG_QP, "mac_addr=[%pM]\n", dst_mac);
506e411e058SKalderon, Michal 		} else {
507e411e058SKalderon, Michal 			neigh_event_send(neigh, NULL);
508e411e058SKalderon, Michal 		}
509e411e058SKalderon, Michal 		rcu_read_unlock();
510e411e058SKalderon, Michal 		neigh_release(neigh);
511e411e058SKalderon, Michal 	}
512e411e058SKalderon, Michal 
513e411e058SKalderon, Michal 	dst_release(dst);
514e411e058SKalderon, Michal 
515e411e058SKalderon, Michal 	return rc;
516e411e058SKalderon, Michal }
517e411e058SKalderon, Michal 
qedr_iw_load_qp(struct qedr_dev * dev,u32 qpn)5189a5407d7SKamal Heib static struct qedr_qp *qedr_iw_load_qp(struct qedr_dev *dev, u32 qpn)
51982af6d19SMichal Kalderon {
52082af6d19SMichal Kalderon 	struct qedr_qp *qp;
52182af6d19SMichal Kalderon 
52282af6d19SMichal Kalderon 	xa_lock(&dev->qps);
52382af6d19SMichal Kalderon 	qp = xa_load(&dev->qps, qpn);
52482af6d19SMichal Kalderon 	if (qp)
52582af6d19SMichal Kalderon 		kref_get(&qp->refcnt);
52682af6d19SMichal Kalderon 	xa_unlock(&dev->qps);
52782af6d19SMichal Kalderon 
52882af6d19SMichal Kalderon 	return qp;
52982af6d19SMichal Kalderon }
53082af6d19SMichal Kalderon 
qedr_iw_connect(struct iw_cm_id * cm_id,struct iw_cm_conn_param * conn_param)531e411e058SKalderon, Michal int qedr_iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
532e411e058SKalderon, Michal {
533e411e058SKalderon, Michal 	struct qedr_dev *dev = get_qedr_dev(cm_id->device);
534e411e058SKalderon, Michal 	struct qed_iwarp_connect_out out_params;
535e411e058SKalderon, Michal 	struct qed_iwarp_connect_in in_params;
536e411e058SKalderon, Michal 	struct qed_iwarp_cm_info *cm_info;
537e411e058SKalderon, Michal 	struct sockaddr_in6 *laddr6;
538e411e058SKalderon, Michal 	struct sockaddr_in6 *raddr6;
539e411e058SKalderon, Michal 	struct sockaddr_in *laddr;
540e411e058SKalderon, Michal 	struct sockaddr_in *raddr;
541e411e058SKalderon, Michal 	struct qedr_iw_ep *ep;
542e411e058SKalderon, Michal 	struct qedr_qp *qp;
543e411e058SKalderon, Michal 	int rc = 0;
544e411e058SKalderon, Michal 	int i;
545e411e058SKalderon, Michal 
546ea0ed478SKalderon, Michal 	laddr = (struct sockaddr_in *)&cm_id->m_local_addr;
547ea0ed478SKalderon, Michal 	raddr = (struct sockaddr_in *)&cm_id->m_remote_addr;
548ea0ed478SKalderon, Michal 	laddr6 = (struct sockaddr_in6 *)&cm_id->m_local_addr;
549ea0ed478SKalderon, Michal 	raddr6 = (struct sockaddr_in6 *)&cm_id->m_remote_addr;
550ea0ed478SKalderon, Michal 
551ea0ed478SKalderon, Michal 	DP_DEBUG(dev, QEDR_MSG_IWARP, "MAPPED %d %d\n",
552ea0ed478SKalderon, Michal 		 ntohs(((struct sockaddr_in *)&cm_id->remote_addr)->sin_port),
553ea0ed478SKalderon, Michal 		 ntohs(raddr->sin_port));
554e411e058SKalderon, Michal 
555e411e058SKalderon, Michal 	DP_DEBUG(dev, QEDR_MSG_IWARP,
556e411e058SKalderon, Michal 		 "Connect source address: %pISpc, remote address: %pISpc\n",
557e411e058SKalderon, Michal 		 &cm_id->local_addr, &cm_id->remote_addr);
558e411e058SKalderon, Michal 
559e411e058SKalderon, Michal 	if (!laddr->sin_port || !raddr->sin_port)
560e411e058SKalderon, Michal 		return -EINVAL;
561e411e058SKalderon, Michal 
562e411e058SKalderon, Michal 	ep = kzalloc(sizeof(*ep), GFP_KERNEL);
563e411e058SKalderon, Michal 	if (!ep)
564e411e058SKalderon, Michal 		return -ENOMEM;
565e411e058SKalderon, Michal 
566e411e058SKalderon, Michal 	ep->dev = dev;
56782af6d19SMichal Kalderon 	kref_init(&ep->refcnt);
56882af6d19SMichal Kalderon 
56982af6d19SMichal Kalderon 	qp = qedr_iw_load_qp(dev, conn_param->qpn);
57082af6d19SMichal Kalderon 	if (!qp) {
57182af6d19SMichal Kalderon 		rc = -EINVAL;
57282af6d19SMichal Kalderon 		goto err;
57382af6d19SMichal Kalderon 	}
57482af6d19SMichal Kalderon 
575e411e058SKalderon, Michal 	ep->qp = qp;
576e411e058SKalderon, Michal 	cm_id->add_ref(cm_id);
577e411e058SKalderon, Michal 	ep->cm_id = cm_id;
578e411e058SKalderon, Michal 
579e411e058SKalderon, Michal 	in_params.event_cb = qedr_iw_event_handler;
580e411e058SKalderon, Michal 	in_params.cb_context = ep;
581e411e058SKalderon, Michal 
582e411e058SKalderon, Michal 	cm_info = &in_params.cm_info;
583e411e058SKalderon, Michal 	memset(cm_info->local_ip, 0, sizeof(cm_info->local_ip));
584e411e058SKalderon, Michal 	memset(cm_info->remote_ip, 0, sizeof(cm_info->remote_ip));
585e411e058SKalderon, Michal 
586bd491d2aSArnd Bergmann 	if (!IS_ENABLED(CONFIG_IPV6) ||
587bd491d2aSArnd Bergmann 	    cm_id->remote_addr.ss_family == AF_INET) {
588e411e058SKalderon, Michal 		cm_info->ip_version = QED_TCP_IPV4;
589e411e058SKalderon, Michal 
590e411e058SKalderon, Michal 		cm_info->remote_ip[0] = ntohl(raddr->sin_addr.s_addr);
591e411e058SKalderon, Michal 		cm_info->local_ip[0] = ntohl(laddr->sin_addr.s_addr);
592e411e058SKalderon, Michal 		cm_info->remote_port = ntohs(raddr->sin_port);
593e411e058SKalderon, Michal 		cm_info->local_port = ntohs(laddr->sin_port);
594e411e058SKalderon, Michal 		cm_info->vlan = qedr_iw_get_vlan_ipv4(dev, cm_info->local_ip);
595e411e058SKalderon, Michal 
596e411e058SKalderon, Michal 		rc = qedr_addr4_resolve(dev, laddr, raddr,
597e411e058SKalderon, Michal 					(u8 *)in_params.remote_mac_addr);
598e411e058SKalderon, Michal 
599e411e058SKalderon, Michal 		in_params.mss = dev->iwarp_max_mtu -
600e411e058SKalderon, Michal 		    (sizeof(struct iphdr) + sizeof(struct tcphdr));
601e411e058SKalderon, Michal 
602e411e058SKalderon, Michal 	} else {
603e411e058SKalderon, Michal 		in_params.cm_info.ip_version = QED_TCP_IPV6;
604e411e058SKalderon, Michal 
605e411e058SKalderon, Michal 		for (i = 0; i < 4; i++) {
606e411e058SKalderon, Michal 			cm_info->remote_ip[i] =
607e411e058SKalderon, Michal 			    ntohl(raddr6->sin6_addr.in6_u.u6_addr32[i]);
608e411e058SKalderon, Michal 			cm_info->local_ip[i] =
609e411e058SKalderon, Michal 			    ntohl(laddr6->sin6_addr.in6_u.u6_addr32[i]);
610e411e058SKalderon, Michal 		}
611e411e058SKalderon, Michal 
612e411e058SKalderon, Michal 		cm_info->local_port = ntohs(laddr6->sin6_port);
613e411e058SKalderon, Michal 		cm_info->remote_port = ntohs(raddr6->sin6_port);
614e411e058SKalderon, Michal 
615e411e058SKalderon, Michal 		in_params.mss = dev->iwarp_max_mtu -
616e411e058SKalderon, Michal 		    (sizeof(struct ipv6hdr) + sizeof(struct tcphdr));
617e411e058SKalderon, Michal 
618e411e058SKalderon, Michal 		cm_info->vlan = qedr_iw_get_vlan_ipv6(cm_info->local_ip);
619e411e058SKalderon, Michal 
620e411e058SKalderon, Michal 		rc = qedr_addr6_resolve(dev, laddr6, raddr6,
621e411e058SKalderon, Michal 					(u8 *)in_params.remote_mac_addr);
622e411e058SKalderon, Michal 	}
623e411e058SKalderon, Michal 	if (rc)
624e411e058SKalderon, Michal 		goto err;
625e411e058SKalderon, Michal 
626e411e058SKalderon, Michal 	DP_DEBUG(dev, QEDR_MSG_IWARP,
627e411e058SKalderon, Michal 		 "ord = %d ird=%d private_data=%p private_data_len=%d rq_psn=%d\n",
628e411e058SKalderon, Michal 		 conn_param->ord, conn_param->ird, conn_param->private_data,
629e411e058SKalderon, Michal 		 conn_param->private_data_len, qp->rq_psn);
630e411e058SKalderon, Michal 
631e411e058SKalderon, Michal 	cm_info->ord = conn_param->ord;
632e411e058SKalderon, Michal 	cm_info->ird = conn_param->ird;
633e411e058SKalderon, Michal 	cm_info->private_data = conn_param->private_data;
634e411e058SKalderon, Michal 	cm_info->private_data_len = conn_param->private_data_len;
635e411e058SKalderon, Michal 	in_params.qp = qp->qed_qp;
636e411e058SKalderon, Michal 	memcpy(in_params.local_mac_addr, dev->ndev->dev_addr, ETH_ALEN);
637e411e058SKalderon, Michal 
63882af6d19SMichal Kalderon 	if (test_and_set_bit(QEDR_IWARP_CM_WAIT_FOR_CONNECT,
63910dd83dbSWang Wensheng 			     &qp->iwarp_cm_flags)) {
64010dd83dbSWang Wensheng 		rc = -ENODEV;
64182af6d19SMichal Kalderon 		goto err; /* QP already being destroyed */
64210dd83dbSWang Wensheng 	}
64382af6d19SMichal Kalderon 
644e411e058SKalderon, Michal 	rc = dev->ops->iwarp_connect(dev->rdma_ctx, &in_params, &out_params);
64582af6d19SMichal Kalderon 	if (rc) {
64682af6d19SMichal Kalderon 		complete(&qp->iwarp_cm_comp);
647e411e058SKalderon, Michal 		goto err;
64882af6d19SMichal Kalderon 	}
649e411e058SKalderon, Michal 
650e411e058SKalderon, Michal 	return rc;
651e411e058SKalderon, Michal 
652e411e058SKalderon, Michal err:
65382af6d19SMichal Kalderon 	kref_put(&ep->refcnt, qedr_iw_free_ep);
654e411e058SKalderon, Michal 	return rc;
655e411e058SKalderon, Michal }
656e411e058SKalderon, Michal 
qedr_iw_create_listen(struct iw_cm_id * cm_id,int backlog)657e411e058SKalderon, Michal int qedr_iw_create_listen(struct iw_cm_id *cm_id, int backlog)
658e411e058SKalderon, Michal {
659e411e058SKalderon, Michal 	struct qedr_dev *dev = get_qedr_dev(cm_id->device);
660e411e058SKalderon, Michal 	struct qedr_iw_listener *listener;
661e411e058SKalderon, Michal 	struct qed_iwarp_listen_in iparams;
662e411e058SKalderon, Michal 	struct qed_iwarp_listen_out oparams;
663e411e058SKalderon, Michal 	struct sockaddr_in *laddr;
664e411e058SKalderon, Michal 	struct sockaddr_in6 *laddr6;
665e411e058SKalderon, Michal 	int rc;
666e411e058SKalderon, Michal 	int i;
667e411e058SKalderon, Michal 
668ea0ed478SKalderon, Michal 	laddr = (struct sockaddr_in *)&cm_id->m_local_addr;
669ea0ed478SKalderon, Michal 	laddr6 = (struct sockaddr_in6 *)&cm_id->m_local_addr;
670e411e058SKalderon, Michal 
671e411e058SKalderon, Michal 	DP_DEBUG(dev, QEDR_MSG_IWARP,
672e411e058SKalderon, Michal 		 "Create Listener address: %pISpc\n", &cm_id->local_addr);
673e411e058SKalderon, Michal 
674e411e058SKalderon, Michal 	listener = kzalloc(sizeof(*listener), GFP_KERNEL);
675e411e058SKalderon, Michal 	if (!listener)
676e411e058SKalderon, Michal 		return -ENOMEM;
677e411e058SKalderon, Michal 
678e411e058SKalderon, Michal 	listener->dev = dev;
679e411e058SKalderon, Michal 	cm_id->add_ref(cm_id);
680e411e058SKalderon, Michal 	listener->cm_id = cm_id;
681e411e058SKalderon, Michal 	listener->backlog = backlog;
682e411e058SKalderon, Michal 
683e411e058SKalderon, Michal 	iparams.cb_context = listener;
684e411e058SKalderon, Michal 	iparams.event_cb = qedr_iw_event_handler;
685e411e058SKalderon, Michal 	iparams.max_backlog = backlog;
686e411e058SKalderon, Michal 
687bd491d2aSArnd Bergmann 	if (!IS_ENABLED(CONFIG_IPV6) ||
688bd491d2aSArnd Bergmann 	    cm_id->local_addr.ss_family == AF_INET) {
689e411e058SKalderon, Michal 		iparams.ip_version = QED_TCP_IPV4;
690e411e058SKalderon, Michal 		memset(iparams.ip_addr, 0, sizeof(iparams.ip_addr));
691e411e058SKalderon, Michal 
692e411e058SKalderon, Michal 		iparams.ip_addr[0] = ntohl(laddr->sin_addr.s_addr);
693e411e058SKalderon, Michal 		iparams.port = ntohs(laddr->sin_port);
694e411e058SKalderon, Michal 		iparams.vlan = qedr_iw_get_vlan_ipv4(dev, iparams.ip_addr);
695e411e058SKalderon, Michal 	} else {
696e411e058SKalderon, Michal 		iparams.ip_version = QED_TCP_IPV6;
697e411e058SKalderon, Michal 
698e411e058SKalderon, Michal 		for (i = 0; i < 4; i++) {
699e411e058SKalderon, Michal 			iparams.ip_addr[i] =
700e411e058SKalderon, Michal 			    ntohl(laddr6->sin6_addr.in6_u.u6_addr32[i]);
701e411e058SKalderon, Michal 		}
702e411e058SKalderon, Michal 
703e411e058SKalderon, Michal 		iparams.port = ntohs(laddr6->sin6_port);
704e411e058SKalderon, Michal 
705e411e058SKalderon, Michal 		iparams.vlan = qedr_iw_get_vlan_ipv6(iparams.ip_addr);
706e411e058SKalderon, Michal 	}
707e411e058SKalderon, Michal 	rc = dev->ops->iwarp_create_listen(dev->rdma_ctx, &iparams, &oparams);
708e411e058SKalderon, Michal 	if (rc)
709e411e058SKalderon, Michal 		goto err;
710e411e058SKalderon, Michal 
711e411e058SKalderon, Michal 	listener->qed_handle = oparams.handle;
712e411e058SKalderon, Michal 	cm_id->provider_data = listener;
713e411e058SKalderon, Michal 	return rc;
714e411e058SKalderon, Michal 
715e411e058SKalderon, Michal err:
716e411e058SKalderon, Michal 	cm_id->rem_ref(cm_id);
717e411e058SKalderon, Michal 	kfree(listener);
718e411e058SKalderon, Michal 	return rc;
719e411e058SKalderon, Michal }
720e411e058SKalderon, Michal 
qedr_iw_destroy_listen(struct iw_cm_id * cm_id)721e411e058SKalderon, Michal int qedr_iw_destroy_listen(struct iw_cm_id *cm_id)
722e411e058SKalderon, Michal {
723e411e058SKalderon, Michal 	struct qedr_iw_listener *listener = cm_id->provider_data;
724e411e058SKalderon, Michal 	struct qedr_dev *dev = get_qedr_dev(cm_id->device);
725e411e058SKalderon, Michal 	int rc = 0;
726e411e058SKalderon, Michal 
727e411e058SKalderon, Michal 	if (listener->qed_handle)
728e411e058SKalderon, Michal 		rc = dev->ops->iwarp_destroy_listen(dev->rdma_ctx,
729e411e058SKalderon, Michal 						    listener->qed_handle);
730e411e058SKalderon, Michal 
731e411e058SKalderon, Michal 	cm_id->rem_ref(cm_id);
732a2267f8aSAlok Prasad 	kfree(listener);
733e411e058SKalderon, Michal 	return rc;
734e411e058SKalderon, Michal }
735e411e058SKalderon, Michal 
qedr_iw_accept(struct iw_cm_id * cm_id,struct iw_cm_conn_param * conn_param)736e411e058SKalderon, Michal int qedr_iw_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
737e411e058SKalderon, Michal {
738e411e058SKalderon, Michal 	struct qedr_iw_ep *ep = (struct qedr_iw_ep *)cm_id->provider_data;
739e411e058SKalderon, Michal 	struct qedr_dev *dev = ep->dev;
740e411e058SKalderon, Michal 	struct qedr_qp *qp;
741e411e058SKalderon, Michal 	struct qed_iwarp_accept_in params;
7428a5a10a1SMichal Kalderon 	int rc;
743e411e058SKalderon, Michal 
744e411e058SKalderon, Michal 	DP_DEBUG(dev, QEDR_MSG_IWARP, "Accept on qpid=%d\n", conn_param->qpn);
745e411e058SKalderon, Michal 
74682af6d19SMichal Kalderon 	qp = qedr_iw_load_qp(dev, conn_param->qpn);
747e411e058SKalderon, Michal 	if (!qp) {
748e411e058SKalderon, Michal 		DP_ERR(dev, "Invalid QP number %d\n", conn_param->qpn);
749e411e058SKalderon, Michal 		return -EINVAL;
750e411e058SKalderon, Michal 	}
751e411e058SKalderon, Michal 
752e411e058SKalderon, Michal 	ep->qp = qp;
753e411e058SKalderon, Michal 	cm_id->add_ref(cm_id);
754e411e058SKalderon, Michal 	ep->cm_id = cm_id;
755e411e058SKalderon, Michal 
756e411e058SKalderon, Michal 	params.ep_context = ep->qed_context;
757e411e058SKalderon, Michal 	params.cb_context = ep;
758e411e058SKalderon, Michal 	params.qp = ep->qp->qed_qp;
759e411e058SKalderon, Michal 	params.private_data = conn_param->private_data;
760e411e058SKalderon, Michal 	params.private_data_len = conn_param->private_data_len;
761e411e058SKalderon, Michal 	params.ird = conn_param->ird;
762e411e058SKalderon, Michal 	params.ord = conn_param->ord;
763e411e058SKalderon, Michal 
76482af6d19SMichal Kalderon 	if (test_and_set_bit(QEDR_IWARP_CM_WAIT_FOR_CONNECT,
7658a5a10a1SMichal Kalderon 			     &qp->iwarp_cm_flags)) {
7668a5a10a1SMichal Kalderon 		rc = -EINVAL;
76782af6d19SMichal Kalderon 		goto err; /* QP already destroyed */
7688a5a10a1SMichal Kalderon 	}
76982af6d19SMichal Kalderon 
770e411e058SKalderon, Michal 	rc = dev->ops->iwarp_accept(dev->rdma_ctx, &params);
77182af6d19SMichal Kalderon 	if (rc) {
77282af6d19SMichal Kalderon 		complete(&qp->iwarp_cm_comp);
773e411e058SKalderon, Michal 		goto err;
77482af6d19SMichal Kalderon 	}
775e411e058SKalderon, Michal 
776e411e058SKalderon, Michal 	return rc;
77782af6d19SMichal Kalderon 
778e411e058SKalderon, Michal err:
77982af6d19SMichal Kalderon 	kref_put(&ep->refcnt, qedr_iw_free_ep);
78082af6d19SMichal Kalderon 
781e411e058SKalderon, Michal 	return rc;
782e411e058SKalderon, Michal }
783e411e058SKalderon, Michal 
qedr_iw_reject(struct iw_cm_id * cm_id,const void * pdata,u8 pdata_len)784e411e058SKalderon, Michal int qedr_iw_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
785e411e058SKalderon, Michal {
786e411e058SKalderon, Michal 	struct qedr_iw_ep *ep = (struct qedr_iw_ep *)cm_id->provider_data;
787e411e058SKalderon, Michal 	struct qedr_dev *dev = ep->dev;
788e411e058SKalderon, Michal 	struct qed_iwarp_reject_in params;
789e411e058SKalderon, Michal 
790e411e058SKalderon, Michal 	params.ep_context = ep->qed_context;
791e411e058SKalderon, Michal 	params.cb_context = ep;
792e411e058SKalderon, Michal 	params.private_data = pdata;
793e411e058SKalderon, Michal 	params.private_data_len = pdata_len;
794e411e058SKalderon, Michal 	ep->qp = NULL;
795e411e058SKalderon, Michal 
796e411e058SKalderon, Michal 	return dev->ops->iwarp_reject(dev->rdma_ctx, &params);
797e411e058SKalderon, Michal }
798e411e058SKalderon, Michal 
qedr_iw_qp_add_ref(struct ib_qp * ibqp)799de0089e6SKalderon, Michal void qedr_iw_qp_add_ref(struct ib_qp *ibqp)
800de0089e6SKalderon, Michal {
801de0089e6SKalderon, Michal 	struct qedr_qp *qp = get_qedr_qp(ibqp);
802de0089e6SKalderon, Michal 
80382af6d19SMichal Kalderon 	kref_get(&qp->refcnt);
804de0089e6SKalderon, Michal }
805de0089e6SKalderon, Michal 
qedr_iw_qp_rem_ref(struct ib_qp * ibqp)806de0089e6SKalderon, Michal void qedr_iw_qp_rem_ref(struct ib_qp *ibqp)
807de0089e6SKalderon, Michal {
808de0089e6SKalderon, Michal 	struct qedr_qp *qp = get_qedr_qp(ibqp);
809de0089e6SKalderon, Michal 
81082af6d19SMichal Kalderon 	kref_put(&qp->refcnt, qedr_iw_free_qp);
811de0089e6SKalderon, Michal }
812de0089e6SKalderon, Michal 
qedr_iw_get_qp(struct ib_device * ibdev,int qpn)813de0089e6SKalderon, Michal struct ib_qp *qedr_iw_get_qp(struct ib_device *ibdev, int qpn)
814de0089e6SKalderon, Michal {
815de0089e6SKalderon, Michal 	struct qedr_dev *dev = get_qedr_dev(ibdev);
816de0089e6SKalderon, Michal 
817b6014f9eSMatthew Wilcox 	return xa_load(&dev->qps, qpn);
818de0089e6SKalderon, Michal }
819