18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2009-2014 Chelsio, Inc. All rights reserved.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two
58c2ecf20Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the
88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below:
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
118c2ecf20Sopenharmony_ci *     without modification, are permitted provided that the following
128c2ecf20Sopenharmony_ci *     conditions are met:
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *      - Redistributions of source code must retain the above
158c2ecf20Sopenharmony_ci *	  copyright notice, this list of conditions and the following
168c2ecf20Sopenharmony_ci *	  disclaimer.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
198c2ecf20Sopenharmony_ci *	  copyright notice, this list of conditions and the following
208c2ecf20Sopenharmony_ci *	  disclaimer in the documentation and/or other materials
218c2ecf20Sopenharmony_ci *	  provided with the distribution.
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
308c2ecf20Sopenharmony_ci * SOFTWARE.
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_ci#include <linux/module.h>
338c2ecf20Sopenharmony_ci#include <linux/list.h>
348c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
358c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
368c2ecf20Sopenharmony_ci#include <linux/timer.h>
378c2ecf20Sopenharmony_ci#include <linux/notifier.h>
388c2ecf20Sopenharmony_ci#include <linux/inetdevice.h>
398c2ecf20Sopenharmony_ci#include <linux/ip.h>
408c2ecf20Sopenharmony_ci#include <linux/tcp.h>
418c2ecf20Sopenharmony_ci#include <linux/if_vlan.h>
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#include <net/neighbour.h>
448c2ecf20Sopenharmony_ci#include <net/netevent.h>
458c2ecf20Sopenharmony_ci#include <net/route.h>
468c2ecf20Sopenharmony_ci#include <net/tcp.h>
478c2ecf20Sopenharmony_ci#include <net/ip6_route.h>
488c2ecf20Sopenharmony_ci#include <net/addrconf.h>
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#include <rdma/ib_addr.h>
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#include <libcxgb_cm.h>
538c2ecf20Sopenharmony_ci#include "iw_cxgb4.h"
548c2ecf20Sopenharmony_ci#include "clip_tbl.h"
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic char *states[] = {
578c2ecf20Sopenharmony_ci	"idle",
588c2ecf20Sopenharmony_ci	"listen",
598c2ecf20Sopenharmony_ci	"connecting",
608c2ecf20Sopenharmony_ci	"mpa_wait_req",
618c2ecf20Sopenharmony_ci	"mpa_req_sent",
628c2ecf20Sopenharmony_ci	"mpa_req_rcvd",
638c2ecf20Sopenharmony_ci	"mpa_rep_sent",
648c2ecf20Sopenharmony_ci	"fpdu_mode",
658c2ecf20Sopenharmony_ci	"aborting",
668c2ecf20Sopenharmony_ci	"closing",
678c2ecf20Sopenharmony_ci	"moribund",
688c2ecf20Sopenharmony_ci	"dead",
698c2ecf20Sopenharmony_ci	NULL,
708c2ecf20Sopenharmony_ci};
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic int nocong;
738c2ecf20Sopenharmony_cimodule_param(nocong, int, 0644);
748c2ecf20Sopenharmony_ciMODULE_PARM_DESC(nocong, "Turn of congestion control (default=0)");
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic int enable_ecn;
778c2ecf20Sopenharmony_cimodule_param(enable_ecn, int, 0644);
788c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enable_ecn, "Enable ECN (default=0/disabled)");
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic int dack_mode;
818c2ecf20Sopenharmony_cimodule_param(dack_mode, int, 0644);
828c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dack_mode, "Delayed ack mode (default=0)");
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ciuint c4iw_max_read_depth = 32;
858c2ecf20Sopenharmony_cimodule_param(c4iw_max_read_depth, int, 0644);
868c2ecf20Sopenharmony_ciMODULE_PARM_DESC(c4iw_max_read_depth,
878c2ecf20Sopenharmony_ci		 "Per-connection max ORD/IRD (default=32)");
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistatic int enable_tcp_timestamps;
908c2ecf20Sopenharmony_cimodule_param(enable_tcp_timestamps, int, 0644);
918c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enable_tcp_timestamps, "Enable tcp timestamps (default=0)");
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic int enable_tcp_sack;
948c2ecf20Sopenharmony_cimodule_param(enable_tcp_sack, int, 0644);
958c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enable_tcp_sack, "Enable tcp SACK (default=0)");
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_cistatic int enable_tcp_window_scaling = 1;
988c2ecf20Sopenharmony_cimodule_param(enable_tcp_window_scaling, int, 0644);
998c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enable_tcp_window_scaling,
1008c2ecf20Sopenharmony_ci		 "Enable tcp window scaling (default=1)");
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic int peer2peer = 1;
1038c2ecf20Sopenharmony_cimodule_param(peer2peer, int, 0644);
1048c2ecf20Sopenharmony_ciMODULE_PARM_DESC(peer2peer, "Support peer2peer ULPs (default=1)");
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic int p2p_type = FW_RI_INIT_P2PTYPE_READ_REQ;
1078c2ecf20Sopenharmony_cimodule_param(p2p_type, int, 0644);
1088c2ecf20Sopenharmony_ciMODULE_PARM_DESC(p2p_type, "RDMAP opcode to use for the RTR message: "
1098c2ecf20Sopenharmony_ci			   "1=RDMA_READ 0=RDMA_WRITE (default 1)");
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic int ep_timeout_secs = 60;
1128c2ecf20Sopenharmony_cimodule_param(ep_timeout_secs, int, 0644);
1138c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ep_timeout_secs, "CM Endpoint operation timeout "
1148c2ecf20Sopenharmony_ci				   "in seconds (default=60)");
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic int mpa_rev = 2;
1178c2ecf20Sopenharmony_cimodule_param(mpa_rev, int, 0644);
1188c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mpa_rev, "MPA Revision, 0 supports amso1100, "
1198c2ecf20Sopenharmony_ci		"1 is RFC5044 spec compliant, 2 is IETF MPA Peer Connect Draft"
1208c2ecf20Sopenharmony_ci		" compliant (default=2)");
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic int markers_enabled;
1238c2ecf20Sopenharmony_cimodule_param(markers_enabled, int, 0644);
1248c2ecf20Sopenharmony_ciMODULE_PARM_DESC(markers_enabled, "Enable MPA MARKERS (default(0)=disabled)");
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_cistatic int crc_enabled = 1;
1278c2ecf20Sopenharmony_cimodule_param(crc_enabled, int, 0644);
1288c2ecf20Sopenharmony_ciMODULE_PARM_DESC(crc_enabled, "Enable MPA CRC (default(1)=enabled)");
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic int rcv_win = 256 * 1024;
1318c2ecf20Sopenharmony_cimodule_param(rcv_win, int, 0644);
1328c2ecf20Sopenharmony_ciMODULE_PARM_DESC(rcv_win, "TCP receive window in bytes (default=256KB)");
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic int snd_win = 128 * 1024;
1358c2ecf20Sopenharmony_cimodule_param(snd_win, int, 0644);
1368c2ecf20Sopenharmony_ciMODULE_PARM_DESC(snd_win, "TCP send window in bytes (default=128KB)");
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic struct workqueue_struct *workq;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic struct sk_buff_head rxq;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistatic struct sk_buff *get_skb(struct sk_buff *skb, int len, gfp_t gfp);
1438c2ecf20Sopenharmony_cistatic void ep_timeout(struct timer_list *t);
1448c2ecf20Sopenharmony_cistatic void connect_reply_upcall(struct c4iw_ep *ep, int status);
1458c2ecf20Sopenharmony_cistatic int sched(struct c4iw_dev *dev, struct sk_buff *skb);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic LIST_HEAD(timeout_list);
1488c2ecf20Sopenharmony_cistatic spinlock_t timeout_lock;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cistatic void deref_cm_id(struct c4iw_ep_common *epc)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	epc->cm_id->rem_ref(epc->cm_id);
1538c2ecf20Sopenharmony_ci	epc->cm_id = NULL;
1548c2ecf20Sopenharmony_ci	set_bit(CM_ID_DEREFED, &epc->history);
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic void ref_cm_id(struct c4iw_ep_common *epc)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	set_bit(CM_ID_REFED, &epc->history);
1608c2ecf20Sopenharmony_ci	epc->cm_id->add_ref(epc->cm_id);
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic void deref_qp(struct c4iw_ep *ep)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	c4iw_qp_rem_ref(&ep->com.qp->ibqp);
1668c2ecf20Sopenharmony_ci	clear_bit(QP_REFERENCED, &ep->com.flags);
1678c2ecf20Sopenharmony_ci	set_bit(QP_DEREFED, &ep->com.history);
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic void ref_qp(struct c4iw_ep *ep)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	set_bit(QP_REFERENCED, &ep->com.flags);
1738c2ecf20Sopenharmony_ci	set_bit(QP_REFED, &ep->com.history);
1748c2ecf20Sopenharmony_ci	c4iw_qp_add_ref(&ep->com.qp->ibqp);
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_cistatic void start_ep_timer(struct c4iw_ep *ep)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	pr_debug("ep %p\n", ep);
1808c2ecf20Sopenharmony_ci	if (timer_pending(&ep->timer)) {
1818c2ecf20Sopenharmony_ci		pr_err("%s timer already started! ep %p\n",
1828c2ecf20Sopenharmony_ci		       __func__, ep);
1838c2ecf20Sopenharmony_ci		return;
1848c2ecf20Sopenharmony_ci	}
1858c2ecf20Sopenharmony_ci	clear_bit(TIMEOUT, &ep->com.flags);
1868c2ecf20Sopenharmony_ci	c4iw_get_ep(&ep->com);
1878c2ecf20Sopenharmony_ci	ep->timer.expires = jiffies + ep_timeout_secs * HZ;
1888c2ecf20Sopenharmony_ci	add_timer(&ep->timer);
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistatic int stop_ep_timer(struct c4iw_ep *ep)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	pr_debug("ep %p stopping\n", ep);
1948c2ecf20Sopenharmony_ci	del_timer_sync(&ep->timer);
1958c2ecf20Sopenharmony_ci	if (!test_and_set_bit(TIMEOUT, &ep->com.flags)) {
1968c2ecf20Sopenharmony_ci		c4iw_put_ep(&ep->com);
1978c2ecf20Sopenharmony_ci		return 0;
1988c2ecf20Sopenharmony_ci	}
1998c2ecf20Sopenharmony_ci	return 1;
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic int c4iw_l2t_send(struct c4iw_rdev *rdev, struct sk_buff *skb,
2038c2ecf20Sopenharmony_ci		  struct l2t_entry *l2e)
2048c2ecf20Sopenharmony_ci{
2058c2ecf20Sopenharmony_ci	int	error = 0;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	if (c4iw_fatal_error(rdev)) {
2088c2ecf20Sopenharmony_ci		kfree_skb(skb);
2098c2ecf20Sopenharmony_ci		pr_err("%s - device in error state - dropping\n", __func__);
2108c2ecf20Sopenharmony_ci		return -EIO;
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci	error = cxgb4_l2t_send(rdev->lldi.ports[0], skb, l2e);
2138c2ecf20Sopenharmony_ci	if (error < 0)
2148c2ecf20Sopenharmony_ci		kfree_skb(skb);
2158c2ecf20Sopenharmony_ci	else if (error == NET_XMIT_DROP)
2168c2ecf20Sopenharmony_ci		return -ENOMEM;
2178c2ecf20Sopenharmony_ci	return error < 0 ? error : 0;
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ciint c4iw_ofld_send(struct c4iw_rdev *rdev, struct sk_buff *skb)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	int	error = 0;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	if (c4iw_fatal_error(rdev)) {
2258c2ecf20Sopenharmony_ci		kfree_skb(skb);
2268c2ecf20Sopenharmony_ci		pr_err("%s - device in error state - dropping\n", __func__);
2278c2ecf20Sopenharmony_ci		return -EIO;
2288c2ecf20Sopenharmony_ci	}
2298c2ecf20Sopenharmony_ci	error = cxgb4_ofld_send(rdev->lldi.ports[0], skb);
2308c2ecf20Sopenharmony_ci	if (error < 0)
2318c2ecf20Sopenharmony_ci		kfree_skb(skb);
2328c2ecf20Sopenharmony_ci	return error < 0 ? error : 0;
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic void release_tid(struct c4iw_rdev *rdev, u32 hwtid, struct sk_buff *skb)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	u32 len = roundup(sizeof(struct cpl_tid_release), 16);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	skb = get_skb(skb, len, GFP_KERNEL);
2408c2ecf20Sopenharmony_ci	if (!skb)
2418c2ecf20Sopenharmony_ci		return;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	cxgb_mk_tid_release(skb, len, hwtid, 0);
2448c2ecf20Sopenharmony_ci	c4iw_ofld_send(rdev, skb);
2458c2ecf20Sopenharmony_ci	return;
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cistatic void set_emss(struct c4iw_ep *ep, u16 opt)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	ep->emss = ep->com.dev->rdev.lldi.mtus[TCPOPT_MSS_G(opt)] -
2518c2ecf20Sopenharmony_ci		   ((AF_INET == ep->com.remote_addr.ss_family) ?
2528c2ecf20Sopenharmony_ci		    sizeof(struct iphdr) : sizeof(struct ipv6hdr)) -
2538c2ecf20Sopenharmony_ci		   sizeof(struct tcphdr);
2548c2ecf20Sopenharmony_ci	ep->mss = ep->emss;
2558c2ecf20Sopenharmony_ci	if (TCPOPT_TSTAMP_G(opt))
2568c2ecf20Sopenharmony_ci		ep->emss -= round_up(TCPOLEN_TIMESTAMP, 4);
2578c2ecf20Sopenharmony_ci	if (ep->emss < 128)
2588c2ecf20Sopenharmony_ci		ep->emss = 128;
2598c2ecf20Sopenharmony_ci	if (ep->emss & 7)
2608c2ecf20Sopenharmony_ci		pr_debug("Warning: misaligned mtu idx %u mss %u emss=%u\n",
2618c2ecf20Sopenharmony_ci			 TCPOPT_MSS_G(opt), ep->mss, ep->emss);
2628c2ecf20Sopenharmony_ci	pr_debug("mss_idx %u mss %u emss=%u\n", TCPOPT_MSS_G(opt), ep->mss,
2638c2ecf20Sopenharmony_ci		 ep->emss);
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_cistatic enum c4iw_ep_state state_read(struct c4iw_ep_common *epc)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	enum c4iw_ep_state state;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	mutex_lock(&epc->mutex);
2718c2ecf20Sopenharmony_ci	state = epc->state;
2728c2ecf20Sopenharmony_ci	mutex_unlock(&epc->mutex);
2738c2ecf20Sopenharmony_ci	return state;
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cistatic void __state_set(struct c4iw_ep_common *epc, enum c4iw_ep_state new)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	epc->state = new;
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_cistatic void state_set(struct c4iw_ep_common *epc, enum c4iw_ep_state new)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	mutex_lock(&epc->mutex);
2848c2ecf20Sopenharmony_ci	pr_debug("%s -> %s\n", states[epc->state], states[new]);
2858c2ecf20Sopenharmony_ci	__state_set(epc, new);
2868c2ecf20Sopenharmony_ci	mutex_unlock(&epc->mutex);
2878c2ecf20Sopenharmony_ci	return;
2888c2ecf20Sopenharmony_ci}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cistatic int alloc_ep_skb_list(struct sk_buff_head *ep_skb_list, int size)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci	struct sk_buff *skb;
2938c2ecf20Sopenharmony_ci	unsigned int i;
2948c2ecf20Sopenharmony_ci	size_t len;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	len = roundup(sizeof(union cpl_wr_size), 16);
2978c2ecf20Sopenharmony_ci	for (i = 0; i < size; i++) {
2988c2ecf20Sopenharmony_ci		skb = alloc_skb(len, GFP_KERNEL);
2998c2ecf20Sopenharmony_ci		if (!skb)
3008c2ecf20Sopenharmony_ci			goto fail;
3018c2ecf20Sopenharmony_ci		skb_queue_tail(ep_skb_list, skb);
3028c2ecf20Sopenharmony_ci	}
3038c2ecf20Sopenharmony_ci	return 0;
3048c2ecf20Sopenharmony_cifail:
3058c2ecf20Sopenharmony_ci	skb_queue_purge(ep_skb_list);
3068c2ecf20Sopenharmony_ci	return -ENOMEM;
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cistatic void *alloc_ep(int size, gfp_t gfp)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	struct c4iw_ep_common *epc;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	epc = kzalloc(size, gfp);
3148c2ecf20Sopenharmony_ci	if (epc) {
3158c2ecf20Sopenharmony_ci		epc->wr_waitp = c4iw_alloc_wr_wait(gfp);
3168c2ecf20Sopenharmony_ci		if (!epc->wr_waitp) {
3178c2ecf20Sopenharmony_ci			kfree(epc);
3188c2ecf20Sopenharmony_ci			epc = NULL;
3198c2ecf20Sopenharmony_ci			goto out;
3208c2ecf20Sopenharmony_ci		}
3218c2ecf20Sopenharmony_ci		kref_init(&epc->kref);
3228c2ecf20Sopenharmony_ci		mutex_init(&epc->mutex);
3238c2ecf20Sopenharmony_ci		c4iw_init_wr_wait(epc->wr_waitp);
3248c2ecf20Sopenharmony_ci	}
3258c2ecf20Sopenharmony_ci	pr_debug("alloc ep %p\n", epc);
3268c2ecf20Sopenharmony_ciout:
3278c2ecf20Sopenharmony_ci	return epc;
3288c2ecf20Sopenharmony_ci}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_cistatic void remove_ep_tid(struct c4iw_ep *ep)
3318c2ecf20Sopenharmony_ci{
3328c2ecf20Sopenharmony_ci	unsigned long flags;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	xa_lock_irqsave(&ep->com.dev->hwtids, flags);
3358c2ecf20Sopenharmony_ci	__xa_erase(&ep->com.dev->hwtids, ep->hwtid);
3368c2ecf20Sopenharmony_ci	if (xa_empty(&ep->com.dev->hwtids))
3378c2ecf20Sopenharmony_ci		wake_up(&ep->com.dev->wait);
3388c2ecf20Sopenharmony_ci	xa_unlock_irqrestore(&ep->com.dev->hwtids, flags);
3398c2ecf20Sopenharmony_ci}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_cistatic int insert_ep_tid(struct c4iw_ep *ep)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	unsigned long flags;
3448c2ecf20Sopenharmony_ci	int err;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	xa_lock_irqsave(&ep->com.dev->hwtids, flags);
3478c2ecf20Sopenharmony_ci	err = __xa_insert(&ep->com.dev->hwtids, ep->hwtid, ep, GFP_KERNEL);
3488c2ecf20Sopenharmony_ci	xa_unlock_irqrestore(&ep->com.dev->hwtids, flags);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	return err;
3518c2ecf20Sopenharmony_ci}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci/*
3548c2ecf20Sopenharmony_ci * Atomically lookup the ep ptr given the tid and grab a reference on the ep.
3558c2ecf20Sopenharmony_ci */
3568c2ecf20Sopenharmony_cistatic struct c4iw_ep *get_ep_from_tid(struct c4iw_dev *dev, unsigned int tid)
3578c2ecf20Sopenharmony_ci{
3588c2ecf20Sopenharmony_ci	struct c4iw_ep *ep;
3598c2ecf20Sopenharmony_ci	unsigned long flags;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	xa_lock_irqsave(&dev->hwtids, flags);
3628c2ecf20Sopenharmony_ci	ep = xa_load(&dev->hwtids, tid);
3638c2ecf20Sopenharmony_ci	if (ep)
3648c2ecf20Sopenharmony_ci		c4iw_get_ep(&ep->com);
3658c2ecf20Sopenharmony_ci	xa_unlock_irqrestore(&dev->hwtids, flags);
3668c2ecf20Sopenharmony_ci	return ep;
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci/*
3708c2ecf20Sopenharmony_ci * Atomically lookup the ep ptr given the stid and grab a reference on the ep.
3718c2ecf20Sopenharmony_ci */
3728c2ecf20Sopenharmony_cistatic struct c4iw_listen_ep *get_ep_from_stid(struct c4iw_dev *dev,
3738c2ecf20Sopenharmony_ci					       unsigned int stid)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	struct c4iw_listen_ep *ep;
3768c2ecf20Sopenharmony_ci	unsigned long flags;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	xa_lock_irqsave(&dev->stids, flags);
3798c2ecf20Sopenharmony_ci	ep = xa_load(&dev->stids, stid);
3808c2ecf20Sopenharmony_ci	if (ep)
3818c2ecf20Sopenharmony_ci		c4iw_get_ep(&ep->com);
3828c2ecf20Sopenharmony_ci	xa_unlock_irqrestore(&dev->stids, flags);
3838c2ecf20Sopenharmony_ci	return ep;
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_civoid _c4iw_free_ep(struct kref *kref)
3878c2ecf20Sopenharmony_ci{
3888c2ecf20Sopenharmony_ci	struct c4iw_ep *ep;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	ep = container_of(kref, struct c4iw_ep, com.kref);
3918c2ecf20Sopenharmony_ci	pr_debug("ep %p state %s\n", ep, states[ep->com.state]);
3928c2ecf20Sopenharmony_ci	if (test_bit(QP_REFERENCED, &ep->com.flags))
3938c2ecf20Sopenharmony_ci		deref_qp(ep);
3948c2ecf20Sopenharmony_ci	if (test_bit(RELEASE_RESOURCES, &ep->com.flags)) {
3958c2ecf20Sopenharmony_ci		if (ep->com.remote_addr.ss_family == AF_INET6) {
3968c2ecf20Sopenharmony_ci			struct sockaddr_in6 *sin6 =
3978c2ecf20Sopenharmony_ci					(struct sockaddr_in6 *)
3988c2ecf20Sopenharmony_ci					&ep->com.local_addr;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci			cxgb4_clip_release(
4018c2ecf20Sopenharmony_ci					ep->com.dev->rdev.lldi.ports[0],
4028c2ecf20Sopenharmony_ci					(const u32 *)&sin6->sin6_addr.s6_addr,
4038c2ecf20Sopenharmony_ci					1);
4048c2ecf20Sopenharmony_ci		}
4058c2ecf20Sopenharmony_ci		cxgb4_remove_tid(ep->com.dev->rdev.lldi.tids, 0, ep->hwtid,
4068c2ecf20Sopenharmony_ci				 ep->com.local_addr.ss_family);
4078c2ecf20Sopenharmony_ci		dst_release(ep->dst);
4088c2ecf20Sopenharmony_ci		cxgb4_l2t_release(ep->l2t);
4098c2ecf20Sopenharmony_ci		kfree_skb(ep->mpa_skb);
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci	if (!skb_queue_empty(&ep->com.ep_skb_list))
4128c2ecf20Sopenharmony_ci		skb_queue_purge(&ep->com.ep_skb_list);
4138c2ecf20Sopenharmony_ci	c4iw_put_wr_wait(ep->com.wr_waitp);
4148c2ecf20Sopenharmony_ci	kfree(ep);
4158c2ecf20Sopenharmony_ci}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_cistatic void release_ep_resources(struct c4iw_ep *ep)
4188c2ecf20Sopenharmony_ci{
4198c2ecf20Sopenharmony_ci	set_bit(RELEASE_RESOURCES, &ep->com.flags);
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	/*
4228c2ecf20Sopenharmony_ci	 * If we have a hwtid, then remove it from the idr table
4238c2ecf20Sopenharmony_ci	 * so lookups will no longer find this endpoint.  Otherwise
4248c2ecf20Sopenharmony_ci	 * we have a race where one thread finds the ep ptr just
4258c2ecf20Sopenharmony_ci	 * before the other thread is freeing the ep memory.
4268c2ecf20Sopenharmony_ci	 */
4278c2ecf20Sopenharmony_ci	if (ep->hwtid != -1)
4288c2ecf20Sopenharmony_ci		remove_ep_tid(ep);
4298c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->com);
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_cistatic int status2errno(int status)
4338c2ecf20Sopenharmony_ci{
4348c2ecf20Sopenharmony_ci	switch (status) {
4358c2ecf20Sopenharmony_ci	case CPL_ERR_NONE:
4368c2ecf20Sopenharmony_ci		return 0;
4378c2ecf20Sopenharmony_ci	case CPL_ERR_CONN_RESET:
4388c2ecf20Sopenharmony_ci		return -ECONNRESET;
4398c2ecf20Sopenharmony_ci	case CPL_ERR_ARP_MISS:
4408c2ecf20Sopenharmony_ci		return -EHOSTUNREACH;
4418c2ecf20Sopenharmony_ci	case CPL_ERR_CONN_TIMEDOUT:
4428c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
4438c2ecf20Sopenharmony_ci	case CPL_ERR_TCAM_FULL:
4448c2ecf20Sopenharmony_ci		return -ENOMEM;
4458c2ecf20Sopenharmony_ci	case CPL_ERR_CONN_EXIST:
4468c2ecf20Sopenharmony_ci		return -EADDRINUSE;
4478c2ecf20Sopenharmony_ci	default:
4488c2ecf20Sopenharmony_ci		return -EIO;
4498c2ecf20Sopenharmony_ci	}
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci/*
4538c2ecf20Sopenharmony_ci * Try and reuse skbs already allocated...
4548c2ecf20Sopenharmony_ci */
4558c2ecf20Sopenharmony_cistatic struct sk_buff *get_skb(struct sk_buff *skb, int len, gfp_t gfp)
4568c2ecf20Sopenharmony_ci{
4578c2ecf20Sopenharmony_ci	if (skb && !skb_is_nonlinear(skb) && !skb_cloned(skb)) {
4588c2ecf20Sopenharmony_ci		skb_trim(skb, 0);
4598c2ecf20Sopenharmony_ci		skb_get(skb);
4608c2ecf20Sopenharmony_ci		skb_reset_transport_header(skb);
4618c2ecf20Sopenharmony_ci	} else {
4628c2ecf20Sopenharmony_ci		skb = alloc_skb(len, gfp);
4638c2ecf20Sopenharmony_ci		if (!skb)
4648c2ecf20Sopenharmony_ci			return NULL;
4658c2ecf20Sopenharmony_ci	}
4668c2ecf20Sopenharmony_ci	t4_set_arp_err_handler(skb, NULL, NULL);
4678c2ecf20Sopenharmony_ci	return skb;
4688c2ecf20Sopenharmony_ci}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_cistatic struct net_device *get_real_dev(struct net_device *egress_dev)
4718c2ecf20Sopenharmony_ci{
4728c2ecf20Sopenharmony_ci	return rdma_vlan_dev_real_dev(egress_dev) ? : egress_dev;
4738c2ecf20Sopenharmony_ci}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_cistatic void arp_failure_discard(void *handle, struct sk_buff *skb)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	pr_err("ARP failure\n");
4788c2ecf20Sopenharmony_ci	kfree_skb(skb);
4798c2ecf20Sopenharmony_ci}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_cistatic void mpa_start_arp_failure(void *handle, struct sk_buff *skb)
4828c2ecf20Sopenharmony_ci{
4838c2ecf20Sopenharmony_ci	pr_err("ARP failure during MPA Negotiation - Closing Connection\n");
4848c2ecf20Sopenharmony_ci}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_cienum {
4878c2ecf20Sopenharmony_ci	NUM_FAKE_CPLS = 2,
4888c2ecf20Sopenharmony_ci	FAKE_CPL_PUT_EP_SAFE = NUM_CPL_CMDS + 0,
4898c2ecf20Sopenharmony_ci	FAKE_CPL_PASS_PUT_EP_SAFE = NUM_CPL_CMDS + 1,
4908c2ecf20Sopenharmony_ci};
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_cistatic int _put_ep_safe(struct c4iw_dev *dev, struct sk_buff *skb)
4938c2ecf20Sopenharmony_ci{
4948c2ecf20Sopenharmony_ci	struct c4iw_ep *ep;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	ep = *((struct c4iw_ep **)(skb->cb + 2 * sizeof(void *)));
4978c2ecf20Sopenharmony_ci	release_ep_resources(ep);
4988c2ecf20Sopenharmony_ci	return 0;
4998c2ecf20Sopenharmony_ci}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_cistatic int _put_pass_ep_safe(struct c4iw_dev *dev, struct sk_buff *skb)
5028c2ecf20Sopenharmony_ci{
5038c2ecf20Sopenharmony_ci	struct c4iw_ep *ep;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	ep = *((struct c4iw_ep **)(skb->cb + 2 * sizeof(void *)));
5068c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->parent_ep->com);
5078c2ecf20Sopenharmony_ci	release_ep_resources(ep);
5088c2ecf20Sopenharmony_ci	return 0;
5098c2ecf20Sopenharmony_ci}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci/*
5128c2ecf20Sopenharmony_ci * Fake up a special CPL opcode and call sched() so process_work() will call
5138c2ecf20Sopenharmony_ci * _put_ep_safe() in a safe context to free the ep resources.  This is needed
5148c2ecf20Sopenharmony_ci * because ARP error handlers are called in an ATOMIC context, and
5158c2ecf20Sopenharmony_ci * _c4iw_free_ep() needs to block.
5168c2ecf20Sopenharmony_ci */
5178c2ecf20Sopenharmony_cistatic void queue_arp_failure_cpl(struct c4iw_ep *ep, struct sk_buff *skb,
5188c2ecf20Sopenharmony_ci				  int cpl)
5198c2ecf20Sopenharmony_ci{
5208c2ecf20Sopenharmony_ci	struct cpl_act_establish *rpl = cplhdr(skb);
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	/* Set our special ARP_FAILURE opcode */
5238c2ecf20Sopenharmony_ci	rpl->ot.opcode = cpl;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	/*
5268c2ecf20Sopenharmony_ci	 * Save ep in the skb->cb area, after where sched() will save the dev
5278c2ecf20Sopenharmony_ci	 * ptr.
5288c2ecf20Sopenharmony_ci	 */
5298c2ecf20Sopenharmony_ci	*((struct c4iw_ep **)(skb->cb + 2 * sizeof(void *))) = ep;
5308c2ecf20Sopenharmony_ci	sched(ep->com.dev, skb);
5318c2ecf20Sopenharmony_ci}
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci/* Handle an ARP failure for an accept */
5348c2ecf20Sopenharmony_cistatic void pass_accept_rpl_arp_failure(void *handle, struct sk_buff *skb)
5358c2ecf20Sopenharmony_ci{
5368c2ecf20Sopenharmony_ci	struct c4iw_ep *ep = handle;
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	pr_err("ARP failure during accept - tid %u - dropping connection\n",
5398c2ecf20Sopenharmony_ci	       ep->hwtid);
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	__state_set(&ep->com, DEAD);
5428c2ecf20Sopenharmony_ci	queue_arp_failure_cpl(ep, skb, FAKE_CPL_PASS_PUT_EP_SAFE);
5438c2ecf20Sopenharmony_ci}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci/*
5468c2ecf20Sopenharmony_ci * Handle an ARP failure for an active open.
5478c2ecf20Sopenharmony_ci */
5488c2ecf20Sopenharmony_cistatic void act_open_req_arp_failure(void *handle, struct sk_buff *skb)
5498c2ecf20Sopenharmony_ci{
5508c2ecf20Sopenharmony_ci	struct c4iw_ep *ep = handle;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	pr_err("ARP failure during connect\n");
5538c2ecf20Sopenharmony_ci	connect_reply_upcall(ep, -EHOSTUNREACH);
5548c2ecf20Sopenharmony_ci	__state_set(&ep->com, DEAD);
5558c2ecf20Sopenharmony_ci	if (ep->com.remote_addr.ss_family == AF_INET6) {
5568c2ecf20Sopenharmony_ci		struct sockaddr_in6 *sin6 =
5578c2ecf20Sopenharmony_ci			(struct sockaddr_in6 *)&ep->com.local_addr;
5588c2ecf20Sopenharmony_ci		cxgb4_clip_release(ep->com.dev->rdev.lldi.ports[0],
5598c2ecf20Sopenharmony_ci				   (const u32 *)&sin6->sin6_addr.s6_addr, 1);
5608c2ecf20Sopenharmony_ci	}
5618c2ecf20Sopenharmony_ci	xa_erase_irq(&ep->com.dev->atids, ep->atid);
5628c2ecf20Sopenharmony_ci	cxgb4_free_atid(ep->com.dev->rdev.lldi.tids, ep->atid);
5638c2ecf20Sopenharmony_ci	queue_arp_failure_cpl(ep, skb, FAKE_CPL_PUT_EP_SAFE);
5648c2ecf20Sopenharmony_ci}
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci/*
5678c2ecf20Sopenharmony_ci * Handle an ARP failure for a CPL_ABORT_REQ.  Change it into a no RST variant
5688c2ecf20Sopenharmony_ci * and send it along.
5698c2ecf20Sopenharmony_ci */
5708c2ecf20Sopenharmony_cistatic void abort_arp_failure(void *handle, struct sk_buff *skb)
5718c2ecf20Sopenharmony_ci{
5728c2ecf20Sopenharmony_ci	int ret;
5738c2ecf20Sopenharmony_ci	struct c4iw_ep *ep = handle;
5748c2ecf20Sopenharmony_ci	struct c4iw_rdev *rdev = &ep->com.dev->rdev;
5758c2ecf20Sopenharmony_ci	struct cpl_abort_req *req = cplhdr(skb);
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	pr_debug("rdev %p\n", rdev);
5788c2ecf20Sopenharmony_ci	req->cmd = CPL_ABORT_NO_RST;
5798c2ecf20Sopenharmony_ci	skb_get(skb);
5808c2ecf20Sopenharmony_ci	ret = c4iw_ofld_send(rdev, skb);
5818c2ecf20Sopenharmony_ci	if (ret) {
5828c2ecf20Sopenharmony_ci		__state_set(&ep->com, DEAD);
5838c2ecf20Sopenharmony_ci		queue_arp_failure_cpl(ep, skb, FAKE_CPL_PUT_EP_SAFE);
5848c2ecf20Sopenharmony_ci	} else
5858c2ecf20Sopenharmony_ci		kfree_skb(skb);
5868c2ecf20Sopenharmony_ci}
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_cistatic int send_flowc(struct c4iw_ep *ep)
5898c2ecf20Sopenharmony_ci{
5908c2ecf20Sopenharmony_ci	struct fw_flowc_wr *flowc;
5918c2ecf20Sopenharmony_ci	struct sk_buff *skb = skb_dequeue(&ep->com.ep_skb_list);
5928c2ecf20Sopenharmony_ci	u16 vlan = ep->l2t->vlan;
5938c2ecf20Sopenharmony_ci	int nparams;
5948c2ecf20Sopenharmony_ci	int flowclen, flowclen16;
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	if (WARN_ON(!skb))
5978c2ecf20Sopenharmony_ci		return -ENOMEM;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	if (vlan == CPL_L2T_VLAN_NONE)
6008c2ecf20Sopenharmony_ci		nparams = 9;
6018c2ecf20Sopenharmony_ci	else
6028c2ecf20Sopenharmony_ci		nparams = 10;
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	flowclen = offsetof(struct fw_flowc_wr, mnemval[nparams]);
6058c2ecf20Sopenharmony_ci	flowclen16 = DIV_ROUND_UP(flowclen, 16);
6068c2ecf20Sopenharmony_ci	flowclen = flowclen16 * 16;
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	flowc = __skb_put(skb, flowclen);
6098c2ecf20Sopenharmony_ci	memset(flowc, 0, flowclen);
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	flowc->op_to_nparams = cpu_to_be32(FW_WR_OP_V(FW_FLOWC_WR) |
6128c2ecf20Sopenharmony_ci					   FW_FLOWC_WR_NPARAMS_V(nparams));
6138c2ecf20Sopenharmony_ci	flowc->flowid_len16 = cpu_to_be32(FW_WR_LEN16_V(flowclen16) |
6148c2ecf20Sopenharmony_ci					  FW_WR_FLOWID_V(ep->hwtid));
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	flowc->mnemval[0].mnemonic = FW_FLOWC_MNEM_PFNVFN;
6178c2ecf20Sopenharmony_ci	flowc->mnemval[0].val = cpu_to_be32(FW_PFVF_CMD_PFN_V
6188c2ecf20Sopenharmony_ci					    (ep->com.dev->rdev.lldi.pf));
6198c2ecf20Sopenharmony_ci	flowc->mnemval[1].mnemonic = FW_FLOWC_MNEM_CH;
6208c2ecf20Sopenharmony_ci	flowc->mnemval[1].val = cpu_to_be32(ep->tx_chan);
6218c2ecf20Sopenharmony_ci	flowc->mnemval[2].mnemonic = FW_FLOWC_MNEM_PORT;
6228c2ecf20Sopenharmony_ci	flowc->mnemval[2].val = cpu_to_be32(ep->tx_chan);
6238c2ecf20Sopenharmony_ci	flowc->mnemval[3].mnemonic = FW_FLOWC_MNEM_IQID;
6248c2ecf20Sopenharmony_ci	flowc->mnemval[3].val = cpu_to_be32(ep->rss_qid);
6258c2ecf20Sopenharmony_ci	flowc->mnemval[4].mnemonic = FW_FLOWC_MNEM_SNDNXT;
6268c2ecf20Sopenharmony_ci	flowc->mnemval[4].val = cpu_to_be32(ep->snd_seq);
6278c2ecf20Sopenharmony_ci	flowc->mnemval[5].mnemonic = FW_FLOWC_MNEM_RCVNXT;
6288c2ecf20Sopenharmony_ci	flowc->mnemval[5].val = cpu_to_be32(ep->rcv_seq);
6298c2ecf20Sopenharmony_ci	flowc->mnemval[6].mnemonic = FW_FLOWC_MNEM_SNDBUF;
6308c2ecf20Sopenharmony_ci	flowc->mnemval[6].val = cpu_to_be32(ep->snd_win);
6318c2ecf20Sopenharmony_ci	flowc->mnemval[7].mnemonic = FW_FLOWC_MNEM_MSS;
6328c2ecf20Sopenharmony_ci	flowc->mnemval[7].val = cpu_to_be32(ep->emss);
6338c2ecf20Sopenharmony_ci	flowc->mnemval[8].mnemonic = FW_FLOWC_MNEM_RCV_SCALE;
6348c2ecf20Sopenharmony_ci	flowc->mnemval[8].val = cpu_to_be32(ep->snd_wscale);
6358c2ecf20Sopenharmony_ci	if (nparams == 10) {
6368c2ecf20Sopenharmony_ci		u16 pri;
6378c2ecf20Sopenharmony_ci		pri = (vlan & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
6388c2ecf20Sopenharmony_ci		flowc->mnemval[9].mnemonic = FW_FLOWC_MNEM_SCHEDCLASS;
6398c2ecf20Sopenharmony_ci		flowc->mnemval[9].val = cpu_to_be32(pri);
6408c2ecf20Sopenharmony_ci	}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	set_wr_txq(skb, CPL_PRIORITY_DATA, ep->txq_idx);
6438c2ecf20Sopenharmony_ci	return c4iw_ofld_send(&ep->com.dev->rdev, skb);
6448c2ecf20Sopenharmony_ci}
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_cistatic int send_halfclose(struct c4iw_ep *ep)
6478c2ecf20Sopenharmony_ci{
6488c2ecf20Sopenharmony_ci	struct sk_buff *skb = skb_dequeue(&ep->com.ep_skb_list);
6498c2ecf20Sopenharmony_ci	u32 wrlen = roundup(sizeof(struct cpl_close_con_req), 16);
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u\n", ep, ep->hwtid);
6528c2ecf20Sopenharmony_ci	if (WARN_ON(!skb))
6538c2ecf20Sopenharmony_ci		return -ENOMEM;
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	cxgb_mk_close_con_req(skb, wrlen, ep->hwtid, ep->txq_idx,
6568c2ecf20Sopenharmony_ci			      NULL, arp_failure_discard);
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	return c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
6598c2ecf20Sopenharmony_ci}
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_cistatic void read_tcb(struct c4iw_ep *ep)
6628c2ecf20Sopenharmony_ci{
6638c2ecf20Sopenharmony_ci	struct sk_buff *skb;
6648c2ecf20Sopenharmony_ci	struct cpl_get_tcb *req;
6658c2ecf20Sopenharmony_ci	int wrlen = roundup(sizeof(*req), 16);
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	skb = get_skb(NULL, sizeof(*req), GFP_KERNEL);
6688c2ecf20Sopenharmony_ci	if (WARN_ON(!skb))
6698c2ecf20Sopenharmony_ci		return;
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	set_wr_txq(skb, CPL_PRIORITY_CONTROL, ep->ctrlq_idx);
6728c2ecf20Sopenharmony_ci	req = (struct cpl_get_tcb *) skb_put(skb, wrlen);
6738c2ecf20Sopenharmony_ci	memset(req, 0, wrlen);
6748c2ecf20Sopenharmony_ci	INIT_TP_WR(req, ep->hwtid);
6758c2ecf20Sopenharmony_ci	OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_GET_TCB, ep->hwtid));
6768c2ecf20Sopenharmony_ci	req->reply_ctrl = htons(REPLY_CHAN_V(0) | QUEUENO_V(ep->rss_qid));
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	/*
6798c2ecf20Sopenharmony_ci	 * keep a ref on the ep so the tcb is not unlocked before this
6808c2ecf20Sopenharmony_ci	 * cpl completes. The ref is released in read_tcb_rpl().
6818c2ecf20Sopenharmony_ci	 */
6828c2ecf20Sopenharmony_ci	c4iw_get_ep(&ep->com);
6838c2ecf20Sopenharmony_ci	if (WARN_ON(c4iw_ofld_send(&ep->com.dev->rdev, skb)))
6848c2ecf20Sopenharmony_ci		c4iw_put_ep(&ep->com);
6858c2ecf20Sopenharmony_ci}
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_cistatic int send_abort_req(struct c4iw_ep *ep)
6888c2ecf20Sopenharmony_ci{
6898c2ecf20Sopenharmony_ci	u32 wrlen = roundup(sizeof(struct cpl_abort_req), 16);
6908c2ecf20Sopenharmony_ci	struct sk_buff *req_skb = skb_dequeue(&ep->com.ep_skb_list);
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u\n", ep, ep->hwtid);
6938c2ecf20Sopenharmony_ci	if (WARN_ON(!req_skb))
6948c2ecf20Sopenharmony_ci		return -ENOMEM;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	cxgb_mk_abort_req(req_skb, wrlen, ep->hwtid, ep->txq_idx,
6978c2ecf20Sopenharmony_ci			  ep, abort_arp_failure);
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	return c4iw_l2t_send(&ep->com.dev->rdev, req_skb, ep->l2t);
7008c2ecf20Sopenharmony_ci}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_cistatic int send_abort(struct c4iw_ep *ep)
7038c2ecf20Sopenharmony_ci{
7048c2ecf20Sopenharmony_ci	if (!ep->com.qp || !ep->com.qp->srq) {
7058c2ecf20Sopenharmony_ci		send_abort_req(ep);
7068c2ecf20Sopenharmony_ci		return 0;
7078c2ecf20Sopenharmony_ci	}
7088c2ecf20Sopenharmony_ci	set_bit(ABORT_REQ_IN_PROGRESS, &ep->com.flags);
7098c2ecf20Sopenharmony_ci	read_tcb(ep);
7108c2ecf20Sopenharmony_ci	return 0;
7118c2ecf20Sopenharmony_ci}
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_cistatic int send_connect(struct c4iw_ep *ep)
7148c2ecf20Sopenharmony_ci{
7158c2ecf20Sopenharmony_ci	struct cpl_act_open_req *req = NULL;
7168c2ecf20Sopenharmony_ci	struct cpl_t5_act_open_req *t5req = NULL;
7178c2ecf20Sopenharmony_ci	struct cpl_t6_act_open_req *t6req = NULL;
7188c2ecf20Sopenharmony_ci	struct cpl_act_open_req6 *req6 = NULL;
7198c2ecf20Sopenharmony_ci	struct cpl_t5_act_open_req6 *t5req6 = NULL;
7208c2ecf20Sopenharmony_ci	struct cpl_t6_act_open_req6 *t6req6 = NULL;
7218c2ecf20Sopenharmony_ci	struct sk_buff *skb;
7228c2ecf20Sopenharmony_ci	u64 opt0;
7238c2ecf20Sopenharmony_ci	u32 opt2;
7248c2ecf20Sopenharmony_ci	unsigned int mtu_idx;
7258c2ecf20Sopenharmony_ci	u32 wscale;
7268c2ecf20Sopenharmony_ci	int win, sizev4, sizev6, wrlen;
7278c2ecf20Sopenharmony_ci	struct sockaddr_in *la = (struct sockaddr_in *)
7288c2ecf20Sopenharmony_ci				 &ep->com.local_addr;
7298c2ecf20Sopenharmony_ci	struct sockaddr_in *ra = (struct sockaddr_in *)
7308c2ecf20Sopenharmony_ci				 &ep->com.remote_addr;
7318c2ecf20Sopenharmony_ci	struct sockaddr_in6 *la6 = (struct sockaddr_in6 *)
7328c2ecf20Sopenharmony_ci				   &ep->com.local_addr;
7338c2ecf20Sopenharmony_ci	struct sockaddr_in6 *ra6 = (struct sockaddr_in6 *)
7348c2ecf20Sopenharmony_ci				   &ep->com.remote_addr;
7358c2ecf20Sopenharmony_ci	int ret;
7368c2ecf20Sopenharmony_ci	enum chip_type adapter_type = ep->com.dev->rdev.lldi.adapter_type;
7378c2ecf20Sopenharmony_ci	u32 isn = (prandom_u32() & ~7UL) - 1;
7388c2ecf20Sopenharmony_ci	struct net_device *netdev;
7398c2ecf20Sopenharmony_ci	u64 params;
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	netdev = ep->com.dev->rdev.lldi.ports[0];
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	switch (CHELSIO_CHIP_VERSION(adapter_type)) {
7448c2ecf20Sopenharmony_ci	case CHELSIO_T4:
7458c2ecf20Sopenharmony_ci		sizev4 = sizeof(struct cpl_act_open_req);
7468c2ecf20Sopenharmony_ci		sizev6 = sizeof(struct cpl_act_open_req6);
7478c2ecf20Sopenharmony_ci		break;
7488c2ecf20Sopenharmony_ci	case CHELSIO_T5:
7498c2ecf20Sopenharmony_ci		sizev4 = sizeof(struct cpl_t5_act_open_req);
7508c2ecf20Sopenharmony_ci		sizev6 = sizeof(struct cpl_t5_act_open_req6);
7518c2ecf20Sopenharmony_ci		break;
7528c2ecf20Sopenharmony_ci	case CHELSIO_T6:
7538c2ecf20Sopenharmony_ci		sizev4 = sizeof(struct cpl_t6_act_open_req);
7548c2ecf20Sopenharmony_ci		sizev6 = sizeof(struct cpl_t6_act_open_req6);
7558c2ecf20Sopenharmony_ci		break;
7568c2ecf20Sopenharmony_ci	default:
7578c2ecf20Sopenharmony_ci		pr_err("T%d Chip is not supported\n",
7588c2ecf20Sopenharmony_ci		       CHELSIO_CHIP_VERSION(adapter_type));
7598c2ecf20Sopenharmony_ci		return -EINVAL;
7608c2ecf20Sopenharmony_ci	}
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	wrlen = (ep->com.remote_addr.ss_family == AF_INET) ?
7638c2ecf20Sopenharmony_ci			roundup(sizev4, 16) :
7648c2ecf20Sopenharmony_ci			roundup(sizev6, 16);
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	pr_debug("ep %p atid %u\n", ep, ep->atid);
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	skb = get_skb(NULL, wrlen, GFP_KERNEL);
7698c2ecf20Sopenharmony_ci	if (!skb) {
7708c2ecf20Sopenharmony_ci		pr_err("%s - failed to alloc skb\n", __func__);
7718c2ecf20Sopenharmony_ci		return -ENOMEM;
7728c2ecf20Sopenharmony_ci	}
7738c2ecf20Sopenharmony_ci	set_wr_txq(skb, CPL_PRIORITY_SETUP, ep->ctrlq_idx);
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	cxgb_best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx,
7768c2ecf20Sopenharmony_ci		      enable_tcp_timestamps,
7778c2ecf20Sopenharmony_ci		      (ep->com.remote_addr.ss_family == AF_INET) ? 0 : 1);
7788c2ecf20Sopenharmony_ci	wscale = cxgb_compute_wscale(rcv_win);
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	/*
7818c2ecf20Sopenharmony_ci	 * Specify the largest window that will fit in opt0. The
7828c2ecf20Sopenharmony_ci	 * remainder will be specified in the rx_data_ack.
7838c2ecf20Sopenharmony_ci	 */
7848c2ecf20Sopenharmony_ci	win = ep->rcv_win >> 10;
7858c2ecf20Sopenharmony_ci	if (win > RCV_BUFSIZ_M)
7868c2ecf20Sopenharmony_ci		win = RCV_BUFSIZ_M;
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	opt0 = (nocong ? NO_CONG_F : 0) |
7898c2ecf20Sopenharmony_ci	       KEEP_ALIVE_F |
7908c2ecf20Sopenharmony_ci	       DELACK_F |
7918c2ecf20Sopenharmony_ci	       WND_SCALE_V(wscale) |
7928c2ecf20Sopenharmony_ci	       MSS_IDX_V(mtu_idx) |
7938c2ecf20Sopenharmony_ci	       L2T_IDX_V(ep->l2t->idx) |
7948c2ecf20Sopenharmony_ci	       TX_CHAN_V(ep->tx_chan) |
7958c2ecf20Sopenharmony_ci	       SMAC_SEL_V(ep->smac_idx) |
7968c2ecf20Sopenharmony_ci	       DSCP_V(ep->tos >> 2) |
7978c2ecf20Sopenharmony_ci	       ULP_MODE_V(ULP_MODE_TCPDDP) |
7988c2ecf20Sopenharmony_ci	       RCV_BUFSIZ_V(win);
7998c2ecf20Sopenharmony_ci	opt2 = RX_CHANNEL_V(0) |
8008c2ecf20Sopenharmony_ci	       CCTRL_ECN_V(enable_ecn) |
8018c2ecf20Sopenharmony_ci	       RSS_QUEUE_VALID_F | RSS_QUEUE_V(ep->rss_qid);
8028c2ecf20Sopenharmony_ci	if (enable_tcp_timestamps)
8038c2ecf20Sopenharmony_ci		opt2 |= TSTAMPS_EN_F;
8048c2ecf20Sopenharmony_ci	if (enable_tcp_sack)
8058c2ecf20Sopenharmony_ci		opt2 |= SACK_EN_F;
8068c2ecf20Sopenharmony_ci	if (wscale && enable_tcp_window_scaling)
8078c2ecf20Sopenharmony_ci		opt2 |= WND_SCALE_EN_F;
8088c2ecf20Sopenharmony_ci	if (CHELSIO_CHIP_VERSION(adapter_type) > CHELSIO_T4) {
8098c2ecf20Sopenharmony_ci		if (peer2peer)
8108c2ecf20Sopenharmony_ci			isn += 4;
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci		opt2 |= T5_OPT_2_VALID_F;
8138c2ecf20Sopenharmony_ci		opt2 |= CONG_CNTRL_V(CONG_ALG_TAHOE);
8148c2ecf20Sopenharmony_ci		opt2 |= T5_ISS_F;
8158c2ecf20Sopenharmony_ci	}
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	params = cxgb4_select_ntuple(netdev, ep->l2t);
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	if (ep->com.remote_addr.ss_family == AF_INET6)
8208c2ecf20Sopenharmony_ci		cxgb4_clip_get(ep->com.dev->rdev.lldi.ports[0],
8218c2ecf20Sopenharmony_ci			       (const u32 *)&la6->sin6_addr.s6_addr, 1);
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	t4_set_arp_err_handler(skb, ep, act_open_req_arp_failure);
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	if (ep->com.remote_addr.ss_family == AF_INET) {
8268c2ecf20Sopenharmony_ci		switch (CHELSIO_CHIP_VERSION(adapter_type)) {
8278c2ecf20Sopenharmony_ci		case CHELSIO_T4:
8288c2ecf20Sopenharmony_ci			req = skb_put(skb, wrlen);
8298c2ecf20Sopenharmony_ci			INIT_TP_WR(req, 0);
8308c2ecf20Sopenharmony_ci			break;
8318c2ecf20Sopenharmony_ci		case CHELSIO_T5:
8328c2ecf20Sopenharmony_ci			t5req = skb_put(skb, wrlen);
8338c2ecf20Sopenharmony_ci			INIT_TP_WR(t5req, 0);
8348c2ecf20Sopenharmony_ci			req = (struct cpl_act_open_req *)t5req;
8358c2ecf20Sopenharmony_ci			break;
8368c2ecf20Sopenharmony_ci		case CHELSIO_T6:
8378c2ecf20Sopenharmony_ci			t6req = skb_put(skb, wrlen);
8388c2ecf20Sopenharmony_ci			INIT_TP_WR(t6req, 0);
8398c2ecf20Sopenharmony_ci			req = (struct cpl_act_open_req *)t6req;
8408c2ecf20Sopenharmony_ci			t5req = (struct cpl_t5_act_open_req *)t6req;
8418c2ecf20Sopenharmony_ci			break;
8428c2ecf20Sopenharmony_ci		default:
8438c2ecf20Sopenharmony_ci			pr_err("T%d Chip is not supported\n",
8448c2ecf20Sopenharmony_ci			       CHELSIO_CHIP_VERSION(adapter_type));
8458c2ecf20Sopenharmony_ci			ret = -EINVAL;
8468c2ecf20Sopenharmony_ci			goto clip_release;
8478c2ecf20Sopenharmony_ci		}
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci		OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ,
8508c2ecf20Sopenharmony_ci					((ep->rss_qid<<14) | ep->atid)));
8518c2ecf20Sopenharmony_ci		req->local_port = la->sin_port;
8528c2ecf20Sopenharmony_ci		req->peer_port = ra->sin_port;
8538c2ecf20Sopenharmony_ci		req->local_ip = la->sin_addr.s_addr;
8548c2ecf20Sopenharmony_ci		req->peer_ip = ra->sin_addr.s_addr;
8558c2ecf20Sopenharmony_ci		req->opt0 = cpu_to_be64(opt0);
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci		if (is_t4(ep->com.dev->rdev.lldi.adapter_type)) {
8588c2ecf20Sopenharmony_ci			req->params = cpu_to_be32(params);
8598c2ecf20Sopenharmony_ci			req->opt2 = cpu_to_be32(opt2);
8608c2ecf20Sopenharmony_ci		} else {
8618c2ecf20Sopenharmony_ci			if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) {
8628c2ecf20Sopenharmony_ci				t5req->params =
8638c2ecf20Sopenharmony_ci					  cpu_to_be64(FILTER_TUPLE_V(params));
8648c2ecf20Sopenharmony_ci				t5req->rsvd = cpu_to_be32(isn);
8658c2ecf20Sopenharmony_ci				pr_debug("snd_isn %u\n", t5req->rsvd);
8668c2ecf20Sopenharmony_ci				t5req->opt2 = cpu_to_be32(opt2);
8678c2ecf20Sopenharmony_ci			} else {
8688c2ecf20Sopenharmony_ci				t6req->params =
8698c2ecf20Sopenharmony_ci					  cpu_to_be64(FILTER_TUPLE_V(params));
8708c2ecf20Sopenharmony_ci				t6req->rsvd = cpu_to_be32(isn);
8718c2ecf20Sopenharmony_ci				pr_debug("snd_isn %u\n", t6req->rsvd);
8728c2ecf20Sopenharmony_ci				t6req->opt2 = cpu_to_be32(opt2);
8738c2ecf20Sopenharmony_ci			}
8748c2ecf20Sopenharmony_ci		}
8758c2ecf20Sopenharmony_ci	} else {
8768c2ecf20Sopenharmony_ci		switch (CHELSIO_CHIP_VERSION(adapter_type)) {
8778c2ecf20Sopenharmony_ci		case CHELSIO_T4:
8788c2ecf20Sopenharmony_ci			req6 = skb_put(skb, wrlen);
8798c2ecf20Sopenharmony_ci			INIT_TP_WR(req6, 0);
8808c2ecf20Sopenharmony_ci			break;
8818c2ecf20Sopenharmony_ci		case CHELSIO_T5:
8828c2ecf20Sopenharmony_ci			t5req6 = skb_put(skb, wrlen);
8838c2ecf20Sopenharmony_ci			INIT_TP_WR(t5req6, 0);
8848c2ecf20Sopenharmony_ci			req6 = (struct cpl_act_open_req6 *)t5req6;
8858c2ecf20Sopenharmony_ci			break;
8868c2ecf20Sopenharmony_ci		case CHELSIO_T6:
8878c2ecf20Sopenharmony_ci			t6req6 = skb_put(skb, wrlen);
8888c2ecf20Sopenharmony_ci			INIT_TP_WR(t6req6, 0);
8898c2ecf20Sopenharmony_ci			req6 = (struct cpl_act_open_req6 *)t6req6;
8908c2ecf20Sopenharmony_ci			t5req6 = (struct cpl_t5_act_open_req6 *)t6req6;
8918c2ecf20Sopenharmony_ci			break;
8928c2ecf20Sopenharmony_ci		default:
8938c2ecf20Sopenharmony_ci			pr_err("T%d Chip is not supported\n",
8948c2ecf20Sopenharmony_ci			       CHELSIO_CHIP_VERSION(adapter_type));
8958c2ecf20Sopenharmony_ci			ret = -EINVAL;
8968c2ecf20Sopenharmony_ci			goto clip_release;
8978c2ecf20Sopenharmony_ci		}
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci		OPCODE_TID(req6) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ6,
9008c2ecf20Sopenharmony_ci					((ep->rss_qid<<14)|ep->atid)));
9018c2ecf20Sopenharmony_ci		req6->local_port = la6->sin6_port;
9028c2ecf20Sopenharmony_ci		req6->peer_port = ra6->sin6_port;
9038c2ecf20Sopenharmony_ci		req6->local_ip_hi = *((__be64 *)(la6->sin6_addr.s6_addr));
9048c2ecf20Sopenharmony_ci		req6->local_ip_lo = *((__be64 *)(la6->sin6_addr.s6_addr + 8));
9058c2ecf20Sopenharmony_ci		req6->peer_ip_hi = *((__be64 *)(ra6->sin6_addr.s6_addr));
9068c2ecf20Sopenharmony_ci		req6->peer_ip_lo = *((__be64 *)(ra6->sin6_addr.s6_addr + 8));
9078c2ecf20Sopenharmony_ci		req6->opt0 = cpu_to_be64(opt0);
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci		if (is_t4(ep->com.dev->rdev.lldi.adapter_type)) {
9108c2ecf20Sopenharmony_ci			req6->params = cpu_to_be32(cxgb4_select_ntuple(netdev,
9118c2ecf20Sopenharmony_ci								      ep->l2t));
9128c2ecf20Sopenharmony_ci			req6->opt2 = cpu_to_be32(opt2);
9138c2ecf20Sopenharmony_ci		} else {
9148c2ecf20Sopenharmony_ci			if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) {
9158c2ecf20Sopenharmony_ci				t5req6->params =
9168c2ecf20Sopenharmony_ci					    cpu_to_be64(FILTER_TUPLE_V(params));
9178c2ecf20Sopenharmony_ci				t5req6->rsvd = cpu_to_be32(isn);
9188c2ecf20Sopenharmony_ci				pr_debug("snd_isn %u\n", t5req6->rsvd);
9198c2ecf20Sopenharmony_ci				t5req6->opt2 = cpu_to_be32(opt2);
9208c2ecf20Sopenharmony_ci			} else {
9218c2ecf20Sopenharmony_ci				t6req6->params =
9228c2ecf20Sopenharmony_ci					    cpu_to_be64(FILTER_TUPLE_V(params));
9238c2ecf20Sopenharmony_ci				t6req6->rsvd = cpu_to_be32(isn);
9248c2ecf20Sopenharmony_ci				pr_debug("snd_isn %u\n", t6req6->rsvd);
9258c2ecf20Sopenharmony_ci				t6req6->opt2 = cpu_to_be32(opt2);
9268c2ecf20Sopenharmony_ci			}
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci		}
9298c2ecf20Sopenharmony_ci	}
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	set_bit(ACT_OPEN_REQ, &ep->com.history);
9328c2ecf20Sopenharmony_ci	ret = c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
9338c2ecf20Sopenharmony_ciclip_release:
9348c2ecf20Sopenharmony_ci	if (ret && ep->com.remote_addr.ss_family == AF_INET6)
9358c2ecf20Sopenharmony_ci		cxgb4_clip_release(ep->com.dev->rdev.lldi.ports[0],
9368c2ecf20Sopenharmony_ci				   (const u32 *)&la6->sin6_addr.s6_addr, 1);
9378c2ecf20Sopenharmony_ci	return ret;
9388c2ecf20Sopenharmony_ci}
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_cistatic int send_mpa_req(struct c4iw_ep *ep, struct sk_buff *skb,
9418c2ecf20Sopenharmony_ci			u8 mpa_rev_to_use)
9428c2ecf20Sopenharmony_ci{
9438c2ecf20Sopenharmony_ci	int mpalen, wrlen, ret;
9448c2ecf20Sopenharmony_ci	struct fw_ofld_tx_data_wr *req;
9458c2ecf20Sopenharmony_ci	struct mpa_message *mpa;
9468c2ecf20Sopenharmony_ci	struct mpa_v2_conn_params mpa_v2_params;
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u pd_len %d\n",
9498c2ecf20Sopenharmony_ci		 ep, ep->hwtid, ep->plen);
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	mpalen = sizeof(*mpa) + ep->plen;
9528c2ecf20Sopenharmony_ci	if (mpa_rev_to_use == 2)
9538c2ecf20Sopenharmony_ci		mpalen += sizeof(struct mpa_v2_conn_params);
9548c2ecf20Sopenharmony_ci	wrlen = roundup(mpalen + sizeof(*req), 16);
9558c2ecf20Sopenharmony_ci	skb = get_skb(skb, wrlen, GFP_KERNEL);
9568c2ecf20Sopenharmony_ci	if (!skb) {
9578c2ecf20Sopenharmony_ci		connect_reply_upcall(ep, -ENOMEM);
9588c2ecf20Sopenharmony_ci		return -ENOMEM;
9598c2ecf20Sopenharmony_ci	}
9608c2ecf20Sopenharmony_ci	set_wr_txq(skb, CPL_PRIORITY_DATA, ep->txq_idx);
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci	req = skb_put_zero(skb, wrlen);
9638c2ecf20Sopenharmony_ci	req->op_to_immdlen = cpu_to_be32(
9648c2ecf20Sopenharmony_ci		FW_WR_OP_V(FW_OFLD_TX_DATA_WR) |
9658c2ecf20Sopenharmony_ci		FW_WR_COMPL_F |
9668c2ecf20Sopenharmony_ci		FW_WR_IMMDLEN_V(mpalen));
9678c2ecf20Sopenharmony_ci	req->flowid_len16 = cpu_to_be32(
9688c2ecf20Sopenharmony_ci		FW_WR_FLOWID_V(ep->hwtid) |
9698c2ecf20Sopenharmony_ci		FW_WR_LEN16_V(wrlen >> 4));
9708c2ecf20Sopenharmony_ci	req->plen = cpu_to_be32(mpalen);
9718c2ecf20Sopenharmony_ci	req->tunnel_to_proxy = cpu_to_be32(
9728c2ecf20Sopenharmony_ci		FW_OFLD_TX_DATA_WR_FLUSH_F |
9738c2ecf20Sopenharmony_ci		FW_OFLD_TX_DATA_WR_SHOVE_F);
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	mpa = (struct mpa_message *)(req + 1);
9768c2ecf20Sopenharmony_ci	memcpy(mpa->key, MPA_KEY_REQ, sizeof(mpa->key));
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	mpa->flags = 0;
9798c2ecf20Sopenharmony_ci	if (crc_enabled)
9808c2ecf20Sopenharmony_ci		mpa->flags |= MPA_CRC;
9818c2ecf20Sopenharmony_ci	if (markers_enabled) {
9828c2ecf20Sopenharmony_ci		mpa->flags |= MPA_MARKERS;
9838c2ecf20Sopenharmony_ci		ep->mpa_attr.recv_marker_enabled = 1;
9848c2ecf20Sopenharmony_ci	} else {
9858c2ecf20Sopenharmony_ci		ep->mpa_attr.recv_marker_enabled = 0;
9868c2ecf20Sopenharmony_ci	}
9878c2ecf20Sopenharmony_ci	if (mpa_rev_to_use == 2)
9888c2ecf20Sopenharmony_ci		mpa->flags |= MPA_ENHANCED_RDMA_CONN;
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	mpa->private_data_size = htons(ep->plen);
9918c2ecf20Sopenharmony_ci	mpa->revision = mpa_rev_to_use;
9928c2ecf20Sopenharmony_ci	if (mpa_rev_to_use == 1) {
9938c2ecf20Sopenharmony_ci		ep->tried_with_mpa_v1 = 1;
9948c2ecf20Sopenharmony_ci		ep->retry_with_mpa_v1 = 0;
9958c2ecf20Sopenharmony_ci	}
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	if (mpa_rev_to_use == 2) {
9988c2ecf20Sopenharmony_ci		mpa->private_data_size =
9998c2ecf20Sopenharmony_ci			htons(ntohs(mpa->private_data_size) +
10008c2ecf20Sopenharmony_ci			      sizeof(struct mpa_v2_conn_params));
10018c2ecf20Sopenharmony_ci		pr_debug("initiator ird %u ord %u\n", ep->ird,
10028c2ecf20Sopenharmony_ci			 ep->ord);
10038c2ecf20Sopenharmony_ci		mpa_v2_params.ird = htons((u16)ep->ird);
10048c2ecf20Sopenharmony_ci		mpa_v2_params.ord = htons((u16)ep->ord);
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci		if (peer2peer) {
10078c2ecf20Sopenharmony_ci			mpa_v2_params.ird |= htons(MPA_V2_PEER2PEER_MODEL);
10088c2ecf20Sopenharmony_ci			if (p2p_type == FW_RI_INIT_P2PTYPE_RDMA_WRITE)
10098c2ecf20Sopenharmony_ci				mpa_v2_params.ord |=
10108c2ecf20Sopenharmony_ci					htons(MPA_V2_RDMA_WRITE_RTR);
10118c2ecf20Sopenharmony_ci			else if (p2p_type == FW_RI_INIT_P2PTYPE_READ_REQ)
10128c2ecf20Sopenharmony_ci				mpa_v2_params.ord |=
10138c2ecf20Sopenharmony_ci					htons(MPA_V2_RDMA_READ_RTR);
10148c2ecf20Sopenharmony_ci		}
10158c2ecf20Sopenharmony_ci		memcpy(mpa->private_data, &mpa_v2_params,
10168c2ecf20Sopenharmony_ci		       sizeof(struct mpa_v2_conn_params));
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci		if (ep->plen)
10198c2ecf20Sopenharmony_ci			memcpy(mpa->private_data +
10208c2ecf20Sopenharmony_ci			       sizeof(struct mpa_v2_conn_params),
10218c2ecf20Sopenharmony_ci			       ep->mpa_pkt + sizeof(*mpa), ep->plen);
10228c2ecf20Sopenharmony_ci	} else
10238c2ecf20Sopenharmony_ci		if (ep->plen)
10248c2ecf20Sopenharmony_ci			memcpy(mpa->private_data,
10258c2ecf20Sopenharmony_ci					ep->mpa_pkt + sizeof(*mpa), ep->plen);
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	/*
10288c2ecf20Sopenharmony_ci	 * Reference the mpa skb.  This ensures the data area
10298c2ecf20Sopenharmony_ci	 * will remain in memory until the hw acks the tx.
10308c2ecf20Sopenharmony_ci	 * Function fw4_ack() will deref it.
10318c2ecf20Sopenharmony_ci	 */
10328c2ecf20Sopenharmony_ci	skb_get(skb);
10338c2ecf20Sopenharmony_ci	t4_set_arp_err_handler(skb, NULL, arp_failure_discard);
10348c2ecf20Sopenharmony_ci	ep->mpa_skb = skb;
10358c2ecf20Sopenharmony_ci	ret = c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
10368c2ecf20Sopenharmony_ci	if (ret)
10378c2ecf20Sopenharmony_ci		return ret;
10388c2ecf20Sopenharmony_ci	start_ep_timer(ep);
10398c2ecf20Sopenharmony_ci	__state_set(&ep->com, MPA_REQ_SENT);
10408c2ecf20Sopenharmony_ci	ep->mpa_attr.initiator = 1;
10418c2ecf20Sopenharmony_ci	ep->snd_seq += mpalen;
10428c2ecf20Sopenharmony_ci	return ret;
10438c2ecf20Sopenharmony_ci}
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_cistatic int send_mpa_reject(struct c4iw_ep *ep, const void *pdata, u8 plen)
10468c2ecf20Sopenharmony_ci{
10478c2ecf20Sopenharmony_ci	int mpalen, wrlen;
10488c2ecf20Sopenharmony_ci	struct fw_ofld_tx_data_wr *req;
10498c2ecf20Sopenharmony_ci	struct mpa_message *mpa;
10508c2ecf20Sopenharmony_ci	struct sk_buff *skb;
10518c2ecf20Sopenharmony_ci	struct mpa_v2_conn_params mpa_v2_params;
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u pd_len %d\n",
10548c2ecf20Sopenharmony_ci		 ep, ep->hwtid, ep->plen);
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	mpalen = sizeof(*mpa) + plen;
10578c2ecf20Sopenharmony_ci	if (ep->mpa_attr.version == 2 && ep->mpa_attr.enhanced_rdma_conn)
10588c2ecf20Sopenharmony_ci		mpalen += sizeof(struct mpa_v2_conn_params);
10598c2ecf20Sopenharmony_ci	wrlen = roundup(mpalen + sizeof(*req), 16);
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	skb = get_skb(NULL, wrlen, GFP_KERNEL);
10628c2ecf20Sopenharmony_ci	if (!skb) {
10638c2ecf20Sopenharmony_ci		pr_err("%s - cannot alloc skb!\n", __func__);
10648c2ecf20Sopenharmony_ci		return -ENOMEM;
10658c2ecf20Sopenharmony_ci	}
10668c2ecf20Sopenharmony_ci	set_wr_txq(skb, CPL_PRIORITY_DATA, ep->txq_idx);
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	req = skb_put_zero(skb, wrlen);
10698c2ecf20Sopenharmony_ci	req->op_to_immdlen = cpu_to_be32(
10708c2ecf20Sopenharmony_ci		FW_WR_OP_V(FW_OFLD_TX_DATA_WR) |
10718c2ecf20Sopenharmony_ci		FW_WR_COMPL_F |
10728c2ecf20Sopenharmony_ci		FW_WR_IMMDLEN_V(mpalen));
10738c2ecf20Sopenharmony_ci	req->flowid_len16 = cpu_to_be32(
10748c2ecf20Sopenharmony_ci		FW_WR_FLOWID_V(ep->hwtid) |
10758c2ecf20Sopenharmony_ci		FW_WR_LEN16_V(wrlen >> 4));
10768c2ecf20Sopenharmony_ci	req->plen = cpu_to_be32(mpalen);
10778c2ecf20Sopenharmony_ci	req->tunnel_to_proxy = cpu_to_be32(
10788c2ecf20Sopenharmony_ci		FW_OFLD_TX_DATA_WR_FLUSH_F |
10798c2ecf20Sopenharmony_ci		FW_OFLD_TX_DATA_WR_SHOVE_F);
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	mpa = (struct mpa_message *)(req + 1);
10828c2ecf20Sopenharmony_ci	memset(mpa, 0, sizeof(*mpa));
10838c2ecf20Sopenharmony_ci	memcpy(mpa->key, MPA_KEY_REP, sizeof(mpa->key));
10848c2ecf20Sopenharmony_ci	mpa->flags = MPA_REJECT;
10858c2ecf20Sopenharmony_ci	mpa->revision = ep->mpa_attr.version;
10868c2ecf20Sopenharmony_ci	mpa->private_data_size = htons(plen);
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci	if (ep->mpa_attr.version == 2 && ep->mpa_attr.enhanced_rdma_conn) {
10898c2ecf20Sopenharmony_ci		mpa->flags |= MPA_ENHANCED_RDMA_CONN;
10908c2ecf20Sopenharmony_ci		mpa->private_data_size =
10918c2ecf20Sopenharmony_ci			htons(ntohs(mpa->private_data_size) +
10928c2ecf20Sopenharmony_ci			      sizeof(struct mpa_v2_conn_params));
10938c2ecf20Sopenharmony_ci		mpa_v2_params.ird = htons(((u16)ep->ird) |
10948c2ecf20Sopenharmony_ci					  (peer2peer ? MPA_V2_PEER2PEER_MODEL :
10958c2ecf20Sopenharmony_ci					   0));
10968c2ecf20Sopenharmony_ci		mpa_v2_params.ord = htons(((u16)ep->ord) | (peer2peer ?
10978c2ecf20Sopenharmony_ci					  (p2p_type ==
10988c2ecf20Sopenharmony_ci					   FW_RI_INIT_P2PTYPE_RDMA_WRITE ?
10998c2ecf20Sopenharmony_ci					   MPA_V2_RDMA_WRITE_RTR : p2p_type ==
11008c2ecf20Sopenharmony_ci					   FW_RI_INIT_P2PTYPE_READ_REQ ?
11018c2ecf20Sopenharmony_ci					   MPA_V2_RDMA_READ_RTR : 0) : 0));
11028c2ecf20Sopenharmony_ci		memcpy(mpa->private_data, &mpa_v2_params,
11038c2ecf20Sopenharmony_ci		       sizeof(struct mpa_v2_conn_params));
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci		if (ep->plen)
11068c2ecf20Sopenharmony_ci			memcpy(mpa->private_data +
11078c2ecf20Sopenharmony_ci			       sizeof(struct mpa_v2_conn_params), pdata, plen);
11088c2ecf20Sopenharmony_ci	} else
11098c2ecf20Sopenharmony_ci		if (plen)
11108c2ecf20Sopenharmony_ci			memcpy(mpa->private_data, pdata, plen);
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci	/*
11138c2ecf20Sopenharmony_ci	 * Reference the mpa skb again.  This ensures the data area
11148c2ecf20Sopenharmony_ci	 * will remain in memory until the hw acks the tx.
11158c2ecf20Sopenharmony_ci	 * Function fw4_ack() will deref it.
11168c2ecf20Sopenharmony_ci	 */
11178c2ecf20Sopenharmony_ci	skb_get(skb);
11188c2ecf20Sopenharmony_ci	set_wr_txq(skb, CPL_PRIORITY_DATA, ep->txq_idx);
11198c2ecf20Sopenharmony_ci	t4_set_arp_err_handler(skb, NULL, mpa_start_arp_failure);
11208c2ecf20Sopenharmony_ci	ep->mpa_skb = skb;
11218c2ecf20Sopenharmony_ci	ep->snd_seq += mpalen;
11228c2ecf20Sopenharmony_ci	return c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
11238c2ecf20Sopenharmony_ci}
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_cistatic int send_mpa_reply(struct c4iw_ep *ep, const void *pdata, u8 plen)
11268c2ecf20Sopenharmony_ci{
11278c2ecf20Sopenharmony_ci	int mpalen, wrlen;
11288c2ecf20Sopenharmony_ci	struct fw_ofld_tx_data_wr *req;
11298c2ecf20Sopenharmony_ci	struct mpa_message *mpa;
11308c2ecf20Sopenharmony_ci	struct sk_buff *skb;
11318c2ecf20Sopenharmony_ci	struct mpa_v2_conn_params mpa_v2_params;
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u pd_len %d\n",
11348c2ecf20Sopenharmony_ci		 ep, ep->hwtid, ep->plen);
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci	mpalen = sizeof(*mpa) + plen;
11378c2ecf20Sopenharmony_ci	if (ep->mpa_attr.version == 2 && ep->mpa_attr.enhanced_rdma_conn)
11388c2ecf20Sopenharmony_ci		mpalen += sizeof(struct mpa_v2_conn_params);
11398c2ecf20Sopenharmony_ci	wrlen = roundup(mpalen + sizeof(*req), 16);
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci	skb = get_skb(NULL, wrlen, GFP_KERNEL);
11428c2ecf20Sopenharmony_ci	if (!skb) {
11438c2ecf20Sopenharmony_ci		pr_err("%s - cannot alloc skb!\n", __func__);
11448c2ecf20Sopenharmony_ci		return -ENOMEM;
11458c2ecf20Sopenharmony_ci	}
11468c2ecf20Sopenharmony_ci	set_wr_txq(skb, CPL_PRIORITY_DATA, ep->txq_idx);
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	req = skb_put_zero(skb, wrlen);
11498c2ecf20Sopenharmony_ci	req->op_to_immdlen = cpu_to_be32(
11508c2ecf20Sopenharmony_ci		FW_WR_OP_V(FW_OFLD_TX_DATA_WR) |
11518c2ecf20Sopenharmony_ci		FW_WR_COMPL_F |
11528c2ecf20Sopenharmony_ci		FW_WR_IMMDLEN_V(mpalen));
11538c2ecf20Sopenharmony_ci	req->flowid_len16 = cpu_to_be32(
11548c2ecf20Sopenharmony_ci		FW_WR_FLOWID_V(ep->hwtid) |
11558c2ecf20Sopenharmony_ci		FW_WR_LEN16_V(wrlen >> 4));
11568c2ecf20Sopenharmony_ci	req->plen = cpu_to_be32(mpalen);
11578c2ecf20Sopenharmony_ci	req->tunnel_to_proxy = cpu_to_be32(
11588c2ecf20Sopenharmony_ci		FW_OFLD_TX_DATA_WR_FLUSH_F |
11598c2ecf20Sopenharmony_ci		FW_OFLD_TX_DATA_WR_SHOVE_F);
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	mpa = (struct mpa_message *)(req + 1);
11628c2ecf20Sopenharmony_ci	memset(mpa, 0, sizeof(*mpa));
11638c2ecf20Sopenharmony_ci	memcpy(mpa->key, MPA_KEY_REP, sizeof(mpa->key));
11648c2ecf20Sopenharmony_ci	mpa->flags = 0;
11658c2ecf20Sopenharmony_ci	if (ep->mpa_attr.crc_enabled)
11668c2ecf20Sopenharmony_ci		mpa->flags |= MPA_CRC;
11678c2ecf20Sopenharmony_ci	if (ep->mpa_attr.recv_marker_enabled)
11688c2ecf20Sopenharmony_ci		mpa->flags |= MPA_MARKERS;
11698c2ecf20Sopenharmony_ci	mpa->revision = ep->mpa_attr.version;
11708c2ecf20Sopenharmony_ci	mpa->private_data_size = htons(plen);
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ci	if (ep->mpa_attr.version == 2 && ep->mpa_attr.enhanced_rdma_conn) {
11738c2ecf20Sopenharmony_ci		mpa->flags |= MPA_ENHANCED_RDMA_CONN;
11748c2ecf20Sopenharmony_ci		mpa->private_data_size =
11758c2ecf20Sopenharmony_ci			htons(ntohs(mpa->private_data_size) +
11768c2ecf20Sopenharmony_ci			      sizeof(struct mpa_v2_conn_params));
11778c2ecf20Sopenharmony_ci		mpa_v2_params.ird = htons((u16)ep->ird);
11788c2ecf20Sopenharmony_ci		mpa_v2_params.ord = htons((u16)ep->ord);
11798c2ecf20Sopenharmony_ci		if (peer2peer && (ep->mpa_attr.p2p_type !=
11808c2ecf20Sopenharmony_ci					FW_RI_INIT_P2PTYPE_DISABLED)) {
11818c2ecf20Sopenharmony_ci			mpa_v2_params.ird |= htons(MPA_V2_PEER2PEER_MODEL);
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci			if (p2p_type == FW_RI_INIT_P2PTYPE_RDMA_WRITE)
11848c2ecf20Sopenharmony_ci				mpa_v2_params.ord |=
11858c2ecf20Sopenharmony_ci					htons(MPA_V2_RDMA_WRITE_RTR);
11868c2ecf20Sopenharmony_ci			else if (p2p_type == FW_RI_INIT_P2PTYPE_READ_REQ)
11878c2ecf20Sopenharmony_ci				mpa_v2_params.ord |=
11888c2ecf20Sopenharmony_ci					htons(MPA_V2_RDMA_READ_RTR);
11898c2ecf20Sopenharmony_ci		}
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci		memcpy(mpa->private_data, &mpa_v2_params,
11928c2ecf20Sopenharmony_ci		       sizeof(struct mpa_v2_conn_params));
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci		if (ep->plen)
11958c2ecf20Sopenharmony_ci			memcpy(mpa->private_data +
11968c2ecf20Sopenharmony_ci			       sizeof(struct mpa_v2_conn_params), pdata, plen);
11978c2ecf20Sopenharmony_ci	} else
11988c2ecf20Sopenharmony_ci		if (plen)
11998c2ecf20Sopenharmony_ci			memcpy(mpa->private_data, pdata, plen);
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci	/*
12028c2ecf20Sopenharmony_ci	 * Reference the mpa skb.  This ensures the data area
12038c2ecf20Sopenharmony_ci	 * will remain in memory until the hw acks the tx.
12048c2ecf20Sopenharmony_ci	 * Function fw4_ack() will deref it.
12058c2ecf20Sopenharmony_ci	 */
12068c2ecf20Sopenharmony_ci	skb_get(skb);
12078c2ecf20Sopenharmony_ci	t4_set_arp_err_handler(skb, NULL, mpa_start_arp_failure);
12088c2ecf20Sopenharmony_ci	ep->mpa_skb = skb;
12098c2ecf20Sopenharmony_ci	__state_set(&ep->com, MPA_REP_SENT);
12108c2ecf20Sopenharmony_ci	ep->snd_seq += mpalen;
12118c2ecf20Sopenharmony_ci	return c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
12128c2ecf20Sopenharmony_ci}
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_cistatic int act_establish(struct c4iw_dev *dev, struct sk_buff *skb)
12158c2ecf20Sopenharmony_ci{
12168c2ecf20Sopenharmony_ci	struct c4iw_ep *ep;
12178c2ecf20Sopenharmony_ci	struct cpl_act_establish *req = cplhdr(skb);
12188c2ecf20Sopenharmony_ci	unsigned short tcp_opt = ntohs(req->tcp_opt);
12198c2ecf20Sopenharmony_ci	unsigned int tid = GET_TID(req);
12208c2ecf20Sopenharmony_ci	unsigned int atid = TID_TID_G(ntohl(req->tos_atid));
12218c2ecf20Sopenharmony_ci	struct tid_info *t = dev->rdev.lldi.tids;
12228c2ecf20Sopenharmony_ci	int ret;
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci	ep = lookup_atid(t, atid);
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u snd_isn %u rcv_isn %u\n", ep, tid,
12278c2ecf20Sopenharmony_ci		 be32_to_cpu(req->snd_isn), be32_to_cpu(req->rcv_isn));
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci	mutex_lock(&ep->com.mutex);
12308c2ecf20Sopenharmony_ci	dst_confirm(ep->dst);
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ci	/* setup the hwtid for this connection */
12338c2ecf20Sopenharmony_ci	ep->hwtid = tid;
12348c2ecf20Sopenharmony_ci	cxgb4_insert_tid(t, ep, tid, ep->com.local_addr.ss_family);
12358c2ecf20Sopenharmony_ci	insert_ep_tid(ep);
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	ep->snd_seq = be32_to_cpu(req->snd_isn);
12388c2ecf20Sopenharmony_ci	ep->rcv_seq = be32_to_cpu(req->rcv_isn);
12398c2ecf20Sopenharmony_ci	ep->snd_wscale = TCPOPT_SND_WSCALE_G(tcp_opt);
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci	set_emss(ep, tcp_opt);
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	/* dealloc the atid */
12448c2ecf20Sopenharmony_ci	xa_erase_irq(&ep->com.dev->atids, atid);
12458c2ecf20Sopenharmony_ci	cxgb4_free_atid(t, atid);
12468c2ecf20Sopenharmony_ci	set_bit(ACT_ESTAB, &ep->com.history);
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci	/* start MPA negotiation */
12498c2ecf20Sopenharmony_ci	ret = send_flowc(ep);
12508c2ecf20Sopenharmony_ci	if (ret)
12518c2ecf20Sopenharmony_ci		goto err;
12528c2ecf20Sopenharmony_ci	if (ep->retry_with_mpa_v1)
12538c2ecf20Sopenharmony_ci		ret = send_mpa_req(ep, skb, 1);
12548c2ecf20Sopenharmony_ci	else
12558c2ecf20Sopenharmony_ci		ret = send_mpa_req(ep, skb, mpa_rev);
12568c2ecf20Sopenharmony_ci	if (ret)
12578c2ecf20Sopenharmony_ci		goto err;
12588c2ecf20Sopenharmony_ci	mutex_unlock(&ep->com.mutex);
12598c2ecf20Sopenharmony_ci	return 0;
12608c2ecf20Sopenharmony_cierr:
12618c2ecf20Sopenharmony_ci	mutex_unlock(&ep->com.mutex);
12628c2ecf20Sopenharmony_ci	connect_reply_upcall(ep, -ENOMEM);
12638c2ecf20Sopenharmony_ci	c4iw_ep_disconnect(ep, 0, GFP_KERNEL);
12648c2ecf20Sopenharmony_ci	return 0;
12658c2ecf20Sopenharmony_ci}
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_cistatic void close_complete_upcall(struct c4iw_ep *ep, int status)
12688c2ecf20Sopenharmony_ci{
12698c2ecf20Sopenharmony_ci	struct iw_cm_event event;
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u\n", ep, ep->hwtid);
12728c2ecf20Sopenharmony_ci	memset(&event, 0, sizeof(event));
12738c2ecf20Sopenharmony_ci	event.event = IW_CM_EVENT_CLOSE;
12748c2ecf20Sopenharmony_ci	event.status = status;
12758c2ecf20Sopenharmony_ci	if (ep->com.cm_id) {
12768c2ecf20Sopenharmony_ci		pr_debug("close complete delivered ep %p cm_id %p tid %u\n",
12778c2ecf20Sopenharmony_ci			 ep, ep->com.cm_id, ep->hwtid);
12788c2ecf20Sopenharmony_ci		ep->com.cm_id->event_handler(ep->com.cm_id, &event);
12798c2ecf20Sopenharmony_ci		deref_cm_id(&ep->com);
12808c2ecf20Sopenharmony_ci		set_bit(CLOSE_UPCALL, &ep->com.history);
12818c2ecf20Sopenharmony_ci	}
12828c2ecf20Sopenharmony_ci}
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_cistatic void peer_close_upcall(struct c4iw_ep *ep)
12858c2ecf20Sopenharmony_ci{
12868c2ecf20Sopenharmony_ci	struct iw_cm_event event;
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u\n", ep, ep->hwtid);
12898c2ecf20Sopenharmony_ci	memset(&event, 0, sizeof(event));
12908c2ecf20Sopenharmony_ci	event.event = IW_CM_EVENT_DISCONNECT;
12918c2ecf20Sopenharmony_ci	if (ep->com.cm_id) {
12928c2ecf20Sopenharmony_ci		pr_debug("peer close delivered ep %p cm_id %p tid %u\n",
12938c2ecf20Sopenharmony_ci			 ep, ep->com.cm_id, ep->hwtid);
12948c2ecf20Sopenharmony_ci		ep->com.cm_id->event_handler(ep->com.cm_id, &event);
12958c2ecf20Sopenharmony_ci		set_bit(DISCONN_UPCALL, &ep->com.history);
12968c2ecf20Sopenharmony_ci	}
12978c2ecf20Sopenharmony_ci}
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_cistatic void peer_abort_upcall(struct c4iw_ep *ep)
13008c2ecf20Sopenharmony_ci{
13018c2ecf20Sopenharmony_ci	struct iw_cm_event event;
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u\n", ep, ep->hwtid);
13048c2ecf20Sopenharmony_ci	memset(&event, 0, sizeof(event));
13058c2ecf20Sopenharmony_ci	event.event = IW_CM_EVENT_CLOSE;
13068c2ecf20Sopenharmony_ci	event.status = -ECONNRESET;
13078c2ecf20Sopenharmony_ci	if (ep->com.cm_id) {
13088c2ecf20Sopenharmony_ci		pr_debug("abort delivered ep %p cm_id %p tid %u\n", ep,
13098c2ecf20Sopenharmony_ci			 ep->com.cm_id, ep->hwtid);
13108c2ecf20Sopenharmony_ci		ep->com.cm_id->event_handler(ep->com.cm_id, &event);
13118c2ecf20Sopenharmony_ci		deref_cm_id(&ep->com);
13128c2ecf20Sopenharmony_ci		set_bit(ABORT_UPCALL, &ep->com.history);
13138c2ecf20Sopenharmony_ci	}
13148c2ecf20Sopenharmony_ci}
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_cistatic void connect_reply_upcall(struct c4iw_ep *ep, int status)
13178c2ecf20Sopenharmony_ci{
13188c2ecf20Sopenharmony_ci	struct iw_cm_event event;
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u status %d\n",
13218c2ecf20Sopenharmony_ci		 ep, ep->hwtid, status);
13228c2ecf20Sopenharmony_ci	memset(&event, 0, sizeof(event));
13238c2ecf20Sopenharmony_ci	event.event = IW_CM_EVENT_CONNECT_REPLY;
13248c2ecf20Sopenharmony_ci	event.status = status;
13258c2ecf20Sopenharmony_ci	memcpy(&event.local_addr, &ep->com.local_addr,
13268c2ecf20Sopenharmony_ci	       sizeof(ep->com.local_addr));
13278c2ecf20Sopenharmony_ci	memcpy(&event.remote_addr, &ep->com.remote_addr,
13288c2ecf20Sopenharmony_ci	       sizeof(ep->com.remote_addr));
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci	if ((status == 0) || (status == -ECONNREFUSED)) {
13318c2ecf20Sopenharmony_ci		if (!ep->tried_with_mpa_v1) {
13328c2ecf20Sopenharmony_ci			/* this means MPA_v2 is used */
13338c2ecf20Sopenharmony_ci			event.ord = ep->ird;
13348c2ecf20Sopenharmony_ci			event.ird = ep->ord;
13358c2ecf20Sopenharmony_ci			event.private_data_len = ep->plen -
13368c2ecf20Sopenharmony_ci				sizeof(struct mpa_v2_conn_params);
13378c2ecf20Sopenharmony_ci			event.private_data = ep->mpa_pkt +
13388c2ecf20Sopenharmony_ci				sizeof(struct mpa_message) +
13398c2ecf20Sopenharmony_ci				sizeof(struct mpa_v2_conn_params);
13408c2ecf20Sopenharmony_ci		} else {
13418c2ecf20Sopenharmony_ci			/* this means MPA_v1 is used */
13428c2ecf20Sopenharmony_ci			event.ord = cur_max_read_depth(ep->com.dev);
13438c2ecf20Sopenharmony_ci			event.ird = cur_max_read_depth(ep->com.dev);
13448c2ecf20Sopenharmony_ci			event.private_data_len = ep->plen;
13458c2ecf20Sopenharmony_ci			event.private_data = ep->mpa_pkt +
13468c2ecf20Sopenharmony_ci				sizeof(struct mpa_message);
13478c2ecf20Sopenharmony_ci		}
13488c2ecf20Sopenharmony_ci	}
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u status %d\n", ep,
13518c2ecf20Sopenharmony_ci		 ep->hwtid, status);
13528c2ecf20Sopenharmony_ci	set_bit(CONN_RPL_UPCALL, &ep->com.history);
13538c2ecf20Sopenharmony_ci	ep->com.cm_id->event_handler(ep->com.cm_id, &event);
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci	if (status < 0)
13568c2ecf20Sopenharmony_ci		deref_cm_id(&ep->com);
13578c2ecf20Sopenharmony_ci}
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_cistatic int connect_request_upcall(struct c4iw_ep *ep)
13608c2ecf20Sopenharmony_ci{
13618c2ecf20Sopenharmony_ci	struct iw_cm_event event;
13628c2ecf20Sopenharmony_ci	int ret;
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u\n", ep, ep->hwtid);
13658c2ecf20Sopenharmony_ci	memset(&event, 0, sizeof(event));
13668c2ecf20Sopenharmony_ci	event.event = IW_CM_EVENT_CONNECT_REQUEST;
13678c2ecf20Sopenharmony_ci	memcpy(&event.local_addr, &ep->com.local_addr,
13688c2ecf20Sopenharmony_ci	       sizeof(ep->com.local_addr));
13698c2ecf20Sopenharmony_ci	memcpy(&event.remote_addr, &ep->com.remote_addr,
13708c2ecf20Sopenharmony_ci	       sizeof(ep->com.remote_addr));
13718c2ecf20Sopenharmony_ci	event.provider_data = ep;
13728c2ecf20Sopenharmony_ci	if (!ep->tried_with_mpa_v1) {
13738c2ecf20Sopenharmony_ci		/* this means MPA_v2 is used */
13748c2ecf20Sopenharmony_ci		event.ord = ep->ord;
13758c2ecf20Sopenharmony_ci		event.ird = ep->ird;
13768c2ecf20Sopenharmony_ci		event.private_data_len = ep->plen -
13778c2ecf20Sopenharmony_ci			sizeof(struct mpa_v2_conn_params);
13788c2ecf20Sopenharmony_ci		event.private_data = ep->mpa_pkt + sizeof(struct mpa_message) +
13798c2ecf20Sopenharmony_ci			sizeof(struct mpa_v2_conn_params);
13808c2ecf20Sopenharmony_ci	} else {
13818c2ecf20Sopenharmony_ci		/* this means MPA_v1 is used. Send max supported */
13828c2ecf20Sopenharmony_ci		event.ord = cur_max_read_depth(ep->com.dev);
13838c2ecf20Sopenharmony_ci		event.ird = cur_max_read_depth(ep->com.dev);
13848c2ecf20Sopenharmony_ci		event.private_data_len = ep->plen;
13858c2ecf20Sopenharmony_ci		event.private_data = ep->mpa_pkt + sizeof(struct mpa_message);
13868c2ecf20Sopenharmony_ci	}
13878c2ecf20Sopenharmony_ci	c4iw_get_ep(&ep->com);
13888c2ecf20Sopenharmony_ci	ret = ep->parent_ep->com.cm_id->event_handler(ep->parent_ep->com.cm_id,
13898c2ecf20Sopenharmony_ci						      &event);
13908c2ecf20Sopenharmony_ci	if (ret)
13918c2ecf20Sopenharmony_ci		c4iw_put_ep(&ep->com);
13928c2ecf20Sopenharmony_ci	set_bit(CONNREQ_UPCALL, &ep->com.history);
13938c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->parent_ep->com);
13948c2ecf20Sopenharmony_ci	return ret;
13958c2ecf20Sopenharmony_ci}
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_cistatic void established_upcall(struct c4iw_ep *ep)
13988c2ecf20Sopenharmony_ci{
13998c2ecf20Sopenharmony_ci	struct iw_cm_event event;
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u\n", ep, ep->hwtid);
14028c2ecf20Sopenharmony_ci	memset(&event, 0, sizeof(event));
14038c2ecf20Sopenharmony_ci	event.event = IW_CM_EVENT_ESTABLISHED;
14048c2ecf20Sopenharmony_ci	event.ird = ep->ord;
14058c2ecf20Sopenharmony_ci	event.ord = ep->ird;
14068c2ecf20Sopenharmony_ci	if (ep->com.cm_id) {
14078c2ecf20Sopenharmony_ci		pr_debug("ep %p tid %u\n", ep, ep->hwtid);
14088c2ecf20Sopenharmony_ci		ep->com.cm_id->event_handler(ep->com.cm_id, &event);
14098c2ecf20Sopenharmony_ci		set_bit(ESTAB_UPCALL, &ep->com.history);
14108c2ecf20Sopenharmony_ci	}
14118c2ecf20Sopenharmony_ci}
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_cistatic int update_rx_credits(struct c4iw_ep *ep, u32 credits)
14148c2ecf20Sopenharmony_ci{
14158c2ecf20Sopenharmony_ci	struct sk_buff *skb;
14168c2ecf20Sopenharmony_ci	u32 wrlen = roundup(sizeof(struct cpl_rx_data_ack), 16);
14178c2ecf20Sopenharmony_ci	u32 credit_dack;
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u credits %u\n",
14208c2ecf20Sopenharmony_ci		 ep, ep->hwtid, credits);
14218c2ecf20Sopenharmony_ci	skb = get_skb(NULL, wrlen, GFP_KERNEL);
14228c2ecf20Sopenharmony_ci	if (!skb) {
14238c2ecf20Sopenharmony_ci		pr_err("update_rx_credits - cannot alloc skb!\n");
14248c2ecf20Sopenharmony_ci		return 0;
14258c2ecf20Sopenharmony_ci	}
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_ci	/*
14288c2ecf20Sopenharmony_ci	 * If we couldn't specify the entire rcv window at connection setup
14298c2ecf20Sopenharmony_ci	 * due to the limit in the number of bits in the RCV_BUFSIZ field,
14308c2ecf20Sopenharmony_ci	 * then add the overage in to the credits returned.
14318c2ecf20Sopenharmony_ci	 */
14328c2ecf20Sopenharmony_ci	if (ep->rcv_win > RCV_BUFSIZ_M * 1024)
14338c2ecf20Sopenharmony_ci		credits += ep->rcv_win - RCV_BUFSIZ_M * 1024;
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_ci	credit_dack = credits | RX_FORCE_ACK_F | RX_DACK_CHANGE_F |
14368c2ecf20Sopenharmony_ci		      RX_DACK_MODE_V(dack_mode);
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci	cxgb_mk_rx_data_ack(skb, wrlen, ep->hwtid, ep->ctrlq_idx,
14398c2ecf20Sopenharmony_ci			    credit_dack);
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci	c4iw_ofld_send(&ep->com.dev->rdev, skb);
14428c2ecf20Sopenharmony_ci	return credits;
14438c2ecf20Sopenharmony_ci}
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_ci#define RELAXED_IRD_NEGOTIATION 1
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci/*
14488c2ecf20Sopenharmony_ci * process_mpa_reply - process streaming mode MPA reply
14498c2ecf20Sopenharmony_ci *
14508c2ecf20Sopenharmony_ci * Returns:
14518c2ecf20Sopenharmony_ci *
14528c2ecf20Sopenharmony_ci * 0 upon success indicating a connect request was delivered to the ULP
14538c2ecf20Sopenharmony_ci * or the mpa request is incomplete but valid so far.
14548c2ecf20Sopenharmony_ci *
14558c2ecf20Sopenharmony_ci * 1 if a failure requires the caller to close the connection.
14568c2ecf20Sopenharmony_ci *
14578c2ecf20Sopenharmony_ci * 2 if a failure requires the caller to abort the connection.
14588c2ecf20Sopenharmony_ci */
14598c2ecf20Sopenharmony_cistatic int process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)
14608c2ecf20Sopenharmony_ci{
14618c2ecf20Sopenharmony_ci	struct mpa_message *mpa;
14628c2ecf20Sopenharmony_ci	struct mpa_v2_conn_params *mpa_v2_params;
14638c2ecf20Sopenharmony_ci	u16 plen;
14648c2ecf20Sopenharmony_ci	u16 resp_ird, resp_ord;
14658c2ecf20Sopenharmony_ci	u8 rtr_mismatch = 0, insuff_ird = 0;
14668c2ecf20Sopenharmony_ci	struct c4iw_qp_attributes attrs;
14678c2ecf20Sopenharmony_ci	enum c4iw_qp_attr_mask mask;
14688c2ecf20Sopenharmony_ci	int err;
14698c2ecf20Sopenharmony_ci	int disconnect = 0;
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u\n", ep, ep->hwtid);
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	/*
14748c2ecf20Sopenharmony_ci	 * If we get more than the supported amount of private data
14758c2ecf20Sopenharmony_ci	 * then we must fail this connection.
14768c2ecf20Sopenharmony_ci	 */
14778c2ecf20Sopenharmony_ci	if (ep->mpa_pkt_len + skb->len > sizeof(ep->mpa_pkt)) {
14788c2ecf20Sopenharmony_ci		err = -EINVAL;
14798c2ecf20Sopenharmony_ci		goto err_stop_timer;
14808c2ecf20Sopenharmony_ci	}
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci	/*
14838c2ecf20Sopenharmony_ci	 * copy the new data into our accumulation buffer.
14848c2ecf20Sopenharmony_ci	 */
14858c2ecf20Sopenharmony_ci	skb_copy_from_linear_data(skb, &(ep->mpa_pkt[ep->mpa_pkt_len]),
14868c2ecf20Sopenharmony_ci				  skb->len);
14878c2ecf20Sopenharmony_ci	ep->mpa_pkt_len += skb->len;
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci	/*
14908c2ecf20Sopenharmony_ci	 * if we don't even have the mpa message, then bail.
14918c2ecf20Sopenharmony_ci	 */
14928c2ecf20Sopenharmony_ci	if (ep->mpa_pkt_len < sizeof(*mpa))
14938c2ecf20Sopenharmony_ci		return 0;
14948c2ecf20Sopenharmony_ci	mpa = (struct mpa_message *) ep->mpa_pkt;
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	/* Validate MPA header. */
14978c2ecf20Sopenharmony_ci	if (mpa->revision > mpa_rev) {
14988c2ecf20Sopenharmony_ci		pr_err("%s MPA version mismatch. Local = %d, Received = %d\n",
14998c2ecf20Sopenharmony_ci		       __func__, mpa_rev, mpa->revision);
15008c2ecf20Sopenharmony_ci		err = -EPROTO;
15018c2ecf20Sopenharmony_ci		goto err_stop_timer;
15028c2ecf20Sopenharmony_ci	}
15038c2ecf20Sopenharmony_ci	if (memcmp(mpa->key, MPA_KEY_REP, sizeof(mpa->key))) {
15048c2ecf20Sopenharmony_ci		err = -EPROTO;
15058c2ecf20Sopenharmony_ci		goto err_stop_timer;
15068c2ecf20Sopenharmony_ci	}
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci	plen = ntohs(mpa->private_data_size);
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci	/*
15118c2ecf20Sopenharmony_ci	 * Fail if there's too much private data.
15128c2ecf20Sopenharmony_ci	 */
15138c2ecf20Sopenharmony_ci	if (plen > MPA_MAX_PRIVATE_DATA) {
15148c2ecf20Sopenharmony_ci		err = -EPROTO;
15158c2ecf20Sopenharmony_ci		goto err_stop_timer;
15168c2ecf20Sopenharmony_ci	}
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci	/*
15198c2ecf20Sopenharmony_ci	 * If plen does not account for pkt size
15208c2ecf20Sopenharmony_ci	 */
15218c2ecf20Sopenharmony_ci	if (ep->mpa_pkt_len > (sizeof(*mpa) + plen)) {
15228c2ecf20Sopenharmony_ci		err = -EPROTO;
15238c2ecf20Sopenharmony_ci		goto err_stop_timer;
15248c2ecf20Sopenharmony_ci	}
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_ci	ep->plen = (u8) plen;
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci	/*
15298c2ecf20Sopenharmony_ci	 * If we don't have all the pdata yet, then bail.
15308c2ecf20Sopenharmony_ci	 * We'll continue process when more data arrives.
15318c2ecf20Sopenharmony_ci	 */
15328c2ecf20Sopenharmony_ci	if (ep->mpa_pkt_len < (sizeof(*mpa) + plen))
15338c2ecf20Sopenharmony_ci		return 0;
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci	if (mpa->flags & MPA_REJECT) {
15368c2ecf20Sopenharmony_ci		err = -ECONNREFUSED;
15378c2ecf20Sopenharmony_ci		goto err_stop_timer;
15388c2ecf20Sopenharmony_ci	}
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci	/*
15418c2ecf20Sopenharmony_ci	 * Stop mpa timer.  If it expired, then
15428c2ecf20Sopenharmony_ci	 * we ignore the MPA reply.  process_timeout()
15438c2ecf20Sopenharmony_ci	 * will abort the connection.
15448c2ecf20Sopenharmony_ci	 */
15458c2ecf20Sopenharmony_ci	if (stop_ep_timer(ep))
15468c2ecf20Sopenharmony_ci		return 0;
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci	/*
15498c2ecf20Sopenharmony_ci	 * If we get here we have accumulated the entire mpa
15508c2ecf20Sopenharmony_ci	 * start reply message including private data. And
15518c2ecf20Sopenharmony_ci	 * the MPA header is valid.
15528c2ecf20Sopenharmony_ci	 */
15538c2ecf20Sopenharmony_ci	__state_set(&ep->com, FPDU_MODE);
15548c2ecf20Sopenharmony_ci	ep->mpa_attr.crc_enabled = (mpa->flags & MPA_CRC) | crc_enabled ? 1 : 0;
15558c2ecf20Sopenharmony_ci	ep->mpa_attr.xmit_marker_enabled = mpa->flags & MPA_MARKERS ? 1 : 0;
15568c2ecf20Sopenharmony_ci	ep->mpa_attr.version = mpa->revision;
15578c2ecf20Sopenharmony_ci	ep->mpa_attr.p2p_type = FW_RI_INIT_P2PTYPE_DISABLED;
15588c2ecf20Sopenharmony_ci
15598c2ecf20Sopenharmony_ci	if (mpa->revision == 2) {
15608c2ecf20Sopenharmony_ci		ep->mpa_attr.enhanced_rdma_conn =
15618c2ecf20Sopenharmony_ci			mpa->flags & MPA_ENHANCED_RDMA_CONN ? 1 : 0;
15628c2ecf20Sopenharmony_ci		if (ep->mpa_attr.enhanced_rdma_conn) {
15638c2ecf20Sopenharmony_ci			mpa_v2_params = (struct mpa_v2_conn_params *)
15648c2ecf20Sopenharmony_ci				(ep->mpa_pkt + sizeof(*mpa));
15658c2ecf20Sopenharmony_ci			resp_ird = ntohs(mpa_v2_params->ird) &
15668c2ecf20Sopenharmony_ci				MPA_V2_IRD_ORD_MASK;
15678c2ecf20Sopenharmony_ci			resp_ord = ntohs(mpa_v2_params->ord) &
15688c2ecf20Sopenharmony_ci				MPA_V2_IRD_ORD_MASK;
15698c2ecf20Sopenharmony_ci			pr_debug("responder ird %u ord %u ep ird %u ord %u\n",
15708c2ecf20Sopenharmony_ci				 resp_ird, resp_ord, ep->ird, ep->ord);
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci			/*
15738c2ecf20Sopenharmony_ci			 * This is a double-check. Ideally, below checks are
15748c2ecf20Sopenharmony_ci			 * not required since ird/ord stuff has been taken
15758c2ecf20Sopenharmony_ci			 * care of in c4iw_accept_cr
15768c2ecf20Sopenharmony_ci			 */
15778c2ecf20Sopenharmony_ci			if (ep->ird < resp_ord) {
15788c2ecf20Sopenharmony_ci				if (RELAXED_IRD_NEGOTIATION && resp_ord <=
15798c2ecf20Sopenharmony_ci				    ep->com.dev->rdev.lldi.max_ordird_qp)
15808c2ecf20Sopenharmony_ci					ep->ird = resp_ord;
15818c2ecf20Sopenharmony_ci				else
15828c2ecf20Sopenharmony_ci					insuff_ird = 1;
15838c2ecf20Sopenharmony_ci			} else if (ep->ird > resp_ord) {
15848c2ecf20Sopenharmony_ci				ep->ird = resp_ord;
15858c2ecf20Sopenharmony_ci			}
15868c2ecf20Sopenharmony_ci			if (ep->ord > resp_ird) {
15878c2ecf20Sopenharmony_ci				if (RELAXED_IRD_NEGOTIATION)
15888c2ecf20Sopenharmony_ci					ep->ord = resp_ird;
15898c2ecf20Sopenharmony_ci				else
15908c2ecf20Sopenharmony_ci					insuff_ird = 1;
15918c2ecf20Sopenharmony_ci			}
15928c2ecf20Sopenharmony_ci			if (insuff_ird) {
15938c2ecf20Sopenharmony_ci				err = -ENOMEM;
15948c2ecf20Sopenharmony_ci				ep->ird = resp_ord;
15958c2ecf20Sopenharmony_ci				ep->ord = resp_ird;
15968c2ecf20Sopenharmony_ci			}
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_ci			if (ntohs(mpa_v2_params->ird) &
15998c2ecf20Sopenharmony_ci					MPA_V2_PEER2PEER_MODEL) {
16008c2ecf20Sopenharmony_ci				if (ntohs(mpa_v2_params->ord) &
16018c2ecf20Sopenharmony_ci						MPA_V2_RDMA_WRITE_RTR)
16028c2ecf20Sopenharmony_ci					ep->mpa_attr.p2p_type =
16038c2ecf20Sopenharmony_ci						FW_RI_INIT_P2PTYPE_RDMA_WRITE;
16048c2ecf20Sopenharmony_ci				else if (ntohs(mpa_v2_params->ord) &
16058c2ecf20Sopenharmony_ci						MPA_V2_RDMA_READ_RTR)
16068c2ecf20Sopenharmony_ci					ep->mpa_attr.p2p_type =
16078c2ecf20Sopenharmony_ci						FW_RI_INIT_P2PTYPE_READ_REQ;
16088c2ecf20Sopenharmony_ci			}
16098c2ecf20Sopenharmony_ci		}
16108c2ecf20Sopenharmony_ci	} else if (mpa->revision == 1)
16118c2ecf20Sopenharmony_ci		if (peer2peer)
16128c2ecf20Sopenharmony_ci			ep->mpa_attr.p2p_type = p2p_type;
16138c2ecf20Sopenharmony_ci
16148c2ecf20Sopenharmony_ci	pr_debug("crc_enabled=%d, recv_marker_enabled=%d, xmit_marker_enabled=%d, version=%d p2p_type=%d local-p2p_type = %d\n",
16158c2ecf20Sopenharmony_ci		 ep->mpa_attr.crc_enabled,
16168c2ecf20Sopenharmony_ci		 ep->mpa_attr.recv_marker_enabled,
16178c2ecf20Sopenharmony_ci		 ep->mpa_attr.xmit_marker_enabled, ep->mpa_attr.version,
16188c2ecf20Sopenharmony_ci		 ep->mpa_attr.p2p_type, p2p_type);
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci	/*
16218c2ecf20Sopenharmony_ci	 * If responder's RTR does not match with that of initiator, assign
16228c2ecf20Sopenharmony_ci	 * FW_RI_INIT_P2PTYPE_DISABLED in mpa attributes so that RTR is not
16238c2ecf20Sopenharmony_ci	 * generated when moving QP to RTS state.
16248c2ecf20Sopenharmony_ci	 * A TERM message will be sent after QP has moved to RTS state
16258c2ecf20Sopenharmony_ci	 */
16268c2ecf20Sopenharmony_ci	if ((ep->mpa_attr.version == 2) && peer2peer &&
16278c2ecf20Sopenharmony_ci			(ep->mpa_attr.p2p_type != p2p_type)) {
16288c2ecf20Sopenharmony_ci		ep->mpa_attr.p2p_type = FW_RI_INIT_P2PTYPE_DISABLED;
16298c2ecf20Sopenharmony_ci		rtr_mismatch = 1;
16308c2ecf20Sopenharmony_ci	}
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci	attrs.mpa_attr = ep->mpa_attr;
16338c2ecf20Sopenharmony_ci	attrs.max_ird = ep->ird;
16348c2ecf20Sopenharmony_ci	attrs.max_ord = ep->ord;
16358c2ecf20Sopenharmony_ci	attrs.llp_stream_handle = ep;
16368c2ecf20Sopenharmony_ci	attrs.next_state = C4IW_QP_STATE_RTS;
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci	mask = C4IW_QP_ATTR_NEXT_STATE |
16398c2ecf20Sopenharmony_ci	    C4IW_QP_ATTR_LLP_STREAM_HANDLE | C4IW_QP_ATTR_MPA_ATTR |
16408c2ecf20Sopenharmony_ci	    C4IW_QP_ATTR_MAX_IRD | C4IW_QP_ATTR_MAX_ORD;
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_ci	/* bind QP and TID with INIT_WR */
16438c2ecf20Sopenharmony_ci	err = c4iw_modify_qp(ep->com.qp->rhp,
16448c2ecf20Sopenharmony_ci			     ep->com.qp, mask, &attrs, 1);
16458c2ecf20Sopenharmony_ci	if (err)
16468c2ecf20Sopenharmony_ci		goto err;
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_ci	/*
16498c2ecf20Sopenharmony_ci	 * If responder's RTR requirement did not match with what initiator
16508c2ecf20Sopenharmony_ci	 * supports, generate TERM message
16518c2ecf20Sopenharmony_ci	 */
16528c2ecf20Sopenharmony_ci	if (rtr_mismatch) {
16538c2ecf20Sopenharmony_ci		pr_err("%s: RTR mismatch, sending TERM\n", __func__);
16548c2ecf20Sopenharmony_ci		attrs.layer_etype = LAYER_MPA | DDP_LLP;
16558c2ecf20Sopenharmony_ci		attrs.ecode = MPA_NOMATCH_RTR;
16568c2ecf20Sopenharmony_ci		attrs.next_state = C4IW_QP_STATE_TERMINATE;
16578c2ecf20Sopenharmony_ci		attrs.send_term = 1;
16588c2ecf20Sopenharmony_ci		err = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
16598c2ecf20Sopenharmony_ci				C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
16608c2ecf20Sopenharmony_ci		err = -ENOMEM;
16618c2ecf20Sopenharmony_ci		disconnect = 1;
16628c2ecf20Sopenharmony_ci		goto out;
16638c2ecf20Sopenharmony_ci	}
16648c2ecf20Sopenharmony_ci
16658c2ecf20Sopenharmony_ci	/*
16668c2ecf20Sopenharmony_ci	 * Generate TERM if initiator IRD is not sufficient for responder
16678c2ecf20Sopenharmony_ci	 * provided ORD. Currently, we do the same behaviour even when
16688c2ecf20Sopenharmony_ci	 * responder provided IRD is also not sufficient as regards to
16698c2ecf20Sopenharmony_ci	 * initiator ORD.
16708c2ecf20Sopenharmony_ci	 */
16718c2ecf20Sopenharmony_ci	if (insuff_ird) {
16728c2ecf20Sopenharmony_ci		pr_err("%s: Insufficient IRD, sending TERM\n", __func__);
16738c2ecf20Sopenharmony_ci		attrs.layer_etype = LAYER_MPA | DDP_LLP;
16748c2ecf20Sopenharmony_ci		attrs.ecode = MPA_INSUFF_IRD;
16758c2ecf20Sopenharmony_ci		attrs.next_state = C4IW_QP_STATE_TERMINATE;
16768c2ecf20Sopenharmony_ci		attrs.send_term = 1;
16778c2ecf20Sopenharmony_ci		err = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
16788c2ecf20Sopenharmony_ci				C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
16798c2ecf20Sopenharmony_ci		err = -ENOMEM;
16808c2ecf20Sopenharmony_ci		disconnect = 1;
16818c2ecf20Sopenharmony_ci		goto out;
16828c2ecf20Sopenharmony_ci	}
16838c2ecf20Sopenharmony_ci	goto out;
16848c2ecf20Sopenharmony_cierr_stop_timer:
16858c2ecf20Sopenharmony_ci	stop_ep_timer(ep);
16868c2ecf20Sopenharmony_cierr:
16878c2ecf20Sopenharmony_ci	disconnect = 2;
16888c2ecf20Sopenharmony_ciout:
16898c2ecf20Sopenharmony_ci	connect_reply_upcall(ep, err);
16908c2ecf20Sopenharmony_ci	return disconnect;
16918c2ecf20Sopenharmony_ci}
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci/*
16948c2ecf20Sopenharmony_ci * process_mpa_request - process streaming mode MPA request
16958c2ecf20Sopenharmony_ci *
16968c2ecf20Sopenharmony_ci * Returns:
16978c2ecf20Sopenharmony_ci *
16988c2ecf20Sopenharmony_ci * 0 upon success indicating a connect request was delivered to the ULP
16998c2ecf20Sopenharmony_ci * or the mpa request is incomplete but valid so far.
17008c2ecf20Sopenharmony_ci *
17018c2ecf20Sopenharmony_ci * 1 if a failure requires the caller to close the connection.
17028c2ecf20Sopenharmony_ci *
17038c2ecf20Sopenharmony_ci * 2 if a failure requires the caller to abort the connection.
17048c2ecf20Sopenharmony_ci */
17058c2ecf20Sopenharmony_cistatic int process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb)
17068c2ecf20Sopenharmony_ci{
17078c2ecf20Sopenharmony_ci	struct mpa_message *mpa;
17088c2ecf20Sopenharmony_ci	struct mpa_v2_conn_params *mpa_v2_params;
17098c2ecf20Sopenharmony_ci	u16 plen;
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u\n", ep, ep->hwtid);
17128c2ecf20Sopenharmony_ci
17138c2ecf20Sopenharmony_ci	/*
17148c2ecf20Sopenharmony_ci	 * If we get more than the supported amount of private data
17158c2ecf20Sopenharmony_ci	 * then we must fail this connection.
17168c2ecf20Sopenharmony_ci	 */
17178c2ecf20Sopenharmony_ci	if (ep->mpa_pkt_len + skb->len > sizeof(ep->mpa_pkt))
17188c2ecf20Sopenharmony_ci		goto err_stop_timer;
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ci	pr_debug("enter (%s line %u)\n", __FILE__, __LINE__);
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci	/*
17238c2ecf20Sopenharmony_ci	 * Copy the new data into our accumulation buffer.
17248c2ecf20Sopenharmony_ci	 */
17258c2ecf20Sopenharmony_ci	skb_copy_from_linear_data(skb, &(ep->mpa_pkt[ep->mpa_pkt_len]),
17268c2ecf20Sopenharmony_ci				  skb->len);
17278c2ecf20Sopenharmony_ci	ep->mpa_pkt_len += skb->len;
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_ci	/*
17308c2ecf20Sopenharmony_ci	 * If we don't even have the mpa message, then bail.
17318c2ecf20Sopenharmony_ci	 * We'll continue process when more data arrives.
17328c2ecf20Sopenharmony_ci	 */
17338c2ecf20Sopenharmony_ci	if (ep->mpa_pkt_len < sizeof(*mpa))
17348c2ecf20Sopenharmony_ci		return 0;
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_ci	pr_debug("enter (%s line %u)\n", __FILE__, __LINE__);
17378c2ecf20Sopenharmony_ci	mpa = (struct mpa_message *) ep->mpa_pkt;
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_ci	/*
17408c2ecf20Sopenharmony_ci	 * Validate MPA Header.
17418c2ecf20Sopenharmony_ci	 */
17428c2ecf20Sopenharmony_ci	if (mpa->revision > mpa_rev) {
17438c2ecf20Sopenharmony_ci		pr_err("%s MPA version mismatch. Local = %d, Received = %d\n",
17448c2ecf20Sopenharmony_ci		       __func__, mpa_rev, mpa->revision);
17458c2ecf20Sopenharmony_ci		goto err_stop_timer;
17468c2ecf20Sopenharmony_ci	}
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_ci	if (memcmp(mpa->key, MPA_KEY_REQ, sizeof(mpa->key)))
17498c2ecf20Sopenharmony_ci		goto err_stop_timer;
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_ci	plen = ntohs(mpa->private_data_size);
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_ci	/*
17548c2ecf20Sopenharmony_ci	 * Fail if there's too much private data.
17558c2ecf20Sopenharmony_ci	 */
17568c2ecf20Sopenharmony_ci	if (plen > MPA_MAX_PRIVATE_DATA)
17578c2ecf20Sopenharmony_ci		goto err_stop_timer;
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci	/*
17608c2ecf20Sopenharmony_ci	 * If plen does not account for pkt size
17618c2ecf20Sopenharmony_ci	 */
17628c2ecf20Sopenharmony_ci	if (ep->mpa_pkt_len > (sizeof(*mpa) + plen))
17638c2ecf20Sopenharmony_ci		goto err_stop_timer;
17648c2ecf20Sopenharmony_ci	ep->plen = (u8) plen;
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_ci	/*
17678c2ecf20Sopenharmony_ci	 * If we don't have all the pdata yet, then bail.
17688c2ecf20Sopenharmony_ci	 */
17698c2ecf20Sopenharmony_ci	if (ep->mpa_pkt_len < (sizeof(*mpa) + plen))
17708c2ecf20Sopenharmony_ci		return 0;
17718c2ecf20Sopenharmony_ci
17728c2ecf20Sopenharmony_ci	/*
17738c2ecf20Sopenharmony_ci	 * If we get here we have accumulated the entire mpa
17748c2ecf20Sopenharmony_ci	 * start reply message including private data.
17758c2ecf20Sopenharmony_ci	 */
17768c2ecf20Sopenharmony_ci	ep->mpa_attr.initiator = 0;
17778c2ecf20Sopenharmony_ci	ep->mpa_attr.crc_enabled = (mpa->flags & MPA_CRC) | crc_enabled ? 1 : 0;
17788c2ecf20Sopenharmony_ci	ep->mpa_attr.recv_marker_enabled = markers_enabled;
17798c2ecf20Sopenharmony_ci	ep->mpa_attr.xmit_marker_enabled = mpa->flags & MPA_MARKERS ? 1 : 0;
17808c2ecf20Sopenharmony_ci	ep->mpa_attr.version = mpa->revision;
17818c2ecf20Sopenharmony_ci	if (mpa->revision == 1)
17828c2ecf20Sopenharmony_ci		ep->tried_with_mpa_v1 = 1;
17838c2ecf20Sopenharmony_ci	ep->mpa_attr.p2p_type = FW_RI_INIT_P2PTYPE_DISABLED;
17848c2ecf20Sopenharmony_ci
17858c2ecf20Sopenharmony_ci	if (mpa->revision == 2) {
17868c2ecf20Sopenharmony_ci		ep->mpa_attr.enhanced_rdma_conn =
17878c2ecf20Sopenharmony_ci			mpa->flags & MPA_ENHANCED_RDMA_CONN ? 1 : 0;
17888c2ecf20Sopenharmony_ci		if (ep->mpa_attr.enhanced_rdma_conn) {
17898c2ecf20Sopenharmony_ci			mpa_v2_params = (struct mpa_v2_conn_params *)
17908c2ecf20Sopenharmony_ci				(ep->mpa_pkt + sizeof(*mpa));
17918c2ecf20Sopenharmony_ci			ep->ird = ntohs(mpa_v2_params->ird) &
17928c2ecf20Sopenharmony_ci				MPA_V2_IRD_ORD_MASK;
17938c2ecf20Sopenharmony_ci			ep->ird = min_t(u32, ep->ird,
17948c2ecf20Sopenharmony_ci					cur_max_read_depth(ep->com.dev));
17958c2ecf20Sopenharmony_ci			ep->ord = ntohs(mpa_v2_params->ord) &
17968c2ecf20Sopenharmony_ci				MPA_V2_IRD_ORD_MASK;
17978c2ecf20Sopenharmony_ci			ep->ord = min_t(u32, ep->ord,
17988c2ecf20Sopenharmony_ci					cur_max_read_depth(ep->com.dev));
17998c2ecf20Sopenharmony_ci			pr_debug("initiator ird %u ord %u\n",
18008c2ecf20Sopenharmony_ci				 ep->ird, ep->ord);
18018c2ecf20Sopenharmony_ci			if (ntohs(mpa_v2_params->ird) & MPA_V2_PEER2PEER_MODEL)
18028c2ecf20Sopenharmony_ci				if (peer2peer) {
18038c2ecf20Sopenharmony_ci					if (ntohs(mpa_v2_params->ord) &
18048c2ecf20Sopenharmony_ci							MPA_V2_RDMA_WRITE_RTR)
18058c2ecf20Sopenharmony_ci						ep->mpa_attr.p2p_type =
18068c2ecf20Sopenharmony_ci						FW_RI_INIT_P2PTYPE_RDMA_WRITE;
18078c2ecf20Sopenharmony_ci					else if (ntohs(mpa_v2_params->ord) &
18088c2ecf20Sopenharmony_ci							MPA_V2_RDMA_READ_RTR)
18098c2ecf20Sopenharmony_ci						ep->mpa_attr.p2p_type =
18108c2ecf20Sopenharmony_ci						FW_RI_INIT_P2PTYPE_READ_REQ;
18118c2ecf20Sopenharmony_ci				}
18128c2ecf20Sopenharmony_ci		}
18138c2ecf20Sopenharmony_ci	} else if (mpa->revision == 1)
18148c2ecf20Sopenharmony_ci		if (peer2peer)
18158c2ecf20Sopenharmony_ci			ep->mpa_attr.p2p_type = p2p_type;
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_ci	pr_debug("crc_enabled=%d, recv_marker_enabled=%d, xmit_marker_enabled=%d, version=%d p2p_type=%d\n",
18188c2ecf20Sopenharmony_ci		 ep->mpa_attr.crc_enabled, ep->mpa_attr.recv_marker_enabled,
18198c2ecf20Sopenharmony_ci		 ep->mpa_attr.xmit_marker_enabled, ep->mpa_attr.version,
18208c2ecf20Sopenharmony_ci		 ep->mpa_attr.p2p_type);
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci	__state_set(&ep->com, MPA_REQ_RCVD);
18238c2ecf20Sopenharmony_ci
18248c2ecf20Sopenharmony_ci	/* drive upcall */
18258c2ecf20Sopenharmony_ci	mutex_lock_nested(&ep->parent_ep->com.mutex, SINGLE_DEPTH_NESTING);
18268c2ecf20Sopenharmony_ci	if (ep->parent_ep->com.state != DEAD) {
18278c2ecf20Sopenharmony_ci		if (connect_request_upcall(ep))
18288c2ecf20Sopenharmony_ci			goto err_unlock_parent;
18298c2ecf20Sopenharmony_ci	} else {
18308c2ecf20Sopenharmony_ci		goto err_unlock_parent;
18318c2ecf20Sopenharmony_ci	}
18328c2ecf20Sopenharmony_ci	mutex_unlock(&ep->parent_ep->com.mutex);
18338c2ecf20Sopenharmony_ci	return 0;
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_cierr_unlock_parent:
18368c2ecf20Sopenharmony_ci	mutex_unlock(&ep->parent_ep->com.mutex);
18378c2ecf20Sopenharmony_ci	goto err_out;
18388c2ecf20Sopenharmony_cierr_stop_timer:
18398c2ecf20Sopenharmony_ci	(void)stop_ep_timer(ep);
18408c2ecf20Sopenharmony_cierr_out:
18418c2ecf20Sopenharmony_ci	return 2;
18428c2ecf20Sopenharmony_ci}
18438c2ecf20Sopenharmony_ci
18448c2ecf20Sopenharmony_cistatic int rx_data(struct c4iw_dev *dev, struct sk_buff *skb)
18458c2ecf20Sopenharmony_ci{
18468c2ecf20Sopenharmony_ci	struct c4iw_ep *ep;
18478c2ecf20Sopenharmony_ci	struct cpl_rx_data *hdr = cplhdr(skb);
18488c2ecf20Sopenharmony_ci	unsigned int dlen = ntohs(hdr->len);
18498c2ecf20Sopenharmony_ci	unsigned int tid = GET_TID(hdr);
18508c2ecf20Sopenharmony_ci	__u8 status = hdr->status;
18518c2ecf20Sopenharmony_ci	int disconnect = 0;
18528c2ecf20Sopenharmony_ci
18538c2ecf20Sopenharmony_ci	ep = get_ep_from_tid(dev, tid);
18548c2ecf20Sopenharmony_ci	if (!ep)
18558c2ecf20Sopenharmony_ci		return 0;
18568c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u dlen %u\n", ep, ep->hwtid, dlen);
18578c2ecf20Sopenharmony_ci	skb_pull(skb, sizeof(*hdr));
18588c2ecf20Sopenharmony_ci	skb_trim(skb, dlen);
18598c2ecf20Sopenharmony_ci	mutex_lock(&ep->com.mutex);
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci	switch (ep->com.state) {
18628c2ecf20Sopenharmony_ci	case MPA_REQ_SENT:
18638c2ecf20Sopenharmony_ci		update_rx_credits(ep, dlen);
18648c2ecf20Sopenharmony_ci		ep->rcv_seq += dlen;
18658c2ecf20Sopenharmony_ci		disconnect = process_mpa_reply(ep, skb);
18668c2ecf20Sopenharmony_ci		break;
18678c2ecf20Sopenharmony_ci	case MPA_REQ_WAIT:
18688c2ecf20Sopenharmony_ci		update_rx_credits(ep, dlen);
18698c2ecf20Sopenharmony_ci		ep->rcv_seq += dlen;
18708c2ecf20Sopenharmony_ci		disconnect = process_mpa_request(ep, skb);
18718c2ecf20Sopenharmony_ci		break;
18728c2ecf20Sopenharmony_ci	case FPDU_MODE: {
18738c2ecf20Sopenharmony_ci		struct c4iw_qp_attributes attrs;
18748c2ecf20Sopenharmony_ci
18758c2ecf20Sopenharmony_ci		update_rx_credits(ep, dlen);
18768c2ecf20Sopenharmony_ci		if (status)
18778c2ecf20Sopenharmony_ci			pr_err("%s Unexpected streaming data." \
18788c2ecf20Sopenharmony_ci			       " qpid %u ep %p state %d tid %u status %d\n",
18798c2ecf20Sopenharmony_ci			       __func__, ep->com.qp->wq.sq.qid, ep,
18808c2ecf20Sopenharmony_ci			       ep->com.state, ep->hwtid, status);
18818c2ecf20Sopenharmony_ci		attrs.next_state = C4IW_QP_STATE_TERMINATE;
18828c2ecf20Sopenharmony_ci		c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
18838c2ecf20Sopenharmony_ci			       C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
18848c2ecf20Sopenharmony_ci		disconnect = 1;
18858c2ecf20Sopenharmony_ci		break;
18868c2ecf20Sopenharmony_ci	}
18878c2ecf20Sopenharmony_ci	default:
18888c2ecf20Sopenharmony_ci		break;
18898c2ecf20Sopenharmony_ci	}
18908c2ecf20Sopenharmony_ci	mutex_unlock(&ep->com.mutex);
18918c2ecf20Sopenharmony_ci	if (disconnect)
18928c2ecf20Sopenharmony_ci		c4iw_ep_disconnect(ep, disconnect == 2, GFP_KERNEL);
18938c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->com);
18948c2ecf20Sopenharmony_ci	return 0;
18958c2ecf20Sopenharmony_ci}
18968c2ecf20Sopenharmony_ci
18978c2ecf20Sopenharmony_cistatic void complete_cached_srq_buffers(struct c4iw_ep *ep, u32 srqidx)
18988c2ecf20Sopenharmony_ci{
18998c2ecf20Sopenharmony_ci	enum chip_type adapter_type;
19008c2ecf20Sopenharmony_ci
19018c2ecf20Sopenharmony_ci	adapter_type = ep->com.dev->rdev.lldi.adapter_type;
19028c2ecf20Sopenharmony_ci
19038c2ecf20Sopenharmony_ci	/*
19048c2ecf20Sopenharmony_ci	 * If this TCB had a srq buffer cached, then we must complete
19058c2ecf20Sopenharmony_ci	 * it. For user mode, that means saving the srqidx in the
19068c2ecf20Sopenharmony_ci	 * user/kernel status page for this qp.  For kernel mode, just
19078c2ecf20Sopenharmony_ci	 * synthesize the CQE now.
19088c2ecf20Sopenharmony_ci	 */
19098c2ecf20Sopenharmony_ci	if (CHELSIO_CHIP_VERSION(adapter_type) > CHELSIO_T5 && srqidx) {
19108c2ecf20Sopenharmony_ci		if (ep->com.qp->ibqp.uobject)
19118c2ecf20Sopenharmony_ci			t4_set_wq_in_error(&ep->com.qp->wq, srqidx);
19128c2ecf20Sopenharmony_ci		else
19138c2ecf20Sopenharmony_ci			c4iw_flush_srqidx(ep->com.qp, srqidx);
19148c2ecf20Sopenharmony_ci	}
19158c2ecf20Sopenharmony_ci}
19168c2ecf20Sopenharmony_ci
19178c2ecf20Sopenharmony_cistatic int abort_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
19188c2ecf20Sopenharmony_ci{
19198c2ecf20Sopenharmony_ci	u32 srqidx;
19208c2ecf20Sopenharmony_ci	struct c4iw_ep *ep;
19218c2ecf20Sopenharmony_ci	struct cpl_abort_rpl_rss6 *rpl = cplhdr(skb);
19228c2ecf20Sopenharmony_ci	int release = 0;
19238c2ecf20Sopenharmony_ci	unsigned int tid = GET_TID(rpl);
19248c2ecf20Sopenharmony_ci
19258c2ecf20Sopenharmony_ci	ep = get_ep_from_tid(dev, tid);
19268c2ecf20Sopenharmony_ci	if (!ep) {
19278c2ecf20Sopenharmony_ci		pr_warn("Abort rpl to freed endpoint\n");
19288c2ecf20Sopenharmony_ci		return 0;
19298c2ecf20Sopenharmony_ci	}
19308c2ecf20Sopenharmony_ci
19318c2ecf20Sopenharmony_ci	if (ep->com.qp && ep->com.qp->srq) {
19328c2ecf20Sopenharmony_ci		srqidx = ABORT_RSS_SRQIDX_G(be32_to_cpu(rpl->srqidx_status));
19338c2ecf20Sopenharmony_ci		complete_cached_srq_buffers(ep, srqidx ? srqidx : ep->srqe_idx);
19348c2ecf20Sopenharmony_ci	}
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u\n", ep, ep->hwtid);
19378c2ecf20Sopenharmony_ci	mutex_lock(&ep->com.mutex);
19388c2ecf20Sopenharmony_ci	switch (ep->com.state) {
19398c2ecf20Sopenharmony_ci	case ABORTING:
19408c2ecf20Sopenharmony_ci		c4iw_wake_up_noref(ep->com.wr_waitp, -ECONNRESET);
19418c2ecf20Sopenharmony_ci		__state_set(&ep->com, DEAD);
19428c2ecf20Sopenharmony_ci		release = 1;
19438c2ecf20Sopenharmony_ci		break;
19448c2ecf20Sopenharmony_ci	default:
19458c2ecf20Sopenharmony_ci		pr_err("%s ep %p state %d\n", __func__, ep, ep->com.state);
19468c2ecf20Sopenharmony_ci		break;
19478c2ecf20Sopenharmony_ci	}
19488c2ecf20Sopenharmony_ci	mutex_unlock(&ep->com.mutex);
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_ci	if (release) {
19518c2ecf20Sopenharmony_ci		close_complete_upcall(ep, -ECONNRESET);
19528c2ecf20Sopenharmony_ci		release_ep_resources(ep);
19538c2ecf20Sopenharmony_ci	}
19548c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->com);
19558c2ecf20Sopenharmony_ci	return 0;
19568c2ecf20Sopenharmony_ci}
19578c2ecf20Sopenharmony_ci
19588c2ecf20Sopenharmony_cistatic int send_fw_act_open_req(struct c4iw_ep *ep, unsigned int atid)
19598c2ecf20Sopenharmony_ci{
19608c2ecf20Sopenharmony_ci	struct sk_buff *skb;
19618c2ecf20Sopenharmony_ci	struct fw_ofld_connection_wr *req;
19628c2ecf20Sopenharmony_ci	unsigned int mtu_idx;
19638c2ecf20Sopenharmony_ci	u32 wscale;
19648c2ecf20Sopenharmony_ci	struct sockaddr_in *sin;
19658c2ecf20Sopenharmony_ci	int win;
19668c2ecf20Sopenharmony_ci
19678c2ecf20Sopenharmony_ci	skb = get_skb(NULL, sizeof(*req), GFP_KERNEL);
19688c2ecf20Sopenharmony_ci	if (!skb)
19698c2ecf20Sopenharmony_ci		return -ENOMEM;
19708c2ecf20Sopenharmony_ci
19718c2ecf20Sopenharmony_ci	req = __skb_put_zero(skb, sizeof(*req));
19728c2ecf20Sopenharmony_ci	req->op_compl = htonl(WR_OP_V(FW_OFLD_CONNECTION_WR));
19738c2ecf20Sopenharmony_ci	req->len16_pkd = htonl(FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*req), 16)));
19748c2ecf20Sopenharmony_ci	req->le.filter = cpu_to_be32(cxgb4_select_ntuple(
19758c2ecf20Sopenharmony_ci				     ep->com.dev->rdev.lldi.ports[0],
19768c2ecf20Sopenharmony_ci				     ep->l2t));
19778c2ecf20Sopenharmony_ci	sin = (struct sockaddr_in *)&ep->com.local_addr;
19788c2ecf20Sopenharmony_ci	req->le.lport = sin->sin_port;
19798c2ecf20Sopenharmony_ci	req->le.u.ipv4.lip = sin->sin_addr.s_addr;
19808c2ecf20Sopenharmony_ci	sin = (struct sockaddr_in *)&ep->com.remote_addr;
19818c2ecf20Sopenharmony_ci	req->le.pport = sin->sin_port;
19828c2ecf20Sopenharmony_ci	req->le.u.ipv4.pip = sin->sin_addr.s_addr;
19838c2ecf20Sopenharmony_ci	req->tcb.t_state_to_astid =
19848c2ecf20Sopenharmony_ci			htonl(FW_OFLD_CONNECTION_WR_T_STATE_V(TCP_SYN_SENT) |
19858c2ecf20Sopenharmony_ci			FW_OFLD_CONNECTION_WR_ASTID_V(atid));
19868c2ecf20Sopenharmony_ci	req->tcb.cplrxdataack_cplpassacceptrpl =
19878c2ecf20Sopenharmony_ci			htons(FW_OFLD_CONNECTION_WR_CPLRXDATAACK_F);
19888c2ecf20Sopenharmony_ci	req->tcb.tx_max = (__force __be32) jiffies;
19898c2ecf20Sopenharmony_ci	req->tcb.rcv_adv = htons(1);
19908c2ecf20Sopenharmony_ci	cxgb_best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx,
19918c2ecf20Sopenharmony_ci		      enable_tcp_timestamps,
19928c2ecf20Sopenharmony_ci		      (ep->com.remote_addr.ss_family == AF_INET) ? 0 : 1);
19938c2ecf20Sopenharmony_ci	wscale = cxgb_compute_wscale(rcv_win);
19948c2ecf20Sopenharmony_ci
19958c2ecf20Sopenharmony_ci	/*
19968c2ecf20Sopenharmony_ci	 * Specify the largest window that will fit in opt0. The
19978c2ecf20Sopenharmony_ci	 * remainder will be specified in the rx_data_ack.
19988c2ecf20Sopenharmony_ci	 */
19998c2ecf20Sopenharmony_ci	win = ep->rcv_win >> 10;
20008c2ecf20Sopenharmony_ci	if (win > RCV_BUFSIZ_M)
20018c2ecf20Sopenharmony_ci		win = RCV_BUFSIZ_M;
20028c2ecf20Sopenharmony_ci
20038c2ecf20Sopenharmony_ci	req->tcb.opt0 = (__force __be64) (TCAM_BYPASS_F |
20048c2ecf20Sopenharmony_ci		(nocong ? NO_CONG_F : 0) |
20058c2ecf20Sopenharmony_ci		KEEP_ALIVE_F |
20068c2ecf20Sopenharmony_ci		DELACK_F |
20078c2ecf20Sopenharmony_ci		WND_SCALE_V(wscale) |
20088c2ecf20Sopenharmony_ci		MSS_IDX_V(mtu_idx) |
20098c2ecf20Sopenharmony_ci		L2T_IDX_V(ep->l2t->idx) |
20108c2ecf20Sopenharmony_ci		TX_CHAN_V(ep->tx_chan) |
20118c2ecf20Sopenharmony_ci		SMAC_SEL_V(ep->smac_idx) |
20128c2ecf20Sopenharmony_ci		DSCP_V(ep->tos >> 2) |
20138c2ecf20Sopenharmony_ci		ULP_MODE_V(ULP_MODE_TCPDDP) |
20148c2ecf20Sopenharmony_ci		RCV_BUFSIZ_V(win));
20158c2ecf20Sopenharmony_ci	req->tcb.opt2 = (__force __be32) (PACE_V(1) |
20168c2ecf20Sopenharmony_ci		TX_QUEUE_V(ep->com.dev->rdev.lldi.tx_modq[ep->tx_chan]) |
20178c2ecf20Sopenharmony_ci		RX_CHANNEL_V(0) |
20188c2ecf20Sopenharmony_ci		CCTRL_ECN_V(enable_ecn) |
20198c2ecf20Sopenharmony_ci		RSS_QUEUE_VALID_F | RSS_QUEUE_V(ep->rss_qid));
20208c2ecf20Sopenharmony_ci	if (enable_tcp_timestamps)
20218c2ecf20Sopenharmony_ci		req->tcb.opt2 |= (__force __be32)TSTAMPS_EN_F;
20228c2ecf20Sopenharmony_ci	if (enable_tcp_sack)
20238c2ecf20Sopenharmony_ci		req->tcb.opt2 |= (__force __be32)SACK_EN_F;
20248c2ecf20Sopenharmony_ci	if (wscale && enable_tcp_window_scaling)
20258c2ecf20Sopenharmony_ci		req->tcb.opt2 |= (__force __be32)WND_SCALE_EN_F;
20268c2ecf20Sopenharmony_ci	req->tcb.opt0 = cpu_to_be64((__force u64)req->tcb.opt0);
20278c2ecf20Sopenharmony_ci	req->tcb.opt2 = cpu_to_be32((__force u32)req->tcb.opt2);
20288c2ecf20Sopenharmony_ci	set_wr_txq(skb, CPL_PRIORITY_CONTROL, ep->ctrlq_idx);
20298c2ecf20Sopenharmony_ci	set_bit(ACT_OFLD_CONN, &ep->com.history);
20308c2ecf20Sopenharmony_ci	return c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
20318c2ecf20Sopenharmony_ci}
20328c2ecf20Sopenharmony_ci
20338c2ecf20Sopenharmony_ci/*
20348c2ecf20Sopenharmony_ci * Some of the error codes above implicitly indicate that there is no TID
20358c2ecf20Sopenharmony_ci * allocated with the result of an ACT_OPEN.  We use this predicate to make
20368c2ecf20Sopenharmony_ci * that explicit.
20378c2ecf20Sopenharmony_ci */
20388c2ecf20Sopenharmony_cistatic inline int act_open_has_tid(int status)
20398c2ecf20Sopenharmony_ci{
20408c2ecf20Sopenharmony_ci	return (status != CPL_ERR_TCAM_PARITY &&
20418c2ecf20Sopenharmony_ci		status != CPL_ERR_TCAM_MISS &&
20428c2ecf20Sopenharmony_ci		status != CPL_ERR_TCAM_FULL &&
20438c2ecf20Sopenharmony_ci		status != CPL_ERR_CONN_EXIST_SYNRECV &&
20448c2ecf20Sopenharmony_ci		status != CPL_ERR_CONN_EXIST);
20458c2ecf20Sopenharmony_ci}
20468c2ecf20Sopenharmony_ci
20478c2ecf20Sopenharmony_cistatic char *neg_adv_str(unsigned int status)
20488c2ecf20Sopenharmony_ci{
20498c2ecf20Sopenharmony_ci	switch (status) {
20508c2ecf20Sopenharmony_ci	case CPL_ERR_RTX_NEG_ADVICE:
20518c2ecf20Sopenharmony_ci		return "Retransmit timeout";
20528c2ecf20Sopenharmony_ci	case CPL_ERR_PERSIST_NEG_ADVICE:
20538c2ecf20Sopenharmony_ci		return "Persist timeout";
20548c2ecf20Sopenharmony_ci	case CPL_ERR_KEEPALV_NEG_ADVICE:
20558c2ecf20Sopenharmony_ci		return "Keepalive timeout";
20568c2ecf20Sopenharmony_ci	default:
20578c2ecf20Sopenharmony_ci		return "Unknown";
20588c2ecf20Sopenharmony_ci	}
20598c2ecf20Sopenharmony_ci}
20608c2ecf20Sopenharmony_ci
20618c2ecf20Sopenharmony_cistatic void set_tcp_window(struct c4iw_ep *ep, struct port_info *pi)
20628c2ecf20Sopenharmony_ci{
20638c2ecf20Sopenharmony_ci	ep->snd_win = snd_win;
20648c2ecf20Sopenharmony_ci	ep->rcv_win = rcv_win;
20658c2ecf20Sopenharmony_ci	pr_debug("snd_win %d rcv_win %d\n",
20668c2ecf20Sopenharmony_ci		 ep->snd_win, ep->rcv_win);
20678c2ecf20Sopenharmony_ci}
20688c2ecf20Sopenharmony_ci
20698c2ecf20Sopenharmony_ci#define ACT_OPEN_RETRY_COUNT 2
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_cistatic int import_ep(struct c4iw_ep *ep, int iptype, __u8 *peer_ip,
20728c2ecf20Sopenharmony_ci		     struct dst_entry *dst, struct c4iw_dev *cdev,
20738c2ecf20Sopenharmony_ci		     bool clear_mpa_v1, enum chip_type adapter_type, u8 tos)
20748c2ecf20Sopenharmony_ci{
20758c2ecf20Sopenharmony_ci	struct neighbour *n;
20768c2ecf20Sopenharmony_ci	int err, step;
20778c2ecf20Sopenharmony_ci	struct net_device *pdev;
20788c2ecf20Sopenharmony_ci
20798c2ecf20Sopenharmony_ci	n = dst_neigh_lookup(dst, peer_ip);
20808c2ecf20Sopenharmony_ci	if (!n)
20818c2ecf20Sopenharmony_ci		return -ENODEV;
20828c2ecf20Sopenharmony_ci
20838c2ecf20Sopenharmony_ci	rcu_read_lock();
20848c2ecf20Sopenharmony_ci	err = -ENOMEM;
20858c2ecf20Sopenharmony_ci	if (n->dev->flags & IFF_LOOPBACK) {
20868c2ecf20Sopenharmony_ci		if (iptype == 4)
20878c2ecf20Sopenharmony_ci			pdev = ip_dev_find(&init_net, *(__be32 *)peer_ip);
20888c2ecf20Sopenharmony_ci		else if (IS_ENABLED(CONFIG_IPV6))
20898c2ecf20Sopenharmony_ci			for_each_netdev(&init_net, pdev) {
20908c2ecf20Sopenharmony_ci				if (ipv6_chk_addr(&init_net,
20918c2ecf20Sopenharmony_ci						  (struct in6_addr *)peer_ip,
20928c2ecf20Sopenharmony_ci						  pdev, 1))
20938c2ecf20Sopenharmony_ci					break;
20948c2ecf20Sopenharmony_ci			}
20958c2ecf20Sopenharmony_ci		else
20968c2ecf20Sopenharmony_ci			pdev = NULL;
20978c2ecf20Sopenharmony_ci
20988c2ecf20Sopenharmony_ci		if (!pdev) {
20998c2ecf20Sopenharmony_ci			err = -ENODEV;
21008c2ecf20Sopenharmony_ci			goto out;
21018c2ecf20Sopenharmony_ci		}
21028c2ecf20Sopenharmony_ci		ep->l2t = cxgb4_l2t_get(cdev->rdev.lldi.l2t,
21038c2ecf20Sopenharmony_ci					n, pdev, rt_tos2priority(tos));
21048c2ecf20Sopenharmony_ci		if (!ep->l2t) {
21058c2ecf20Sopenharmony_ci			dev_put(pdev);
21068c2ecf20Sopenharmony_ci			goto out;
21078c2ecf20Sopenharmony_ci		}
21088c2ecf20Sopenharmony_ci		ep->mtu = pdev->mtu;
21098c2ecf20Sopenharmony_ci		ep->tx_chan = cxgb4_port_chan(pdev);
21108c2ecf20Sopenharmony_ci		ep->smac_idx = ((struct port_info *)netdev_priv(pdev))->smt_idx;
21118c2ecf20Sopenharmony_ci		step = cdev->rdev.lldi.ntxq /
21128c2ecf20Sopenharmony_ci			cdev->rdev.lldi.nchan;
21138c2ecf20Sopenharmony_ci		ep->txq_idx = cxgb4_port_idx(pdev) * step;
21148c2ecf20Sopenharmony_ci		step = cdev->rdev.lldi.nrxq /
21158c2ecf20Sopenharmony_ci			cdev->rdev.lldi.nchan;
21168c2ecf20Sopenharmony_ci		ep->ctrlq_idx = cxgb4_port_idx(pdev);
21178c2ecf20Sopenharmony_ci		ep->rss_qid = cdev->rdev.lldi.rxq_ids[
21188c2ecf20Sopenharmony_ci			cxgb4_port_idx(pdev) * step];
21198c2ecf20Sopenharmony_ci		set_tcp_window(ep, (struct port_info *)netdev_priv(pdev));
21208c2ecf20Sopenharmony_ci		dev_put(pdev);
21218c2ecf20Sopenharmony_ci	} else {
21228c2ecf20Sopenharmony_ci		pdev = get_real_dev(n->dev);
21238c2ecf20Sopenharmony_ci		ep->l2t = cxgb4_l2t_get(cdev->rdev.lldi.l2t,
21248c2ecf20Sopenharmony_ci					n, pdev, rt_tos2priority(tos));
21258c2ecf20Sopenharmony_ci		if (!ep->l2t)
21268c2ecf20Sopenharmony_ci			goto out;
21278c2ecf20Sopenharmony_ci		ep->mtu = dst_mtu(dst);
21288c2ecf20Sopenharmony_ci		ep->tx_chan = cxgb4_port_chan(pdev);
21298c2ecf20Sopenharmony_ci		ep->smac_idx = ((struct port_info *)netdev_priv(pdev))->smt_idx;
21308c2ecf20Sopenharmony_ci		step = cdev->rdev.lldi.ntxq /
21318c2ecf20Sopenharmony_ci			cdev->rdev.lldi.nchan;
21328c2ecf20Sopenharmony_ci		ep->txq_idx = cxgb4_port_idx(pdev) * step;
21338c2ecf20Sopenharmony_ci		ep->ctrlq_idx = cxgb4_port_idx(pdev);
21348c2ecf20Sopenharmony_ci		step = cdev->rdev.lldi.nrxq /
21358c2ecf20Sopenharmony_ci			cdev->rdev.lldi.nchan;
21368c2ecf20Sopenharmony_ci		ep->rss_qid = cdev->rdev.lldi.rxq_ids[
21378c2ecf20Sopenharmony_ci			cxgb4_port_idx(pdev) * step];
21388c2ecf20Sopenharmony_ci		set_tcp_window(ep, (struct port_info *)netdev_priv(pdev));
21398c2ecf20Sopenharmony_ci
21408c2ecf20Sopenharmony_ci		if (clear_mpa_v1) {
21418c2ecf20Sopenharmony_ci			ep->retry_with_mpa_v1 = 0;
21428c2ecf20Sopenharmony_ci			ep->tried_with_mpa_v1 = 0;
21438c2ecf20Sopenharmony_ci		}
21448c2ecf20Sopenharmony_ci	}
21458c2ecf20Sopenharmony_ci	err = 0;
21468c2ecf20Sopenharmony_ciout:
21478c2ecf20Sopenharmony_ci	rcu_read_unlock();
21488c2ecf20Sopenharmony_ci
21498c2ecf20Sopenharmony_ci	neigh_release(n);
21508c2ecf20Sopenharmony_ci
21518c2ecf20Sopenharmony_ci	return err;
21528c2ecf20Sopenharmony_ci}
21538c2ecf20Sopenharmony_ci
21548c2ecf20Sopenharmony_cistatic int c4iw_reconnect(struct c4iw_ep *ep)
21558c2ecf20Sopenharmony_ci{
21568c2ecf20Sopenharmony_ci	int err = 0;
21578c2ecf20Sopenharmony_ci	int size = 0;
21588c2ecf20Sopenharmony_ci	struct sockaddr_in *laddr = (struct sockaddr_in *)
21598c2ecf20Sopenharmony_ci				    &ep->com.cm_id->m_local_addr;
21608c2ecf20Sopenharmony_ci	struct sockaddr_in *raddr = (struct sockaddr_in *)
21618c2ecf20Sopenharmony_ci				    &ep->com.cm_id->m_remote_addr;
21628c2ecf20Sopenharmony_ci	struct sockaddr_in6 *laddr6 = (struct sockaddr_in6 *)
21638c2ecf20Sopenharmony_ci				      &ep->com.cm_id->m_local_addr;
21648c2ecf20Sopenharmony_ci	struct sockaddr_in6 *raddr6 = (struct sockaddr_in6 *)
21658c2ecf20Sopenharmony_ci				      &ep->com.cm_id->m_remote_addr;
21668c2ecf20Sopenharmony_ci	int iptype;
21678c2ecf20Sopenharmony_ci	__u8 *ra;
21688c2ecf20Sopenharmony_ci
21698c2ecf20Sopenharmony_ci	pr_debug("qp %p cm_id %p\n", ep->com.qp, ep->com.cm_id);
21708c2ecf20Sopenharmony_ci	c4iw_init_wr_wait(ep->com.wr_waitp);
21718c2ecf20Sopenharmony_ci
21728c2ecf20Sopenharmony_ci	/* When MPA revision is different on nodes, the node with MPA_rev=2
21738c2ecf20Sopenharmony_ci	 * tries to reconnect with MPA_rev 1 for the same EP through
21748c2ecf20Sopenharmony_ci	 * c4iw_reconnect(), where the same EP is assigned with new tid for
21758c2ecf20Sopenharmony_ci	 * further connection establishment. As we are using the same EP pointer
21768c2ecf20Sopenharmony_ci	 * for reconnect, few skbs are used during the previous c4iw_connect(),
21778c2ecf20Sopenharmony_ci	 * which leaves the EP with inadequate skbs for further
21788c2ecf20Sopenharmony_ci	 * c4iw_reconnect(), Further causing a crash due to an empty
21798c2ecf20Sopenharmony_ci	 * skb_list() during peer_abort(). Allocate skbs which is already used.
21808c2ecf20Sopenharmony_ci	 */
21818c2ecf20Sopenharmony_ci	size = (CN_MAX_CON_BUF - skb_queue_len(&ep->com.ep_skb_list));
21828c2ecf20Sopenharmony_ci	if (alloc_ep_skb_list(&ep->com.ep_skb_list, size)) {
21838c2ecf20Sopenharmony_ci		err = -ENOMEM;
21848c2ecf20Sopenharmony_ci		goto fail1;
21858c2ecf20Sopenharmony_ci	}
21868c2ecf20Sopenharmony_ci
21878c2ecf20Sopenharmony_ci	/*
21888c2ecf20Sopenharmony_ci	 * Allocate an active TID to initiate a TCP connection.
21898c2ecf20Sopenharmony_ci	 */
21908c2ecf20Sopenharmony_ci	ep->atid = cxgb4_alloc_atid(ep->com.dev->rdev.lldi.tids, ep);
21918c2ecf20Sopenharmony_ci	if (ep->atid == -1) {
21928c2ecf20Sopenharmony_ci		pr_err("%s - cannot alloc atid\n", __func__);
21938c2ecf20Sopenharmony_ci		err = -ENOMEM;
21948c2ecf20Sopenharmony_ci		goto fail2;
21958c2ecf20Sopenharmony_ci	}
21968c2ecf20Sopenharmony_ci	err = xa_insert_irq(&ep->com.dev->atids, ep->atid, ep, GFP_KERNEL);
21978c2ecf20Sopenharmony_ci	if (err)
21988c2ecf20Sopenharmony_ci		goto fail2a;
21998c2ecf20Sopenharmony_ci
22008c2ecf20Sopenharmony_ci	/* find a route */
22018c2ecf20Sopenharmony_ci	if (ep->com.cm_id->m_local_addr.ss_family == AF_INET) {
22028c2ecf20Sopenharmony_ci		ep->dst = cxgb_find_route(&ep->com.dev->rdev.lldi, get_real_dev,
22038c2ecf20Sopenharmony_ci					  laddr->sin_addr.s_addr,
22048c2ecf20Sopenharmony_ci					  raddr->sin_addr.s_addr,
22058c2ecf20Sopenharmony_ci					  laddr->sin_port,
22068c2ecf20Sopenharmony_ci					  raddr->sin_port, ep->com.cm_id->tos);
22078c2ecf20Sopenharmony_ci		iptype = 4;
22088c2ecf20Sopenharmony_ci		ra = (__u8 *)&raddr->sin_addr;
22098c2ecf20Sopenharmony_ci	} else {
22108c2ecf20Sopenharmony_ci		ep->dst = cxgb_find_route6(&ep->com.dev->rdev.lldi,
22118c2ecf20Sopenharmony_ci					   get_real_dev,
22128c2ecf20Sopenharmony_ci					   laddr6->sin6_addr.s6_addr,
22138c2ecf20Sopenharmony_ci					   raddr6->sin6_addr.s6_addr,
22148c2ecf20Sopenharmony_ci					   laddr6->sin6_port,
22158c2ecf20Sopenharmony_ci					   raddr6->sin6_port,
22168c2ecf20Sopenharmony_ci					   ep->com.cm_id->tos,
22178c2ecf20Sopenharmony_ci					   raddr6->sin6_scope_id);
22188c2ecf20Sopenharmony_ci		iptype = 6;
22198c2ecf20Sopenharmony_ci		ra = (__u8 *)&raddr6->sin6_addr;
22208c2ecf20Sopenharmony_ci	}
22218c2ecf20Sopenharmony_ci	if (!ep->dst) {
22228c2ecf20Sopenharmony_ci		pr_err("%s - cannot find route\n", __func__);
22238c2ecf20Sopenharmony_ci		err = -EHOSTUNREACH;
22248c2ecf20Sopenharmony_ci		goto fail3;
22258c2ecf20Sopenharmony_ci	}
22268c2ecf20Sopenharmony_ci	err = import_ep(ep, iptype, ra, ep->dst, ep->com.dev, false,
22278c2ecf20Sopenharmony_ci			ep->com.dev->rdev.lldi.adapter_type,
22288c2ecf20Sopenharmony_ci			ep->com.cm_id->tos);
22298c2ecf20Sopenharmony_ci	if (err) {
22308c2ecf20Sopenharmony_ci		pr_err("%s - cannot alloc l2e\n", __func__);
22318c2ecf20Sopenharmony_ci		goto fail4;
22328c2ecf20Sopenharmony_ci	}
22338c2ecf20Sopenharmony_ci
22348c2ecf20Sopenharmony_ci	pr_debug("txq_idx %u tx_chan %u smac_idx %u rss_qid %u l2t_idx %u\n",
22358c2ecf20Sopenharmony_ci		 ep->txq_idx, ep->tx_chan, ep->smac_idx, ep->rss_qid,
22368c2ecf20Sopenharmony_ci		 ep->l2t->idx);
22378c2ecf20Sopenharmony_ci
22388c2ecf20Sopenharmony_ci	state_set(&ep->com, CONNECTING);
22398c2ecf20Sopenharmony_ci	ep->tos = ep->com.cm_id->tos;
22408c2ecf20Sopenharmony_ci
22418c2ecf20Sopenharmony_ci	/* send connect request to rnic */
22428c2ecf20Sopenharmony_ci	err = send_connect(ep);
22438c2ecf20Sopenharmony_ci	if (!err)
22448c2ecf20Sopenharmony_ci		goto out;
22458c2ecf20Sopenharmony_ci
22468c2ecf20Sopenharmony_ci	cxgb4_l2t_release(ep->l2t);
22478c2ecf20Sopenharmony_cifail4:
22488c2ecf20Sopenharmony_ci	dst_release(ep->dst);
22498c2ecf20Sopenharmony_cifail3:
22508c2ecf20Sopenharmony_ci	xa_erase_irq(&ep->com.dev->atids, ep->atid);
22518c2ecf20Sopenharmony_cifail2a:
22528c2ecf20Sopenharmony_ci	cxgb4_free_atid(ep->com.dev->rdev.lldi.tids, ep->atid);
22538c2ecf20Sopenharmony_cifail2:
22548c2ecf20Sopenharmony_ci	/*
22558c2ecf20Sopenharmony_ci	 * remember to send notification to upper layer.
22568c2ecf20Sopenharmony_ci	 * We are in here so the upper layer is not aware that this is
22578c2ecf20Sopenharmony_ci	 * re-connect attempt and so, upper layer is still waiting for
22588c2ecf20Sopenharmony_ci	 * response of 1st connect request.
22598c2ecf20Sopenharmony_ci	 */
22608c2ecf20Sopenharmony_ci	connect_reply_upcall(ep, -ECONNRESET);
22618c2ecf20Sopenharmony_cifail1:
22628c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->com);
22638c2ecf20Sopenharmony_ciout:
22648c2ecf20Sopenharmony_ci	return err;
22658c2ecf20Sopenharmony_ci}
22668c2ecf20Sopenharmony_ci
22678c2ecf20Sopenharmony_cistatic int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
22688c2ecf20Sopenharmony_ci{
22698c2ecf20Sopenharmony_ci	struct c4iw_ep *ep;
22708c2ecf20Sopenharmony_ci	struct cpl_act_open_rpl *rpl = cplhdr(skb);
22718c2ecf20Sopenharmony_ci	unsigned int atid = TID_TID_G(AOPEN_ATID_G(
22728c2ecf20Sopenharmony_ci				      ntohl(rpl->atid_status)));
22738c2ecf20Sopenharmony_ci	struct tid_info *t = dev->rdev.lldi.tids;
22748c2ecf20Sopenharmony_ci	int status = AOPEN_STATUS_G(ntohl(rpl->atid_status));
22758c2ecf20Sopenharmony_ci	struct sockaddr_in *la;
22768c2ecf20Sopenharmony_ci	struct sockaddr_in *ra;
22778c2ecf20Sopenharmony_ci	struct sockaddr_in6 *la6;
22788c2ecf20Sopenharmony_ci	struct sockaddr_in6 *ra6;
22798c2ecf20Sopenharmony_ci	int ret = 0;
22808c2ecf20Sopenharmony_ci
22818c2ecf20Sopenharmony_ci	ep = lookup_atid(t, atid);
22828c2ecf20Sopenharmony_ci	la = (struct sockaddr_in *)&ep->com.local_addr;
22838c2ecf20Sopenharmony_ci	ra = (struct sockaddr_in *)&ep->com.remote_addr;
22848c2ecf20Sopenharmony_ci	la6 = (struct sockaddr_in6 *)&ep->com.local_addr;
22858c2ecf20Sopenharmony_ci	ra6 = (struct sockaddr_in6 *)&ep->com.remote_addr;
22868c2ecf20Sopenharmony_ci
22878c2ecf20Sopenharmony_ci	pr_debug("ep %p atid %u status %u errno %d\n", ep, atid,
22888c2ecf20Sopenharmony_ci		 status, status2errno(status));
22898c2ecf20Sopenharmony_ci
22908c2ecf20Sopenharmony_ci	if (cxgb_is_neg_adv(status)) {
22918c2ecf20Sopenharmony_ci		pr_debug("Connection problems for atid %u status %u (%s)\n",
22928c2ecf20Sopenharmony_ci			 atid, status, neg_adv_str(status));
22938c2ecf20Sopenharmony_ci		ep->stats.connect_neg_adv++;
22948c2ecf20Sopenharmony_ci		mutex_lock(&dev->rdev.stats.lock);
22958c2ecf20Sopenharmony_ci		dev->rdev.stats.neg_adv++;
22968c2ecf20Sopenharmony_ci		mutex_unlock(&dev->rdev.stats.lock);
22978c2ecf20Sopenharmony_ci		return 0;
22988c2ecf20Sopenharmony_ci	}
22998c2ecf20Sopenharmony_ci
23008c2ecf20Sopenharmony_ci	set_bit(ACT_OPEN_RPL, &ep->com.history);
23018c2ecf20Sopenharmony_ci
23028c2ecf20Sopenharmony_ci	/*
23038c2ecf20Sopenharmony_ci	 * Log interesting failures.
23048c2ecf20Sopenharmony_ci	 */
23058c2ecf20Sopenharmony_ci	switch (status) {
23068c2ecf20Sopenharmony_ci	case CPL_ERR_CONN_RESET:
23078c2ecf20Sopenharmony_ci	case CPL_ERR_CONN_TIMEDOUT:
23088c2ecf20Sopenharmony_ci		break;
23098c2ecf20Sopenharmony_ci	case CPL_ERR_TCAM_FULL:
23108c2ecf20Sopenharmony_ci		mutex_lock(&dev->rdev.stats.lock);
23118c2ecf20Sopenharmony_ci		dev->rdev.stats.tcam_full++;
23128c2ecf20Sopenharmony_ci		mutex_unlock(&dev->rdev.stats.lock);
23138c2ecf20Sopenharmony_ci		if (ep->com.local_addr.ss_family == AF_INET &&
23148c2ecf20Sopenharmony_ci		    dev->rdev.lldi.enable_fw_ofld_conn) {
23158c2ecf20Sopenharmony_ci			ret = send_fw_act_open_req(ep, TID_TID_G(AOPEN_ATID_G(
23168c2ecf20Sopenharmony_ci						   ntohl(rpl->atid_status))));
23178c2ecf20Sopenharmony_ci			if (ret)
23188c2ecf20Sopenharmony_ci				goto fail;
23198c2ecf20Sopenharmony_ci			return 0;
23208c2ecf20Sopenharmony_ci		}
23218c2ecf20Sopenharmony_ci		break;
23228c2ecf20Sopenharmony_ci	case CPL_ERR_CONN_EXIST:
23238c2ecf20Sopenharmony_ci		if (ep->retry_count++ < ACT_OPEN_RETRY_COUNT) {
23248c2ecf20Sopenharmony_ci			set_bit(ACT_RETRY_INUSE, &ep->com.history);
23258c2ecf20Sopenharmony_ci			if (ep->com.remote_addr.ss_family == AF_INET6) {
23268c2ecf20Sopenharmony_ci				struct sockaddr_in6 *sin6 =
23278c2ecf20Sopenharmony_ci						(struct sockaddr_in6 *)
23288c2ecf20Sopenharmony_ci						&ep->com.local_addr;
23298c2ecf20Sopenharmony_ci				cxgb4_clip_release(
23308c2ecf20Sopenharmony_ci						ep->com.dev->rdev.lldi.ports[0],
23318c2ecf20Sopenharmony_ci						(const u32 *)
23328c2ecf20Sopenharmony_ci						&sin6->sin6_addr.s6_addr, 1);
23338c2ecf20Sopenharmony_ci			}
23348c2ecf20Sopenharmony_ci			xa_erase_irq(&ep->com.dev->atids, atid);
23358c2ecf20Sopenharmony_ci			cxgb4_free_atid(t, atid);
23368c2ecf20Sopenharmony_ci			dst_release(ep->dst);
23378c2ecf20Sopenharmony_ci			cxgb4_l2t_release(ep->l2t);
23388c2ecf20Sopenharmony_ci			c4iw_reconnect(ep);
23398c2ecf20Sopenharmony_ci			return 0;
23408c2ecf20Sopenharmony_ci		}
23418c2ecf20Sopenharmony_ci		break;
23428c2ecf20Sopenharmony_ci	default:
23438c2ecf20Sopenharmony_ci		if (ep->com.local_addr.ss_family == AF_INET) {
23448c2ecf20Sopenharmony_ci			pr_info("Active open failure - atid %u status %u errno %d %pI4:%u->%pI4:%u\n",
23458c2ecf20Sopenharmony_ci				atid, status, status2errno(status),
23468c2ecf20Sopenharmony_ci				&la->sin_addr.s_addr, ntohs(la->sin_port),
23478c2ecf20Sopenharmony_ci				&ra->sin_addr.s_addr, ntohs(ra->sin_port));
23488c2ecf20Sopenharmony_ci		} else {
23498c2ecf20Sopenharmony_ci			pr_info("Active open failure - atid %u status %u errno %d %pI6:%u->%pI6:%u\n",
23508c2ecf20Sopenharmony_ci				atid, status, status2errno(status),
23518c2ecf20Sopenharmony_ci				la6->sin6_addr.s6_addr, ntohs(la6->sin6_port),
23528c2ecf20Sopenharmony_ci				ra6->sin6_addr.s6_addr, ntohs(ra6->sin6_port));
23538c2ecf20Sopenharmony_ci		}
23548c2ecf20Sopenharmony_ci		break;
23558c2ecf20Sopenharmony_ci	}
23568c2ecf20Sopenharmony_ci
23578c2ecf20Sopenharmony_cifail:
23588c2ecf20Sopenharmony_ci	connect_reply_upcall(ep, status2errno(status));
23598c2ecf20Sopenharmony_ci	state_set(&ep->com, DEAD);
23608c2ecf20Sopenharmony_ci
23618c2ecf20Sopenharmony_ci	if (ep->com.remote_addr.ss_family == AF_INET6) {
23628c2ecf20Sopenharmony_ci		struct sockaddr_in6 *sin6 =
23638c2ecf20Sopenharmony_ci			(struct sockaddr_in6 *)&ep->com.local_addr;
23648c2ecf20Sopenharmony_ci		cxgb4_clip_release(ep->com.dev->rdev.lldi.ports[0],
23658c2ecf20Sopenharmony_ci				   (const u32 *)&sin6->sin6_addr.s6_addr, 1);
23668c2ecf20Sopenharmony_ci	}
23678c2ecf20Sopenharmony_ci	if (status && act_open_has_tid(status))
23688c2ecf20Sopenharmony_ci		cxgb4_remove_tid(ep->com.dev->rdev.lldi.tids, 0, GET_TID(rpl),
23698c2ecf20Sopenharmony_ci				 ep->com.local_addr.ss_family);
23708c2ecf20Sopenharmony_ci
23718c2ecf20Sopenharmony_ci	xa_erase_irq(&ep->com.dev->atids, atid);
23728c2ecf20Sopenharmony_ci	cxgb4_free_atid(t, atid);
23738c2ecf20Sopenharmony_ci	dst_release(ep->dst);
23748c2ecf20Sopenharmony_ci	cxgb4_l2t_release(ep->l2t);
23758c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->com);
23768c2ecf20Sopenharmony_ci
23778c2ecf20Sopenharmony_ci	return 0;
23788c2ecf20Sopenharmony_ci}
23798c2ecf20Sopenharmony_ci
23808c2ecf20Sopenharmony_cistatic int pass_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
23818c2ecf20Sopenharmony_ci{
23828c2ecf20Sopenharmony_ci	struct cpl_pass_open_rpl *rpl = cplhdr(skb);
23838c2ecf20Sopenharmony_ci	unsigned int stid = GET_TID(rpl);
23848c2ecf20Sopenharmony_ci	struct c4iw_listen_ep *ep = get_ep_from_stid(dev, stid);
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_ci	if (!ep) {
23878c2ecf20Sopenharmony_ci		pr_warn("%s stid %d lookup failure!\n", __func__, stid);
23888c2ecf20Sopenharmony_ci		goto out;
23898c2ecf20Sopenharmony_ci	}
23908c2ecf20Sopenharmony_ci	pr_debug("ep %p status %d error %d\n", ep,
23918c2ecf20Sopenharmony_ci		 rpl->status, status2errno(rpl->status));
23928c2ecf20Sopenharmony_ci	c4iw_wake_up_noref(ep->com.wr_waitp, status2errno(rpl->status));
23938c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->com);
23948c2ecf20Sopenharmony_ciout:
23958c2ecf20Sopenharmony_ci	return 0;
23968c2ecf20Sopenharmony_ci}
23978c2ecf20Sopenharmony_ci
23988c2ecf20Sopenharmony_cistatic int close_listsrv_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
23998c2ecf20Sopenharmony_ci{
24008c2ecf20Sopenharmony_ci	struct cpl_close_listsvr_rpl *rpl = cplhdr(skb);
24018c2ecf20Sopenharmony_ci	unsigned int stid = GET_TID(rpl);
24028c2ecf20Sopenharmony_ci	struct c4iw_listen_ep *ep = get_ep_from_stid(dev, stid);
24038c2ecf20Sopenharmony_ci
24048c2ecf20Sopenharmony_ci	if (!ep) {
24058c2ecf20Sopenharmony_ci		pr_warn("%s stid %d lookup failure!\n", __func__, stid);
24068c2ecf20Sopenharmony_ci		goto out;
24078c2ecf20Sopenharmony_ci	}
24088c2ecf20Sopenharmony_ci	pr_debug("ep %p\n", ep);
24098c2ecf20Sopenharmony_ci	c4iw_wake_up_noref(ep->com.wr_waitp, status2errno(rpl->status));
24108c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->com);
24118c2ecf20Sopenharmony_ciout:
24128c2ecf20Sopenharmony_ci	return 0;
24138c2ecf20Sopenharmony_ci}
24148c2ecf20Sopenharmony_ci
24158c2ecf20Sopenharmony_cistatic int accept_cr(struct c4iw_ep *ep, struct sk_buff *skb,
24168c2ecf20Sopenharmony_ci		     struct cpl_pass_accept_req *req)
24178c2ecf20Sopenharmony_ci{
24188c2ecf20Sopenharmony_ci	struct cpl_pass_accept_rpl *rpl;
24198c2ecf20Sopenharmony_ci	unsigned int mtu_idx;
24208c2ecf20Sopenharmony_ci	u64 opt0;
24218c2ecf20Sopenharmony_ci	u32 opt2;
24228c2ecf20Sopenharmony_ci	u32 wscale;
24238c2ecf20Sopenharmony_ci	struct cpl_t5_pass_accept_rpl *rpl5 = NULL;
24248c2ecf20Sopenharmony_ci	int win;
24258c2ecf20Sopenharmony_ci	enum chip_type adapter_type = ep->com.dev->rdev.lldi.adapter_type;
24268c2ecf20Sopenharmony_ci
24278c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u\n", ep, ep->hwtid);
24288c2ecf20Sopenharmony_ci	cxgb_best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx,
24298c2ecf20Sopenharmony_ci		      enable_tcp_timestamps && req->tcpopt.tstamp,
24308c2ecf20Sopenharmony_ci		      (ep->com.remote_addr.ss_family == AF_INET) ? 0 : 1);
24318c2ecf20Sopenharmony_ci	wscale = cxgb_compute_wscale(rcv_win);
24328c2ecf20Sopenharmony_ci
24338c2ecf20Sopenharmony_ci	/*
24348c2ecf20Sopenharmony_ci	 * Specify the largest window that will fit in opt0. The
24358c2ecf20Sopenharmony_ci	 * remainder will be specified in the rx_data_ack.
24368c2ecf20Sopenharmony_ci	 */
24378c2ecf20Sopenharmony_ci	win = ep->rcv_win >> 10;
24388c2ecf20Sopenharmony_ci	if (win > RCV_BUFSIZ_M)
24398c2ecf20Sopenharmony_ci		win = RCV_BUFSIZ_M;
24408c2ecf20Sopenharmony_ci	opt0 = (nocong ? NO_CONG_F : 0) |
24418c2ecf20Sopenharmony_ci	       KEEP_ALIVE_F |
24428c2ecf20Sopenharmony_ci	       DELACK_F |
24438c2ecf20Sopenharmony_ci	       WND_SCALE_V(wscale) |
24448c2ecf20Sopenharmony_ci	       MSS_IDX_V(mtu_idx) |
24458c2ecf20Sopenharmony_ci	       L2T_IDX_V(ep->l2t->idx) |
24468c2ecf20Sopenharmony_ci	       TX_CHAN_V(ep->tx_chan) |
24478c2ecf20Sopenharmony_ci	       SMAC_SEL_V(ep->smac_idx) |
24488c2ecf20Sopenharmony_ci	       DSCP_V(ep->tos >> 2) |
24498c2ecf20Sopenharmony_ci	       ULP_MODE_V(ULP_MODE_TCPDDP) |
24508c2ecf20Sopenharmony_ci	       RCV_BUFSIZ_V(win);
24518c2ecf20Sopenharmony_ci	opt2 = RX_CHANNEL_V(0) |
24528c2ecf20Sopenharmony_ci	       RSS_QUEUE_VALID_F | RSS_QUEUE_V(ep->rss_qid);
24538c2ecf20Sopenharmony_ci
24548c2ecf20Sopenharmony_ci	if (enable_tcp_timestamps && req->tcpopt.tstamp)
24558c2ecf20Sopenharmony_ci		opt2 |= TSTAMPS_EN_F;
24568c2ecf20Sopenharmony_ci	if (enable_tcp_sack && req->tcpopt.sack)
24578c2ecf20Sopenharmony_ci		opt2 |= SACK_EN_F;
24588c2ecf20Sopenharmony_ci	if (wscale && enable_tcp_window_scaling)
24598c2ecf20Sopenharmony_ci		opt2 |= WND_SCALE_EN_F;
24608c2ecf20Sopenharmony_ci	if (enable_ecn) {
24618c2ecf20Sopenharmony_ci		const struct tcphdr *tcph;
24628c2ecf20Sopenharmony_ci		u32 hlen = ntohl(req->hdr_len);
24638c2ecf20Sopenharmony_ci
24648c2ecf20Sopenharmony_ci		if (CHELSIO_CHIP_VERSION(adapter_type) <= CHELSIO_T5)
24658c2ecf20Sopenharmony_ci			tcph = (const void *)(req + 1) + ETH_HDR_LEN_G(hlen) +
24668c2ecf20Sopenharmony_ci				IP_HDR_LEN_G(hlen);
24678c2ecf20Sopenharmony_ci		else
24688c2ecf20Sopenharmony_ci			tcph = (const void *)(req + 1) +
24698c2ecf20Sopenharmony_ci				T6_ETH_HDR_LEN_G(hlen) + T6_IP_HDR_LEN_G(hlen);
24708c2ecf20Sopenharmony_ci		if (tcph->ece && tcph->cwr)
24718c2ecf20Sopenharmony_ci			opt2 |= CCTRL_ECN_V(1);
24728c2ecf20Sopenharmony_ci	}
24738c2ecf20Sopenharmony_ci
24748c2ecf20Sopenharmony_ci	skb_get(skb);
24758c2ecf20Sopenharmony_ci	rpl = cplhdr(skb);
24768c2ecf20Sopenharmony_ci	if (!is_t4(adapter_type)) {
24778c2ecf20Sopenharmony_ci		skb_trim(skb, roundup(sizeof(*rpl5), 16));
24788c2ecf20Sopenharmony_ci		rpl5 = (void *)rpl;
24798c2ecf20Sopenharmony_ci		INIT_TP_WR(rpl5, ep->hwtid);
24808c2ecf20Sopenharmony_ci	} else {
24818c2ecf20Sopenharmony_ci		skb_trim(skb, sizeof(*rpl));
24828c2ecf20Sopenharmony_ci		INIT_TP_WR(rpl, ep->hwtid);
24838c2ecf20Sopenharmony_ci	}
24848c2ecf20Sopenharmony_ci	OPCODE_TID(rpl) = cpu_to_be32(MK_OPCODE_TID(CPL_PASS_ACCEPT_RPL,
24858c2ecf20Sopenharmony_ci						    ep->hwtid));
24868c2ecf20Sopenharmony_ci
24878c2ecf20Sopenharmony_ci	if (CHELSIO_CHIP_VERSION(adapter_type) > CHELSIO_T4) {
24888c2ecf20Sopenharmony_ci		u32 isn = (prandom_u32() & ~7UL) - 1;
24898c2ecf20Sopenharmony_ci		opt2 |= T5_OPT_2_VALID_F;
24908c2ecf20Sopenharmony_ci		opt2 |= CONG_CNTRL_V(CONG_ALG_TAHOE);
24918c2ecf20Sopenharmony_ci		opt2 |= T5_ISS_F;
24928c2ecf20Sopenharmony_ci		rpl5 = (void *)rpl;
24938c2ecf20Sopenharmony_ci		memset(&rpl5->iss, 0, roundup(sizeof(*rpl5)-sizeof(*rpl), 16));
24948c2ecf20Sopenharmony_ci		if (peer2peer)
24958c2ecf20Sopenharmony_ci			isn += 4;
24968c2ecf20Sopenharmony_ci		rpl5->iss = cpu_to_be32(isn);
24978c2ecf20Sopenharmony_ci		pr_debug("iss %u\n", be32_to_cpu(rpl5->iss));
24988c2ecf20Sopenharmony_ci	}
24998c2ecf20Sopenharmony_ci
25008c2ecf20Sopenharmony_ci	rpl->opt0 = cpu_to_be64(opt0);
25018c2ecf20Sopenharmony_ci	rpl->opt2 = cpu_to_be32(opt2);
25028c2ecf20Sopenharmony_ci	set_wr_txq(skb, CPL_PRIORITY_SETUP, ep->ctrlq_idx);
25038c2ecf20Sopenharmony_ci	t4_set_arp_err_handler(skb, ep, pass_accept_rpl_arp_failure);
25048c2ecf20Sopenharmony_ci
25058c2ecf20Sopenharmony_ci	return c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
25068c2ecf20Sopenharmony_ci}
25078c2ecf20Sopenharmony_ci
25088c2ecf20Sopenharmony_cistatic void reject_cr(struct c4iw_dev *dev, u32 hwtid, struct sk_buff *skb)
25098c2ecf20Sopenharmony_ci{
25108c2ecf20Sopenharmony_ci	pr_debug("c4iw_dev %p tid %u\n", dev, hwtid);
25118c2ecf20Sopenharmony_ci	skb_trim(skb, sizeof(struct cpl_tid_release));
25128c2ecf20Sopenharmony_ci	release_tid(&dev->rdev, hwtid, skb);
25138c2ecf20Sopenharmony_ci	return;
25148c2ecf20Sopenharmony_ci}
25158c2ecf20Sopenharmony_ci
25168c2ecf20Sopenharmony_cistatic int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
25178c2ecf20Sopenharmony_ci{
25188c2ecf20Sopenharmony_ci	struct c4iw_ep *child_ep = NULL, *parent_ep;
25198c2ecf20Sopenharmony_ci	struct cpl_pass_accept_req *req = cplhdr(skb);
25208c2ecf20Sopenharmony_ci	unsigned int stid = PASS_OPEN_TID_G(ntohl(req->tos_stid));
25218c2ecf20Sopenharmony_ci	struct tid_info *t = dev->rdev.lldi.tids;
25228c2ecf20Sopenharmony_ci	unsigned int hwtid = GET_TID(req);
25238c2ecf20Sopenharmony_ci	struct dst_entry *dst;
25248c2ecf20Sopenharmony_ci	__u8 local_ip[16], peer_ip[16];
25258c2ecf20Sopenharmony_ci	__be16 local_port, peer_port;
25268c2ecf20Sopenharmony_ci	struct sockaddr_in6 *sin6;
25278c2ecf20Sopenharmony_ci	int err;
25288c2ecf20Sopenharmony_ci	u16 peer_mss = ntohs(req->tcpopt.mss);
25298c2ecf20Sopenharmony_ci	int iptype;
25308c2ecf20Sopenharmony_ci	unsigned short hdrs;
25318c2ecf20Sopenharmony_ci	u8 tos;
25328c2ecf20Sopenharmony_ci
25338c2ecf20Sopenharmony_ci	parent_ep = (struct c4iw_ep *)get_ep_from_stid(dev, stid);
25348c2ecf20Sopenharmony_ci	if (!parent_ep) {
25358c2ecf20Sopenharmony_ci		pr_err("%s connect request on invalid stid %d\n",
25368c2ecf20Sopenharmony_ci		       __func__, stid);
25378c2ecf20Sopenharmony_ci		goto reject;
25388c2ecf20Sopenharmony_ci	}
25398c2ecf20Sopenharmony_ci
25408c2ecf20Sopenharmony_ci	if (state_read(&parent_ep->com) != LISTEN) {
25418c2ecf20Sopenharmony_ci		pr_err("%s - listening ep not in LISTEN\n", __func__);
25428c2ecf20Sopenharmony_ci		goto reject;
25438c2ecf20Sopenharmony_ci	}
25448c2ecf20Sopenharmony_ci
25458c2ecf20Sopenharmony_ci	if (parent_ep->com.cm_id->tos_set)
25468c2ecf20Sopenharmony_ci		tos = parent_ep->com.cm_id->tos;
25478c2ecf20Sopenharmony_ci	else
25488c2ecf20Sopenharmony_ci		tos = PASS_OPEN_TOS_G(ntohl(req->tos_stid));
25498c2ecf20Sopenharmony_ci
25508c2ecf20Sopenharmony_ci	cxgb_get_4tuple(req, parent_ep->com.dev->rdev.lldi.adapter_type,
25518c2ecf20Sopenharmony_ci			&iptype, local_ip, peer_ip, &local_port, &peer_port);
25528c2ecf20Sopenharmony_ci
25538c2ecf20Sopenharmony_ci	/* Find output route */
25548c2ecf20Sopenharmony_ci	if (iptype == 4)  {
25558c2ecf20Sopenharmony_ci		pr_debug("parent ep %p hwtid %u laddr %pI4 raddr %pI4 lport %d rport %d peer_mss %d\n"
25568c2ecf20Sopenharmony_ci			 , parent_ep, hwtid,
25578c2ecf20Sopenharmony_ci			 local_ip, peer_ip, ntohs(local_port),
25588c2ecf20Sopenharmony_ci			 ntohs(peer_port), peer_mss);
25598c2ecf20Sopenharmony_ci		dst = cxgb_find_route(&dev->rdev.lldi, get_real_dev,
25608c2ecf20Sopenharmony_ci				      *(__be32 *)local_ip, *(__be32 *)peer_ip,
25618c2ecf20Sopenharmony_ci				      local_port, peer_port, tos);
25628c2ecf20Sopenharmony_ci	} else {
25638c2ecf20Sopenharmony_ci		pr_debug("parent ep %p hwtid %u laddr %pI6 raddr %pI6 lport %d rport %d peer_mss %d\n"
25648c2ecf20Sopenharmony_ci			 , parent_ep, hwtid,
25658c2ecf20Sopenharmony_ci			 local_ip, peer_ip, ntohs(local_port),
25668c2ecf20Sopenharmony_ci			 ntohs(peer_port), peer_mss);
25678c2ecf20Sopenharmony_ci		dst = cxgb_find_route6(&dev->rdev.lldi, get_real_dev,
25688c2ecf20Sopenharmony_ci				local_ip, peer_ip, local_port, peer_port,
25698c2ecf20Sopenharmony_ci				tos,
25708c2ecf20Sopenharmony_ci				((struct sockaddr_in6 *)
25718c2ecf20Sopenharmony_ci				 &parent_ep->com.local_addr)->sin6_scope_id);
25728c2ecf20Sopenharmony_ci	}
25738c2ecf20Sopenharmony_ci	if (!dst) {
25748c2ecf20Sopenharmony_ci		pr_err("%s - failed to find dst entry!\n", __func__);
25758c2ecf20Sopenharmony_ci		goto reject;
25768c2ecf20Sopenharmony_ci	}
25778c2ecf20Sopenharmony_ci
25788c2ecf20Sopenharmony_ci	child_ep = alloc_ep(sizeof(*child_ep), GFP_KERNEL);
25798c2ecf20Sopenharmony_ci	if (!child_ep) {
25808c2ecf20Sopenharmony_ci		pr_err("%s - failed to allocate ep entry!\n", __func__);
25818c2ecf20Sopenharmony_ci		dst_release(dst);
25828c2ecf20Sopenharmony_ci		goto reject;
25838c2ecf20Sopenharmony_ci	}
25848c2ecf20Sopenharmony_ci
25858c2ecf20Sopenharmony_ci	err = import_ep(child_ep, iptype, peer_ip, dst, dev, false,
25868c2ecf20Sopenharmony_ci			parent_ep->com.dev->rdev.lldi.adapter_type, tos);
25878c2ecf20Sopenharmony_ci	if (err) {
25888c2ecf20Sopenharmony_ci		pr_err("%s - failed to allocate l2t entry!\n", __func__);
25898c2ecf20Sopenharmony_ci		dst_release(dst);
25908c2ecf20Sopenharmony_ci		kfree(child_ep);
25918c2ecf20Sopenharmony_ci		goto reject;
25928c2ecf20Sopenharmony_ci	}
25938c2ecf20Sopenharmony_ci
25948c2ecf20Sopenharmony_ci	hdrs = ((iptype == 4) ? sizeof(struct iphdr) : sizeof(struct ipv6hdr)) +
25958c2ecf20Sopenharmony_ci	       sizeof(struct tcphdr) +
25968c2ecf20Sopenharmony_ci	       ((enable_tcp_timestamps && req->tcpopt.tstamp) ? 12 : 0);
25978c2ecf20Sopenharmony_ci	if (peer_mss && child_ep->mtu > (peer_mss + hdrs))
25988c2ecf20Sopenharmony_ci		child_ep->mtu = peer_mss + hdrs;
25998c2ecf20Sopenharmony_ci
26008c2ecf20Sopenharmony_ci	skb_queue_head_init(&child_ep->com.ep_skb_list);
26018c2ecf20Sopenharmony_ci	if (alloc_ep_skb_list(&child_ep->com.ep_skb_list, CN_MAX_CON_BUF))
26028c2ecf20Sopenharmony_ci		goto fail;
26038c2ecf20Sopenharmony_ci
26048c2ecf20Sopenharmony_ci	state_set(&child_ep->com, CONNECTING);
26058c2ecf20Sopenharmony_ci	child_ep->com.dev = dev;
26068c2ecf20Sopenharmony_ci	child_ep->com.cm_id = NULL;
26078c2ecf20Sopenharmony_ci
26088c2ecf20Sopenharmony_ci	if (iptype == 4) {
26098c2ecf20Sopenharmony_ci		struct sockaddr_in *sin = (struct sockaddr_in *)
26108c2ecf20Sopenharmony_ci			&child_ep->com.local_addr;
26118c2ecf20Sopenharmony_ci
26128c2ecf20Sopenharmony_ci		sin->sin_family = AF_INET;
26138c2ecf20Sopenharmony_ci		sin->sin_port = local_port;
26148c2ecf20Sopenharmony_ci		sin->sin_addr.s_addr = *(__be32 *)local_ip;
26158c2ecf20Sopenharmony_ci
26168c2ecf20Sopenharmony_ci		sin = (struct sockaddr_in *)&child_ep->com.local_addr;
26178c2ecf20Sopenharmony_ci		sin->sin_family = AF_INET;
26188c2ecf20Sopenharmony_ci		sin->sin_port = ((struct sockaddr_in *)
26198c2ecf20Sopenharmony_ci				 &parent_ep->com.local_addr)->sin_port;
26208c2ecf20Sopenharmony_ci		sin->sin_addr.s_addr = *(__be32 *)local_ip;
26218c2ecf20Sopenharmony_ci
26228c2ecf20Sopenharmony_ci		sin = (struct sockaddr_in *)&child_ep->com.remote_addr;
26238c2ecf20Sopenharmony_ci		sin->sin_family = AF_INET;
26248c2ecf20Sopenharmony_ci		sin->sin_port = peer_port;
26258c2ecf20Sopenharmony_ci		sin->sin_addr.s_addr = *(__be32 *)peer_ip;
26268c2ecf20Sopenharmony_ci	} else {
26278c2ecf20Sopenharmony_ci		sin6 = (struct sockaddr_in6 *)&child_ep->com.local_addr;
26288c2ecf20Sopenharmony_ci		sin6->sin6_family = PF_INET6;
26298c2ecf20Sopenharmony_ci		sin6->sin6_port = local_port;
26308c2ecf20Sopenharmony_ci		memcpy(sin6->sin6_addr.s6_addr, local_ip, 16);
26318c2ecf20Sopenharmony_ci
26328c2ecf20Sopenharmony_ci		sin6 = (struct sockaddr_in6 *)&child_ep->com.local_addr;
26338c2ecf20Sopenharmony_ci		sin6->sin6_family = PF_INET6;
26348c2ecf20Sopenharmony_ci		sin6->sin6_port = ((struct sockaddr_in6 *)
26358c2ecf20Sopenharmony_ci				   &parent_ep->com.local_addr)->sin6_port;
26368c2ecf20Sopenharmony_ci		memcpy(sin6->sin6_addr.s6_addr, local_ip, 16);
26378c2ecf20Sopenharmony_ci
26388c2ecf20Sopenharmony_ci		sin6 = (struct sockaddr_in6 *)&child_ep->com.remote_addr;
26398c2ecf20Sopenharmony_ci		sin6->sin6_family = PF_INET6;
26408c2ecf20Sopenharmony_ci		sin6->sin6_port = peer_port;
26418c2ecf20Sopenharmony_ci		memcpy(sin6->sin6_addr.s6_addr, peer_ip, 16);
26428c2ecf20Sopenharmony_ci	}
26438c2ecf20Sopenharmony_ci
26448c2ecf20Sopenharmony_ci	c4iw_get_ep(&parent_ep->com);
26458c2ecf20Sopenharmony_ci	child_ep->parent_ep = parent_ep;
26468c2ecf20Sopenharmony_ci	child_ep->tos = tos;
26478c2ecf20Sopenharmony_ci	child_ep->dst = dst;
26488c2ecf20Sopenharmony_ci	child_ep->hwtid = hwtid;
26498c2ecf20Sopenharmony_ci
26508c2ecf20Sopenharmony_ci	pr_debug("tx_chan %u smac_idx %u rss_qid %u\n",
26518c2ecf20Sopenharmony_ci		 child_ep->tx_chan, child_ep->smac_idx, child_ep->rss_qid);
26528c2ecf20Sopenharmony_ci
26538c2ecf20Sopenharmony_ci	timer_setup(&child_ep->timer, ep_timeout, 0);
26548c2ecf20Sopenharmony_ci	cxgb4_insert_tid(t, child_ep, hwtid,
26558c2ecf20Sopenharmony_ci			 child_ep->com.local_addr.ss_family);
26568c2ecf20Sopenharmony_ci	insert_ep_tid(child_ep);
26578c2ecf20Sopenharmony_ci	if (accept_cr(child_ep, skb, req)) {
26588c2ecf20Sopenharmony_ci		c4iw_put_ep(&parent_ep->com);
26598c2ecf20Sopenharmony_ci		release_ep_resources(child_ep);
26608c2ecf20Sopenharmony_ci	} else {
26618c2ecf20Sopenharmony_ci		set_bit(PASS_ACCEPT_REQ, &child_ep->com.history);
26628c2ecf20Sopenharmony_ci	}
26638c2ecf20Sopenharmony_ci	if (iptype == 6) {
26648c2ecf20Sopenharmony_ci		sin6 = (struct sockaddr_in6 *)&child_ep->com.local_addr;
26658c2ecf20Sopenharmony_ci		cxgb4_clip_get(child_ep->com.dev->rdev.lldi.ports[0],
26668c2ecf20Sopenharmony_ci			       (const u32 *)&sin6->sin6_addr.s6_addr, 1);
26678c2ecf20Sopenharmony_ci	}
26688c2ecf20Sopenharmony_ci	goto out;
26698c2ecf20Sopenharmony_cifail:
26708c2ecf20Sopenharmony_ci	c4iw_put_ep(&child_ep->com);
26718c2ecf20Sopenharmony_cireject:
26728c2ecf20Sopenharmony_ci	reject_cr(dev, hwtid, skb);
26738c2ecf20Sopenharmony_ciout:
26748c2ecf20Sopenharmony_ci	if (parent_ep)
26758c2ecf20Sopenharmony_ci		c4iw_put_ep(&parent_ep->com);
26768c2ecf20Sopenharmony_ci	return 0;
26778c2ecf20Sopenharmony_ci}
26788c2ecf20Sopenharmony_ci
26798c2ecf20Sopenharmony_cistatic int pass_establish(struct c4iw_dev *dev, struct sk_buff *skb)
26808c2ecf20Sopenharmony_ci{
26818c2ecf20Sopenharmony_ci	struct c4iw_ep *ep;
26828c2ecf20Sopenharmony_ci	struct cpl_pass_establish *req = cplhdr(skb);
26838c2ecf20Sopenharmony_ci	unsigned int tid = GET_TID(req);
26848c2ecf20Sopenharmony_ci	int ret;
26858c2ecf20Sopenharmony_ci	u16 tcp_opt = ntohs(req->tcp_opt);
26868c2ecf20Sopenharmony_ci
26878c2ecf20Sopenharmony_ci	ep = get_ep_from_tid(dev, tid);
26888c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u\n", ep, ep->hwtid);
26898c2ecf20Sopenharmony_ci	ep->snd_seq = be32_to_cpu(req->snd_isn);
26908c2ecf20Sopenharmony_ci	ep->rcv_seq = be32_to_cpu(req->rcv_isn);
26918c2ecf20Sopenharmony_ci	ep->snd_wscale = TCPOPT_SND_WSCALE_G(tcp_opt);
26928c2ecf20Sopenharmony_ci
26938c2ecf20Sopenharmony_ci	pr_debug("ep %p hwtid %u tcp_opt 0x%02x\n", ep, tid, tcp_opt);
26948c2ecf20Sopenharmony_ci
26958c2ecf20Sopenharmony_ci	set_emss(ep, tcp_opt);
26968c2ecf20Sopenharmony_ci
26978c2ecf20Sopenharmony_ci	dst_confirm(ep->dst);
26988c2ecf20Sopenharmony_ci	mutex_lock(&ep->com.mutex);
26998c2ecf20Sopenharmony_ci	ep->com.state = MPA_REQ_WAIT;
27008c2ecf20Sopenharmony_ci	start_ep_timer(ep);
27018c2ecf20Sopenharmony_ci	set_bit(PASS_ESTAB, &ep->com.history);
27028c2ecf20Sopenharmony_ci	ret = send_flowc(ep);
27038c2ecf20Sopenharmony_ci	mutex_unlock(&ep->com.mutex);
27048c2ecf20Sopenharmony_ci	if (ret)
27058c2ecf20Sopenharmony_ci		c4iw_ep_disconnect(ep, 1, GFP_KERNEL);
27068c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->com);
27078c2ecf20Sopenharmony_ci
27088c2ecf20Sopenharmony_ci	return 0;
27098c2ecf20Sopenharmony_ci}
27108c2ecf20Sopenharmony_ci
27118c2ecf20Sopenharmony_cistatic int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
27128c2ecf20Sopenharmony_ci{
27138c2ecf20Sopenharmony_ci	struct cpl_peer_close *hdr = cplhdr(skb);
27148c2ecf20Sopenharmony_ci	struct c4iw_ep *ep;
27158c2ecf20Sopenharmony_ci	struct c4iw_qp_attributes attrs;
27168c2ecf20Sopenharmony_ci	int disconnect = 1;
27178c2ecf20Sopenharmony_ci	int release = 0;
27188c2ecf20Sopenharmony_ci	unsigned int tid = GET_TID(hdr);
27198c2ecf20Sopenharmony_ci	int ret;
27208c2ecf20Sopenharmony_ci
27218c2ecf20Sopenharmony_ci	ep = get_ep_from_tid(dev, tid);
27228c2ecf20Sopenharmony_ci	if (!ep)
27238c2ecf20Sopenharmony_ci		return 0;
27248c2ecf20Sopenharmony_ci
27258c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u\n", ep, ep->hwtid);
27268c2ecf20Sopenharmony_ci	dst_confirm(ep->dst);
27278c2ecf20Sopenharmony_ci
27288c2ecf20Sopenharmony_ci	set_bit(PEER_CLOSE, &ep->com.history);
27298c2ecf20Sopenharmony_ci	mutex_lock(&ep->com.mutex);
27308c2ecf20Sopenharmony_ci	switch (ep->com.state) {
27318c2ecf20Sopenharmony_ci	case MPA_REQ_WAIT:
27328c2ecf20Sopenharmony_ci		__state_set(&ep->com, CLOSING);
27338c2ecf20Sopenharmony_ci		break;
27348c2ecf20Sopenharmony_ci	case MPA_REQ_SENT:
27358c2ecf20Sopenharmony_ci		__state_set(&ep->com, CLOSING);
27368c2ecf20Sopenharmony_ci		connect_reply_upcall(ep, -ECONNRESET);
27378c2ecf20Sopenharmony_ci		break;
27388c2ecf20Sopenharmony_ci	case MPA_REQ_RCVD:
27398c2ecf20Sopenharmony_ci
27408c2ecf20Sopenharmony_ci		/*
27418c2ecf20Sopenharmony_ci		 * We're gonna mark this puppy DEAD, but keep
27428c2ecf20Sopenharmony_ci		 * the reference on it until the ULP accepts or
27438c2ecf20Sopenharmony_ci		 * rejects the CR. Also wake up anyone waiting
27448c2ecf20Sopenharmony_ci		 * in rdma connection migration (see c4iw_accept_cr()).
27458c2ecf20Sopenharmony_ci		 */
27468c2ecf20Sopenharmony_ci		__state_set(&ep->com, CLOSING);
27478c2ecf20Sopenharmony_ci		pr_debug("waking up ep %p tid %u\n", ep, ep->hwtid);
27488c2ecf20Sopenharmony_ci		c4iw_wake_up_noref(ep->com.wr_waitp, -ECONNRESET);
27498c2ecf20Sopenharmony_ci		break;
27508c2ecf20Sopenharmony_ci	case MPA_REP_SENT:
27518c2ecf20Sopenharmony_ci		__state_set(&ep->com, CLOSING);
27528c2ecf20Sopenharmony_ci		pr_debug("waking up ep %p tid %u\n", ep, ep->hwtid);
27538c2ecf20Sopenharmony_ci		c4iw_wake_up_noref(ep->com.wr_waitp, -ECONNRESET);
27548c2ecf20Sopenharmony_ci		break;
27558c2ecf20Sopenharmony_ci	case FPDU_MODE:
27568c2ecf20Sopenharmony_ci		start_ep_timer(ep);
27578c2ecf20Sopenharmony_ci		__state_set(&ep->com, CLOSING);
27588c2ecf20Sopenharmony_ci		attrs.next_state = C4IW_QP_STATE_CLOSING;
27598c2ecf20Sopenharmony_ci		ret = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
27608c2ecf20Sopenharmony_ci				       C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
27618c2ecf20Sopenharmony_ci		if (ret != -ECONNRESET) {
27628c2ecf20Sopenharmony_ci			peer_close_upcall(ep);
27638c2ecf20Sopenharmony_ci			disconnect = 1;
27648c2ecf20Sopenharmony_ci		}
27658c2ecf20Sopenharmony_ci		break;
27668c2ecf20Sopenharmony_ci	case ABORTING:
27678c2ecf20Sopenharmony_ci		disconnect = 0;
27688c2ecf20Sopenharmony_ci		break;
27698c2ecf20Sopenharmony_ci	case CLOSING:
27708c2ecf20Sopenharmony_ci		__state_set(&ep->com, MORIBUND);
27718c2ecf20Sopenharmony_ci		disconnect = 0;
27728c2ecf20Sopenharmony_ci		break;
27738c2ecf20Sopenharmony_ci	case MORIBUND:
27748c2ecf20Sopenharmony_ci		(void)stop_ep_timer(ep);
27758c2ecf20Sopenharmony_ci		if (ep->com.cm_id && ep->com.qp) {
27768c2ecf20Sopenharmony_ci			attrs.next_state = C4IW_QP_STATE_IDLE;
27778c2ecf20Sopenharmony_ci			c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
27788c2ecf20Sopenharmony_ci				       C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
27798c2ecf20Sopenharmony_ci		}
27808c2ecf20Sopenharmony_ci		close_complete_upcall(ep, 0);
27818c2ecf20Sopenharmony_ci		__state_set(&ep->com, DEAD);
27828c2ecf20Sopenharmony_ci		release = 1;
27838c2ecf20Sopenharmony_ci		disconnect = 0;
27848c2ecf20Sopenharmony_ci		break;
27858c2ecf20Sopenharmony_ci	case DEAD:
27868c2ecf20Sopenharmony_ci		disconnect = 0;
27878c2ecf20Sopenharmony_ci		break;
27888c2ecf20Sopenharmony_ci	default:
27898c2ecf20Sopenharmony_ci		WARN_ONCE(1, "Bad endpoint state %u\n", ep->com.state);
27908c2ecf20Sopenharmony_ci	}
27918c2ecf20Sopenharmony_ci	mutex_unlock(&ep->com.mutex);
27928c2ecf20Sopenharmony_ci	if (disconnect)
27938c2ecf20Sopenharmony_ci		c4iw_ep_disconnect(ep, 0, GFP_KERNEL);
27948c2ecf20Sopenharmony_ci	if (release)
27958c2ecf20Sopenharmony_ci		release_ep_resources(ep);
27968c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->com);
27978c2ecf20Sopenharmony_ci	return 0;
27988c2ecf20Sopenharmony_ci}
27998c2ecf20Sopenharmony_ci
28008c2ecf20Sopenharmony_cistatic void finish_peer_abort(struct c4iw_dev *dev, struct c4iw_ep *ep)
28018c2ecf20Sopenharmony_ci{
28028c2ecf20Sopenharmony_ci	complete_cached_srq_buffers(ep, ep->srqe_idx);
28038c2ecf20Sopenharmony_ci	if (ep->com.cm_id && ep->com.qp) {
28048c2ecf20Sopenharmony_ci		struct c4iw_qp_attributes attrs;
28058c2ecf20Sopenharmony_ci
28068c2ecf20Sopenharmony_ci		attrs.next_state = C4IW_QP_STATE_ERROR;
28078c2ecf20Sopenharmony_ci		c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
28088c2ecf20Sopenharmony_ci			       C4IW_QP_ATTR_NEXT_STATE,	&attrs, 1);
28098c2ecf20Sopenharmony_ci	}
28108c2ecf20Sopenharmony_ci	peer_abort_upcall(ep);
28118c2ecf20Sopenharmony_ci	release_ep_resources(ep);
28128c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->com);
28138c2ecf20Sopenharmony_ci}
28148c2ecf20Sopenharmony_ci
28158c2ecf20Sopenharmony_cistatic int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
28168c2ecf20Sopenharmony_ci{
28178c2ecf20Sopenharmony_ci	struct cpl_abort_req_rss6 *req = cplhdr(skb);
28188c2ecf20Sopenharmony_ci	struct c4iw_ep *ep;
28198c2ecf20Sopenharmony_ci	struct sk_buff *rpl_skb;
28208c2ecf20Sopenharmony_ci	struct c4iw_qp_attributes attrs;
28218c2ecf20Sopenharmony_ci	int ret;
28228c2ecf20Sopenharmony_ci	int release = 0;
28238c2ecf20Sopenharmony_ci	unsigned int tid = GET_TID(req);
28248c2ecf20Sopenharmony_ci	u8 status;
28258c2ecf20Sopenharmony_ci	u32 srqidx;
28268c2ecf20Sopenharmony_ci
28278c2ecf20Sopenharmony_ci	u32 len = roundup(sizeof(struct cpl_abort_rpl), 16);
28288c2ecf20Sopenharmony_ci
28298c2ecf20Sopenharmony_ci	ep = get_ep_from_tid(dev, tid);
28308c2ecf20Sopenharmony_ci	if (!ep)
28318c2ecf20Sopenharmony_ci		return 0;
28328c2ecf20Sopenharmony_ci
28338c2ecf20Sopenharmony_ci	status = ABORT_RSS_STATUS_G(be32_to_cpu(req->srqidx_status));
28348c2ecf20Sopenharmony_ci
28358c2ecf20Sopenharmony_ci	if (cxgb_is_neg_adv(status)) {
28368c2ecf20Sopenharmony_ci		pr_debug("Negative advice on abort- tid %u status %d (%s)\n",
28378c2ecf20Sopenharmony_ci			 ep->hwtid, status, neg_adv_str(status));
28388c2ecf20Sopenharmony_ci		ep->stats.abort_neg_adv++;
28398c2ecf20Sopenharmony_ci		mutex_lock(&dev->rdev.stats.lock);
28408c2ecf20Sopenharmony_ci		dev->rdev.stats.neg_adv++;
28418c2ecf20Sopenharmony_ci		mutex_unlock(&dev->rdev.stats.lock);
28428c2ecf20Sopenharmony_ci		goto deref_ep;
28438c2ecf20Sopenharmony_ci	}
28448c2ecf20Sopenharmony_ci
28458c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u state %u\n", ep, ep->hwtid,
28468c2ecf20Sopenharmony_ci		 ep->com.state);
28478c2ecf20Sopenharmony_ci	set_bit(PEER_ABORT, &ep->com.history);
28488c2ecf20Sopenharmony_ci
28498c2ecf20Sopenharmony_ci	/*
28508c2ecf20Sopenharmony_ci	 * Wake up any threads in rdma_init() or rdma_fini().
28518c2ecf20Sopenharmony_ci	 * However, this is not needed if com state is just
28528c2ecf20Sopenharmony_ci	 * MPA_REQ_SENT
28538c2ecf20Sopenharmony_ci	 */
28548c2ecf20Sopenharmony_ci	if (ep->com.state != MPA_REQ_SENT)
28558c2ecf20Sopenharmony_ci		c4iw_wake_up_noref(ep->com.wr_waitp, -ECONNRESET);
28568c2ecf20Sopenharmony_ci
28578c2ecf20Sopenharmony_ci	mutex_lock(&ep->com.mutex);
28588c2ecf20Sopenharmony_ci	switch (ep->com.state) {
28598c2ecf20Sopenharmony_ci	case CONNECTING:
28608c2ecf20Sopenharmony_ci		c4iw_put_ep(&ep->parent_ep->com);
28618c2ecf20Sopenharmony_ci		break;
28628c2ecf20Sopenharmony_ci	case MPA_REQ_WAIT:
28638c2ecf20Sopenharmony_ci		(void)stop_ep_timer(ep);
28648c2ecf20Sopenharmony_ci		break;
28658c2ecf20Sopenharmony_ci	case MPA_REQ_SENT:
28668c2ecf20Sopenharmony_ci		(void)stop_ep_timer(ep);
28678c2ecf20Sopenharmony_ci		if (status != CPL_ERR_CONN_RESET || mpa_rev == 1 ||
28688c2ecf20Sopenharmony_ci		    (mpa_rev == 2 && ep->tried_with_mpa_v1))
28698c2ecf20Sopenharmony_ci			connect_reply_upcall(ep, -ECONNRESET);
28708c2ecf20Sopenharmony_ci		else {
28718c2ecf20Sopenharmony_ci			/*
28728c2ecf20Sopenharmony_ci			 * we just don't send notification upwards because we
28738c2ecf20Sopenharmony_ci			 * want to retry with mpa_v1 without upper layers even
28748c2ecf20Sopenharmony_ci			 * knowing it.
28758c2ecf20Sopenharmony_ci			 *
28768c2ecf20Sopenharmony_ci			 * do some housekeeping so as to re-initiate the
28778c2ecf20Sopenharmony_ci			 * connection
28788c2ecf20Sopenharmony_ci			 */
28798c2ecf20Sopenharmony_ci			pr_info("%s: mpa_rev=%d. Retrying with mpav1\n",
28808c2ecf20Sopenharmony_ci				__func__, mpa_rev);
28818c2ecf20Sopenharmony_ci			ep->retry_with_mpa_v1 = 1;
28828c2ecf20Sopenharmony_ci		}
28838c2ecf20Sopenharmony_ci		break;
28848c2ecf20Sopenharmony_ci	case MPA_REP_SENT:
28858c2ecf20Sopenharmony_ci		break;
28868c2ecf20Sopenharmony_ci	case MPA_REQ_RCVD:
28878c2ecf20Sopenharmony_ci		break;
28888c2ecf20Sopenharmony_ci	case MORIBUND:
28898c2ecf20Sopenharmony_ci	case CLOSING:
28908c2ecf20Sopenharmony_ci		stop_ep_timer(ep);
28918c2ecf20Sopenharmony_ci		fallthrough;
28928c2ecf20Sopenharmony_ci	case FPDU_MODE:
28938c2ecf20Sopenharmony_ci		if (ep->com.qp && ep->com.qp->srq) {
28948c2ecf20Sopenharmony_ci			srqidx = ABORT_RSS_SRQIDX_G(
28958c2ecf20Sopenharmony_ci					be32_to_cpu(req->srqidx_status));
28968c2ecf20Sopenharmony_ci			if (srqidx) {
28978c2ecf20Sopenharmony_ci				complete_cached_srq_buffers(ep, srqidx);
28988c2ecf20Sopenharmony_ci			} else {
28998c2ecf20Sopenharmony_ci				/* Hold ep ref until finish_peer_abort() */
29008c2ecf20Sopenharmony_ci				c4iw_get_ep(&ep->com);
29018c2ecf20Sopenharmony_ci				__state_set(&ep->com, ABORTING);
29028c2ecf20Sopenharmony_ci				set_bit(PEER_ABORT_IN_PROGRESS, &ep->com.flags);
29038c2ecf20Sopenharmony_ci				read_tcb(ep);
29048c2ecf20Sopenharmony_ci				break;
29058c2ecf20Sopenharmony_ci
29068c2ecf20Sopenharmony_ci			}
29078c2ecf20Sopenharmony_ci		}
29088c2ecf20Sopenharmony_ci
29098c2ecf20Sopenharmony_ci		if (ep->com.cm_id && ep->com.qp) {
29108c2ecf20Sopenharmony_ci			attrs.next_state = C4IW_QP_STATE_ERROR;
29118c2ecf20Sopenharmony_ci			ret = c4iw_modify_qp(ep->com.qp->rhp,
29128c2ecf20Sopenharmony_ci				     ep->com.qp, C4IW_QP_ATTR_NEXT_STATE,
29138c2ecf20Sopenharmony_ci				     &attrs, 1);
29148c2ecf20Sopenharmony_ci			if (ret)
29158c2ecf20Sopenharmony_ci				pr_err("%s - qp <- error failed!\n", __func__);
29168c2ecf20Sopenharmony_ci		}
29178c2ecf20Sopenharmony_ci		peer_abort_upcall(ep);
29188c2ecf20Sopenharmony_ci		break;
29198c2ecf20Sopenharmony_ci	case ABORTING:
29208c2ecf20Sopenharmony_ci		break;
29218c2ecf20Sopenharmony_ci	case DEAD:
29228c2ecf20Sopenharmony_ci		pr_warn("%s PEER_ABORT IN DEAD STATE!!!!\n", __func__);
29238c2ecf20Sopenharmony_ci		mutex_unlock(&ep->com.mutex);
29248c2ecf20Sopenharmony_ci		goto deref_ep;
29258c2ecf20Sopenharmony_ci	default:
29268c2ecf20Sopenharmony_ci		WARN_ONCE(1, "Bad endpoint state %u\n", ep->com.state);
29278c2ecf20Sopenharmony_ci		break;
29288c2ecf20Sopenharmony_ci	}
29298c2ecf20Sopenharmony_ci	dst_confirm(ep->dst);
29308c2ecf20Sopenharmony_ci	if (ep->com.state != ABORTING) {
29318c2ecf20Sopenharmony_ci		__state_set(&ep->com, DEAD);
29328c2ecf20Sopenharmony_ci		/* we don't release if we want to retry with mpa_v1 */
29338c2ecf20Sopenharmony_ci		if (!ep->retry_with_mpa_v1)
29348c2ecf20Sopenharmony_ci			release = 1;
29358c2ecf20Sopenharmony_ci	}
29368c2ecf20Sopenharmony_ci	mutex_unlock(&ep->com.mutex);
29378c2ecf20Sopenharmony_ci
29388c2ecf20Sopenharmony_ci	rpl_skb = skb_dequeue(&ep->com.ep_skb_list);
29398c2ecf20Sopenharmony_ci	if (WARN_ON(!rpl_skb)) {
29408c2ecf20Sopenharmony_ci		release = 1;
29418c2ecf20Sopenharmony_ci		goto out;
29428c2ecf20Sopenharmony_ci	}
29438c2ecf20Sopenharmony_ci
29448c2ecf20Sopenharmony_ci	cxgb_mk_abort_rpl(rpl_skb, len, ep->hwtid, ep->txq_idx);
29458c2ecf20Sopenharmony_ci
29468c2ecf20Sopenharmony_ci	c4iw_ofld_send(&ep->com.dev->rdev, rpl_skb);
29478c2ecf20Sopenharmony_ciout:
29488c2ecf20Sopenharmony_ci	if (release)
29498c2ecf20Sopenharmony_ci		release_ep_resources(ep);
29508c2ecf20Sopenharmony_ci	else if (ep->retry_with_mpa_v1) {
29518c2ecf20Sopenharmony_ci		if (ep->com.remote_addr.ss_family == AF_INET6) {
29528c2ecf20Sopenharmony_ci			struct sockaddr_in6 *sin6 =
29538c2ecf20Sopenharmony_ci					(struct sockaddr_in6 *)
29548c2ecf20Sopenharmony_ci					&ep->com.local_addr;
29558c2ecf20Sopenharmony_ci			cxgb4_clip_release(
29568c2ecf20Sopenharmony_ci					ep->com.dev->rdev.lldi.ports[0],
29578c2ecf20Sopenharmony_ci					(const u32 *)&sin6->sin6_addr.s6_addr,
29588c2ecf20Sopenharmony_ci					1);
29598c2ecf20Sopenharmony_ci		}
29608c2ecf20Sopenharmony_ci		xa_erase_irq(&ep->com.dev->hwtids, ep->hwtid);
29618c2ecf20Sopenharmony_ci		cxgb4_remove_tid(ep->com.dev->rdev.lldi.tids, 0, ep->hwtid,
29628c2ecf20Sopenharmony_ci				 ep->com.local_addr.ss_family);
29638c2ecf20Sopenharmony_ci		dst_release(ep->dst);
29648c2ecf20Sopenharmony_ci		cxgb4_l2t_release(ep->l2t);
29658c2ecf20Sopenharmony_ci		c4iw_reconnect(ep);
29668c2ecf20Sopenharmony_ci	}
29678c2ecf20Sopenharmony_ci
29688c2ecf20Sopenharmony_cideref_ep:
29698c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->com);
29708c2ecf20Sopenharmony_ci	/* Dereferencing ep, referenced in peer_abort_intr() */
29718c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->com);
29728c2ecf20Sopenharmony_ci	return 0;
29738c2ecf20Sopenharmony_ci}
29748c2ecf20Sopenharmony_ci
29758c2ecf20Sopenharmony_cistatic int close_con_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
29768c2ecf20Sopenharmony_ci{
29778c2ecf20Sopenharmony_ci	struct c4iw_ep *ep;
29788c2ecf20Sopenharmony_ci	struct c4iw_qp_attributes attrs;
29798c2ecf20Sopenharmony_ci	struct cpl_close_con_rpl *rpl = cplhdr(skb);
29808c2ecf20Sopenharmony_ci	int release = 0;
29818c2ecf20Sopenharmony_ci	unsigned int tid = GET_TID(rpl);
29828c2ecf20Sopenharmony_ci
29838c2ecf20Sopenharmony_ci	ep = get_ep_from_tid(dev, tid);
29848c2ecf20Sopenharmony_ci	if (!ep)
29858c2ecf20Sopenharmony_ci		return 0;
29868c2ecf20Sopenharmony_ci
29878c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u\n", ep, ep->hwtid);
29888c2ecf20Sopenharmony_ci
29898c2ecf20Sopenharmony_ci	/* The cm_id may be null if we failed to connect */
29908c2ecf20Sopenharmony_ci	mutex_lock(&ep->com.mutex);
29918c2ecf20Sopenharmony_ci	set_bit(CLOSE_CON_RPL, &ep->com.history);
29928c2ecf20Sopenharmony_ci	switch (ep->com.state) {
29938c2ecf20Sopenharmony_ci	case CLOSING:
29948c2ecf20Sopenharmony_ci		__state_set(&ep->com, MORIBUND);
29958c2ecf20Sopenharmony_ci		break;
29968c2ecf20Sopenharmony_ci	case MORIBUND:
29978c2ecf20Sopenharmony_ci		(void)stop_ep_timer(ep);
29988c2ecf20Sopenharmony_ci		if ((ep->com.cm_id) && (ep->com.qp)) {
29998c2ecf20Sopenharmony_ci			attrs.next_state = C4IW_QP_STATE_IDLE;
30008c2ecf20Sopenharmony_ci			c4iw_modify_qp(ep->com.qp->rhp,
30018c2ecf20Sopenharmony_ci					     ep->com.qp,
30028c2ecf20Sopenharmony_ci					     C4IW_QP_ATTR_NEXT_STATE,
30038c2ecf20Sopenharmony_ci					     &attrs, 1);
30048c2ecf20Sopenharmony_ci		}
30058c2ecf20Sopenharmony_ci		close_complete_upcall(ep, 0);
30068c2ecf20Sopenharmony_ci		__state_set(&ep->com, DEAD);
30078c2ecf20Sopenharmony_ci		release = 1;
30088c2ecf20Sopenharmony_ci		break;
30098c2ecf20Sopenharmony_ci	case ABORTING:
30108c2ecf20Sopenharmony_ci	case DEAD:
30118c2ecf20Sopenharmony_ci		break;
30128c2ecf20Sopenharmony_ci	default:
30138c2ecf20Sopenharmony_ci		WARN_ONCE(1, "Bad endpoint state %u\n", ep->com.state);
30148c2ecf20Sopenharmony_ci		break;
30158c2ecf20Sopenharmony_ci	}
30168c2ecf20Sopenharmony_ci	mutex_unlock(&ep->com.mutex);
30178c2ecf20Sopenharmony_ci	if (release)
30188c2ecf20Sopenharmony_ci		release_ep_resources(ep);
30198c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->com);
30208c2ecf20Sopenharmony_ci	return 0;
30218c2ecf20Sopenharmony_ci}
30228c2ecf20Sopenharmony_ci
30238c2ecf20Sopenharmony_cistatic int terminate(struct c4iw_dev *dev, struct sk_buff *skb)
30248c2ecf20Sopenharmony_ci{
30258c2ecf20Sopenharmony_ci	struct cpl_rdma_terminate *rpl = cplhdr(skb);
30268c2ecf20Sopenharmony_ci	unsigned int tid = GET_TID(rpl);
30278c2ecf20Sopenharmony_ci	struct c4iw_ep *ep;
30288c2ecf20Sopenharmony_ci	struct c4iw_qp_attributes attrs;
30298c2ecf20Sopenharmony_ci
30308c2ecf20Sopenharmony_ci	ep = get_ep_from_tid(dev, tid);
30318c2ecf20Sopenharmony_ci
30328c2ecf20Sopenharmony_ci	if (ep) {
30338c2ecf20Sopenharmony_ci		if (ep->com.qp) {
30348c2ecf20Sopenharmony_ci			pr_warn("TERM received tid %u qpid %u\n", tid,
30358c2ecf20Sopenharmony_ci				ep->com.qp->wq.sq.qid);
30368c2ecf20Sopenharmony_ci			attrs.next_state = C4IW_QP_STATE_TERMINATE;
30378c2ecf20Sopenharmony_ci			c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
30388c2ecf20Sopenharmony_ci				       C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
30398c2ecf20Sopenharmony_ci		}
30408c2ecf20Sopenharmony_ci
30418c2ecf20Sopenharmony_ci		/* As per draft-hilland-iwarp-verbs-v1.0, sec 6.2.3,
30428c2ecf20Sopenharmony_ci		 * when entering the TERM state the RNIC MUST initiate a CLOSE.
30438c2ecf20Sopenharmony_ci		 */
30448c2ecf20Sopenharmony_ci		c4iw_ep_disconnect(ep, 1, GFP_KERNEL);
30458c2ecf20Sopenharmony_ci		c4iw_put_ep(&ep->com);
30468c2ecf20Sopenharmony_ci	} else
30478c2ecf20Sopenharmony_ci		pr_warn("TERM received tid %u no ep/qp\n", tid);
30488c2ecf20Sopenharmony_ci
30498c2ecf20Sopenharmony_ci	return 0;
30508c2ecf20Sopenharmony_ci}
30518c2ecf20Sopenharmony_ci
30528c2ecf20Sopenharmony_ci/*
30538c2ecf20Sopenharmony_ci * Upcall from the adapter indicating data has been transmitted.
30548c2ecf20Sopenharmony_ci * For us its just the single MPA request or reply.  We can now free
30558c2ecf20Sopenharmony_ci * the skb holding the mpa message.
30568c2ecf20Sopenharmony_ci */
30578c2ecf20Sopenharmony_cistatic int fw4_ack(struct c4iw_dev *dev, struct sk_buff *skb)
30588c2ecf20Sopenharmony_ci{
30598c2ecf20Sopenharmony_ci	struct c4iw_ep *ep;
30608c2ecf20Sopenharmony_ci	struct cpl_fw4_ack *hdr = cplhdr(skb);
30618c2ecf20Sopenharmony_ci	u8 credits = hdr->credits;
30628c2ecf20Sopenharmony_ci	unsigned int tid = GET_TID(hdr);
30638c2ecf20Sopenharmony_ci
30648c2ecf20Sopenharmony_ci
30658c2ecf20Sopenharmony_ci	ep = get_ep_from_tid(dev, tid);
30668c2ecf20Sopenharmony_ci	if (!ep)
30678c2ecf20Sopenharmony_ci		return 0;
30688c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u credits %u\n",
30698c2ecf20Sopenharmony_ci		 ep, ep->hwtid, credits);
30708c2ecf20Sopenharmony_ci	if (credits == 0) {
30718c2ecf20Sopenharmony_ci		pr_debug("0 credit ack ep %p tid %u state %u\n",
30728c2ecf20Sopenharmony_ci			 ep, ep->hwtid, state_read(&ep->com));
30738c2ecf20Sopenharmony_ci		goto out;
30748c2ecf20Sopenharmony_ci	}
30758c2ecf20Sopenharmony_ci
30768c2ecf20Sopenharmony_ci	dst_confirm(ep->dst);
30778c2ecf20Sopenharmony_ci	if (ep->mpa_skb) {
30788c2ecf20Sopenharmony_ci		pr_debug("last streaming msg ack ep %p tid %u state %u initiator %u freeing skb\n",
30798c2ecf20Sopenharmony_ci			 ep, ep->hwtid, state_read(&ep->com),
30808c2ecf20Sopenharmony_ci			 ep->mpa_attr.initiator ? 1 : 0);
30818c2ecf20Sopenharmony_ci		mutex_lock(&ep->com.mutex);
30828c2ecf20Sopenharmony_ci		kfree_skb(ep->mpa_skb);
30838c2ecf20Sopenharmony_ci		ep->mpa_skb = NULL;
30848c2ecf20Sopenharmony_ci		if (test_bit(STOP_MPA_TIMER, &ep->com.flags))
30858c2ecf20Sopenharmony_ci			stop_ep_timer(ep);
30868c2ecf20Sopenharmony_ci		mutex_unlock(&ep->com.mutex);
30878c2ecf20Sopenharmony_ci	}
30888c2ecf20Sopenharmony_ciout:
30898c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->com);
30908c2ecf20Sopenharmony_ci	return 0;
30918c2ecf20Sopenharmony_ci}
30928c2ecf20Sopenharmony_ci
30938c2ecf20Sopenharmony_ciint c4iw_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
30948c2ecf20Sopenharmony_ci{
30958c2ecf20Sopenharmony_ci	int abort;
30968c2ecf20Sopenharmony_ci	struct c4iw_ep *ep = to_ep(cm_id);
30978c2ecf20Sopenharmony_ci
30988c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u\n", ep, ep->hwtid);
30998c2ecf20Sopenharmony_ci
31008c2ecf20Sopenharmony_ci	mutex_lock(&ep->com.mutex);
31018c2ecf20Sopenharmony_ci	if (ep->com.state != MPA_REQ_RCVD) {
31028c2ecf20Sopenharmony_ci		mutex_unlock(&ep->com.mutex);
31038c2ecf20Sopenharmony_ci		c4iw_put_ep(&ep->com);
31048c2ecf20Sopenharmony_ci		return -ECONNRESET;
31058c2ecf20Sopenharmony_ci	}
31068c2ecf20Sopenharmony_ci	set_bit(ULP_REJECT, &ep->com.history);
31078c2ecf20Sopenharmony_ci	if (mpa_rev == 0)
31088c2ecf20Sopenharmony_ci		abort = 1;
31098c2ecf20Sopenharmony_ci	else
31108c2ecf20Sopenharmony_ci		abort = send_mpa_reject(ep, pdata, pdata_len);
31118c2ecf20Sopenharmony_ci	mutex_unlock(&ep->com.mutex);
31128c2ecf20Sopenharmony_ci
31138c2ecf20Sopenharmony_ci	stop_ep_timer(ep);
31148c2ecf20Sopenharmony_ci	c4iw_ep_disconnect(ep, abort != 0, GFP_KERNEL);
31158c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->com);
31168c2ecf20Sopenharmony_ci	return 0;
31178c2ecf20Sopenharmony_ci}
31188c2ecf20Sopenharmony_ci
31198c2ecf20Sopenharmony_ciint c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
31208c2ecf20Sopenharmony_ci{
31218c2ecf20Sopenharmony_ci	int err;
31228c2ecf20Sopenharmony_ci	struct c4iw_qp_attributes attrs;
31238c2ecf20Sopenharmony_ci	enum c4iw_qp_attr_mask mask;
31248c2ecf20Sopenharmony_ci	struct c4iw_ep *ep = to_ep(cm_id);
31258c2ecf20Sopenharmony_ci	struct c4iw_dev *h = to_c4iw_dev(cm_id->device);
31268c2ecf20Sopenharmony_ci	struct c4iw_qp *qp = get_qhp(h, conn_param->qpn);
31278c2ecf20Sopenharmony_ci	int abort = 0;
31288c2ecf20Sopenharmony_ci
31298c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u\n", ep, ep->hwtid);
31308c2ecf20Sopenharmony_ci
31318c2ecf20Sopenharmony_ci	mutex_lock(&ep->com.mutex);
31328c2ecf20Sopenharmony_ci	if (ep->com.state != MPA_REQ_RCVD) {
31338c2ecf20Sopenharmony_ci		err = -ECONNRESET;
31348c2ecf20Sopenharmony_ci		goto err_out;
31358c2ecf20Sopenharmony_ci	}
31368c2ecf20Sopenharmony_ci
31378c2ecf20Sopenharmony_ci	if (!qp) {
31388c2ecf20Sopenharmony_ci		err = -EINVAL;
31398c2ecf20Sopenharmony_ci		goto err_out;
31408c2ecf20Sopenharmony_ci	}
31418c2ecf20Sopenharmony_ci
31428c2ecf20Sopenharmony_ci	set_bit(ULP_ACCEPT, &ep->com.history);
31438c2ecf20Sopenharmony_ci	if ((conn_param->ord > cur_max_read_depth(ep->com.dev)) ||
31448c2ecf20Sopenharmony_ci	    (conn_param->ird > cur_max_read_depth(ep->com.dev))) {
31458c2ecf20Sopenharmony_ci		err = -EINVAL;
31468c2ecf20Sopenharmony_ci		goto err_abort;
31478c2ecf20Sopenharmony_ci	}
31488c2ecf20Sopenharmony_ci
31498c2ecf20Sopenharmony_ci	if (ep->mpa_attr.version == 2 && ep->mpa_attr.enhanced_rdma_conn) {
31508c2ecf20Sopenharmony_ci		if (conn_param->ord > ep->ird) {
31518c2ecf20Sopenharmony_ci			if (RELAXED_IRD_NEGOTIATION) {
31528c2ecf20Sopenharmony_ci				conn_param->ord = ep->ird;
31538c2ecf20Sopenharmony_ci			} else {
31548c2ecf20Sopenharmony_ci				ep->ird = conn_param->ird;
31558c2ecf20Sopenharmony_ci				ep->ord = conn_param->ord;
31568c2ecf20Sopenharmony_ci				send_mpa_reject(ep, conn_param->private_data,
31578c2ecf20Sopenharmony_ci						conn_param->private_data_len);
31588c2ecf20Sopenharmony_ci				err = -ENOMEM;
31598c2ecf20Sopenharmony_ci				goto err_abort;
31608c2ecf20Sopenharmony_ci			}
31618c2ecf20Sopenharmony_ci		}
31628c2ecf20Sopenharmony_ci		if (conn_param->ird < ep->ord) {
31638c2ecf20Sopenharmony_ci			if (RELAXED_IRD_NEGOTIATION &&
31648c2ecf20Sopenharmony_ci			    ep->ord <= h->rdev.lldi.max_ordird_qp) {
31658c2ecf20Sopenharmony_ci				conn_param->ird = ep->ord;
31668c2ecf20Sopenharmony_ci			} else {
31678c2ecf20Sopenharmony_ci				err = -ENOMEM;
31688c2ecf20Sopenharmony_ci				goto err_abort;
31698c2ecf20Sopenharmony_ci			}
31708c2ecf20Sopenharmony_ci		}
31718c2ecf20Sopenharmony_ci	}
31728c2ecf20Sopenharmony_ci	ep->ird = conn_param->ird;
31738c2ecf20Sopenharmony_ci	ep->ord = conn_param->ord;
31748c2ecf20Sopenharmony_ci
31758c2ecf20Sopenharmony_ci	if (ep->mpa_attr.version == 1) {
31768c2ecf20Sopenharmony_ci		if (peer2peer && ep->ird == 0)
31778c2ecf20Sopenharmony_ci			ep->ird = 1;
31788c2ecf20Sopenharmony_ci	} else {
31798c2ecf20Sopenharmony_ci		if (peer2peer &&
31808c2ecf20Sopenharmony_ci		    (ep->mpa_attr.p2p_type != FW_RI_INIT_P2PTYPE_DISABLED) &&
31818c2ecf20Sopenharmony_ci		    (p2p_type == FW_RI_INIT_P2PTYPE_READ_REQ) && ep->ird == 0)
31828c2ecf20Sopenharmony_ci			ep->ird = 1;
31838c2ecf20Sopenharmony_ci	}
31848c2ecf20Sopenharmony_ci
31858c2ecf20Sopenharmony_ci	pr_debug("ird %d ord %d\n", ep->ird, ep->ord);
31868c2ecf20Sopenharmony_ci
31878c2ecf20Sopenharmony_ci	ep->com.cm_id = cm_id;
31888c2ecf20Sopenharmony_ci	ref_cm_id(&ep->com);
31898c2ecf20Sopenharmony_ci	ep->com.qp = qp;
31908c2ecf20Sopenharmony_ci	ref_qp(ep);
31918c2ecf20Sopenharmony_ci
31928c2ecf20Sopenharmony_ci	/* bind QP to EP and move to RTS */
31938c2ecf20Sopenharmony_ci	attrs.mpa_attr = ep->mpa_attr;
31948c2ecf20Sopenharmony_ci	attrs.max_ird = ep->ird;
31958c2ecf20Sopenharmony_ci	attrs.max_ord = ep->ord;
31968c2ecf20Sopenharmony_ci	attrs.llp_stream_handle = ep;
31978c2ecf20Sopenharmony_ci	attrs.next_state = C4IW_QP_STATE_RTS;
31988c2ecf20Sopenharmony_ci
31998c2ecf20Sopenharmony_ci	/* bind QP and TID with INIT_WR */
32008c2ecf20Sopenharmony_ci	mask = C4IW_QP_ATTR_NEXT_STATE |
32018c2ecf20Sopenharmony_ci			     C4IW_QP_ATTR_LLP_STREAM_HANDLE |
32028c2ecf20Sopenharmony_ci			     C4IW_QP_ATTR_MPA_ATTR |
32038c2ecf20Sopenharmony_ci			     C4IW_QP_ATTR_MAX_IRD |
32048c2ecf20Sopenharmony_ci			     C4IW_QP_ATTR_MAX_ORD;
32058c2ecf20Sopenharmony_ci
32068c2ecf20Sopenharmony_ci	err = c4iw_modify_qp(ep->com.qp->rhp,
32078c2ecf20Sopenharmony_ci			     ep->com.qp, mask, &attrs, 1);
32088c2ecf20Sopenharmony_ci	if (err)
32098c2ecf20Sopenharmony_ci		goto err_deref_cm_id;
32108c2ecf20Sopenharmony_ci
32118c2ecf20Sopenharmony_ci	set_bit(STOP_MPA_TIMER, &ep->com.flags);
32128c2ecf20Sopenharmony_ci	err = send_mpa_reply(ep, conn_param->private_data,
32138c2ecf20Sopenharmony_ci			     conn_param->private_data_len);
32148c2ecf20Sopenharmony_ci	if (err)
32158c2ecf20Sopenharmony_ci		goto err_deref_cm_id;
32168c2ecf20Sopenharmony_ci
32178c2ecf20Sopenharmony_ci	__state_set(&ep->com, FPDU_MODE);
32188c2ecf20Sopenharmony_ci	established_upcall(ep);
32198c2ecf20Sopenharmony_ci	mutex_unlock(&ep->com.mutex);
32208c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->com);
32218c2ecf20Sopenharmony_ci	return 0;
32228c2ecf20Sopenharmony_cierr_deref_cm_id:
32238c2ecf20Sopenharmony_ci	deref_cm_id(&ep->com);
32248c2ecf20Sopenharmony_cierr_abort:
32258c2ecf20Sopenharmony_ci	abort = 1;
32268c2ecf20Sopenharmony_cierr_out:
32278c2ecf20Sopenharmony_ci	mutex_unlock(&ep->com.mutex);
32288c2ecf20Sopenharmony_ci	if (abort)
32298c2ecf20Sopenharmony_ci		c4iw_ep_disconnect(ep, 1, GFP_KERNEL);
32308c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->com);
32318c2ecf20Sopenharmony_ci	return err;
32328c2ecf20Sopenharmony_ci}
32338c2ecf20Sopenharmony_ci
32348c2ecf20Sopenharmony_cistatic int pick_local_ipaddrs(struct c4iw_dev *dev, struct iw_cm_id *cm_id)
32358c2ecf20Sopenharmony_ci{
32368c2ecf20Sopenharmony_ci	struct in_device *ind;
32378c2ecf20Sopenharmony_ci	int found = 0;
32388c2ecf20Sopenharmony_ci	struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_id->m_local_addr;
32398c2ecf20Sopenharmony_ci	struct sockaddr_in *raddr = (struct sockaddr_in *)&cm_id->m_remote_addr;
32408c2ecf20Sopenharmony_ci	const struct in_ifaddr *ifa;
32418c2ecf20Sopenharmony_ci
32428c2ecf20Sopenharmony_ci	ind = in_dev_get(dev->rdev.lldi.ports[0]);
32438c2ecf20Sopenharmony_ci	if (!ind)
32448c2ecf20Sopenharmony_ci		return -EADDRNOTAVAIL;
32458c2ecf20Sopenharmony_ci	rcu_read_lock();
32468c2ecf20Sopenharmony_ci	in_dev_for_each_ifa_rcu(ifa, ind) {
32478c2ecf20Sopenharmony_ci		if (ifa->ifa_flags & IFA_F_SECONDARY)
32488c2ecf20Sopenharmony_ci			continue;
32498c2ecf20Sopenharmony_ci		laddr->sin_addr.s_addr = ifa->ifa_address;
32508c2ecf20Sopenharmony_ci		raddr->sin_addr.s_addr = ifa->ifa_address;
32518c2ecf20Sopenharmony_ci		found = 1;
32528c2ecf20Sopenharmony_ci		break;
32538c2ecf20Sopenharmony_ci	}
32548c2ecf20Sopenharmony_ci	rcu_read_unlock();
32558c2ecf20Sopenharmony_ci
32568c2ecf20Sopenharmony_ci	in_dev_put(ind);
32578c2ecf20Sopenharmony_ci	return found ? 0 : -EADDRNOTAVAIL;
32588c2ecf20Sopenharmony_ci}
32598c2ecf20Sopenharmony_ci
32608c2ecf20Sopenharmony_cistatic int get_lladdr(struct net_device *dev, struct in6_addr *addr,
32618c2ecf20Sopenharmony_ci		      unsigned char banned_flags)
32628c2ecf20Sopenharmony_ci{
32638c2ecf20Sopenharmony_ci	struct inet6_dev *idev;
32648c2ecf20Sopenharmony_ci	int err = -EADDRNOTAVAIL;
32658c2ecf20Sopenharmony_ci
32668c2ecf20Sopenharmony_ci	rcu_read_lock();
32678c2ecf20Sopenharmony_ci	idev = __in6_dev_get(dev);
32688c2ecf20Sopenharmony_ci	if (idev != NULL) {
32698c2ecf20Sopenharmony_ci		struct inet6_ifaddr *ifp;
32708c2ecf20Sopenharmony_ci
32718c2ecf20Sopenharmony_ci		read_lock_bh(&idev->lock);
32728c2ecf20Sopenharmony_ci		list_for_each_entry(ifp, &idev->addr_list, if_list) {
32738c2ecf20Sopenharmony_ci			if (ifp->scope == IFA_LINK &&
32748c2ecf20Sopenharmony_ci			    !(ifp->flags & banned_flags)) {
32758c2ecf20Sopenharmony_ci				memcpy(addr, &ifp->addr, 16);
32768c2ecf20Sopenharmony_ci				err = 0;
32778c2ecf20Sopenharmony_ci				break;
32788c2ecf20Sopenharmony_ci			}
32798c2ecf20Sopenharmony_ci		}
32808c2ecf20Sopenharmony_ci		read_unlock_bh(&idev->lock);
32818c2ecf20Sopenharmony_ci	}
32828c2ecf20Sopenharmony_ci	rcu_read_unlock();
32838c2ecf20Sopenharmony_ci	return err;
32848c2ecf20Sopenharmony_ci}
32858c2ecf20Sopenharmony_ci
32868c2ecf20Sopenharmony_cistatic int pick_local_ip6addrs(struct c4iw_dev *dev, struct iw_cm_id *cm_id)
32878c2ecf20Sopenharmony_ci{
32888c2ecf20Sopenharmony_ci	struct in6_addr addr;
32898c2ecf20Sopenharmony_ci	struct sockaddr_in6 *la6 = (struct sockaddr_in6 *)&cm_id->m_local_addr;
32908c2ecf20Sopenharmony_ci	struct sockaddr_in6 *ra6 = (struct sockaddr_in6 *)&cm_id->m_remote_addr;
32918c2ecf20Sopenharmony_ci
32928c2ecf20Sopenharmony_ci	if (!get_lladdr(dev->rdev.lldi.ports[0], &addr, IFA_F_TENTATIVE)) {
32938c2ecf20Sopenharmony_ci		memcpy(la6->sin6_addr.s6_addr, &addr, 16);
32948c2ecf20Sopenharmony_ci		memcpy(ra6->sin6_addr.s6_addr, &addr, 16);
32958c2ecf20Sopenharmony_ci		return 0;
32968c2ecf20Sopenharmony_ci	}
32978c2ecf20Sopenharmony_ci	return -EADDRNOTAVAIL;
32988c2ecf20Sopenharmony_ci}
32998c2ecf20Sopenharmony_ci
33008c2ecf20Sopenharmony_ciint c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
33018c2ecf20Sopenharmony_ci{
33028c2ecf20Sopenharmony_ci	struct c4iw_dev *dev = to_c4iw_dev(cm_id->device);
33038c2ecf20Sopenharmony_ci	struct c4iw_ep *ep;
33048c2ecf20Sopenharmony_ci	int err = 0;
33058c2ecf20Sopenharmony_ci	struct sockaddr_in *laddr;
33068c2ecf20Sopenharmony_ci	struct sockaddr_in *raddr;
33078c2ecf20Sopenharmony_ci	struct sockaddr_in6 *laddr6;
33088c2ecf20Sopenharmony_ci	struct sockaddr_in6 *raddr6;
33098c2ecf20Sopenharmony_ci	__u8 *ra;
33108c2ecf20Sopenharmony_ci	int iptype;
33118c2ecf20Sopenharmony_ci
33128c2ecf20Sopenharmony_ci	if ((conn_param->ord > cur_max_read_depth(dev)) ||
33138c2ecf20Sopenharmony_ci	    (conn_param->ird > cur_max_read_depth(dev))) {
33148c2ecf20Sopenharmony_ci		err = -EINVAL;
33158c2ecf20Sopenharmony_ci		goto out;
33168c2ecf20Sopenharmony_ci	}
33178c2ecf20Sopenharmony_ci	ep = alloc_ep(sizeof(*ep), GFP_KERNEL);
33188c2ecf20Sopenharmony_ci	if (!ep) {
33198c2ecf20Sopenharmony_ci		pr_err("%s - cannot alloc ep\n", __func__);
33208c2ecf20Sopenharmony_ci		err = -ENOMEM;
33218c2ecf20Sopenharmony_ci		goto out;
33228c2ecf20Sopenharmony_ci	}
33238c2ecf20Sopenharmony_ci
33248c2ecf20Sopenharmony_ci	skb_queue_head_init(&ep->com.ep_skb_list);
33258c2ecf20Sopenharmony_ci	if (alloc_ep_skb_list(&ep->com.ep_skb_list, CN_MAX_CON_BUF)) {
33268c2ecf20Sopenharmony_ci		err = -ENOMEM;
33278c2ecf20Sopenharmony_ci		goto fail1;
33288c2ecf20Sopenharmony_ci	}
33298c2ecf20Sopenharmony_ci
33308c2ecf20Sopenharmony_ci	timer_setup(&ep->timer, ep_timeout, 0);
33318c2ecf20Sopenharmony_ci	ep->plen = conn_param->private_data_len;
33328c2ecf20Sopenharmony_ci	if (ep->plen)
33338c2ecf20Sopenharmony_ci		memcpy(ep->mpa_pkt + sizeof(struct mpa_message),
33348c2ecf20Sopenharmony_ci		       conn_param->private_data, ep->plen);
33358c2ecf20Sopenharmony_ci	ep->ird = conn_param->ird;
33368c2ecf20Sopenharmony_ci	ep->ord = conn_param->ord;
33378c2ecf20Sopenharmony_ci
33388c2ecf20Sopenharmony_ci	if (peer2peer && ep->ord == 0)
33398c2ecf20Sopenharmony_ci		ep->ord = 1;
33408c2ecf20Sopenharmony_ci
33418c2ecf20Sopenharmony_ci	ep->com.cm_id = cm_id;
33428c2ecf20Sopenharmony_ci	ref_cm_id(&ep->com);
33438c2ecf20Sopenharmony_ci	cm_id->provider_data = ep;
33448c2ecf20Sopenharmony_ci	ep->com.dev = dev;
33458c2ecf20Sopenharmony_ci	ep->com.qp = get_qhp(dev, conn_param->qpn);
33468c2ecf20Sopenharmony_ci	if (!ep->com.qp) {
33478c2ecf20Sopenharmony_ci		pr_warn("%s qpn 0x%x not found!\n", __func__, conn_param->qpn);
33488c2ecf20Sopenharmony_ci		err = -EINVAL;
33498c2ecf20Sopenharmony_ci		goto fail2;
33508c2ecf20Sopenharmony_ci	}
33518c2ecf20Sopenharmony_ci	ref_qp(ep);
33528c2ecf20Sopenharmony_ci	pr_debug("qpn 0x%x qp %p cm_id %p\n", conn_param->qpn,
33538c2ecf20Sopenharmony_ci		 ep->com.qp, cm_id);
33548c2ecf20Sopenharmony_ci
33558c2ecf20Sopenharmony_ci	/*
33568c2ecf20Sopenharmony_ci	 * Allocate an active TID to initiate a TCP connection.
33578c2ecf20Sopenharmony_ci	 */
33588c2ecf20Sopenharmony_ci	ep->atid = cxgb4_alloc_atid(dev->rdev.lldi.tids, ep);
33598c2ecf20Sopenharmony_ci	if (ep->atid == -1) {
33608c2ecf20Sopenharmony_ci		pr_err("%s - cannot alloc atid\n", __func__);
33618c2ecf20Sopenharmony_ci		err = -ENOMEM;
33628c2ecf20Sopenharmony_ci		goto fail2;
33638c2ecf20Sopenharmony_ci	}
33648c2ecf20Sopenharmony_ci	err = xa_insert_irq(&dev->atids, ep->atid, ep, GFP_KERNEL);
33658c2ecf20Sopenharmony_ci	if (err)
33668c2ecf20Sopenharmony_ci		goto fail5;
33678c2ecf20Sopenharmony_ci
33688c2ecf20Sopenharmony_ci	memcpy(&ep->com.local_addr, &cm_id->m_local_addr,
33698c2ecf20Sopenharmony_ci	       sizeof(ep->com.local_addr));
33708c2ecf20Sopenharmony_ci	memcpy(&ep->com.remote_addr, &cm_id->m_remote_addr,
33718c2ecf20Sopenharmony_ci	       sizeof(ep->com.remote_addr));
33728c2ecf20Sopenharmony_ci
33738c2ecf20Sopenharmony_ci	laddr = (struct sockaddr_in *)&ep->com.local_addr;
33748c2ecf20Sopenharmony_ci	raddr = (struct sockaddr_in *)&ep->com.remote_addr;
33758c2ecf20Sopenharmony_ci	laddr6 = (struct sockaddr_in6 *)&ep->com.local_addr;
33768c2ecf20Sopenharmony_ci	raddr6 = (struct sockaddr_in6 *) &ep->com.remote_addr;
33778c2ecf20Sopenharmony_ci
33788c2ecf20Sopenharmony_ci	if (cm_id->m_remote_addr.ss_family == AF_INET) {
33798c2ecf20Sopenharmony_ci		iptype = 4;
33808c2ecf20Sopenharmony_ci		ra = (__u8 *)&raddr->sin_addr;
33818c2ecf20Sopenharmony_ci
33828c2ecf20Sopenharmony_ci		/*
33838c2ecf20Sopenharmony_ci		 * Handle loopback requests to INADDR_ANY.
33848c2ecf20Sopenharmony_ci		 */
33858c2ecf20Sopenharmony_ci		if (raddr->sin_addr.s_addr == htonl(INADDR_ANY)) {
33868c2ecf20Sopenharmony_ci			err = pick_local_ipaddrs(dev, cm_id);
33878c2ecf20Sopenharmony_ci			if (err)
33888c2ecf20Sopenharmony_ci				goto fail3;
33898c2ecf20Sopenharmony_ci		}
33908c2ecf20Sopenharmony_ci
33918c2ecf20Sopenharmony_ci		/* find a route */
33928c2ecf20Sopenharmony_ci		pr_debug("saddr %pI4 sport 0x%x raddr %pI4 rport 0x%x\n",
33938c2ecf20Sopenharmony_ci			 &laddr->sin_addr, ntohs(laddr->sin_port),
33948c2ecf20Sopenharmony_ci			 ra, ntohs(raddr->sin_port));
33958c2ecf20Sopenharmony_ci		ep->dst = cxgb_find_route(&dev->rdev.lldi, get_real_dev,
33968c2ecf20Sopenharmony_ci					  laddr->sin_addr.s_addr,
33978c2ecf20Sopenharmony_ci					  raddr->sin_addr.s_addr,
33988c2ecf20Sopenharmony_ci					  laddr->sin_port,
33998c2ecf20Sopenharmony_ci					  raddr->sin_port, cm_id->tos);
34008c2ecf20Sopenharmony_ci	} else {
34018c2ecf20Sopenharmony_ci		iptype = 6;
34028c2ecf20Sopenharmony_ci		ra = (__u8 *)&raddr6->sin6_addr;
34038c2ecf20Sopenharmony_ci
34048c2ecf20Sopenharmony_ci		/*
34058c2ecf20Sopenharmony_ci		 * Handle loopback requests to INADDR_ANY.
34068c2ecf20Sopenharmony_ci		 */
34078c2ecf20Sopenharmony_ci		if (ipv6_addr_type(&raddr6->sin6_addr) == IPV6_ADDR_ANY) {
34088c2ecf20Sopenharmony_ci			err = pick_local_ip6addrs(dev, cm_id);
34098c2ecf20Sopenharmony_ci			if (err)
34108c2ecf20Sopenharmony_ci				goto fail3;
34118c2ecf20Sopenharmony_ci		}
34128c2ecf20Sopenharmony_ci
34138c2ecf20Sopenharmony_ci		/* find a route */
34148c2ecf20Sopenharmony_ci		pr_debug("saddr %pI6 sport 0x%x raddr %pI6 rport 0x%x\n",
34158c2ecf20Sopenharmony_ci			 laddr6->sin6_addr.s6_addr,
34168c2ecf20Sopenharmony_ci			 ntohs(laddr6->sin6_port),
34178c2ecf20Sopenharmony_ci			 raddr6->sin6_addr.s6_addr, ntohs(raddr6->sin6_port));
34188c2ecf20Sopenharmony_ci		ep->dst = cxgb_find_route6(&dev->rdev.lldi, get_real_dev,
34198c2ecf20Sopenharmony_ci					   laddr6->sin6_addr.s6_addr,
34208c2ecf20Sopenharmony_ci					   raddr6->sin6_addr.s6_addr,
34218c2ecf20Sopenharmony_ci					   laddr6->sin6_port,
34228c2ecf20Sopenharmony_ci					   raddr6->sin6_port, cm_id->tos,
34238c2ecf20Sopenharmony_ci					   raddr6->sin6_scope_id);
34248c2ecf20Sopenharmony_ci	}
34258c2ecf20Sopenharmony_ci	if (!ep->dst) {
34268c2ecf20Sopenharmony_ci		pr_err("%s - cannot find route\n", __func__);
34278c2ecf20Sopenharmony_ci		err = -EHOSTUNREACH;
34288c2ecf20Sopenharmony_ci		goto fail3;
34298c2ecf20Sopenharmony_ci	}
34308c2ecf20Sopenharmony_ci
34318c2ecf20Sopenharmony_ci	err = import_ep(ep, iptype, ra, ep->dst, ep->com.dev, true,
34328c2ecf20Sopenharmony_ci			ep->com.dev->rdev.lldi.adapter_type, cm_id->tos);
34338c2ecf20Sopenharmony_ci	if (err) {
34348c2ecf20Sopenharmony_ci		pr_err("%s - cannot alloc l2e\n", __func__);
34358c2ecf20Sopenharmony_ci		goto fail4;
34368c2ecf20Sopenharmony_ci	}
34378c2ecf20Sopenharmony_ci
34388c2ecf20Sopenharmony_ci	pr_debug("txq_idx %u tx_chan %u smac_idx %u rss_qid %u l2t_idx %u\n",
34398c2ecf20Sopenharmony_ci		 ep->txq_idx, ep->tx_chan, ep->smac_idx, ep->rss_qid,
34408c2ecf20Sopenharmony_ci		 ep->l2t->idx);
34418c2ecf20Sopenharmony_ci
34428c2ecf20Sopenharmony_ci	state_set(&ep->com, CONNECTING);
34438c2ecf20Sopenharmony_ci	ep->tos = cm_id->tos;
34448c2ecf20Sopenharmony_ci
34458c2ecf20Sopenharmony_ci	/* send connect request to rnic */
34468c2ecf20Sopenharmony_ci	err = send_connect(ep);
34478c2ecf20Sopenharmony_ci	if (!err)
34488c2ecf20Sopenharmony_ci		goto out;
34498c2ecf20Sopenharmony_ci
34508c2ecf20Sopenharmony_ci	cxgb4_l2t_release(ep->l2t);
34518c2ecf20Sopenharmony_cifail4:
34528c2ecf20Sopenharmony_ci	dst_release(ep->dst);
34538c2ecf20Sopenharmony_cifail3:
34548c2ecf20Sopenharmony_ci	xa_erase_irq(&ep->com.dev->atids, ep->atid);
34558c2ecf20Sopenharmony_cifail5:
34568c2ecf20Sopenharmony_ci	cxgb4_free_atid(ep->com.dev->rdev.lldi.tids, ep->atid);
34578c2ecf20Sopenharmony_cifail2:
34588c2ecf20Sopenharmony_ci	skb_queue_purge(&ep->com.ep_skb_list);
34598c2ecf20Sopenharmony_ci	deref_cm_id(&ep->com);
34608c2ecf20Sopenharmony_cifail1:
34618c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->com);
34628c2ecf20Sopenharmony_ciout:
34638c2ecf20Sopenharmony_ci	return err;
34648c2ecf20Sopenharmony_ci}
34658c2ecf20Sopenharmony_ci
34668c2ecf20Sopenharmony_cistatic int create_server6(struct c4iw_dev *dev, struct c4iw_listen_ep *ep)
34678c2ecf20Sopenharmony_ci{
34688c2ecf20Sopenharmony_ci	int err;
34698c2ecf20Sopenharmony_ci	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)
34708c2ecf20Sopenharmony_ci				    &ep->com.local_addr;
34718c2ecf20Sopenharmony_ci
34728c2ecf20Sopenharmony_ci	if (ipv6_addr_type(&sin6->sin6_addr) != IPV6_ADDR_ANY) {
34738c2ecf20Sopenharmony_ci		err = cxgb4_clip_get(ep->com.dev->rdev.lldi.ports[0],
34748c2ecf20Sopenharmony_ci				     (const u32 *)&sin6->sin6_addr.s6_addr, 1);
34758c2ecf20Sopenharmony_ci		if (err)
34768c2ecf20Sopenharmony_ci			return err;
34778c2ecf20Sopenharmony_ci	}
34788c2ecf20Sopenharmony_ci	c4iw_init_wr_wait(ep->com.wr_waitp);
34798c2ecf20Sopenharmony_ci	err = cxgb4_create_server6(ep->com.dev->rdev.lldi.ports[0],
34808c2ecf20Sopenharmony_ci				   ep->stid, &sin6->sin6_addr,
34818c2ecf20Sopenharmony_ci				   sin6->sin6_port,
34828c2ecf20Sopenharmony_ci				   ep->com.dev->rdev.lldi.rxq_ids[0]);
34838c2ecf20Sopenharmony_ci	if (!err)
34848c2ecf20Sopenharmony_ci		err = c4iw_wait_for_reply(&ep->com.dev->rdev,
34858c2ecf20Sopenharmony_ci					  ep->com.wr_waitp,
34868c2ecf20Sopenharmony_ci					  0, 0, __func__);
34878c2ecf20Sopenharmony_ci	else if (err > 0)
34888c2ecf20Sopenharmony_ci		err = net_xmit_errno(err);
34898c2ecf20Sopenharmony_ci	if (err) {
34908c2ecf20Sopenharmony_ci		cxgb4_clip_release(ep->com.dev->rdev.lldi.ports[0],
34918c2ecf20Sopenharmony_ci				   (const u32 *)&sin6->sin6_addr.s6_addr, 1);
34928c2ecf20Sopenharmony_ci		pr_err("cxgb4_create_server6/filter failed err %d stid %d laddr %pI6 lport %d\n",
34938c2ecf20Sopenharmony_ci		       err, ep->stid,
34948c2ecf20Sopenharmony_ci		       sin6->sin6_addr.s6_addr, ntohs(sin6->sin6_port));
34958c2ecf20Sopenharmony_ci	}
34968c2ecf20Sopenharmony_ci	return err;
34978c2ecf20Sopenharmony_ci}
34988c2ecf20Sopenharmony_ci
34998c2ecf20Sopenharmony_cistatic int create_server4(struct c4iw_dev *dev, struct c4iw_listen_ep *ep)
35008c2ecf20Sopenharmony_ci{
35018c2ecf20Sopenharmony_ci	int err;
35028c2ecf20Sopenharmony_ci	struct sockaddr_in *sin = (struct sockaddr_in *)
35038c2ecf20Sopenharmony_ci				  &ep->com.local_addr;
35048c2ecf20Sopenharmony_ci
35058c2ecf20Sopenharmony_ci	if (dev->rdev.lldi.enable_fw_ofld_conn) {
35068c2ecf20Sopenharmony_ci		do {
35078c2ecf20Sopenharmony_ci			err = cxgb4_create_server_filter(
35088c2ecf20Sopenharmony_ci				ep->com.dev->rdev.lldi.ports[0], ep->stid,
35098c2ecf20Sopenharmony_ci				sin->sin_addr.s_addr, sin->sin_port, 0,
35108c2ecf20Sopenharmony_ci				ep->com.dev->rdev.lldi.rxq_ids[0], 0, 0);
35118c2ecf20Sopenharmony_ci			if (err == -EBUSY) {
35128c2ecf20Sopenharmony_ci				if (c4iw_fatal_error(&ep->com.dev->rdev)) {
35138c2ecf20Sopenharmony_ci					err = -EIO;
35148c2ecf20Sopenharmony_ci					break;
35158c2ecf20Sopenharmony_ci				}
35168c2ecf20Sopenharmony_ci				set_current_state(TASK_UNINTERRUPTIBLE);
35178c2ecf20Sopenharmony_ci				schedule_timeout(usecs_to_jiffies(100));
35188c2ecf20Sopenharmony_ci			}
35198c2ecf20Sopenharmony_ci		} while (err == -EBUSY);
35208c2ecf20Sopenharmony_ci	} else {
35218c2ecf20Sopenharmony_ci		c4iw_init_wr_wait(ep->com.wr_waitp);
35228c2ecf20Sopenharmony_ci		err = cxgb4_create_server(ep->com.dev->rdev.lldi.ports[0],
35238c2ecf20Sopenharmony_ci				ep->stid, sin->sin_addr.s_addr, sin->sin_port,
35248c2ecf20Sopenharmony_ci				0, ep->com.dev->rdev.lldi.rxq_ids[0]);
35258c2ecf20Sopenharmony_ci		if (!err)
35268c2ecf20Sopenharmony_ci			err = c4iw_wait_for_reply(&ep->com.dev->rdev,
35278c2ecf20Sopenharmony_ci						  ep->com.wr_waitp,
35288c2ecf20Sopenharmony_ci						  0, 0, __func__);
35298c2ecf20Sopenharmony_ci		else if (err > 0)
35308c2ecf20Sopenharmony_ci			err = net_xmit_errno(err);
35318c2ecf20Sopenharmony_ci	}
35328c2ecf20Sopenharmony_ci	if (err)
35338c2ecf20Sopenharmony_ci		pr_err("cxgb4_create_server/filter failed err %d stid %d laddr %pI4 lport %d\n"
35348c2ecf20Sopenharmony_ci		       , err, ep->stid,
35358c2ecf20Sopenharmony_ci		       &sin->sin_addr, ntohs(sin->sin_port));
35368c2ecf20Sopenharmony_ci	return err;
35378c2ecf20Sopenharmony_ci}
35388c2ecf20Sopenharmony_ci
35398c2ecf20Sopenharmony_ciint c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)
35408c2ecf20Sopenharmony_ci{
35418c2ecf20Sopenharmony_ci	int err = 0;
35428c2ecf20Sopenharmony_ci	struct c4iw_dev *dev = to_c4iw_dev(cm_id->device);
35438c2ecf20Sopenharmony_ci	struct c4iw_listen_ep *ep;
35448c2ecf20Sopenharmony_ci
35458c2ecf20Sopenharmony_ci	might_sleep();
35468c2ecf20Sopenharmony_ci
35478c2ecf20Sopenharmony_ci	ep = alloc_ep(sizeof(*ep), GFP_KERNEL);
35488c2ecf20Sopenharmony_ci	if (!ep) {
35498c2ecf20Sopenharmony_ci		pr_err("%s - cannot alloc ep\n", __func__);
35508c2ecf20Sopenharmony_ci		err = -ENOMEM;
35518c2ecf20Sopenharmony_ci		goto fail1;
35528c2ecf20Sopenharmony_ci	}
35538c2ecf20Sopenharmony_ci	skb_queue_head_init(&ep->com.ep_skb_list);
35548c2ecf20Sopenharmony_ci	pr_debug("ep %p\n", ep);
35558c2ecf20Sopenharmony_ci	ep->com.cm_id = cm_id;
35568c2ecf20Sopenharmony_ci	ref_cm_id(&ep->com);
35578c2ecf20Sopenharmony_ci	ep->com.dev = dev;
35588c2ecf20Sopenharmony_ci	ep->backlog = backlog;
35598c2ecf20Sopenharmony_ci	memcpy(&ep->com.local_addr, &cm_id->m_local_addr,
35608c2ecf20Sopenharmony_ci	       sizeof(ep->com.local_addr));
35618c2ecf20Sopenharmony_ci
35628c2ecf20Sopenharmony_ci	/*
35638c2ecf20Sopenharmony_ci	 * Allocate a server TID.
35648c2ecf20Sopenharmony_ci	 */
35658c2ecf20Sopenharmony_ci	if (dev->rdev.lldi.enable_fw_ofld_conn &&
35668c2ecf20Sopenharmony_ci	    ep->com.local_addr.ss_family == AF_INET)
35678c2ecf20Sopenharmony_ci		ep->stid = cxgb4_alloc_sftid(dev->rdev.lldi.tids,
35688c2ecf20Sopenharmony_ci					     cm_id->m_local_addr.ss_family, ep);
35698c2ecf20Sopenharmony_ci	else
35708c2ecf20Sopenharmony_ci		ep->stid = cxgb4_alloc_stid(dev->rdev.lldi.tids,
35718c2ecf20Sopenharmony_ci					    cm_id->m_local_addr.ss_family, ep);
35728c2ecf20Sopenharmony_ci
35738c2ecf20Sopenharmony_ci	if (ep->stid == -1) {
35748c2ecf20Sopenharmony_ci		pr_err("%s - cannot alloc stid\n", __func__);
35758c2ecf20Sopenharmony_ci		err = -ENOMEM;
35768c2ecf20Sopenharmony_ci		goto fail2;
35778c2ecf20Sopenharmony_ci	}
35788c2ecf20Sopenharmony_ci	err = xa_insert_irq(&dev->stids, ep->stid, ep, GFP_KERNEL);
35798c2ecf20Sopenharmony_ci	if (err)
35808c2ecf20Sopenharmony_ci		goto fail3;
35818c2ecf20Sopenharmony_ci
35828c2ecf20Sopenharmony_ci	state_set(&ep->com, LISTEN);
35838c2ecf20Sopenharmony_ci	if (ep->com.local_addr.ss_family == AF_INET)
35848c2ecf20Sopenharmony_ci		err = create_server4(dev, ep);
35858c2ecf20Sopenharmony_ci	else
35868c2ecf20Sopenharmony_ci		err = create_server6(dev, ep);
35878c2ecf20Sopenharmony_ci	if (!err) {
35888c2ecf20Sopenharmony_ci		cm_id->provider_data = ep;
35898c2ecf20Sopenharmony_ci		goto out;
35908c2ecf20Sopenharmony_ci	}
35918c2ecf20Sopenharmony_ci	xa_erase_irq(&ep->com.dev->stids, ep->stid);
35928c2ecf20Sopenharmony_cifail3:
35938c2ecf20Sopenharmony_ci	cxgb4_free_stid(ep->com.dev->rdev.lldi.tids, ep->stid,
35948c2ecf20Sopenharmony_ci			ep->com.local_addr.ss_family);
35958c2ecf20Sopenharmony_cifail2:
35968c2ecf20Sopenharmony_ci	deref_cm_id(&ep->com);
35978c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->com);
35988c2ecf20Sopenharmony_cifail1:
35998c2ecf20Sopenharmony_ciout:
36008c2ecf20Sopenharmony_ci	return err;
36018c2ecf20Sopenharmony_ci}
36028c2ecf20Sopenharmony_ci
36038c2ecf20Sopenharmony_ciint c4iw_destroy_listen(struct iw_cm_id *cm_id)
36048c2ecf20Sopenharmony_ci{
36058c2ecf20Sopenharmony_ci	int err;
36068c2ecf20Sopenharmony_ci	struct c4iw_listen_ep *ep = to_listen_ep(cm_id);
36078c2ecf20Sopenharmony_ci
36088c2ecf20Sopenharmony_ci	pr_debug("ep %p\n", ep);
36098c2ecf20Sopenharmony_ci
36108c2ecf20Sopenharmony_ci	might_sleep();
36118c2ecf20Sopenharmony_ci	state_set(&ep->com, DEAD);
36128c2ecf20Sopenharmony_ci	if (ep->com.dev->rdev.lldi.enable_fw_ofld_conn &&
36138c2ecf20Sopenharmony_ci	    ep->com.local_addr.ss_family == AF_INET) {
36148c2ecf20Sopenharmony_ci		err = cxgb4_remove_server_filter(
36158c2ecf20Sopenharmony_ci			ep->com.dev->rdev.lldi.ports[0], ep->stid,
36168c2ecf20Sopenharmony_ci			ep->com.dev->rdev.lldi.rxq_ids[0], false);
36178c2ecf20Sopenharmony_ci	} else {
36188c2ecf20Sopenharmony_ci		struct sockaddr_in6 *sin6;
36198c2ecf20Sopenharmony_ci		c4iw_init_wr_wait(ep->com.wr_waitp);
36208c2ecf20Sopenharmony_ci		err = cxgb4_remove_server(
36218c2ecf20Sopenharmony_ci				ep->com.dev->rdev.lldi.ports[0], ep->stid,
36228c2ecf20Sopenharmony_ci				ep->com.dev->rdev.lldi.rxq_ids[0],
36238c2ecf20Sopenharmony_ci				ep->com.local_addr.ss_family == AF_INET6);
36248c2ecf20Sopenharmony_ci		if (err)
36258c2ecf20Sopenharmony_ci			goto done;
36268c2ecf20Sopenharmony_ci		err = c4iw_wait_for_reply(&ep->com.dev->rdev, ep->com.wr_waitp,
36278c2ecf20Sopenharmony_ci					  0, 0, __func__);
36288c2ecf20Sopenharmony_ci		sin6 = (struct sockaddr_in6 *)&ep->com.local_addr;
36298c2ecf20Sopenharmony_ci		cxgb4_clip_release(ep->com.dev->rdev.lldi.ports[0],
36308c2ecf20Sopenharmony_ci				   (const u32 *)&sin6->sin6_addr.s6_addr, 1);
36318c2ecf20Sopenharmony_ci	}
36328c2ecf20Sopenharmony_ci	xa_erase_irq(&ep->com.dev->stids, ep->stid);
36338c2ecf20Sopenharmony_ci	cxgb4_free_stid(ep->com.dev->rdev.lldi.tids, ep->stid,
36348c2ecf20Sopenharmony_ci			ep->com.local_addr.ss_family);
36358c2ecf20Sopenharmony_cidone:
36368c2ecf20Sopenharmony_ci	deref_cm_id(&ep->com);
36378c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->com);
36388c2ecf20Sopenharmony_ci	return err;
36398c2ecf20Sopenharmony_ci}
36408c2ecf20Sopenharmony_ci
36418c2ecf20Sopenharmony_ciint c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
36428c2ecf20Sopenharmony_ci{
36438c2ecf20Sopenharmony_ci	int ret = 0;
36448c2ecf20Sopenharmony_ci	int close = 0;
36458c2ecf20Sopenharmony_ci	int fatal = 0;
36468c2ecf20Sopenharmony_ci	struct c4iw_rdev *rdev;
36478c2ecf20Sopenharmony_ci
36488c2ecf20Sopenharmony_ci	mutex_lock(&ep->com.mutex);
36498c2ecf20Sopenharmony_ci
36508c2ecf20Sopenharmony_ci	pr_debug("ep %p state %s, abrupt %d\n", ep,
36518c2ecf20Sopenharmony_ci		 states[ep->com.state], abrupt);
36528c2ecf20Sopenharmony_ci
36538c2ecf20Sopenharmony_ci	/*
36548c2ecf20Sopenharmony_ci	 * Ref the ep here in case we have fatal errors causing the
36558c2ecf20Sopenharmony_ci	 * ep to be released and freed.
36568c2ecf20Sopenharmony_ci	 */
36578c2ecf20Sopenharmony_ci	c4iw_get_ep(&ep->com);
36588c2ecf20Sopenharmony_ci
36598c2ecf20Sopenharmony_ci	rdev = &ep->com.dev->rdev;
36608c2ecf20Sopenharmony_ci	if (c4iw_fatal_error(rdev)) {
36618c2ecf20Sopenharmony_ci		fatal = 1;
36628c2ecf20Sopenharmony_ci		close_complete_upcall(ep, -EIO);
36638c2ecf20Sopenharmony_ci		ep->com.state = DEAD;
36648c2ecf20Sopenharmony_ci	}
36658c2ecf20Sopenharmony_ci	switch (ep->com.state) {
36668c2ecf20Sopenharmony_ci	case MPA_REQ_WAIT:
36678c2ecf20Sopenharmony_ci	case MPA_REQ_SENT:
36688c2ecf20Sopenharmony_ci	case MPA_REQ_RCVD:
36698c2ecf20Sopenharmony_ci	case MPA_REP_SENT:
36708c2ecf20Sopenharmony_ci	case FPDU_MODE:
36718c2ecf20Sopenharmony_ci	case CONNECTING:
36728c2ecf20Sopenharmony_ci		close = 1;
36738c2ecf20Sopenharmony_ci		if (abrupt)
36748c2ecf20Sopenharmony_ci			ep->com.state = ABORTING;
36758c2ecf20Sopenharmony_ci		else {
36768c2ecf20Sopenharmony_ci			ep->com.state = CLOSING;
36778c2ecf20Sopenharmony_ci
36788c2ecf20Sopenharmony_ci			/*
36798c2ecf20Sopenharmony_ci			 * if we close before we see the fw4_ack() then we fix
36808c2ecf20Sopenharmony_ci			 * up the timer state since we're reusing it.
36818c2ecf20Sopenharmony_ci			 */
36828c2ecf20Sopenharmony_ci			if (ep->mpa_skb &&
36838c2ecf20Sopenharmony_ci			    test_bit(STOP_MPA_TIMER, &ep->com.flags)) {
36848c2ecf20Sopenharmony_ci				clear_bit(STOP_MPA_TIMER, &ep->com.flags);
36858c2ecf20Sopenharmony_ci				stop_ep_timer(ep);
36868c2ecf20Sopenharmony_ci			}
36878c2ecf20Sopenharmony_ci			start_ep_timer(ep);
36888c2ecf20Sopenharmony_ci		}
36898c2ecf20Sopenharmony_ci		set_bit(CLOSE_SENT, &ep->com.flags);
36908c2ecf20Sopenharmony_ci		break;
36918c2ecf20Sopenharmony_ci	case CLOSING:
36928c2ecf20Sopenharmony_ci		if (!test_and_set_bit(CLOSE_SENT, &ep->com.flags)) {
36938c2ecf20Sopenharmony_ci			close = 1;
36948c2ecf20Sopenharmony_ci			if (abrupt) {
36958c2ecf20Sopenharmony_ci				(void)stop_ep_timer(ep);
36968c2ecf20Sopenharmony_ci				ep->com.state = ABORTING;
36978c2ecf20Sopenharmony_ci			} else
36988c2ecf20Sopenharmony_ci				ep->com.state = MORIBUND;
36998c2ecf20Sopenharmony_ci		}
37008c2ecf20Sopenharmony_ci		break;
37018c2ecf20Sopenharmony_ci	case MORIBUND:
37028c2ecf20Sopenharmony_ci	case ABORTING:
37038c2ecf20Sopenharmony_ci	case DEAD:
37048c2ecf20Sopenharmony_ci		pr_debug("ignoring disconnect ep %p state %u\n",
37058c2ecf20Sopenharmony_ci			 ep, ep->com.state);
37068c2ecf20Sopenharmony_ci		break;
37078c2ecf20Sopenharmony_ci	default:
37088c2ecf20Sopenharmony_ci		WARN_ONCE(1, "Bad endpoint state %u\n", ep->com.state);
37098c2ecf20Sopenharmony_ci		break;
37108c2ecf20Sopenharmony_ci	}
37118c2ecf20Sopenharmony_ci
37128c2ecf20Sopenharmony_ci	if (close) {
37138c2ecf20Sopenharmony_ci		if (abrupt) {
37148c2ecf20Sopenharmony_ci			set_bit(EP_DISC_ABORT, &ep->com.history);
37158c2ecf20Sopenharmony_ci			ret = send_abort(ep);
37168c2ecf20Sopenharmony_ci		} else {
37178c2ecf20Sopenharmony_ci			set_bit(EP_DISC_CLOSE, &ep->com.history);
37188c2ecf20Sopenharmony_ci			ret = send_halfclose(ep);
37198c2ecf20Sopenharmony_ci		}
37208c2ecf20Sopenharmony_ci		if (ret) {
37218c2ecf20Sopenharmony_ci			set_bit(EP_DISC_FAIL, &ep->com.history);
37228c2ecf20Sopenharmony_ci			if (!abrupt) {
37238c2ecf20Sopenharmony_ci				stop_ep_timer(ep);
37248c2ecf20Sopenharmony_ci				close_complete_upcall(ep, -EIO);
37258c2ecf20Sopenharmony_ci			}
37268c2ecf20Sopenharmony_ci			if (ep->com.qp) {
37278c2ecf20Sopenharmony_ci				struct c4iw_qp_attributes attrs;
37288c2ecf20Sopenharmony_ci
37298c2ecf20Sopenharmony_ci				attrs.next_state = C4IW_QP_STATE_ERROR;
37308c2ecf20Sopenharmony_ci				ret = c4iw_modify_qp(ep->com.qp->rhp,
37318c2ecf20Sopenharmony_ci						     ep->com.qp,
37328c2ecf20Sopenharmony_ci						     C4IW_QP_ATTR_NEXT_STATE,
37338c2ecf20Sopenharmony_ci						     &attrs, 1);
37348c2ecf20Sopenharmony_ci				if (ret)
37358c2ecf20Sopenharmony_ci					pr_err("%s - qp <- error failed!\n",
37368c2ecf20Sopenharmony_ci					       __func__);
37378c2ecf20Sopenharmony_ci			}
37388c2ecf20Sopenharmony_ci			fatal = 1;
37398c2ecf20Sopenharmony_ci		}
37408c2ecf20Sopenharmony_ci	}
37418c2ecf20Sopenharmony_ci	mutex_unlock(&ep->com.mutex);
37428c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->com);
37438c2ecf20Sopenharmony_ci	if (fatal)
37448c2ecf20Sopenharmony_ci		release_ep_resources(ep);
37458c2ecf20Sopenharmony_ci	return ret;
37468c2ecf20Sopenharmony_ci}
37478c2ecf20Sopenharmony_ci
37488c2ecf20Sopenharmony_cistatic void active_ofld_conn_reply(struct c4iw_dev *dev, struct sk_buff *skb,
37498c2ecf20Sopenharmony_ci			struct cpl_fw6_msg_ofld_connection_wr_rpl *req)
37508c2ecf20Sopenharmony_ci{
37518c2ecf20Sopenharmony_ci	struct c4iw_ep *ep;
37528c2ecf20Sopenharmony_ci	int atid = be32_to_cpu(req->tid);
37538c2ecf20Sopenharmony_ci
37548c2ecf20Sopenharmony_ci	ep = (struct c4iw_ep *)lookup_atid(dev->rdev.lldi.tids,
37558c2ecf20Sopenharmony_ci					   (__force u32) req->tid);
37568c2ecf20Sopenharmony_ci	if (!ep)
37578c2ecf20Sopenharmony_ci		return;
37588c2ecf20Sopenharmony_ci
37598c2ecf20Sopenharmony_ci	switch (req->retval) {
37608c2ecf20Sopenharmony_ci	case FW_ENOMEM:
37618c2ecf20Sopenharmony_ci		set_bit(ACT_RETRY_NOMEM, &ep->com.history);
37628c2ecf20Sopenharmony_ci		if (ep->retry_count++ < ACT_OPEN_RETRY_COUNT) {
37638c2ecf20Sopenharmony_ci			send_fw_act_open_req(ep, atid);
37648c2ecf20Sopenharmony_ci			return;
37658c2ecf20Sopenharmony_ci		}
37668c2ecf20Sopenharmony_ci		fallthrough;
37678c2ecf20Sopenharmony_ci	case FW_EADDRINUSE:
37688c2ecf20Sopenharmony_ci		set_bit(ACT_RETRY_INUSE, &ep->com.history);
37698c2ecf20Sopenharmony_ci		if (ep->retry_count++ < ACT_OPEN_RETRY_COUNT) {
37708c2ecf20Sopenharmony_ci			send_fw_act_open_req(ep, atid);
37718c2ecf20Sopenharmony_ci			return;
37728c2ecf20Sopenharmony_ci		}
37738c2ecf20Sopenharmony_ci		break;
37748c2ecf20Sopenharmony_ci	default:
37758c2ecf20Sopenharmony_ci		pr_info("%s unexpected ofld conn wr retval %d\n",
37768c2ecf20Sopenharmony_ci		       __func__, req->retval);
37778c2ecf20Sopenharmony_ci		break;
37788c2ecf20Sopenharmony_ci	}
37798c2ecf20Sopenharmony_ci	pr_err("active ofld_connect_wr failure %d atid %d\n",
37808c2ecf20Sopenharmony_ci	       req->retval, atid);
37818c2ecf20Sopenharmony_ci	mutex_lock(&dev->rdev.stats.lock);
37828c2ecf20Sopenharmony_ci	dev->rdev.stats.act_ofld_conn_fails++;
37838c2ecf20Sopenharmony_ci	mutex_unlock(&dev->rdev.stats.lock);
37848c2ecf20Sopenharmony_ci	connect_reply_upcall(ep, status2errno(req->retval));
37858c2ecf20Sopenharmony_ci	state_set(&ep->com, DEAD);
37868c2ecf20Sopenharmony_ci	if (ep->com.remote_addr.ss_family == AF_INET6) {
37878c2ecf20Sopenharmony_ci		struct sockaddr_in6 *sin6 =
37888c2ecf20Sopenharmony_ci			(struct sockaddr_in6 *)&ep->com.local_addr;
37898c2ecf20Sopenharmony_ci		cxgb4_clip_release(ep->com.dev->rdev.lldi.ports[0],
37908c2ecf20Sopenharmony_ci				   (const u32 *)&sin6->sin6_addr.s6_addr, 1);
37918c2ecf20Sopenharmony_ci	}
37928c2ecf20Sopenharmony_ci	xa_erase_irq(&dev->atids, atid);
37938c2ecf20Sopenharmony_ci	cxgb4_free_atid(dev->rdev.lldi.tids, atid);
37948c2ecf20Sopenharmony_ci	dst_release(ep->dst);
37958c2ecf20Sopenharmony_ci	cxgb4_l2t_release(ep->l2t);
37968c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->com);
37978c2ecf20Sopenharmony_ci}
37988c2ecf20Sopenharmony_ci
37998c2ecf20Sopenharmony_cistatic void passive_ofld_conn_reply(struct c4iw_dev *dev, struct sk_buff *skb,
38008c2ecf20Sopenharmony_ci			struct cpl_fw6_msg_ofld_connection_wr_rpl *req)
38018c2ecf20Sopenharmony_ci{
38028c2ecf20Sopenharmony_ci	struct sk_buff *rpl_skb;
38038c2ecf20Sopenharmony_ci	struct cpl_pass_accept_req *cpl;
38048c2ecf20Sopenharmony_ci	int ret;
38058c2ecf20Sopenharmony_ci
38068c2ecf20Sopenharmony_ci	rpl_skb = (struct sk_buff *)(unsigned long)req->cookie;
38078c2ecf20Sopenharmony_ci	if (req->retval) {
38088c2ecf20Sopenharmony_ci		pr_err("%s passive open failure %d\n", __func__, req->retval);
38098c2ecf20Sopenharmony_ci		mutex_lock(&dev->rdev.stats.lock);
38108c2ecf20Sopenharmony_ci		dev->rdev.stats.pas_ofld_conn_fails++;
38118c2ecf20Sopenharmony_ci		mutex_unlock(&dev->rdev.stats.lock);
38128c2ecf20Sopenharmony_ci		kfree_skb(rpl_skb);
38138c2ecf20Sopenharmony_ci	} else {
38148c2ecf20Sopenharmony_ci		cpl = (struct cpl_pass_accept_req *)cplhdr(rpl_skb);
38158c2ecf20Sopenharmony_ci		OPCODE_TID(cpl) = htonl(MK_OPCODE_TID(CPL_PASS_ACCEPT_REQ,
38168c2ecf20Sopenharmony_ci					(__force u32) htonl(
38178c2ecf20Sopenharmony_ci					(__force u32) req->tid)));
38188c2ecf20Sopenharmony_ci		ret = pass_accept_req(dev, rpl_skb);
38198c2ecf20Sopenharmony_ci		if (!ret)
38208c2ecf20Sopenharmony_ci			kfree_skb(rpl_skb);
38218c2ecf20Sopenharmony_ci	}
38228c2ecf20Sopenharmony_ci	return;
38238c2ecf20Sopenharmony_ci}
38248c2ecf20Sopenharmony_ci
38258c2ecf20Sopenharmony_cistatic inline u64 t4_tcb_get_field64(__be64 *tcb, u16 word)
38268c2ecf20Sopenharmony_ci{
38278c2ecf20Sopenharmony_ci	u64 tlo = be64_to_cpu(tcb[((31 - word) / 2)]);
38288c2ecf20Sopenharmony_ci	u64 thi = be64_to_cpu(tcb[((31 - word) / 2) - 1]);
38298c2ecf20Sopenharmony_ci	u64 t;
38308c2ecf20Sopenharmony_ci	u32 shift = 32;
38318c2ecf20Sopenharmony_ci
38328c2ecf20Sopenharmony_ci	t = (thi << shift) | (tlo >> shift);
38338c2ecf20Sopenharmony_ci
38348c2ecf20Sopenharmony_ci	return t;
38358c2ecf20Sopenharmony_ci}
38368c2ecf20Sopenharmony_ci
38378c2ecf20Sopenharmony_cistatic inline u32 t4_tcb_get_field32(__be64 *tcb, u16 word, u32 mask, u32 shift)
38388c2ecf20Sopenharmony_ci{
38398c2ecf20Sopenharmony_ci	u32 v;
38408c2ecf20Sopenharmony_ci	u64 t = be64_to_cpu(tcb[(31 - word) / 2]);
38418c2ecf20Sopenharmony_ci
38428c2ecf20Sopenharmony_ci	if (word & 0x1)
38438c2ecf20Sopenharmony_ci		shift += 32;
38448c2ecf20Sopenharmony_ci	v = (t >> shift) & mask;
38458c2ecf20Sopenharmony_ci	return v;
38468c2ecf20Sopenharmony_ci}
38478c2ecf20Sopenharmony_ci
38488c2ecf20Sopenharmony_cistatic int read_tcb_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
38498c2ecf20Sopenharmony_ci{
38508c2ecf20Sopenharmony_ci	struct cpl_get_tcb_rpl *rpl = cplhdr(skb);
38518c2ecf20Sopenharmony_ci	__be64 *tcb = (__be64 *)(rpl + 1);
38528c2ecf20Sopenharmony_ci	unsigned int tid = GET_TID(rpl);
38538c2ecf20Sopenharmony_ci	struct c4iw_ep *ep;
38548c2ecf20Sopenharmony_ci	u64 t_flags_64;
38558c2ecf20Sopenharmony_ci	u32 rx_pdu_out;
38568c2ecf20Sopenharmony_ci
38578c2ecf20Sopenharmony_ci	ep = get_ep_from_tid(dev, tid);
38588c2ecf20Sopenharmony_ci	if (!ep)
38598c2ecf20Sopenharmony_ci		return 0;
38608c2ecf20Sopenharmony_ci	/* Examine the TF_RX_PDU_OUT (bit 49 of the t_flags) in order to
38618c2ecf20Sopenharmony_ci	 * determine if there's a rx PDU feedback event pending.
38628c2ecf20Sopenharmony_ci	 *
38638c2ecf20Sopenharmony_ci	 * If that bit is set, it means we'll need to re-read the TCB's
38648c2ecf20Sopenharmony_ci	 * rq_start value. The final value is the one present in a TCB
38658c2ecf20Sopenharmony_ci	 * with the TF_RX_PDU_OUT bit cleared.
38668c2ecf20Sopenharmony_ci	 */
38678c2ecf20Sopenharmony_ci
38688c2ecf20Sopenharmony_ci	t_flags_64 = t4_tcb_get_field64(tcb, TCB_T_FLAGS_W);
38698c2ecf20Sopenharmony_ci	rx_pdu_out = (t_flags_64 & TF_RX_PDU_OUT_V(1)) >> TF_RX_PDU_OUT_S;
38708c2ecf20Sopenharmony_ci
38718c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->com); /* from get_ep_from_tid() */
38728c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->com); /* from read_tcb() */
38738c2ecf20Sopenharmony_ci
38748c2ecf20Sopenharmony_ci	/* If TF_RX_PDU_OUT bit is set, re-read the TCB */
38758c2ecf20Sopenharmony_ci	if (rx_pdu_out) {
38768c2ecf20Sopenharmony_ci		if (++ep->rx_pdu_out_cnt >= 2) {
38778c2ecf20Sopenharmony_ci			WARN_ONCE(1, "tcb re-read() reached the guard limit, finishing the cleanup\n");
38788c2ecf20Sopenharmony_ci			goto cleanup;
38798c2ecf20Sopenharmony_ci		}
38808c2ecf20Sopenharmony_ci		read_tcb(ep);
38818c2ecf20Sopenharmony_ci		return 0;
38828c2ecf20Sopenharmony_ci	}
38838c2ecf20Sopenharmony_ci
38848c2ecf20Sopenharmony_ci	ep->srqe_idx = t4_tcb_get_field32(tcb, TCB_RQ_START_W, TCB_RQ_START_M,
38858c2ecf20Sopenharmony_ci					  TCB_RQ_START_S);
38868c2ecf20Sopenharmony_cicleanup:
38878c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u %016x\n", ep, ep->hwtid, ep->srqe_idx);
38888c2ecf20Sopenharmony_ci
38898c2ecf20Sopenharmony_ci	if (test_bit(PEER_ABORT_IN_PROGRESS, &ep->com.flags))
38908c2ecf20Sopenharmony_ci		finish_peer_abort(dev, ep);
38918c2ecf20Sopenharmony_ci	else if (test_bit(ABORT_REQ_IN_PROGRESS, &ep->com.flags))
38928c2ecf20Sopenharmony_ci		send_abort_req(ep);
38938c2ecf20Sopenharmony_ci	else
38948c2ecf20Sopenharmony_ci		WARN_ONCE(1, "unexpected state!");
38958c2ecf20Sopenharmony_ci
38968c2ecf20Sopenharmony_ci	return 0;
38978c2ecf20Sopenharmony_ci}
38988c2ecf20Sopenharmony_ci
38998c2ecf20Sopenharmony_cistatic int deferred_fw6_msg(struct c4iw_dev *dev, struct sk_buff *skb)
39008c2ecf20Sopenharmony_ci{
39018c2ecf20Sopenharmony_ci	struct cpl_fw6_msg *rpl = cplhdr(skb);
39028c2ecf20Sopenharmony_ci	struct cpl_fw6_msg_ofld_connection_wr_rpl *req;
39038c2ecf20Sopenharmony_ci
39048c2ecf20Sopenharmony_ci	switch (rpl->type) {
39058c2ecf20Sopenharmony_ci	case FW6_TYPE_CQE:
39068c2ecf20Sopenharmony_ci		c4iw_ev_dispatch(dev, (struct t4_cqe *)&rpl->data[0]);
39078c2ecf20Sopenharmony_ci		break;
39088c2ecf20Sopenharmony_ci	case FW6_TYPE_OFLD_CONNECTION_WR_RPL:
39098c2ecf20Sopenharmony_ci		req = (struct cpl_fw6_msg_ofld_connection_wr_rpl *)rpl->data;
39108c2ecf20Sopenharmony_ci		switch (req->t_state) {
39118c2ecf20Sopenharmony_ci		case TCP_SYN_SENT:
39128c2ecf20Sopenharmony_ci			active_ofld_conn_reply(dev, skb, req);
39138c2ecf20Sopenharmony_ci			break;
39148c2ecf20Sopenharmony_ci		case TCP_SYN_RECV:
39158c2ecf20Sopenharmony_ci			passive_ofld_conn_reply(dev, skb, req);
39168c2ecf20Sopenharmony_ci			break;
39178c2ecf20Sopenharmony_ci		default:
39188c2ecf20Sopenharmony_ci			pr_err("%s unexpected ofld conn wr state %d\n",
39198c2ecf20Sopenharmony_ci			       __func__, req->t_state);
39208c2ecf20Sopenharmony_ci			break;
39218c2ecf20Sopenharmony_ci		}
39228c2ecf20Sopenharmony_ci		break;
39238c2ecf20Sopenharmony_ci	}
39248c2ecf20Sopenharmony_ci	return 0;
39258c2ecf20Sopenharmony_ci}
39268c2ecf20Sopenharmony_ci
39278c2ecf20Sopenharmony_cistatic void build_cpl_pass_accept_req(struct sk_buff *skb, int stid , u8 tos)
39288c2ecf20Sopenharmony_ci{
39298c2ecf20Sopenharmony_ci	__be32 l2info;
39308c2ecf20Sopenharmony_ci	__be16 hdr_len, vlantag, len;
39318c2ecf20Sopenharmony_ci	u16 eth_hdr_len;
39328c2ecf20Sopenharmony_ci	int tcp_hdr_len, ip_hdr_len;
39338c2ecf20Sopenharmony_ci	u8 intf;
39348c2ecf20Sopenharmony_ci	struct cpl_rx_pkt *cpl = cplhdr(skb);
39358c2ecf20Sopenharmony_ci	struct cpl_pass_accept_req *req;
39368c2ecf20Sopenharmony_ci	struct tcp_options_received tmp_opt;
39378c2ecf20Sopenharmony_ci	struct c4iw_dev *dev;
39388c2ecf20Sopenharmony_ci	enum chip_type type;
39398c2ecf20Sopenharmony_ci
39408c2ecf20Sopenharmony_ci	dev = *((struct c4iw_dev **) (skb->cb + sizeof(void *)));
39418c2ecf20Sopenharmony_ci	/* Store values from cpl_rx_pkt in temporary location. */
39428c2ecf20Sopenharmony_ci	vlantag = cpl->vlan;
39438c2ecf20Sopenharmony_ci	len = cpl->len;
39448c2ecf20Sopenharmony_ci	l2info  = cpl->l2info;
39458c2ecf20Sopenharmony_ci	hdr_len = cpl->hdr_len;
39468c2ecf20Sopenharmony_ci	intf = cpl->iff;
39478c2ecf20Sopenharmony_ci
39488c2ecf20Sopenharmony_ci	__skb_pull(skb, sizeof(*req) + sizeof(struct rss_header));
39498c2ecf20Sopenharmony_ci
39508c2ecf20Sopenharmony_ci	/*
39518c2ecf20Sopenharmony_ci	 * We need to parse the TCP options from SYN packet.
39528c2ecf20Sopenharmony_ci	 * to generate cpl_pass_accept_req.
39538c2ecf20Sopenharmony_ci	 */
39548c2ecf20Sopenharmony_ci	memset(&tmp_opt, 0, sizeof(tmp_opt));
39558c2ecf20Sopenharmony_ci	tcp_clear_options(&tmp_opt);
39568c2ecf20Sopenharmony_ci	tcp_parse_options(&init_net, skb, &tmp_opt, 0, NULL);
39578c2ecf20Sopenharmony_ci
39588c2ecf20Sopenharmony_ci	req = __skb_push(skb, sizeof(*req));
39598c2ecf20Sopenharmony_ci	memset(req, 0, sizeof(*req));
39608c2ecf20Sopenharmony_ci	req->l2info = cpu_to_be16(SYN_INTF_V(intf) |
39618c2ecf20Sopenharmony_ci			 SYN_MAC_IDX_V(RX_MACIDX_G(
39628c2ecf20Sopenharmony_ci			 be32_to_cpu(l2info))) |
39638c2ecf20Sopenharmony_ci			 SYN_XACT_MATCH_F);
39648c2ecf20Sopenharmony_ci	type = dev->rdev.lldi.adapter_type;
39658c2ecf20Sopenharmony_ci	tcp_hdr_len = RX_TCPHDR_LEN_G(be16_to_cpu(hdr_len));
39668c2ecf20Sopenharmony_ci	ip_hdr_len = RX_IPHDR_LEN_G(be16_to_cpu(hdr_len));
39678c2ecf20Sopenharmony_ci	req->hdr_len =
39688c2ecf20Sopenharmony_ci		cpu_to_be32(SYN_RX_CHAN_V(RX_CHAN_G(be32_to_cpu(l2info))));
39698c2ecf20Sopenharmony_ci	if (CHELSIO_CHIP_VERSION(type) <= CHELSIO_T5) {
39708c2ecf20Sopenharmony_ci		eth_hdr_len = is_t4(type) ?
39718c2ecf20Sopenharmony_ci				RX_ETHHDR_LEN_G(be32_to_cpu(l2info)) :
39728c2ecf20Sopenharmony_ci				RX_T5_ETHHDR_LEN_G(be32_to_cpu(l2info));
39738c2ecf20Sopenharmony_ci		req->hdr_len |= cpu_to_be32(TCP_HDR_LEN_V(tcp_hdr_len) |
39748c2ecf20Sopenharmony_ci					    IP_HDR_LEN_V(ip_hdr_len) |
39758c2ecf20Sopenharmony_ci					    ETH_HDR_LEN_V(eth_hdr_len));
39768c2ecf20Sopenharmony_ci	} else { /* T6 and later */
39778c2ecf20Sopenharmony_ci		eth_hdr_len = RX_T6_ETHHDR_LEN_G(be32_to_cpu(l2info));
39788c2ecf20Sopenharmony_ci		req->hdr_len |= cpu_to_be32(T6_TCP_HDR_LEN_V(tcp_hdr_len) |
39798c2ecf20Sopenharmony_ci					    T6_IP_HDR_LEN_V(ip_hdr_len) |
39808c2ecf20Sopenharmony_ci					    T6_ETH_HDR_LEN_V(eth_hdr_len));
39818c2ecf20Sopenharmony_ci	}
39828c2ecf20Sopenharmony_ci	req->vlan = vlantag;
39838c2ecf20Sopenharmony_ci	req->len = len;
39848c2ecf20Sopenharmony_ci	req->tos_stid = cpu_to_be32(PASS_OPEN_TID_V(stid) |
39858c2ecf20Sopenharmony_ci				    PASS_OPEN_TOS_V(tos));
39868c2ecf20Sopenharmony_ci	req->tcpopt.mss = htons(tmp_opt.mss_clamp);
39878c2ecf20Sopenharmony_ci	if (tmp_opt.wscale_ok)
39888c2ecf20Sopenharmony_ci		req->tcpopt.wsf = tmp_opt.snd_wscale;
39898c2ecf20Sopenharmony_ci	req->tcpopt.tstamp = tmp_opt.saw_tstamp;
39908c2ecf20Sopenharmony_ci	if (tmp_opt.sack_ok)
39918c2ecf20Sopenharmony_ci		req->tcpopt.sack = 1;
39928c2ecf20Sopenharmony_ci	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_PASS_ACCEPT_REQ, 0));
39938c2ecf20Sopenharmony_ci	return;
39948c2ecf20Sopenharmony_ci}
39958c2ecf20Sopenharmony_ci
39968c2ecf20Sopenharmony_cistatic void send_fw_pass_open_req(struct c4iw_dev *dev, struct sk_buff *skb,
39978c2ecf20Sopenharmony_ci				  __be32 laddr, __be16 lport,
39988c2ecf20Sopenharmony_ci				  __be32 raddr, __be16 rport,
39998c2ecf20Sopenharmony_ci				  u32 rcv_isn, u32 filter, u16 window,
40008c2ecf20Sopenharmony_ci				  u32 rss_qid, u8 port_id)
40018c2ecf20Sopenharmony_ci{
40028c2ecf20Sopenharmony_ci	struct sk_buff *req_skb;
40038c2ecf20Sopenharmony_ci	struct fw_ofld_connection_wr *req;
40048c2ecf20Sopenharmony_ci	struct cpl_pass_accept_req *cpl = cplhdr(skb);
40058c2ecf20Sopenharmony_ci	int ret;
40068c2ecf20Sopenharmony_ci
40078c2ecf20Sopenharmony_ci	req_skb = alloc_skb(sizeof(struct fw_ofld_connection_wr), GFP_KERNEL);
40088c2ecf20Sopenharmony_ci	if (!req_skb)
40098c2ecf20Sopenharmony_ci		return;
40108c2ecf20Sopenharmony_ci	req = __skb_put_zero(req_skb, sizeof(*req));
40118c2ecf20Sopenharmony_ci	req->op_compl = htonl(WR_OP_V(FW_OFLD_CONNECTION_WR) | FW_WR_COMPL_F);
40128c2ecf20Sopenharmony_ci	req->len16_pkd = htonl(FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*req), 16)));
40138c2ecf20Sopenharmony_ci	req->le.version_cpl = htonl(FW_OFLD_CONNECTION_WR_CPL_F);
40148c2ecf20Sopenharmony_ci	req->le.filter = (__force __be32) filter;
40158c2ecf20Sopenharmony_ci	req->le.lport = lport;
40168c2ecf20Sopenharmony_ci	req->le.pport = rport;
40178c2ecf20Sopenharmony_ci	req->le.u.ipv4.lip = laddr;
40188c2ecf20Sopenharmony_ci	req->le.u.ipv4.pip = raddr;
40198c2ecf20Sopenharmony_ci	req->tcb.rcv_nxt = htonl(rcv_isn + 1);
40208c2ecf20Sopenharmony_ci	req->tcb.rcv_adv = htons(window);
40218c2ecf20Sopenharmony_ci	req->tcb.t_state_to_astid =
40228c2ecf20Sopenharmony_ci		 htonl(FW_OFLD_CONNECTION_WR_T_STATE_V(TCP_SYN_RECV) |
40238c2ecf20Sopenharmony_ci			FW_OFLD_CONNECTION_WR_RCV_SCALE_V(cpl->tcpopt.wsf) |
40248c2ecf20Sopenharmony_ci			FW_OFLD_CONNECTION_WR_ASTID_V(
40258c2ecf20Sopenharmony_ci			PASS_OPEN_TID_G(ntohl(cpl->tos_stid))));
40268c2ecf20Sopenharmony_ci
40278c2ecf20Sopenharmony_ci	/*
40288c2ecf20Sopenharmony_ci	 * We store the qid in opt2 which will be used by the firmware
40298c2ecf20Sopenharmony_ci	 * to send us the wr response.
40308c2ecf20Sopenharmony_ci	 */
40318c2ecf20Sopenharmony_ci	req->tcb.opt2 = htonl(RSS_QUEUE_V(rss_qid));
40328c2ecf20Sopenharmony_ci
40338c2ecf20Sopenharmony_ci	/*
40348c2ecf20Sopenharmony_ci	 * We initialize the MSS index in TCB to 0xF.
40358c2ecf20Sopenharmony_ci	 * So that when driver sends cpl_pass_accept_rpl
40368c2ecf20Sopenharmony_ci	 * TCB picks up the correct value. If this was 0
40378c2ecf20Sopenharmony_ci	 * TP will ignore any value > 0 for MSS index.
40388c2ecf20Sopenharmony_ci	 */
40398c2ecf20Sopenharmony_ci	req->tcb.opt0 = cpu_to_be64(MSS_IDX_V(0xF));
40408c2ecf20Sopenharmony_ci	req->cookie = (uintptr_t)skb;
40418c2ecf20Sopenharmony_ci
40428c2ecf20Sopenharmony_ci	set_wr_txq(req_skb, CPL_PRIORITY_CONTROL, port_id);
40438c2ecf20Sopenharmony_ci	ret = cxgb4_ofld_send(dev->rdev.lldi.ports[0], req_skb);
40448c2ecf20Sopenharmony_ci	if (ret < 0) {
40458c2ecf20Sopenharmony_ci		pr_err("%s - cxgb4_ofld_send error %d - dropping\n", __func__,
40468c2ecf20Sopenharmony_ci		       ret);
40478c2ecf20Sopenharmony_ci		kfree_skb(skb);
40488c2ecf20Sopenharmony_ci		kfree_skb(req_skb);
40498c2ecf20Sopenharmony_ci	}
40508c2ecf20Sopenharmony_ci}
40518c2ecf20Sopenharmony_ci
40528c2ecf20Sopenharmony_ci/*
40538c2ecf20Sopenharmony_ci * Handler for CPL_RX_PKT message. Need to handle cpl_rx_pkt
40548c2ecf20Sopenharmony_ci * messages when a filter is being used instead of server to
40558c2ecf20Sopenharmony_ci * redirect a syn packet. When packets hit filter they are redirected
40568c2ecf20Sopenharmony_ci * to the offload queue and driver tries to establish the connection
40578c2ecf20Sopenharmony_ci * using firmware work request.
40588c2ecf20Sopenharmony_ci */
40598c2ecf20Sopenharmony_cistatic int rx_pkt(struct c4iw_dev *dev, struct sk_buff *skb)
40608c2ecf20Sopenharmony_ci{
40618c2ecf20Sopenharmony_ci	int stid;
40628c2ecf20Sopenharmony_ci	unsigned int filter;
40638c2ecf20Sopenharmony_ci	struct ethhdr *eh = NULL;
40648c2ecf20Sopenharmony_ci	struct vlan_ethhdr *vlan_eh = NULL;
40658c2ecf20Sopenharmony_ci	struct iphdr *iph;
40668c2ecf20Sopenharmony_ci	struct tcphdr *tcph;
40678c2ecf20Sopenharmony_ci	struct rss_header *rss = (void *)skb->data;
40688c2ecf20Sopenharmony_ci	struct cpl_rx_pkt *cpl = (void *)skb->data;
40698c2ecf20Sopenharmony_ci	struct cpl_pass_accept_req *req = (void *)(rss + 1);
40708c2ecf20Sopenharmony_ci	struct l2t_entry *e;
40718c2ecf20Sopenharmony_ci	struct dst_entry *dst;
40728c2ecf20Sopenharmony_ci	struct c4iw_ep *lep = NULL;
40738c2ecf20Sopenharmony_ci	u16 window;
40748c2ecf20Sopenharmony_ci	struct port_info *pi;
40758c2ecf20Sopenharmony_ci	struct net_device *pdev;
40768c2ecf20Sopenharmony_ci	u16 rss_qid, eth_hdr_len;
40778c2ecf20Sopenharmony_ci	int step;
40788c2ecf20Sopenharmony_ci	struct neighbour *neigh;
40798c2ecf20Sopenharmony_ci
40808c2ecf20Sopenharmony_ci	/* Drop all non-SYN packets */
40818c2ecf20Sopenharmony_ci	if (!(cpl->l2info & cpu_to_be32(RXF_SYN_F)))
40828c2ecf20Sopenharmony_ci		goto reject;
40838c2ecf20Sopenharmony_ci
40848c2ecf20Sopenharmony_ci	/*
40858c2ecf20Sopenharmony_ci	 * Drop all packets which did not hit the filter.
40868c2ecf20Sopenharmony_ci	 * Unlikely to happen.
40878c2ecf20Sopenharmony_ci	 */
40888c2ecf20Sopenharmony_ci	if (!(rss->filter_hit && rss->filter_tid))
40898c2ecf20Sopenharmony_ci		goto reject;
40908c2ecf20Sopenharmony_ci
40918c2ecf20Sopenharmony_ci	/*
40928c2ecf20Sopenharmony_ci	 * Calculate the server tid from filter hit index from cpl_rx_pkt.
40938c2ecf20Sopenharmony_ci	 */
40948c2ecf20Sopenharmony_ci	stid = (__force int) cpu_to_be32((__force u32) rss->hash_val);
40958c2ecf20Sopenharmony_ci
40968c2ecf20Sopenharmony_ci	lep = (struct c4iw_ep *)get_ep_from_stid(dev, stid);
40978c2ecf20Sopenharmony_ci	if (!lep) {
40988c2ecf20Sopenharmony_ci		pr_warn("%s connect request on invalid stid %d\n",
40998c2ecf20Sopenharmony_ci			__func__, stid);
41008c2ecf20Sopenharmony_ci		goto reject;
41018c2ecf20Sopenharmony_ci	}
41028c2ecf20Sopenharmony_ci
41038c2ecf20Sopenharmony_ci	switch (CHELSIO_CHIP_VERSION(dev->rdev.lldi.adapter_type)) {
41048c2ecf20Sopenharmony_ci	case CHELSIO_T4:
41058c2ecf20Sopenharmony_ci		eth_hdr_len = RX_ETHHDR_LEN_G(be32_to_cpu(cpl->l2info));
41068c2ecf20Sopenharmony_ci		break;
41078c2ecf20Sopenharmony_ci	case CHELSIO_T5:
41088c2ecf20Sopenharmony_ci		eth_hdr_len = RX_T5_ETHHDR_LEN_G(be32_to_cpu(cpl->l2info));
41098c2ecf20Sopenharmony_ci		break;
41108c2ecf20Sopenharmony_ci	case CHELSIO_T6:
41118c2ecf20Sopenharmony_ci		eth_hdr_len = RX_T6_ETHHDR_LEN_G(be32_to_cpu(cpl->l2info));
41128c2ecf20Sopenharmony_ci		break;
41138c2ecf20Sopenharmony_ci	default:
41148c2ecf20Sopenharmony_ci		pr_err("T%d Chip is not supported\n",
41158c2ecf20Sopenharmony_ci		       CHELSIO_CHIP_VERSION(dev->rdev.lldi.adapter_type));
41168c2ecf20Sopenharmony_ci		goto reject;
41178c2ecf20Sopenharmony_ci	}
41188c2ecf20Sopenharmony_ci
41198c2ecf20Sopenharmony_ci	if (eth_hdr_len == ETH_HLEN) {
41208c2ecf20Sopenharmony_ci		eh = (struct ethhdr *)(req + 1);
41218c2ecf20Sopenharmony_ci		iph = (struct iphdr *)(eh + 1);
41228c2ecf20Sopenharmony_ci	} else {
41238c2ecf20Sopenharmony_ci		vlan_eh = (struct vlan_ethhdr *)(req + 1);
41248c2ecf20Sopenharmony_ci		iph = (struct iphdr *)(vlan_eh + 1);
41258c2ecf20Sopenharmony_ci		__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(cpl->vlan));
41268c2ecf20Sopenharmony_ci	}
41278c2ecf20Sopenharmony_ci
41288c2ecf20Sopenharmony_ci	if (iph->version != 0x4)
41298c2ecf20Sopenharmony_ci		goto reject;
41308c2ecf20Sopenharmony_ci
41318c2ecf20Sopenharmony_ci	tcph = (struct tcphdr *)(iph + 1);
41328c2ecf20Sopenharmony_ci	skb_set_network_header(skb, (void *)iph - (void *)rss);
41338c2ecf20Sopenharmony_ci	skb_set_transport_header(skb, (void *)tcph - (void *)rss);
41348c2ecf20Sopenharmony_ci	skb_get(skb);
41358c2ecf20Sopenharmony_ci
41368c2ecf20Sopenharmony_ci	pr_debug("lip 0x%x lport %u pip 0x%x pport %u tos %d\n",
41378c2ecf20Sopenharmony_ci		 ntohl(iph->daddr), ntohs(tcph->dest), ntohl(iph->saddr),
41388c2ecf20Sopenharmony_ci		 ntohs(tcph->source), iph->tos);
41398c2ecf20Sopenharmony_ci
41408c2ecf20Sopenharmony_ci	dst = cxgb_find_route(&dev->rdev.lldi, get_real_dev,
41418c2ecf20Sopenharmony_ci			      iph->daddr, iph->saddr, tcph->dest,
41428c2ecf20Sopenharmony_ci			      tcph->source, iph->tos);
41438c2ecf20Sopenharmony_ci	if (!dst) {
41448c2ecf20Sopenharmony_ci		pr_err("%s - failed to find dst entry!\n", __func__);
41458c2ecf20Sopenharmony_ci		goto reject;
41468c2ecf20Sopenharmony_ci	}
41478c2ecf20Sopenharmony_ci	neigh = dst_neigh_lookup_skb(dst, skb);
41488c2ecf20Sopenharmony_ci
41498c2ecf20Sopenharmony_ci	if (!neigh) {
41508c2ecf20Sopenharmony_ci		pr_err("%s - failed to allocate neigh!\n", __func__);
41518c2ecf20Sopenharmony_ci		goto free_dst;
41528c2ecf20Sopenharmony_ci	}
41538c2ecf20Sopenharmony_ci
41548c2ecf20Sopenharmony_ci	if (neigh->dev->flags & IFF_LOOPBACK) {
41558c2ecf20Sopenharmony_ci		pdev = ip_dev_find(&init_net, iph->daddr);
41568c2ecf20Sopenharmony_ci		e = cxgb4_l2t_get(dev->rdev.lldi.l2t, neigh,
41578c2ecf20Sopenharmony_ci				    pdev, 0);
41588c2ecf20Sopenharmony_ci		pi = (struct port_info *)netdev_priv(pdev);
41598c2ecf20Sopenharmony_ci		dev_put(pdev);
41608c2ecf20Sopenharmony_ci	} else {
41618c2ecf20Sopenharmony_ci		pdev = get_real_dev(neigh->dev);
41628c2ecf20Sopenharmony_ci		e = cxgb4_l2t_get(dev->rdev.lldi.l2t, neigh,
41638c2ecf20Sopenharmony_ci					pdev, 0);
41648c2ecf20Sopenharmony_ci		pi = (struct port_info *)netdev_priv(pdev);
41658c2ecf20Sopenharmony_ci	}
41668c2ecf20Sopenharmony_ci	neigh_release(neigh);
41678c2ecf20Sopenharmony_ci	if (!e) {
41688c2ecf20Sopenharmony_ci		pr_err("%s - failed to allocate l2t entry!\n",
41698c2ecf20Sopenharmony_ci		       __func__);
41708c2ecf20Sopenharmony_ci		goto free_dst;
41718c2ecf20Sopenharmony_ci	}
41728c2ecf20Sopenharmony_ci
41738c2ecf20Sopenharmony_ci	step = dev->rdev.lldi.nrxq / dev->rdev.lldi.nchan;
41748c2ecf20Sopenharmony_ci	rss_qid = dev->rdev.lldi.rxq_ids[pi->port_id * step];
41758c2ecf20Sopenharmony_ci	window = (__force u16) htons((__force u16)tcph->window);
41768c2ecf20Sopenharmony_ci
41778c2ecf20Sopenharmony_ci	/* Calcuate filter portion for LE region. */
41788c2ecf20Sopenharmony_ci	filter = (__force unsigned int) cpu_to_be32(cxgb4_select_ntuple(
41798c2ecf20Sopenharmony_ci						    dev->rdev.lldi.ports[0],
41808c2ecf20Sopenharmony_ci						    e));
41818c2ecf20Sopenharmony_ci
41828c2ecf20Sopenharmony_ci	/*
41838c2ecf20Sopenharmony_ci	 * Synthesize the cpl_pass_accept_req. We have everything except the
41848c2ecf20Sopenharmony_ci	 * TID. Once firmware sends a reply with TID we update the TID field
41858c2ecf20Sopenharmony_ci	 * in cpl and pass it through the regular cpl_pass_accept_req path.
41868c2ecf20Sopenharmony_ci	 */
41878c2ecf20Sopenharmony_ci	build_cpl_pass_accept_req(skb, stid, iph->tos);
41888c2ecf20Sopenharmony_ci	send_fw_pass_open_req(dev, skb, iph->daddr, tcph->dest, iph->saddr,
41898c2ecf20Sopenharmony_ci			      tcph->source, ntohl(tcph->seq), filter, window,
41908c2ecf20Sopenharmony_ci			      rss_qid, pi->port_id);
41918c2ecf20Sopenharmony_ci	cxgb4_l2t_release(e);
41928c2ecf20Sopenharmony_cifree_dst:
41938c2ecf20Sopenharmony_ci	dst_release(dst);
41948c2ecf20Sopenharmony_cireject:
41958c2ecf20Sopenharmony_ci	if (lep)
41968c2ecf20Sopenharmony_ci		c4iw_put_ep(&lep->com);
41978c2ecf20Sopenharmony_ci	return 0;
41988c2ecf20Sopenharmony_ci}
41998c2ecf20Sopenharmony_ci
42008c2ecf20Sopenharmony_ci/*
42018c2ecf20Sopenharmony_ci * These are the real handlers that are called from a
42028c2ecf20Sopenharmony_ci * work queue.
42038c2ecf20Sopenharmony_ci */
42048c2ecf20Sopenharmony_cistatic c4iw_handler_func work_handlers[NUM_CPL_CMDS + NUM_FAKE_CPLS] = {
42058c2ecf20Sopenharmony_ci	[CPL_ACT_ESTABLISH] = act_establish,
42068c2ecf20Sopenharmony_ci	[CPL_ACT_OPEN_RPL] = act_open_rpl,
42078c2ecf20Sopenharmony_ci	[CPL_RX_DATA] = rx_data,
42088c2ecf20Sopenharmony_ci	[CPL_ABORT_RPL_RSS] = abort_rpl,
42098c2ecf20Sopenharmony_ci	[CPL_ABORT_RPL] = abort_rpl,
42108c2ecf20Sopenharmony_ci	[CPL_PASS_OPEN_RPL] = pass_open_rpl,
42118c2ecf20Sopenharmony_ci	[CPL_CLOSE_LISTSRV_RPL] = close_listsrv_rpl,
42128c2ecf20Sopenharmony_ci	[CPL_PASS_ACCEPT_REQ] = pass_accept_req,
42138c2ecf20Sopenharmony_ci	[CPL_PASS_ESTABLISH] = pass_establish,
42148c2ecf20Sopenharmony_ci	[CPL_PEER_CLOSE] = peer_close,
42158c2ecf20Sopenharmony_ci	[CPL_ABORT_REQ_RSS] = peer_abort,
42168c2ecf20Sopenharmony_ci	[CPL_CLOSE_CON_RPL] = close_con_rpl,
42178c2ecf20Sopenharmony_ci	[CPL_RDMA_TERMINATE] = terminate,
42188c2ecf20Sopenharmony_ci	[CPL_FW4_ACK] = fw4_ack,
42198c2ecf20Sopenharmony_ci	[CPL_GET_TCB_RPL] = read_tcb_rpl,
42208c2ecf20Sopenharmony_ci	[CPL_FW6_MSG] = deferred_fw6_msg,
42218c2ecf20Sopenharmony_ci	[CPL_RX_PKT] = rx_pkt,
42228c2ecf20Sopenharmony_ci	[FAKE_CPL_PUT_EP_SAFE] = _put_ep_safe,
42238c2ecf20Sopenharmony_ci	[FAKE_CPL_PASS_PUT_EP_SAFE] = _put_pass_ep_safe
42248c2ecf20Sopenharmony_ci};
42258c2ecf20Sopenharmony_ci
42268c2ecf20Sopenharmony_cistatic void process_timeout(struct c4iw_ep *ep)
42278c2ecf20Sopenharmony_ci{
42288c2ecf20Sopenharmony_ci	struct c4iw_qp_attributes attrs;
42298c2ecf20Sopenharmony_ci	int abort = 1;
42308c2ecf20Sopenharmony_ci
42318c2ecf20Sopenharmony_ci	mutex_lock(&ep->com.mutex);
42328c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u state %d\n", ep, ep->hwtid, ep->com.state);
42338c2ecf20Sopenharmony_ci	set_bit(TIMEDOUT, &ep->com.history);
42348c2ecf20Sopenharmony_ci	switch (ep->com.state) {
42358c2ecf20Sopenharmony_ci	case MPA_REQ_SENT:
42368c2ecf20Sopenharmony_ci		connect_reply_upcall(ep, -ETIMEDOUT);
42378c2ecf20Sopenharmony_ci		break;
42388c2ecf20Sopenharmony_ci	case MPA_REQ_WAIT:
42398c2ecf20Sopenharmony_ci	case MPA_REQ_RCVD:
42408c2ecf20Sopenharmony_ci	case MPA_REP_SENT:
42418c2ecf20Sopenharmony_ci	case FPDU_MODE:
42428c2ecf20Sopenharmony_ci		break;
42438c2ecf20Sopenharmony_ci	case CLOSING:
42448c2ecf20Sopenharmony_ci	case MORIBUND:
42458c2ecf20Sopenharmony_ci		if (ep->com.cm_id && ep->com.qp) {
42468c2ecf20Sopenharmony_ci			attrs.next_state = C4IW_QP_STATE_ERROR;
42478c2ecf20Sopenharmony_ci			c4iw_modify_qp(ep->com.qp->rhp,
42488c2ecf20Sopenharmony_ci				     ep->com.qp, C4IW_QP_ATTR_NEXT_STATE,
42498c2ecf20Sopenharmony_ci				     &attrs, 1);
42508c2ecf20Sopenharmony_ci		}
42518c2ecf20Sopenharmony_ci		close_complete_upcall(ep, -ETIMEDOUT);
42528c2ecf20Sopenharmony_ci		break;
42538c2ecf20Sopenharmony_ci	case ABORTING:
42548c2ecf20Sopenharmony_ci	case DEAD:
42558c2ecf20Sopenharmony_ci
42568c2ecf20Sopenharmony_ci		/*
42578c2ecf20Sopenharmony_ci		 * These states are expected if the ep timed out at the same
42588c2ecf20Sopenharmony_ci		 * time as another thread was calling stop_ep_timer().
42598c2ecf20Sopenharmony_ci		 * So we silently do nothing for these states.
42608c2ecf20Sopenharmony_ci		 */
42618c2ecf20Sopenharmony_ci		abort = 0;
42628c2ecf20Sopenharmony_ci		break;
42638c2ecf20Sopenharmony_ci	default:
42648c2ecf20Sopenharmony_ci		WARN(1, "%s unexpected state ep %p tid %u state %u\n",
42658c2ecf20Sopenharmony_ci			__func__, ep, ep->hwtid, ep->com.state);
42668c2ecf20Sopenharmony_ci		abort = 0;
42678c2ecf20Sopenharmony_ci	}
42688c2ecf20Sopenharmony_ci	mutex_unlock(&ep->com.mutex);
42698c2ecf20Sopenharmony_ci	if (abort)
42708c2ecf20Sopenharmony_ci		c4iw_ep_disconnect(ep, 1, GFP_KERNEL);
42718c2ecf20Sopenharmony_ci	c4iw_put_ep(&ep->com);
42728c2ecf20Sopenharmony_ci}
42738c2ecf20Sopenharmony_ci
42748c2ecf20Sopenharmony_cistatic void process_timedout_eps(void)
42758c2ecf20Sopenharmony_ci{
42768c2ecf20Sopenharmony_ci	struct c4iw_ep *ep;
42778c2ecf20Sopenharmony_ci
42788c2ecf20Sopenharmony_ci	spin_lock_irq(&timeout_lock);
42798c2ecf20Sopenharmony_ci	while (!list_empty(&timeout_list)) {
42808c2ecf20Sopenharmony_ci		struct list_head *tmp;
42818c2ecf20Sopenharmony_ci
42828c2ecf20Sopenharmony_ci		tmp = timeout_list.next;
42838c2ecf20Sopenharmony_ci		list_del(tmp);
42848c2ecf20Sopenharmony_ci		tmp->next = NULL;
42858c2ecf20Sopenharmony_ci		tmp->prev = NULL;
42868c2ecf20Sopenharmony_ci		spin_unlock_irq(&timeout_lock);
42878c2ecf20Sopenharmony_ci		ep = list_entry(tmp, struct c4iw_ep, entry);
42888c2ecf20Sopenharmony_ci		process_timeout(ep);
42898c2ecf20Sopenharmony_ci		spin_lock_irq(&timeout_lock);
42908c2ecf20Sopenharmony_ci	}
42918c2ecf20Sopenharmony_ci	spin_unlock_irq(&timeout_lock);
42928c2ecf20Sopenharmony_ci}
42938c2ecf20Sopenharmony_ci
42948c2ecf20Sopenharmony_cistatic void process_work(struct work_struct *work)
42958c2ecf20Sopenharmony_ci{
42968c2ecf20Sopenharmony_ci	struct sk_buff *skb = NULL;
42978c2ecf20Sopenharmony_ci	struct c4iw_dev *dev;
42988c2ecf20Sopenharmony_ci	struct cpl_act_establish *rpl;
42998c2ecf20Sopenharmony_ci	unsigned int opcode;
43008c2ecf20Sopenharmony_ci	int ret;
43018c2ecf20Sopenharmony_ci
43028c2ecf20Sopenharmony_ci	process_timedout_eps();
43038c2ecf20Sopenharmony_ci	while ((skb = skb_dequeue(&rxq))) {
43048c2ecf20Sopenharmony_ci		rpl = cplhdr(skb);
43058c2ecf20Sopenharmony_ci		dev = *((struct c4iw_dev **) (skb->cb + sizeof(void *)));
43068c2ecf20Sopenharmony_ci		opcode = rpl->ot.opcode;
43078c2ecf20Sopenharmony_ci
43088c2ecf20Sopenharmony_ci		if (opcode >= ARRAY_SIZE(work_handlers) ||
43098c2ecf20Sopenharmony_ci		    !work_handlers[opcode]) {
43108c2ecf20Sopenharmony_ci			pr_err("No handler for opcode 0x%x.\n", opcode);
43118c2ecf20Sopenharmony_ci			kfree_skb(skb);
43128c2ecf20Sopenharmony_ci		} else {
43138c2ecf20Sopenharmony_ci			ret = work_handlers[opcode](dev, skb);
43148c2ecf20Sopenharmony_ci			if (!ret)
43158c2ecf20Sopenharmony_ci				kfree_skb(skb);
43168c2ecf20Sopenharmony_ci		}
43178c2ecf20Sopenharmony_ci		process_timedout_eps();
43188c2ecf20Sopenharmony_ci	}
43198c2ecf20Sopenharmony_ci}
43208c2ecf20Sopenharmony_ci
43218c2ecf20Sopenharmony_cistatic DECLARE_WORK(skb_work, process_work);
43228c2ecf20Sopenharmony_ci
43238c2ecf20Sopenharmony_cistatic void ep_timeout(struct timer_list *t)
43248c2ecf20Sopenharmony_ci{
43258c2ecf20Sopenharmony_ci	struct c4iw_ep *ep = from_timer(ep, t, timer);
43268c2ecf20Sopenharmony_ci	int kickit = 0;
43278c2ecf20Sopenharmony_ci
43288c2ecf20Sopenharmony_ci	spin_lock(&timeout_lock);
43298c2ecf20Sopenharmony_ci	if (!test_and_set_bit(TIMEOUT, &ep->com.flags)) {
43308c2ecf20Sopenharmony_ci		/*
43318c2ecf20Sopenharmony_ci		 * Only insert if it is not already on the list.
43328c2ecf20Sopenharmony_ci		 */
43338c2ecf20Sopenharmony_ci		if (!ep->entry.next) {
43348c2ecf20Sopenharmony_ci			list_add_tail(&ep->entry, &timeout_list);
43358c2ecf20Sopenharmony_ci			kickit = 1;
43368c2ecf20Sopenharmony_ci		}
43378c2ecf20Sopenharmony_ci	}
43388c2ecf20Sopenharmony_ci	spin_unlock(&timeout_lock);
43398c2ecf20Sopenharmony_ci	if (kickit)
43408c2ecf20Sopenharmony_ci		queue_work(workq, &skb_work);
43418c2ecf20Sopenharmony_ci}
43428c2ecf20Sopenharmony_ci
43438c2ecf20Sopenharmony_ci/*
43448c2ecf20Sopenharmony_ci * All the CM events are handled on a work queue to have a safe context.
43458c2ecf20Sopenharmony_ci */
43468c2ecf20Sopenharmony_cistatic int sched(struct c4iw_dev *dev, struct sk_buff *skb)
43478c2ecf20Sopenharmony_ci{
43488c2ecf20Sopenharmony_ci
43498c2ecf20Sopenharmony_ci	/*
43508c2ecf20Sopenharmony_ci	 * Save dev in the skb->cb area.
43518c2ecf20Sopenharmony_ci	 */
43528c2ecf20Sopenharmony_ci	*((struct c4iw_dev **) (skb->cb + sizeof(void *))) = dev;
43538c2ecf20Sopenharmony_ci
43548c2ecf20Sopenharmony_ci	/*
43558c2ecf20Sopenharmony_ci	 * Queue the skb and schedule the worker thread.
43568c2ecf20Sopenharmony_ci	 */
43578c2ecf20Sopenharmony_ci	skb_queue_tail(&rxq, skb);
43588c2ecf20Sopenharmony_ci	queue_work(workq, &skb_work);
43598c2ecf20Sopenharmony_ci	return 0;
43608c2ecf20Sopenharmony_ci}
43618c2ecf20Sopenharmony_ci
43628c2ecf20Sopenharmony_cistatic int set_tcb_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
43638c2ecf20Sopenharmony_ci{
43648c2ecf20Sopenharmony_ci	struct cpl_set_tcb_rpl *rpl = cplhdr(skb);
43658c2ecf20Sopenharmony_ci
43668c2ecf20Sopenharmony_ci	if (rpl->status != CPL_ERR_NONE) {
43678c2ecf20Sopenharmony_ci		pr_err("Unexpected SET_TCB_RPL status %u for tid %u\n",
43688c2ecf20Sopenharmony_ci		       rpl->status, GET_TID(rpl));
43698c2ecf20Sopenharmony_ci	}
43708c2ecf20Sopenharmony_ci	kfree_skb(skb);
43718c2ecf20Sopenharmony_ci	return 0;
43728c2ecf20Sopenharmony_ci}
43738c2ecf20Sopenharmony_ci
43748c2ecf20Sopenharmony_cistatic int fw6_msg(struct c4iw_dev *dev, struct sk_buff *skb)
43758c2ecf20Sopenharmony_ci{
43768c2ecf20Sopenharmony_ci	struct cpl_fw6_msg *rpl = cplhdr(skb);
43778c2ecf20Sopenharmony_ci	struct c4iw_wr_wait *wr_waitp;
43788c2ecf20Sopenharmony_ci	int ret;
43798c2ecf20Sopenharmony_ci
43808c2ecf20Sopenharmony_ci	pr_debug("type %u\n", rpl->type);
43818c2ecf20Sopenharmony_ci
43828c2ecf20Sopenharmony_ci	switch (rpl->type) {
43838c2ecf20Sopenharmony_ci	case FW6_TYPE_WR_RPL:
43848c2ecf20Sopenharmony_ci		ret = (int)((be64_to_cpu(rpl->data[0]) >> 8) & 0xff);
43858c2ecf20Sopenharmony_ci		wr_waitp = (struct c4iw_wr_wait *)(__force unsigned long) rpl->data[1];
43868c2ecf20Sopenharmony_ci		pr_debug("wr_waitp %p ret %u\n", wr_waitp, ret);
43878c2ecf20Sopenharmony_ci		if (wr_waitp)
43888c2ecf20Sopenharmony_ci			c4iw_wake_up_deref(wr_waitp, ret ? -ret : 0);
43898c2ecf20Sopenharmony_ci		kfree_skb(skb);
43908c2ecf20Sopenharmony_ci		break;
43918c2ecf20Sopenharmony_ci	case FW6_TYPE_CQE:
43928c2ecf20Sopenharmony_ci	case FW6_TYPE_OFLD_CONNECTION_WR_RPL:
43938c2ecf20Sopenharmony_ci		sched(dev, skb);
43948c2ecf20Sopenharmony_ci		break;
43958c2ecf20Sopenharmony_ci	default:
43968c2ecf20Sopenharmony_ci		pr_err("%s unexpected fw6 msg type %u\n",
43978c2ecf20Sopenharmony_ci		       __func__, rpl->type);
43988c2ecf20Sopenharmony_ci		kfree_skb(skb);
43998c2ecf20Sopenharmony_ci		break;
44008c2ecf20Sopenharmony_ci	}
44018c2ecf20Sopenharmony_ci	return 0;
44028c2ecf20Sopenharmony_ci}
44038c2ecf20Sopenharmony_ci
44048c2ecf20Sopenharmony_cistatic int peer_abort_intr(struct c4iw_dev *dev, struct sk_buff *skb)
44058c2ecf20Sopenharmony_ci{
44068c2ecf20Sopenharmony_ci	struct cpl_abort_req_rss *req = cplhdr(skb);
44078c2ecf20Sopenharmony_ci	struct c4iw_ep *ep;
44088c2ecf20Sopenharmony_ci	unsigned int tid = GET_TID(req);
44098c2ecf20Sopenharmony_ci
44108c2ecf20Sopenharmony_ci	ep = get_ep_from_tid(dev, tid);
44118c2ecf20Sopenharmony_ci	/* This EP will be dereferenced in peer_abort() */
44128c2ecf20Sopenharmony_ci	if (!ep) {
44138c2ecf20Sopenharmony_ci		pr_warn("Abort on non-existent endpoint, tid %d\n", tid);
44148c2ecf20Sopenharmony_ci		kfree_skb(skb);
44158c2ecf20Sopenharmony_ci		return 0;
44168c2ecf20Sopenharmony_ci	}
44178c2ecf20Sopenharmony_ci	if (cxgb_is_neg_adv(req->status)) {
44188c2ecf20Sopenharmony_ci		pr_debug("Negative advice on abort- tid %u status %d (%s)\n",
44198c2ecf20Sopenharmony_ci			 ep->hwtid, req->status,
44208c2ecf20Sopenharmony_ci			 neg_adv_str(req->status));
44218c2ecf20Sopenharmony_ci		goto out;
44228c2ecf20Sopenharmony_ci	}
44238c2ecf20Sopenharmony_ci	pr_debug("ep %p tid %u state %u\n", ep, ep->hwtid, ep->com.state);
44248c2ecf20Sopenharmony_ci
44258c2ecf20Sopenharmony_ci	c4iw_wake_up_noref(ep->com.wr_waitp, -ECONNRESET);
44268c2ecf20Sopenharmony_ciout:
44278c2ecf20Sopenharmony_ci	sched(dev, skb);
44288c2ecf20Sopenharmony_ci	return 0;
44298c2ecf20Sopenharmony_ci}
44308c2ecf20Sopenharmony_ci
44318c2ecf20Sopenharmony_ci/*
44328c2ecf20Sopenharmony_ci * Most upcalls from the T4 Core go to sched() to
44338c2ecf20Sopenharmony_ci * schedule the processing on a work queue.
44348c2ecf20Sopenharmony_ci */
44358c2ecf20Sopenharmony_cic4iw_handler_func c4iw_handlers[NUM_CPL_CMDS] = {
44368c2ecf20Sopenharmony_ci	[CPL_ACT_ESTABLISH] = sched,
44378c2ecf20Sopenharmony_ci	[CPL_ACT_OPEN_RPL] = sched,
44388c2ecf20Sopenharmony_ci	[CPL_RX_DATA] = sched,
44398c2ecf20Sopenharmony_ci	[CPL_ABORT_RPL_RSS] = sched,
44408c2ecf20Sopenharmony_ci	[CPL_ABORT_RPL] = sched,
44418c2ecf20Sopenharmony_ci	[CPL_PASS_OPEN_RPL] = sched,
44428c2ecf20Sopenharmony_ci	[CPL_CLOSE_LISTSRV_RPL] = sched,
44438c2ecf20Sopenharmony_ci	[CPL_PASS_ACCEPT_REQ] = sched,
44448c2ecf20Sopenharmony_ci	[CPL_PASS_ESTABLISH] = sched,
44458c2ecf20Sopenharmony_ci	[CPL_PEER_CLOSE] = sched,
44468c2ecf20Sopenharmony_ci	[CPL_CLOSE_CON_RPL] = sched,
44478c2ecf20Sopenharmony_ci	[CPL_ABORT_REQ_RSS] = peer_abort_intr,
44488c2ecf20Sopenharmony_ci	[CPL_RDMA_TERMINATE] = sched,
44498c2ecf20Sopenharmony_ci	[CPL_FW4_ACK] = sched,
44508c2ecf20Sopenharmony_ci	[CPL_SET_TCB_RPL] = set_tcb_rpl,
44518c2ecf20Sopenharmony_ci	[CPL_GET_TCB_RPL] = sched,
44528c2ecf20Sopenharmony_ci	[CPL_FW6_MSG] = fw6_msg,
44538c2ecf20Sopenharmony_ci	[CPL_RX_PKT] = sched
44548c2ecf20Sopenharmony_ci};
44558c2ecf20Sopenharmony_ci
44568c2ecf20Sopenharmony_ciint __init c4iw_cm_init(void)
44578c2ecf20Sopenharmony_ci{
44588c2ecf20Sopenharmony_ci	spin_lock_init(&timeout_lock);
44598c2ecf20Sopenharmony_ci	skb_queue_head_init(&rxq);
44608c2ecf20Sopenharmony_ci
44618c2ecf20Sopenharmony_ci	workq = alloc_ordered_workqueue("iw_cxgb4", WQ_MEM_RECLAIM);
44628c2ecf20Sopenharmony_ci	if (!workq)
44638c2ecf20Sopenharmony_ci		return -ENOMEM;
44648c2ecf20Sopenharmony_ci
44658c2ecf20Sopenharmony_ci	return 0;
44668c2ecf20Sopenharmony_ci}
44678c2ecf20Sopenharmony_ci
44688c2ecf20Sopenharmony_civoid c4iw_cm_term(void)
44698c2ecf20Sopenharmony_ci{
44708c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&timeout_list));
44718c2ecf20Sopenharmony_ci	flush_workqueue(workq);
44728c2ecf20Sopenharmony_ci	destroy_workqueue(workq);
44738c2ecf20Sopenharmony_ci}
4474