brintos

brintos / linux-shallow public Read only

0
0
Text · 21.0 KiB · 259303b Raw
820 lines · c
1/* QLogic qedr NIC Driver2 * Copyright (c) 2015-2017  QLogic Corporation3 *4 * This software is available to you under a choice of one of two5 * licenses.  You may choose to be licensed under the terms of the GNU6 * General Public License (GPL) Version 2, available from the file7 * COPYING in the main directory of this source tree, or the8 * OpenIB.org BSD license below:9 *10 *     Redistribution and use in source and binary forms, with or11 *     without modification, are permitted provided that the following12 *     conditions are met:13 *14 *      - Redistributions of source code must retain the above15 *        copyright notice, this list of conditions and the following16 *        disclaimer.17 *18 *      - Redistributions in binary form must reproduce the above19 *        copyright notice, this list of conditions and the following20 *        disclaimer in the documentation and /or other materials21 *        provided with the distribution.22 *23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE30 * SOFTWARE.31 */32#include <net/ip.h>33#include <net/ipv6.h>34#include <net/udp.h>35#include <net/addrconf.h>36#include <net/route.h>37#include <net/ip6_route.h>38#include <net/flow.h>39#include "qedr.h"40#include "qedr_iw_cm.h"41 42static inline void43qedr_fill_sockaddr4(const struct qed_iwarp_cm_info *cm_info,44		    struct iw_cm_event *event)45{46	struct sockaddr_in *laddr = (struct sockaddr_in *)&event->local_addr;47	struct sockaddr_in *raddr = (struct sockaddr_in *)&event->remote_addr;48 49	laddr->sin_family = AF_INET;50	raddr->sin_family = AF_INET;51 52	laddr->sin_port = htons(cm_info->local_port);53	raddr->sin_port = htons(cm_info->remote_port);54 55	laddr->sin_addr.s_addr = htonl(cm_info->local_ip[0]);56	raddr->sin_addr.s_addr = htonl(cm_info->remote_ip[0]);57}58 59static inline void60qedr_fill_sockaddr6(const struct qed_iwarp_cm_info *cm_info,61		    struct iw_cm_event *event)62{63	struct sockaddr_in6 *laddr6 = (struct sockaddr_in6 *)&event->local_addr;64	struct sockaddr_in6 *raddr6 =65	    (struct sockaddr_in6 *)&event->remote_addr;66	int i;67 68	laddr6->sin6_family = AF_INET6;69	raddr6->sin6_family = AF_INET6;70 71	laddr6->sin6_port = htons(cm_info->local_port);72	raddr6->sin6_port = htons(cm_info->remote_port);73 74	for (i = 0; i < 4; i++) {75		laddr6->sin6_addr.in6_u.u6_addr32[i] =76		    htonl(cm_info->local_ip[i]);77		raddr6->sin6_addr.in6_u.u6_addr32[i] =78		    htonl(cm_info->remote_ip[i]);79	}80}81 82static void qedr_iw_free_qp(struct kref *ref)83{84	struct qedr_qp *qp = container_of(ref, struct qedr_qp, refcnt);85 86	complete(&qp->qp_rel_comp);87}88 89static void90qedr_iw_free_ep(struct kref *ref)91{92	struct qedr_iw_ep *ep = container_of(ref, struct qedr_iw_ep, refcnt);93 94	if (ep->qp)95		kref_put(&ep->qp->refcnt, qedr_iw_free_qp);96 97	if (ep->cm_id)98		ep->cm_id->rem_ref(ep->cm_id);99 100	kfree(ep);101}102 103static void104qedr_iw_mpa_request(void *context, struct qed_iwarp_cm_event_params *params)105{106	struct qedr_iw_listener *listener = (struct qedr_iw_listener *)context;107	struct qedr_dev *dev = listener->dev;108	struct iw_cm_event event;109	struct qedr_iw_ep *ep;110 111	ep = kzalloc(sizeof(*ep), GFP_ATOMIC);112	if (!ep)113		return;114 115	ep->dev = dev;116	ep->qed_context = params->ep_context;117	kref_init(&ep->refcnt);118 119	memset(&event, 0, sizeof(event));120	event.event = IW_CM_EVENT_CONNECT_REQUEST;121	event.status = params->status;122 123	if (!IS_ENABLED(CONFIG_IPV6) ||124	    params->cm_info->ip_version == QED_TCP_IPV4)125		qedr_fill_sockaddr4(params->cm_info, &event);126	else127		qedr_fill_sockaddr6(params->cm_info, &event);128 129	event.provider_data = (void *)ep;130	event.private_data = (void *)params->cm_info->private_data;131	event.private_data_len = (u8)params->cm_info->private_data_len;132	event.ord = params->cm_info->ord;133	event.ird = params->cm_info->ird;134 135	listener->cm_id->event_handler(listener->cm_id, &event);136}137 138static void139qedr_iw_issue_event(void *context,140		    struct qed_iwarp_cm_event_params *params,141		    enum iw_cm_event_type event_type)142{143	struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;144	struct iw_cm_event event;145 146	memset(&event, 0, sizeof(event));147	event.status = params->status;148	event.event = event_type;149 150	if (params->cm_info) {151		event.ird = params->cm_info->ird;152		event.ord = params->cm_info->ord;153		/* Only connect_request and reply have valid private data154		 * the rest of the events this may be left overs from155		 * connection establishment. CONNECT_REQUEST is issued via156		 * qedr_iw_mpa_request157		 */158		if (event_type == IW_CM_EVENT_CONNECT_REPLY) {159			event.private_data_len =160				params->cm_info->private_data_len;161			event.private_data =162				(void *)params->cm_info->private_data;163		}164	}165 166	if (ep->cm_id)167		ep->cm_id->event_handler(ep->cm_id, &event);168}169 170static void171qedr_iw_close_event(void *context, struct qed_iwarp_cm_event_params *params)172{173	struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;174 175	if (ep->cm_id)176		qedr_iw_issue_event(context, params, IW_CM_EVENT_CLOSE);177 178	kref_put(&ep->refcnt, qedr_iw_free_ep);179}180 181static void182qedr_iw_qp_event(void *context,183		 struct qed_iwarp_cm_event_params *params,184		 enum ib_event_type ib_event, char *str)185{186	struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;187	struct qedr_dev *dev = ep->dev;188	struct ib_qp *ibqp = &ep->qp->ibqp;189	struct ib_event event;190 191	DP_NOTICE(dev, "QP error received: %s\n", str);192 193	if (ibqp->event_handler) {194		event.event = ib_event;195		event.device = ibqp->device;196		event.element.qp = ibqp;197		ibqp->event_handler(&event, ibqp->qp_context);198	}199}200 201struct qedr_discon_work {202	struct work_struct		work;203	struct qedr_iw_ep		*ep;204	enum qed_iwarp_event_type	event;205	int				status;206};207 208static void qedr_iw_disconnect_worker(struct work_struct *work)209{210	struct qedr_discon_work *dwork =211	    container_of(work, struct qedr_discon_work, work);212	struct qed_rdma_modify_qp_in_params qp_params = { 0 };213	struct qedr_iw_ep *ep = dwork->ep;214	struct qedr_dev *dev = ep->dev;215	struct qedr_qp *qp = ep->qp;216	struct iw_cm_event event;217 218	/* The qp won't be released until we release the ep.219	 * the ep's refcnt was increased before calling this220	 * function, therefore it is safe to access qp221	 */222	if (test_and_set_bit(QEDR_IWARP_CM_WAIT_FOR_DISCONNECT,223			     &qp->iwarp_cm_flags))224		goto out;225 226	memset(&event, 0, sizeof(event));227	event.status = dwork->status;228	event.event = IW_CM_EVENT_DISCONNECT;229 230	/* Success means graceful disconnect was requested. modifying231	 * to SQD is translated to graceful disconnect. O/w reset is sent232	 */233	if (dwork->status)234		qp_params.new_state = QED_ROCE_QP_STATE_ERR;235	else236		qp_params.new_state = QED_ROCE_QP_STATE_SQD;237 238 239	if (ep->cm_id)240		ep->cm_id->event_handler(ep->cm_id, &event);241 242	SET_FIELD(qp_params.modify_flags,243		  QED_RDMA_MODIFY_QP_VALID_NEW_STATE, 1);244 245	dev->ops->rdma_modify_qp(dev->rdma_ctx, qp->qed_qp, &qp_params);246 247	complete(&ep->qp->iwarp_cm_comp);248out:249	kfree(dwork);250	kref_put(&ep->refcnt, qedr_iw_free_ep);251}252 253static void254qedr_iw_disconnect_event(void *context,255			 struct qed_iwarp_cm_event_params *params)256{257	struct qedr_discon_work *work;258	struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;259	struct qedr_dev *dev = ep->dev;260 261	work = kzalloc(sizeof(*work), GFP_ATOMIC);262	if (!work)263		return;264 265	/* We can't get a close event before disconnect, but since266	 * we're scheduling a work queue we need to make sure close267	 * won't delete the ep, so we increase the refcnt268	 */269	kref_get(&ep->refcnt);270 271	work->ep = ep;272	work->event = params->event;273	work->status = params->status;274 275	INIT_WORK(&work->work, qedr_iw_disconnect_worker);276	queue_work(dev->iwarp_wq, &work->work);277}278 279static void280qedr_iw_passive_complete(void *context,281			 struct qed_iwarp_cm_event_params *params)282{283	struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;284	struct qedr_dev *dev = ep->dev;285 286	/* We will only reach the following state if MPA_REJECT was called on287	 * passive. In this case there will be no associated QP.288	 */289	if ((params->status == -ECONNREFUSED) && (!ep->qp)) {290		DP_DEBUG(dev, QEDR_MSG_IWARP,291			 "PASSIVE connection refused releasing ep...\n");292		kref_put(&ep->refcnt, qedr_iw_free_ep);293		return;294	}295 296	complete(&ep->qp->iwarp_cm_comp);297	qedr_iw_issue_event(context, params, IW_CM_EVENT_ESTABLISHED);298 299	if (params->status < 0)300		qedr_iw_close_event(context, params);301}302 303static void304qedr_iw_active_complete(void *context,305			struct qed_iwarp_cm_event_params *params)306{307	struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;308 309	complete(&ep->qp->iwarp_cm_comp);310	qedr_iw_issue_event(context, params, IW_CM_EVENT_CONNECT_REPLY);311 312	if (params->status < 0)313		kref_put(&ep->refcnt, qedr_iw_free_ep);314}315 316static int317qedr_iw_mpa_reply(void *context, struct qed_iwarp_cm_event_params *params)318{319	struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;320	struct qedr_dev *dev = ep->dev;321	struct qed_iwarp_send_rtr_in rtr_in;322 323	rtr_in.ep_context = params->ep_context;324 325	return dev->ops->iwarp_send_rtr(dev->rdma_ctx, &rtr_in);326}327 328static int329qedr_iw_event_handler(void *context, struct qed_iwarp_cm_event_params *params)330{331	struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;332	struct qedr_dev *dev = ep->dev;333 334	switch (params->event) {335	case QED_IWARP_EVENT_MPA_REQUEST:336		qedr_iw_mpa_request(context, params);337		break;338	case QED_IWARP_EVENT_ACTIVE_MPA_REPLY:339		qedr_iw_mpa_reply(context, params);340		break;341	case QED_IWARP_EVENT_PASSIVE_COMPLETE:342		qedr_iw_passive_complete(context, params);343		break;344	case QED_IWARP_EVENT_ACTIVE_COMPLETE:345		qedr_iw_active_complete(context, params);346		break;347	case QED_IWARP_EVENT_DISCONNECT:348		qedr_iw_disconnect_event(context, params);349		break;350	case QED_IWARP_EVENT_CLOSE:351		qedr_iw_close_event(context, params);352		break;353	case QED_IWARP_EVENT_RQ_EMPTY:354		qedr_iw_qp_event(context, params, IB_EVENT_QP_FATAL,355				 "QED_IWARP_EVENT_RQ_EMPTY");356		break;357	case QED_IWARP_EVENT_IRQ_FULL:358		qedr_iw_qp_event(context, params, IB_EVENT_QP_FATAL,359				 "QED_IWARP_EVENT_IRQ_FULL");360		break;361	case QED_IWARP_EVENT_LLP_TIMEOUT:362		qedr_iw_qp_event(context, params, IB_EVENT_QP_FATAL,363				 "QED_IWARP_EVENT_LLP_TIMEOUT");364		break;365	case QED_IWARP_EVENT_REMOTE_PROTECTION_ERROR:366		qedr_iw_qp_event(context, params, IB_EVENT_QP_ACCESS_ERR,367				 "QED_IWARP_EVENT_REMOTE_PROTECTION_ERROR");368		break;369	case QED_IWARP_EVENT_CQ_OVERFLOW:370		qedr_iw_qp_event(context, params, IB_EVENT_QP_FATAL,371				 "QED_IWARP_EVENT_CQ_OVERFLOW");372		break;373	case QED_IWARP_EVENT_QP_CATASTROPHIC:374		qedr_iw_qp_event(context, params, IB_EVENT_QP_FATAL,375				 "QED_IWARP_EVENT_QP_CATASTROPHIC");376		break;377	case QED_IWARP_EVENT_LOCAL_ACCESS_ERROR:378		qedr_iw_qp_event(context, params, IB_EVENT_QP_ACCESS_ERR,379				 "QED_IWARP_EVENT_LOCAL_ACCESS_ERROR");380		break;381	case QED_IWARP_EVENT_REMOTE_OPERATION_ERROR:382		qedr_iw_qp_event(context, params, IB_EVENT_QP_FATAL,383				 "QED_IWARP_EVENT_REMOTE_OPERATION_ERROR");384		break;385	case QED_IWARP_EVENT_TERMINATE_RECEIVED:386		DP_NOTICE(dev, "Got terminate message\n");387		break;388	default:389		DP_NOTICE(dev, "Unknown event received %d\n", params->event);390		break;391	}392	return 0;393}394 395static u16 qedr_iw_get_vlan_ipv4(struct qedr_dev *dev, u32 *addr)396{397	struct net_device *ndev;398	u16 vlan_id = 0;399 400	ndev = ip_dev_find(&init_net, htonl(addr[0]));401 402	if (ndev) {403		vlan_id = rdma_vlan_dev_vlan_id(ndev);404		dev_put(ndev);405	}406	if (vlan_id == 0xffff)407		vlan_id = 0;408	return vlan_id;409}410 411static u16 qedr_iw_get_vlan_ipv6(u32 *addr)412{413	struct net_device *ndev = NULL;414	struct in6_addr laddr6;415	u16 vlan_id = 0;416	int i;417 418	if (!IS_ENABLED(CONFIG_IPV6))419		return vlan_id;420 421	for (i = 0; i < 4; i++)422		laddr6.in6_u.u6_addr32[i] = htonl(addr[i]);423 424	rcu_read_lock();425	for_each_netdev_rcu(&init_net, ndev) {426		if (ipv6_chk_addr(&init_net, &laddr6, ndev, 1)) {427			vlan_id = rdma_vlan_dev_vlan_id(ndev);428			break;429		}430	}431 432	rcu_read_unlock();433	if (vlan_id == 0xffff)434		vlan_id = 0;435 436	return vlan_id;437}438 439static int440qedr_addr4_resolve(struct qedr_dev *dev,441		   struct sockaddr_in *src_in,442		   struct sockaddr_in *dst_in, u8 *dst_mac)443{444	__be32 src_ip = src_in->sin_addr.s_addr;445	__be32 dst_ip = dst_in->sin_addr.s_addr;446	struct neighbour *neigh = NULL;447	struct rtable *rt = NULL;448	int rc = 0;449 450	rt = ip_route_output(&init_net, dst_ip, src_ip, 0, 0,451			     RT_SCOPE_UNIVERSE);452	if (IS_ERR(rt)) {453		DP_ERR(dev, "ip_route_output returned error\n");454		return -EINVAL;455	}456 457	neigh = dst_neigh_lookup(&rt->dst, &dst_ip);458 459	if (neigh) {460		rcu_read_lock();461		if (neigh->nud_state & NUD_VALID) {462			ether_addr_copy(dst_mac, neigh->ha);463			DP_DEBUG(dev, QEDR_MSG_QP, "mac_addr=[%pM]\n", dst_mac);464		} else {465			neigh_event_send(neigh, NULL);466		}467		rcu_read_unlock();468		neigh_release(neigh);469	}470 471	ip_rt_put(rt);472 473	return rc;474}475 476static int477qedr_addr6_resolve(struct qedr_dev *dev,478		   struct sockaddr_in6 *src_in,479		   struct sockaddr_in6 *dst_in, u8 *dst_mac)480{481	struct neighbour *neigh = NULL;482	struct dst_entry *dst;483	struct flowi6 fl6;484	int rc = 0;485 486	memset(&fl6, 0, sizeof(fl6));487	fl6.daddr = dst_in->sin6_addr;488	fl6.saddr = src_in->sin6_addr;489 490	dst = ip6_route_output(&init_net, NULL, &fl6);491 492	if ((!dst) || dst->error) {493		if (dst) {494			DP_ERR(dev,495			       "ip6_route_output returned dst->error = %d\n",496			       dst->error);497			dst_release(dst);498		}499		return -EINVAL;500	}501	neigh = dst_neigh_lookup(dst, &fl6.daddr);502	if (neigh) {503		rcu_read_lock();504		if (neigh->nud_state & NUD_VALID) {505			ether_addr_copy(dst_mac, neigh->ha);506			DP_DEBUG(dev, QEDR_MSG_QP, "mac_addr=[%pM]\n", dst_mac);507		} else {508			neigh_event_send(neigh, NULL);509		}510		rcu_read_unlock();511		neigh_release(neigh);512	}513 514	dst_release(dst);515 516	return rc;517}518 519static struct qedr_qp *qedr_iw_load_qp(struct qedr_dev *dev, u32 qpn)520{521	struct qedr_qp *qp;522 523	xa_lock(&dev->qps);524	qp = xa_load(&dev->qps, qpn);525	if (qp)526		kref_get(&qp->refcnt);527	xa_unlock(&dev->qps);528 529	return qp;530}531 532int qedr_iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)533{534	struct qedr_dev *dev = get_qedr_dev(cm_id->device);535	struct qed_iwarp_connect_out out_params;536	struct qed_iwarp_connect_in in_params;537	struct qed_iwarp_cm_info *cm_info;538	struct sockaddr_in6 *laddr6;539	struct sockaddr_in6 *raddr6;540	struct sockaddr_in *laddr;541	struct sockaddr_in *raddr;542	struct qedr_iw_ep *ep;543	struct qedr_qp *qp;544	int rc = 0;545	int i;546 547	laddr = (struct sockaddr_in *)&cm_id->m_local_addr;548	raddr = (struct sockaddr_in *)&cm_id->m_remote_addr;549	laddr6 = (struct sockaddr_in6 *)&cm_id->m_local_addr;550	raddr6 = (struct sockaddr_in6 *)&cm_id->m_remote_addr;551 552	DP_DEBUG(dev, QEDR_MSG_IWARP, "MAPPED %d %d\n",553		 ntohs(((struct sockaddr_in *)&cm_id->remote_addr)->sin_port),554		 ntohs(raddr->sin_port));555 556	DP_DEBUG(dev, QEDR_MSG_IWARP,557		 "Connect source address: %pISpc, remote address: %pISpc\n",558		 &cm_id->local_addr, &cm_id->remote_addr);559 560	if (!laddr->sin_port || !raddr->sin_port)561		return -EINVAL;562 563	ep = kzalloc(sizeof(*ep), GFP_KERNEL);564	if (!ep)565		return -ENOMEM;566 567	ep->dev = dev;568	kref_init(&ep->refcnt);569 570	qp = qedr_iw_load_qp(dev, conn_param->qpn);571	if (!qp) {572		rc = -EINVAL;573		goto err;574	}575 576	ep->qp = qp;577	cm_id->add_ref(cm_id);578	ep->cm_id = cm_id;579 580	in_params.event_cb = qedr_iw_event_handler;581	in_params.cb_context = ep;582 583	cm_info = &in_params.cm_info;584	memset(cm_info->local_ip, 0, sizeof(cm_info->local_ip));585	memset(cm_info->remote_ip, 0, sizeof(cm_info->remote_ip));586 587	if (!IS_ENABLED(CONFIG_IPV6) ||588	    cm_id->remote_addr.ss_family == AF_INET) {589		cm_info->ip_version = QED_TCP_IPV4;590 591		cm_info->remote_ip[0] = ntohl(raddr->sin_addr.s_addr);592		cm_info->local_ip[0] = ntohl(laddr->sin_addr.s_addr);593		cm_info->remote_port = ntohs(raddr->sin_port);594		cm_info->local_port = ntohs(laddr->sin_port);595		cm_info->vlan = qedr_iw_get_vlan_ipv4(dev, cm_info->local_ip);596 597		rc = qedr_addr4_resolve(dev, laddr, raddr,598					(u8 *)in_params.remote_mac_addr);599 600		in_params.mss = dev->iwarp_max_mtu -601		    (sizeof(struct iphdr) + sizeof(struct tcphdr));602 603	} else {604		in_params.cm_info.ip_version = QED_TCP_IPV6;605 606		for (i = 0; i < 4; i++) {607			cm_info->remote_ip[i] =608			    ntohl(raddr6->sin6_addr.in6_u.u6_addr32[i]);609			cm_info->local_ip[i] =610			    ntohl(laddr6->sin6_addr.in6_u.u6_addr32[i]);611		}612 613		cm_info->local_port = ntohs(laddr6->sin6_port);614		cm_info->remote_port = ntohs(raddr6->sin6_port);615 616		in_params.mss = dev->iwarp_max_mtu -617		    (sizeof(struct ipv6hdr) + sizeof(struct tcphdr));618 619		cm_info->vlan = qedr_iw_get_vlan_ipv6(cm_info->local_ip);620 621		rc = qedr_addr6_resolve(dev, laddr6, raddr6,622					(u8 *)in_params.remote_mac_addr);623	}624	if (rc)625		goto err;626 627	DP_DEBUG(dev, QEDR_MSG_IWARP,628		 "ord = %d ird=%d private_data=%p private_data_len=%d rq_psn=%d\n",629		 conn_param->ord, conn_param->ird, conn_param->private_data,630		 conn_param->private_data_len, qp->rq_psn);631 632	cm_info->ord = conn_param->ord;633	cm_info->ird = conn_param->ird;634	cm_info->private_data = conn_param->private_data;635	cm_info->private_data_len = conn_param->private_data_len;636	in_params.qp = qp->qed_qp;637	memcpy(in_params.local_mac_addr, dev->ndev->dev_addr, ETH_ALEN);638 639	if (test_and_set_bit(QEDR_IWARP_CM_WAIT_FOR_CONNECT,640			     &qp->iwarp_cm_flags)) {641		rc = -ENODEV;642		goto err; /* QP already being destroyed */643	}644 645	rc = dev->ops->iwarp_connect(dev->rdma_ctx, &in_params, &out_params);646	if (rc) {647		complete(&qp->iwarp_cm_comp);648		goto err;649	}650 651	return rc;652 653err:654	kref_put(&ep->refcnt, qedr_iw_free_ep);655	return rc;656}657 658int qedr_iw_create_listen(struct iw_cm_id *cm_id, int backlog)659{660	struct qedr_dev *dev = get_qedr_dev(cm_id->device);661	struct qedr_iw_listener *listener;662	struct qed_iwarp_listen_in iparams;663	struct qed_iwarp_listen_out oparams;664	struct sockaddr_in *laddr;665	struct sockaddr_in6 *laddr6;666	int rc;667	int i;668 669	laddr = (struct sockaddr_in *)&cm_id->m_local_addr;670	laddr6 = (struct sockaddr_in6 *)&cm_id->m_local_addr;671 672	DP_DEBUG(dev, QEDR_MSG_IWARP,673		 "Create Listener address: %pISpc\n", &cm_id->local_addr);674 675	listener = kzalloc(sizeof(*listener), GFP_KERNEL);676	if (!listener)677		return -ENOMEM;678 679	listener->dev = dev;680	cm_id->add_ref(cm_id);681	listener->cm_id = cm_id;682	listener->backlog = backlog;683 684	iparams.cb_context = listener;685	iparams.event_cb = qedr_iw_event_handler;686	iparams.max_backlog = backlog;687 688	if (!IS_ENABLED(CONFIG_IPV6) ||689	    cm_id->local_addr.ss_family == AF_INET) {690		iparams.ip_version = QED_TCP_IPV4;691		memset(iparams.ip_addr, 0, sizeof(iparams.ip_addr));692 693		iparams.ip_addr[0] = ntohl(laddr->sin_addr.s_addr);694		iparams.port = ntohs(laddr->sin_port);695		iparams.vlan = qedr_iw_get_vlan_ipv4(dev, iparams.ip_addr);696	} else {697		iparams.ip_version = QED_TCP_IPV6;698 699		for (i = 0; i < 4; i++) {700			iparams.ip_addr[i] =701			    ntohl(laddr6->sin6_addr.in6_u.u6_addr32[i]);702		}703 704		iparams.port = ntohs(laddr6->sin6_port);705 706		iparams.vlan = qedr_iw_get_vlan_ipv6(iparams.ip_addr);707	}708	rc = dev->ops->iwarp_create_listen(dev->rdma_ctx, &iparams, &oparams);709	if (rc)710		goto err;711 712	listener->qed_handle = oparams.handle;713	cm_id->provider_data = listener;714	return rc;715 716err:717	cm_id->rem_ref(cm_id);718	kfree(listener);719	return rc;720}721 722int qedr_iw_destroy_listen(struct iw_cm_id *cm_id)723{724	struct qedr_iw_listener *listener = cm_id->provider_data;725	struct qedr_dev *dev = get_qedr_dev(cm_id->device);726	int rc = 0;727 728	if (listener->qed_handle)729		rc = dev->ops->iwarp_destroy_listen(dev->rdma_ctx,730						    listener->qed_handle);731 732	cm_id->rem_ref(cm_id);733	kfree(listener);734	return rc;735}736 737int qedr_iw_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)738{739	struct qedr_iw_ep *ep = (struct qedr_iw_ep *)cm_id->provider_data;740	struct qedr_dev *dev = ep->dev;741	struct qedr_qp *qp;742	struct qed_iwarp_accept_in params;743	int rc;744 745	DP_DEBUG(dev, QEDR_MSG_IWARP, "Accept on qpid=%d\n", conn_param->qpn);746 747	qp = qedr_iw_load_qp(dev, conn_param->qpn);748	if (!qp) {749		DP_ERR(dev, "Invalid QP number %d\n", conn_param->qpn);750		return -EINVAL;751	}752 753	ep->qp = qp;754	cm_id->add_ref(cm_id);755	ep->cm_id = cm_id;756 757	params.ep_context = ep->qed_context;758	params.cb_context = ep;759	params.qp = ep->qp->qed_qp;760	params.private_data = conn_param->private_data;761	params.private_data_len = conn_param->private_data_len;762	params.ird = conn_param->ird;763	params.ord = conn_param->ord;764 765	if (test_and_set_bit(QEDR_IWARP_CM_WAIT_FOR_CONNECT,766			     &qp->iwarp_cm_flags)) {767		rc = -EINVAL;768		goto err; /* QP already destroyed */769	}770 771	rc = dev->ops->iwarp_accept(dev->rdma_ctx, &params);772	if (rc) {773		complete(&qp->iwarp_cm_comp);774		goto err;775	}776 777	return rc;778 779err:780	kref_put(&ep->refcnt, qedr_iw_free_ep);781 782	return rc;783}784 785int qedr_iw_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)786{787	struct qedr_iw_ep *ep = (struct qedr_iw_ep *)cm_id->provider_data;788	struct qedr_dev *dev = ep->dev;789	struct qed_iwarp_reject_in params;790 791	params.ep_context = ep->qed_context;792	params.cb_context = ep;793	params.private_data = pdata;794	params.private_data_len = pdata_len;795	ep->qp = NULL;796 797	return dev->ops->iwarp_reject(dev->rdma_ctx, &params);798}799 800void qedr_iw_qp_add_ref(struct ib_qp *ibqp)801{802	struct qedr_qp *qp = get_qedr_qp(ibqp);803 804	kref_get(&qp->refcnt);805}806 807void qedr_iw_qp_rem_ref(struct ib_qp *ibqp)808{809	struct qedr_qp *qp = get_qedr_qp(ibqp);810 811	kref_put(&qp->refcnt, qedr_iw_free_qp);812}813 814struct ib_qp *qedr_iw_get_qp(struct ib_device *ibdev, int qpn)815{816	struct qedr_dev *dev = get_qedr_dev(ibdev);817 818	return xa_load(&dev->qps, qpn);819}820