18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2016 Chelsio Communications, Inc.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/module.h>
78c2ecf20Sopenharmony_ci#include <linux/list.h>
88c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
98c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
108c2ecf20Sopenharmony_ci#include <linux/timer.h>
118c2ecf20Sopenharmony_ci#include <linux/notifier.h>
128c2ecf20Sopenharmony_ci#include <linux/inetdevice.h>
138c2ecf20Sopenharmony_ci#include <linux/ip.h>
148c2ecf20Sopenharmony_ci#include <linux/tcp.h>
158c2ecf20Sopenharmony_ci#include <linux/if_vlan.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <net/neighbour.h>
188c2ecf20Sopenharmony_ci#include <net/netevent.h>
198c2ecf20Sopenharmony_ci#include <net/route.h>
208c2ecf20Sopenharmony_ci#include <net/tcp.h>
218c2ecf20Sopenharmony_ci#include <net/ip6_route.h>
228c2ecf20Sopenharmony_ci#include <net/addrconf.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include <libcxgb_cm.h>
258c2ecf20Sopenharmony_ci#include "cxgbit.h"
268c2ecf20Sopenharmony_ci#include "clip_tbl.h"
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic void cxgbit_init_wr_wait(struct cxgbit_wr_wait *wr_waitp)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	wr_waitp->ret = 0;
318c2ecf20Sopenharmony_ci	reinit_completion(&wr_waitp->completion);
328c2ecf20Sopenharmony_ci}
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic void
358c2ecf20Sopenharmony_cicxgbit_wake_up(struct cxgbit_wr_wait *wr_waitp, const char *func, u8 ret)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	if (ret == CPL_ERR_NONE)
388c2ecf20Sopenharmony_ci		wr_waitp->ret = 0;
398c2ecf20Sopenharmony_ci	else
408c2ecf20Sopenharmony_ci		wr_waitp->ret = -EIO;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	if (wr_waitp->ret)
438c2ecf20Sopenharmony_ci		pr_err("%s: err:%u", func, ret);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	complete(&wr_waitp->completion);
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic int
498c2ecf20Sopenharmony_cicxgbit_wait_for_reply(struct cxgbit_device *cdev,
508c2ecf20Sopenharmony_ci		      struct cxgbit_wr_wait *wr_waitp, u32 tid, u32 timeout,
518c2ecf20Sopenharmony_ci		      const char *func)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	int ret;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	if (!test_bit(CDEV_STATE_UP, &cdev->flags)) {
568c2ecf20Sopenharmony_ci		wr_waitp->ret = -EIO;
578c2ecf20Sopenharmony_ci		goto out;
588c2ecf20Sopenharmony_ci	}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	ret = wait_for_completion_timeout(&wr_waitp->completion, timeout * HZ);
618c2ecf20Sopenharmony_ci	if (!ret) {
628c2ecf20Sopenharmony_ci		pr_info("%s - Device %s not responding tid %u\n",
638c2ecf20Sopenharmony_ci			func, pci_name(cdev->lldi.pdev), tid);
648c2ecf20Sopenharmony_ci		wr_waitp->ret = -ETIMEDOUT;
658c2ecf20Sopenharmony_ci	}
668c2ecf20Sopenharmony_ciout:
678c2ecf20Sopenharmony_ci	if (wr_waitp->ret)
688c2ecf20Sopenharmony_ci		pr_info("%s: FW reply %d tid %u\n",
698c2ecf20Sopenharmony_ci			pci_name(cdev->lldi.pdev), wr_waitp->ret, tid);
708c2ecf20Sopenharmony_ci	return wr_waitp->ret;
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic int cxgbit_np_hashfn(const struct cxgbit_np *cnp)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	return ((unsigned long)cnp >> 10) & (NP_INFO_HASH_SIZE - 1);
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic struct np_info *
798c2ecf20Sopenharmony_cicxgbit_np_hash_add(struct cxgbit_device *cdev, struct cxgbit_np *cnp,
808c2ecf20Sopenharmony_ci		   unsigned int stid)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	struct np_info *p = kzalloc(sizeof(*p), GFP_KERNEL);
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	if (p) {
858c2ecf20Sopenharmony_ci		int bucket = cxgbit_np_hashfn(cnp);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci		p->cnp = cnp;
888c2ecf20Sopenharmony_ci		p->stid = stid;
898c2ecf20Sopenharmony_ci		spin_lock(&cdev->np_lock);
908c2ecf20Sopenharmony_ci		p->next = cdev->np_hash_tab[bucket];
918c2ecf20Sopenharmony_ci		cdev->np_hash_tab[bucket] = p;
928c2ecf20Sopenharmony_ci		spin_unlock(&cdev->np_lock);
938c2ecf20Sopenharmony_ci	}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	return p;
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic int
998c2ecf20Sopenharmony_cicxgbit_np_hash_find(struct cxgbit_device *cdev, struct cxgbit_np *cnp)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	int stid = -1, bucket = cxgbit_np_hashfn(cnp);
1028c2ecf20Sopenharmony_ci	struct np_info *p;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	spin_lock(&cdev->np_lock);
1058c2ecf20Sopenharmony_ci	for (p = cdev->np_hash_tab[bucket]; p; p = p->next) {
1068c2ecf20Sopenharmony_ci		if (p->cnp == cnp) {
1078c2ecf20Sopenharmony_ci			stid = p->stid;
1088c2ecf20Sopenharmony_ci			break;
1098c2ecf20Sopenharmony_ci		}
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci	spin_unlock(&cdev->np_lock);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	return stid;
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic int cxgbit_np_hash_del(struct cxgbit_device *cdev, struct cxgbit_np *cnp)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	int stid = -1, bucket = cxgbit_np_hashfn(cnp);
1198c2ecf20Sopenharmony_ci	struct np_info *p, **prev = &cdev->np_hash_tab[bucket];
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	spin_lock(&cdev->np_lock);
1228c2ecf20Sopenharmony_ci	for (p = *prev; p; prev = &p->next, p = p->next) {
1238c2ecf20Sopenharmony_ci		if (p->cnp == cnp) {
1248c2ecf20Sopenharmony_ci			stid = p->stid;
1258c2ecf20Sopenharmony_ci			*prev = p->next;
1268c2ecf20Sopenharmony_ci			kfree(p);
1278c2ecf20Sopenharmony_ci			break;
1288c2ecf20Sopenharmony_ci		}
1298c2ecf20Sopenharmony_ci	}
1308c2ecf20Sopenharmony_ci	spin_unlock(&cdev->np_lock);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	return stid;
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_civoid _cxgbit_free_cnp(struct kref *kref)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	struct cxgbit_np *cnp;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	cnp = container_of(kref, struct cxgbit_np, kref);
1408c2ecf20Sopenharmony_ci	kfree(cnp);
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic int
1448c2ecf20Sopenharmony_cicxgbit_create_server6(struct cxgbit_device *cdev, unsigned int stid,
1458c2ecf20Sopenharmony_ci		      struct cxgbit_np *cnp)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)
1488c2ecf20Sopenharmony_ci				     &cnp->com.local_addr;
1498c2ecf20Sopenharmony_ci	int addr_type;
1508c2ecf20Sopenharmony_ci	int ret;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	pr_debug("%s: dev = %s; stid = %u; sin6_port = %u\n",
1538c2ecf20Sopenharmony_ci		 __func__, cdev->lldi.ports[0]->name, stid, sin6->sin6_port);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	addr_type = ipv6_addr_type((const struct in6_addr *)
1568c2ecf20Sopenharmony_ci				   &sin6->sin6_addr);
1578c2ecf20Sopenharmony_ci	if (addr_type != IPV6_ADDR_ANY) {
1588c2ecf20Sopenharmony_ci		ret = cxgb4_clip_get(cdev->lldi.ports[0],
1598c2ecf20Sopenharmony_ci				     (const u32 *)&sin6->sin6_addr.s6_addr, 1);
1608c2ecf20Sopenharmony_ci		if (ret) {
1618c2ecf20Sopenharmony_ci			pr_err("Unable to find clip table entry. laddr %pI6. Error:%d.\n",
1628c2ecf20Sopenharmony_ci			       sin6->sin6_addr.s6_addr, ret);
1638c2ecf20Sopenharmony_ci			return -ENOMEM;
1648c2ecf20Sopenharmony_ci		}
1658c2ecf20Sopenharmony_ci	}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	cxgbit_get_cnp(cnp);
1688c2ecf20Sopenharmony_ci	cxgbit_init_wr_wait(&cnp->com.wr_wait);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	ret = cxgb4_create_server6(cdev->lldi.ports[0],
1718c2ecf20Sopenharmony_ci				   stid, &sin6->sin6_addr,
1728c2ecf20Sopenharmony_ci				   sin6->sin6_port,
1738c2ecf20Sopenharmony_ci				   cdev->lldi.rxq_ids[0]);
1748c2ecf20Sopenharmony_ci	if (!ret)
1758c2ecf20Sopenharmony_ci		ret = cxgbit_wait_for_reply(cdev, &cnp->com.wr_wait,
1768c2ecf20Sopenharmony_ci					    0, 10, __func__);
1778c2ecf20Sopenharmony_ci	else if (ret > 0)
1788c2ecf20Sopenharmony_ci		ret = net_xmit_errno(ret);
1798c2ecf20Sopenharmony_ci	else
1808c2ecf20Sopenharmony_ci		cxgbit_put_cnp(cnp);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	if (ret) {
1838c2ecf20Sopenharmony_ci		if (ret != -ETIMEDOUT)
1848c2ecf20Sopenharmony_ci			cxgb4_clip_release(cdev->lldi.ports[0],
1858c2ecf20Sopenharmony_ci				   (const u32 *)&sin6->sin6_addr.s6_addr, 1);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci		pr_err("create server6 err %d stid %d laddr %pI6 lport %d\n",
1888c2ecf20Sopenharmony_ci		       ret, stid, sin6->sin6_addr.s6_addr,
1898c2ecf20Sopenharmony_ci		       ntohs(sin6->sin6_port));
1908c2ecf20Sopenharmony_ci	}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	return ret;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic int
1968c2ecf20Sopenharmony_cicxgbit_create_server4(struct cxgbit_device *cdev, unsigned int stid,
1978c2ecf20Sopenharmony_ci		      struct cxgbit_np *cnp)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	struct sockaddr_in *sin = (struct sockaddr_in *)
2008c2ecf20Sopenharmony_ci				   &cnp->com.local_addr;
2018c2ecf20Sopenharmony_ci	int ret;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	pr_debug("%s: dev = %s; stid = %u; sin_port = %u\n",
2048c2ecf20Sopenharmony_ci		 __func__, cdev->lldi.ports[0]->name, stid, sin->sin_port);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	cxgbit_get_cnp(cnp);
2078c2ecf20Sopenharmony_ci	cxgbit_init_wr_wait(&cnp->com.wr_wait);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	ret = cxgb4_create_server(cdev->lldi.ports[0],
2108c2ecf20Sopenharmony_ci				  stid, sin->sin_addr.s_addr,
2118c2ecf20Sopenharmony_ci				  sin->sin_port, 0,
2128c2ecf20Sopenharmony_ci				  cdev->lldi.rxq_ids[0]);
2138c2ecf20Sopenharmony_ci	if (!ret)
2148c2ecf20Sopenharmony_ci		ret = cxgbit_wait_for_reply(cdev,
2158c2ecf20Sopenharmony_ci					    &cnp->com.wr_wait,
2168c2ecf20Sopenharmony_ci					    0, 10, __func__);
2178c2ecf20Sopenharmony_ci	else if (ret > 0)
2188c2ecf20Sopenharmony_ci		ret = net_xmit_errno(ret);
2198c2ecf20Sopenharmony_ci	else
2208c2ecf20Sopenharmony_ci		cxgbit_put_cnp(cnp);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	if (ret)
2238c2ecf20Sopenharmony_ci		pr_err("create server failed err %d stid %d laddr %pI4 lport %d\n",
2248c2ecf20Sopenharmony_ci		       ret, stid, &sin->sin_addr, ntohs(sin->sin_port));
2258c2ecf20Sopenharmony_ci	return ret;
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistruct cxgbit_device *cxgbit_find_device(struct net_device *ndev, u8 *port_id)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	struct cxgbit_device *cdev;
2318c2ecf20Sopenharmony_ci	u8 i;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	list_for_each_entry(cdev, &cdev_list_head, list) {
2348c2ecf20Sopenharmony_ci		struct cxgb4_lld_info *lldi = &cdev->lldi;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci		for (i = 0; i < lldi->nports; i++) {
2378c2ecf20Sopenharmony_ci			if (lldi->ports[i] == ndev) {
2388c2ecf20Sopenharmony_ci				if (port_id)
2398c2ecf20Sopenharmony_ci					*port_id = i;
2408c2ecf20Sopenharmony_ci				return cdev;
2418c2ecf20Sopenharmony_ci			}
2428c2ecf20Sopenharmony_ci		}
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	return NULL;
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cistatic struct net_device *cxgbit_get_real_dev(struct net_device *ndev)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	if (ndev->priv_flags & IFF_BONDING) {
2518c2ecf20Sopenharmony_ci		pr_err("Bond devices are not supported. Interface:%s\n",
2528c2ecf20Sopenharmony_ci		       ndev->name);
2538c2ecf20Sopenharmony_ci		return NULL;
2548c2ecf20Sopenharmony_ci	}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	if (is_vlan_dev(ndev))
2578c2ecf20Sopenharmony_ci		return vlan_dev_real_dev(ndev);
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	return ndev;
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_cistatic struct net_device *cxgbit_ipv4_netdev(__be32 saddr)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	struct net_device *ndev;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	ndev = __ip_dev_find(&init_net, saddr, false);
2678c2ecf20Sopenharmony_ci	if (!ndev)
2688c2ecf20Sopenharmony_ci		return NULL;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	return cxgbit_get_real_dev(ndev);
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_cistatic struct net_device *cxgbit_ipv6_netdev(struct in6_addr *addr6)
2748c2ecf20Sopenharmony_ci{
2758c2ecf20Sopenharmony_ci	struct net_device *ndev = NULL;
2768c2ecf20Sopenharmony_ci	bool found = false;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_IPV6)) {
2798c2ecf20Sopenharmony_ci		for_each_netdev_rcu(&init_net, ndev)
2808c2ecf20Sopenharmony_ci			if (ipv6_chk_addr(&init_net, addr6, ndev, 1)) {
2818c2ecf20Sopenharmony_ci				found = true;
2828c2ecf20Sopenharmony_ci				break;
2838c2ecf20Sopenharmony_ci			}
2848c2ecf20Sopenharmony_ci	}
2858c2ecf20Sopenharmony_ci	if (!found)
2868c2ecf20Sopenharmony_ci		return NULL;
2878c2ecf20Sopenharmony_ci	return cxgbit_get_real_dev(ndev);
2888c2ecf20Sopenharmony_ci}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cistatic struct cxgbit_device *cxgbit_find_np_cdev(struct cxgbit_np *cnp)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci	struct sockaddr_storage *sockaddr = &cnp->com.local_addr;
2938c2ecf20Sopenharmony_ci	int ss_family = sockaddr->ss_family;
2948c2ecf20Sopenharmony_ci	struct net_device *ndev = NULL;
2958c2ecf20Sopenharmony_ci	struct cxgbit_device *cdev = NULL;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	rcu_read_lock();
2988c2ecf20Sopenharmony_ci	if (ss_family == AF_INET) {
2998c2ecf20Sopenharmony_ci		struct sockaddr_in *sin;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci		sin = (struct sockaddr_in *)sockaddr;
3028c2ecf20Sopenharmony_ci		ndev = cxgbit_ipv4_netdev(sin->sin_addr.s_addr);
3038c2ecf20Sopenharmony_ci	} else if (ss_family == AF_INET6) {
3048c2ecf20Sopenharmony_ci		struct sockaddr_in6 *sin6;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci		sin6 = (struct sockaddr_in6 *)sockaddr;
3078c2ecf20Sopenharmony_ci		ndev = cxgbit_ipv6_netdev(&sin6->sin6_addr);
3088c2ecf20Sopenharmony_ci	}
3098c2ecf20Sopenharmony_ci	if (!ndev)
3108c2ecf20Sopenharmony_ci		goto out;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	cdev = cxgbit_find_device(ndev, NULL);
3138c2ecf20Sopenharmony_ciout:
3148c2ecf20Sopenharmony_ci	rcu_read_unlock();
3158c2ecf20Sopenharmony_ci	return cdev;
3168c2ecf20Sopenharmony_ci}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_cistatic bool cxgbit_inaddr_any(struct cxgbit_np *cnp)
3198c2ecf20Sopenharmony_ci{
3208c2ecf20Sopenharmony_ci	struct sockaddr_storage *sockaddr = &cnp->com.local_addr;
3218c2ecf20Sopenharmony_ci	int ss_family = sockaddr->ss_family;
3228c2ecf20Sopenharmony_ci	int addr_type;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	if (ss_family == AF_INET) {
3258c2ecf20Sopenharmony_ci		struct sockaddr_in *sin;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci		sin = (struct sockaddr_in *)sockaddr;
3288c2ecf20Sopenharmony_ci		if (sin->sin_addr.s_addr == htonl(INADDR_ANY))
3298c2ecf20Sopenharmony_ci			return true;
3308c2ecf20Sopenharmony_ci	} else if (ss_family == AF_INET6) {
3318c2ecf20Sopenharmony_ci		struct sockaddr_in6 *sin6;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci		sin6 = (struct sockaddr_in6 *)sockaddr;
3348c2ecf20Sopenharmony_ci		addr_type = ipv6_addr_type((const struct in6_addr *)
3358c2ecf20Sopenharmony_ci				&sin6->sin6_addr);
3368c2ecf20Sopenharmony_ci		if (addr_type == IPV6_ADDR_ANY)
3378c2ecf20Sopenharmony_ci			return true;
3388c2ecf20Sopenharmony_ci	}
3398c2ecf20Sopenharmony_ci	return false;
3408c2ecf20Sopenharmony_ci}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_cistatic int
3438c2ecf20Sopenharmony_ci__cxgbit_setup_cdev_np(struct cxgbit_device *cdev, struct cxgbit_np *cnp)
3448c2ecf20Sopenharmony_ci{
3458c2ecf20Sopenharmony_ci	int stid, ret;
3468c2ecf20Sopenharmony_ci	int ss_family = cnp->com.local_addr.ss_family;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	if (!test_bit(CDEV_STATE_UP, &cdev->flags))
3498c2ecf20Sopenharmony_ci		return -EINVAL;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	stid = cxgb4_alloc_stid(cdev->lldi.tids, ss_family, cnp);
3528c2ecf20Sopenharmony_ci	if (stid < 0)
3538c2ecf20Sopenharmony_ci		return -EINVAL;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	if (!cxgbit_np_hash_add(cdev, cnp, stid)) {
3568c2ecf20Sopenharmony_ci		cxgb4_free_stid(cdev->lldi.tids, stid, ss_family);
3578c2ecf20Sopenharmony_ci		return -EINVAL;
3588c2ecf20Sopenharmony_ci	}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	if (ss_family == AF_INET)
3618c2ecf20Sopenharmony_ci		ret = cxgbit_create_server4(cdev, stid, cnp);
3628c2ecf20Sopenharmony_ci	else
3638c2ecf20Sopenharmony_ci		ret = cxgbit_create_server6(cdev, stid, cnp);
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	if (ret) {
3668c2ecf20Sopenharmony_ci		if (ret != -ETIMEDOUT)
3678c2ecf20Sopenharmony_ci			cxgb4_free_stid(cdev->lldi.tids, stid,
3688c2ecf20Sopenharmony_ci					ss_family);
3698c2ecf20Sopenharmony_ci		cxgbit_np_hash_del(cdev, cnp);
3708c2ecf20Sopenharmony_ci		return ret;
3718c2ecf20Sopenharmony_ci	}
3728c2ecf20Sopenharmony_ci	return ret;
3738c2ecf20Sopenharmony_ci}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_cistatic int cxgbit_setup_cdev_np(struct cxgbit_np *cnp)
3768c2ecf20Sopenharmony_ci{
3778c2ecf20Sopenharmony_ci	struct cxgbit_device *cdev;
3788c2ecf20Sopenharmony_ci	int ret = -1;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	mutex_lock(&cdev_list_lock);
3818c2ecf20Sopenharmony_ci	cdev = cxgbit_find_np_cdev(cnp);
3828c2ecf20Sopenharmony_ci	if (!cdev)
3838c2ecf20Sopenharmony_ci		goto out;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	if (cxgbit_np_hash_find(cdev, cnp) >= 0)
3868c2ecf20Sopenharmony_ci		goto out;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	if (__cxgbit_setup_cdev_np(cdev, cnp))
3898c2ecf20Sopenharmony_ci		goto out;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	cnp->com.cdev = cdev;
3928c2ecf20Sopenharmony_ci	ret = 0;
3938c2ecf20Sopenharmony_ciout:
3948c2ecf20Sopenharmony_ci	mutex_unlock(&cdev_list_lock);
3958c2ecf20Sopenharmony_ci	return ret;
3968c2ecf20Sopenharmony_ci}
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_cistatic int cxgbit_setup_all_np(struct cxgbit_np *cnp)
3998c2ecf20Sopenharmony_ci{
4008c2ecf20Sopenharmony_ci	struct cxgbit_device *cdev;
4018c2ecf20Sopenharmony_ci	int ret;
4028c2ecf20Sopenharmony_ci	u32 count = 0;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	mutex_lock(&cdev_list_lock);
4058c2ecf20Sopenharmony_ci	list_for_each_entry(cdev, &cdev_list_head, list) {
4068c2ecf20Sopenharmony_ci		if (cxgbit_np_hash_find(cdev, cnp) >= 0) {
4078c2ecf20Sopenharmony_ci			mutex_unlock(&cdev_list_lock);
4088c2ecf20Sopenharmony_ci			return -1;
4098c2ecf20Sopenharmony_ci		}
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	list_for_each_entry(cdev, &cdev_list_head, list) {
4138c2ecf20Sopenharmony_ci		ret = __cxgbit_setup_cdev_np(cdev, cnp);
4148c2ecf20Sopenharmony_ci		if (ret == -ETIMEDOUT)
4158c2ecf20Sopenharmony_ci			break;
4168c2ecf20Sopenharmony_ci		if (ret != 0)
4178c2ecf20Sopenharmony_ci			continue;
4188c2ecf20Sopenharmony_ci		count++;
4198c2ecf20Sopenharmony_ci	}
4208c2ecf20Sopenharmony_ci	mutex_unlock(&cdev_list_lock);
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	return count ? 0 : -1;
4238c2ecf20Sopenharmony_ci}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ciint cxgbit_setup_np(struct iscsi_np *np, struct sockaddr_storage *ksockaddr)
4268c2ecf20Sopenharmony_ci{
4278c2ecf20Sopenharmony_ci	struct cxgbit_np *cnp;
4288c2ecf20Sopenharmony_ci	int ret;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	if ((ksockaddr->ss_family != AF_INET) &&
4318c2ecf20Sopenharmony_ci	    (ksockaddr->ss_family != AF_INET6))
4328c2ecf20Sopenharmony_ci		return -EINVAL;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	cnp = kzalloc(sizeof(*cnp), GFP_KERNEL);
4358c2ecf20Sopenharmony_ci	if (!cnp)
4368c2ecf20Sopenharmony_ci		return -ENOMEM;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	init_waitqueue_head(&cnp->accept_wait);
4398c2ecf20Sopenharmony_ci	init_completion(&cnp->com.wr_wait.completion);
4408c2ecf20Sopenharmony_ci	init_completion(&cnp->accept_comp);
4418c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&cnp->np_accept_list);
4428c2ecf20Sopenharmony_ci	spin_lock_init(&cnp->np_accept_lock);
4438c2ecf20Sopenharmony_ci	kref_init(&cnp->kref);
4448c2ecf20Sopenharmony_ci	memcpy(&np->np_sockaddr, ksockaddr,
4458c2ecf20Sopenharmony_ci	       sizeof(struct sockaddr_storage));
4468c2ecf20Sopenharmony_ci	memcpy(&cnp->com.local_addr, &np->np_sockaddr,
4478c2ecf20Sopenharmony_ci	       sizeof(cnp->com.local_addr));
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	cnp->np = np;
4508c2ecf20Sopenharmony_ci	cnp->com.cdev = NULL;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	if (cxgbit_inaddr_any(cnp))
4538c2ecf20Sopenharmony_ci		ret = cxgbit_setup_all_np(cnp);
4548c2ecf20Sopenharmony_ci	else
4558c2ecf20Sopenharmony_ci		ret = cxgbit_setup_cdev_np(cnp);
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	if (ret) {
4588c2ecf20Sopenharmony_ci		cxgbit_put_cnp(cnp);
4598c2ecf20Sopenharmony_ci		return -EINVAL;
4608c2ecf20Sopenharmony_ci	}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	np->np_context = cnp;
4638c2ecf20Sopenharmony_ci	cnp->com.state = CSK_STATE_LISTEN;
4648c2ecf20Sopenharmony_ci	return 0;
4658c2ecf20Sopenharmony_ci}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_cistatic void
4688c2ecf20Sopenharmony_cicxgbit_set_conn_info(struct iscsi_np *np, struct iscsi_conn *conn,
4698c2ecf20Sopenharmony_ci		     struct cxgbit_sock *csk)
4708c2ecf20Sopenharmony_ci{
4718c2ecf20Sopenharmony_ci	conn->login_family = np->np_sockaddr.ss_family;
4728c2ecf20Sopenharmony_ci	conn->login_sockaddr = csk->com.remote_addr;
4738c2ecf20Sopenharmony_ci	conn->local_sockaddr = csk->com.local_addr;
4748c2ecf20Sopenharmony_ci}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ciint cxgbit_accept_np(struct iscsi_np *np, struct iscsi_conn *conn)
4778c2ecf20Sopenharmony_ci{
4788c2ecf20Sopenharmony_ci	struct cxgbit_np *cnp = np->np_context;
4798c2ecf20Sopenharmony_ci	struct cxgbit_sock *csk;
4808c2ecf20Sopenharmony_ci	int ret = 0;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ciaccept_wait:
4838c2ecf20Sopenharmony_ci	ret = wait_for_completion_interruptible(&cnp->accept_comp);
4848c2ecf20Sopenharmony_ci	if (ret)
4858c2ecf20Sopenharmony_ci		return -ENODEV;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	spin_lock_bh(&np->np_thread_lock);
4888c2ecf20Sopenharmony_ci	if (np->np_thread_state >= ISCSI_NP_THREAD_RESET) {
4898c2ecf20Sopenharmony_ci		spin_unlock_bh(&np->np_thread_lock);
4908c2ecf20Sopenharmony_ci		/**
4918c2ecf20Sopenharmony_ci		 * No point in stalling here when np_thread
4928c2ecf20Sopenharmony_ci		 * is in state RESET/SHUTDOWN/EXIT - bail
4938c2ecf20Sopenharmony_ci		 **/
4948c2ecf20Sopenharmony_ci		return -ENODEV;
4958c2ecf20Sopenharmony_ci	}
4968c2ecf20Sopenharmony_ci	spin_unlock_bh(&np->np_thread_lock);
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	spin_lock_bh(&cnp->np_accept_lock);
4998c2ecf20Sopenharmony_ci	if (list_empty(&cnp->np_accept_list)) {
5008c2ecf20Sopenharmony_ci		spin_unlock_bh(&cnp->np_accept_lock);
5018c2ecf20Sopenharmony_ci		goto accept_wait;
5028c2ecf20Sopenharmony_ci	}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	csk = list_first_entry(&cnp->np_accept_list,
5058c2ecf20Sopenharmony_ci			       struct cxgbit_sock,
5068c2ecf20Sopenharmony_ci			       accept_node);
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	list_del_init(&csk->accept_node);
5098c2ecf20Sopenharmony_ci	spin_unlock_bh(&cnp->np_accept_lock);
5108c2ecf20Sopenharmony_ci	conn->context = csk;
5118c2ecf20Sopenharmony_ci	csk->conn = conn;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	cxgbit_set_conn_info(np, conn, csk);
5148c2ecf20Sopenharmony_ci	return 0;
5158c2ecf20Sopenharmony_ci}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_cistatic int
5188c2ecf20Sopenharmony_ci__cxgbit_free_cdev_np(struct cxgbit_device *cdev, struct cxgbit_np *cnp)
5198c2ecf20Sopenharmony_ci{
5208c2ecf20Sopenharmony_ci	int stid, ret;
5218c2ecf20Sopenharmony_ci	bool ipv6 = false;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	stid = cxgbit_np_hash_del(cdev, cnp);
5248c2ecf20Sopenharmony_ci	if (stid < 0)
5258c2ecf20Sopenharmony_ci		return -EINVAL;
5268c2ecf20Sopenharmony_ci	if (!test_bit(CDEV_STATE_UP, &cdev->flags))
5278c2ecf20Sopenharmony_ci		return -EINVAL;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	if (cnp->np->np_sockaddr.ss_family == AF_INET6)
5308c2ecf20Sopenharmony_ci		ipv6 = true;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	cxgbit_get_cnp(cnp);
5338c2ecf20Sopenharmony_ci	cxgbit_init_wr_wait(&cnp->com.wr_wait);
5348c2ecf20Sopenharmony_ci	ret = cxgb4_remove_server(cdev->lldi.ports[0], stid,
5358c2ecf20Sopenharmony_ci				  cdev->lldi.rxq_ids[0], ipv6);
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	if (ret > 0)
5388c2ecf20Sopenharmony_ci		ret = net_xmit_errno(ret);
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	if (ret) {
5418c2ecf20Sopenharmony_ci		cxgbit_put_cnp(cnp);
5428c2ecf20Sopenharmony_ci		return ret;
5438c2ecf20Sopenharmony_ci	}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	ret = cxgbit_wait_for_reply(cdev, &cnp->com.wr_wait,
5468c2ecf20Sopenharmony_ci				    0, 10, __func__);
5478c2ecf20Sopenharmony_ci	if (ret == -ETIMEDOUT)
5488c2ecf20Sopenharmony_ci		return ret;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	if (ipv6 && cnp->com.cdev) {
5518c2ecf20Sopenharmony_ci		struct sockaddr_in6 *sin6;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci		sin6 = (struct sockaddr_in6 *)&cnp->com.local_addr;
5548c2ecf20Sopenharmony_ci		cxgb4_clip_release(cdev->lldi.ports[0],
5558c2ecf20Sopenharmony_ci				   (const u32 *)&sin6->sin6_addr.s6_addr,
5568c2ecf20Sopenharmony_ci				   1);
5578c2ecf20Sopenharmony_ci	}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	cxgb4_free_stid(cdev->lldi.tids, stid,
5608c2ecf20Sopenharmony_ci			cnp->com.local_addr.ss_family);
5618c2ecf20Sopenharmony_ci	return 0;
5628c2ecf20Sopenharmony_ci}
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_cistatic void cxgbit_free_all_np(struct cxgbit_np *cnp)
5658c2ecf20Sopenharmony_ci{
5668c2ecf20Sopenharmony_ci	struct cxgbit_device *cdev;
5678c2ecf20Sopenharmony_ci	int ret;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	mutex_lock(&cdev_list_lock);
5708c2ecf20Sopenharmony_ci	list_for_each_entry(cdev, &cdev_list_head, list) {
5718c2ecf20Sopenharmony_ci		ret = __cxgbit_free_cdev_np(cdev, cnp);
5728c2ecf20Sopenharmony_ci		if (ret == -ETIMEDOUT)
5738c2ecf20Sopenharmony_ci			break;
5748c2ecf20Sopenharmony_ci	}
5758c2ecf20Sopenharmony_ci	mutex_unlock(&cdev_list_lock);
5768c2ecf20Sopenharmony_ci}
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_cistatic void cxgbit_free_cdev_np(struct cxgbit_np *cnp)
5798c2ecf20Sopenharmony_ci{
5808c2ecf20Sopenharmony_ci	struct cxgbit_device *cdev;
5818c2ecf20Sopenharmony_ci	bool found = false;
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	mutex_lock(&cdev_list_lock);
5848c2ecf20Sopenharmony_ci	list_for_each_entry(cdev, &cdev_list_head, list) {
5858c2ecf20Sopenharmony_ci		if (cdev == cnp->com.cdev) {
5868c2ecf20Sopenharmony_ci			found = true;
5878c2ecf20Sopenharmony_ci			break;
5888c2ecf20Sopenharmony_ci		}
5898c2ecf20Sopenharmony_ci	}
5908c2ecf20Sopenharmony_ci	if (!found)
5918c2ecf20Sopenharmony_ci		goto out;
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	__cxgbit_free_cdev_np(cdev, cnp);
5948c2ecf20Sopenharmony_ciout:
5958c2ecf20Sopenharmony_ci	mutex_unlock(&cdev_list_lock);
5968c2ecf20Sopenharmony_ci}
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_cistatic void __cxgbit_free_conn(struct cxgbit_sock *csk);
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_civoid cxgbit_free_np(struct iscsi_np *np)
6018c2ecf20Sopenharmony_ci{
6028c2ecf20Sopenharmony_ci	struct cxgbit_np *cnp = np->np_context;
6038c2ecf20Sopenharmony_ci	struct cxgbit_sock *csk, *tmp;
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	cnp->com.state = CSK_STATE_DEAD;
6068c2ecf20Sopenharmony_ci	if (cnp->com.cdev)
6078c2ecf20Sopenharmony_ci		cxgbit_free_cdev_np(cnp);
6088c2ecf20Sopenharmony_ci	else
6098c2ecf20Sopenharmony_ci		cxgbit_free_all_np(cnp);
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	spin_lock_bh(&cnp->np_accept_lock);
6128c2ecf20Sopenharmony_ci	list_for_each_entry_safe(csk, tmp, &cnp->np_accept_list, accept_node) {
6138c2ecf20Sopenharmony_ci		list_del_init(&csk->accept_node);
6148c2ecf20Sopenharmony_ci		__cxgbit_free_conn(csk);
6158c2ecf20Sopenharmony_ci	}
6168c2ecf20Sopenharmony_ci	spin_unlock_bh(&cnp->np_accept_lock);
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	np->np_context = NULL;
6198c2ecf20Sopenharmony_ci	cxgbit_put_cnp(cnp);
6208c2ecf20Sopenharmony_ci}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_cistatic void cxgbit_send_halfclose(struct cxgbit_sock *csk)
6238c2ecf20Sopenharmony_ci{
6248c2ecf20Sopenharmony_ci	struct sk_buff *skb;
6258c2ecf20Sopenharmony_ci	u32 len = roundup(sizeof(struct cpl_close_con_req), 16);
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	skb = alloc_skb(len, GFP_ATOMIC);
6288c2ecf20Sopenharmony_ci	if (!skb)
6298c2ecf20Sopenharmony_ci		return;
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	cxgb_mk_close_con_req(skb, len, csk->tid, csk->txq_idx,
6328c2ecf20Sopenharmony_ci			      NULL, NULL);
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	cxgbit_skcb_flags(skb) |= SKCBF_TX_FLAG_COMPL;
6358c2ecf20Sopenharmony_ci	__skb_queue_tail(&csk->txq, skb);
6368c2ecf20Sopenharmony_ci	cxgbit_push_tx_frames(csk);
6378c2ecf20Sopenharmony_ci}
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_cistatic void cxgbit_arp_failure_discard(void *handle, struct sk_buff *skb)
6408c2ecf20Sopenharmony_ci{
6418c2ecf20Sopenharmony_ci	struct cxgbit_sock *csk = handle;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	pr_debug("%s cxgbit_device %p\n", __func__, handle);
6448c2ecf20Sopenharmony_ci	kfree_skb(skb);
6458c2ecf20Sopenharmony_ci	cxgbit_put_csk(csk);
6468c2ecf20Sopenharmony_ci}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_cistatic void cxgbit_abort_arp_failure(void *handle, struct sk_buff *skb)
6498c2ecf20Sopenharmony_ci{
6508c2ecf20Sopenharmony_ci	struct cxgbit_device *cdev = handle;
6518c2ecf20Sopenharmony_ci	struct cpl_abort_req *req = cplhdr(skb);
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	pr_debug("%s cdev %p\n", __func__, cdev);
6548c2ecf20Sopenharmony_ci	req->cmd = CPL_ABORT_NO_RST;
6558c2ecf20Sopenharmony_ci	cxgbit_ofld_send(cdev, skb);
6568c2ecf20Sopenharmony_ci}
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_cistatic int cxgbit_send_abort_req(struct cxgbit_sock *csk)
6598c2ecf20Sopenharmony_ci{
6608c2ecf20Sopenharmony_ci	struct sk_buff *skb;
6618c2ecf20Sopenharmony_ci	u32 len = roundup(sizeof(struct cpl_abort_req), 16);
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	pr_debug("%s: csk %p tid %u; state %d\n",
6648c2ecf20Sopenharmony_ci		 __func__, csk, csk->tid, csk->com.state);
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	__skb_queue_purge(&csk->txq);
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	if (!test_and_set_bit(CSK_TX_DATA_SENT, &csk->com.flags))
6698c2ecf20Sopenharmony_ci		cxgbit_send_tx_flowc_wr(csk);
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	skb = __skb_dequeue(&csk->skbq);
6728c2ecf20Sopenharmony_ci	cxgb_mk_abort_req(skb, len, csk->tid, csk->txq_idx,
6738c2ecf20Sopenharmony_ci			  csk->com.cdev, cxgbit_abort_arp_failure);
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	return cxgbit_l2t_send(csk->com.cdev, skb, csk->l2t);
6768c2ecf20Sopenharmony_ci}
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_cistatic void
6798c2ecf20Sopenharmony_ci__cxgbit_abort_conn(struct cxgbit_sock *csk, struct sk_buff *skb)
6808c2ecf20Sopenharmony_ci{
6818c2ecf20Sopenharmony_ci	__kfree_skb(skb);
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	if (csk->com.state != CSK_STATE_ESTABLISHED)
6848c2ecf20Sopenharmony_ci		goto no_abort;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	set_bit(CSK_ABORT_RPL_WAIT, &csk->com.flags);
6878c2ecf20Sopenharmony_ci	csk->com.state = CSK_STATE_ABORTING;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	cxgbit_send_abort_req(csk);
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	return;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_cino_abort:
6948c2ecf20Sopenharmony_ci	cxgbit_wake_up(&csk->com.wr_wait, __func__, CPL_ERR_NONE);
6958c2ecf20Sopenharmony_ci	cxgbit_put_csk(csk);
6968c2ecf20Sopenharmony_ci}
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_civoid cxgbit_abort_conn(struct cxgbit_sock *csk)
6998c2ecf20Sopenharmony_ci{
7008c2ecf20Sopenharmony_ci	struct sk_buff *skb = alloc_skb(0, GFP_KERNEL | __GFP_NOFAIL);
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	cxgbit_get_csk(csk);
7038c2ecf20Sopenharmony_ci	cxgbit_init_wr_wait(&csk->com.wr_wait);
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	spin_lock_bh(&csk->lock);
7068c2ecf20Sopenharmony_ci	if (csk->lock_owner) {
7078c2ecf20Sopenharmony_ci		cxgbit_skcb_rx_backlog_fn(skb) = __cxgbit_abort_conn;
7088c2ecf20Sopenharmony_ci		__skb_queue_tail(&csk->backlogq, skb);
7098c2ecf20Sopenharmony_ci	} else {
7108c2ecf20Sopenharmony_ci		__cxgbit_abort_conn(csk, skb);
7118c2ecf20Sopenharmony_ci	}
7128c2ecf20Sopenharmony_ci	spin_unlock_bh(&csk->lock);
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	cxgbit_wait_for_reply(csk->com.cdev, &csk->com.wr_wait,
7158c2ecf20Sopenharmony_ci			      csk->tid, 600, __func__);
7168c2ecf20Sopenharmony_ci}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_cistatic void __cxgbit_free_conn(struct cxgbit_sock *csk)
7198c2ecf20Sopenharmony_ci{
7208c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = csk->conn;
7218c2ecf20Sopenharmony_ci	bool release = false;
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	pr_debug("%s: state %d\n",
7248c2ecf20Sopenharmony_ci		 __func__, csk->com.state);
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	spin_lock_bh(&csk->lock);
7278c2ecf20Sopenharmony_ci	switch (csk->com.state) {
7288c2ecf20Sopenharmony_ci	case CSK_STATE_ESTABLISHED:
7298c2ecf20Sopenharmony_ci		if (conn && (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT)) {
7308c2ecf20Sopenharmony_ci			csk->com.state = CSK_STATE_CLOSING;
7318c2ecf20Sopenharmony_ci			cxgbit_send_halfclose(csk);
7328c2ecf20Sopenharmony_ci		} else {
7338c2ecf20Sopenharmony_ci			csk->com.state = CSK_STATE_ABORTING;
7348c2ecf20Sopenharmony_ci			cxgbit_send_abort_req(csk);
7358c2ecf20Sopenharmony_ci		}
7368c2ecf20Sopenharmony_ci		break;
7378c2ecf20Sopenharmony_ci	case CSK_STATE_CLOSING:
7388c2ecf20Sopenharmony_ci		csk->com.state = CSK_STATE_MORIBUND;
7398c2ecf20Sopenharmony_ci		cxgbit_send_halfclose(csk);
7408c2ecf20Sopenharmony_ci		break;
7418c2ecf20Sopenharmony_ci	case CSK_STATE_DEAD:
7428c2ecf20Sopenharmony_ci		release = true;
7438c2ecf20Sopenharmony_ci		break;
7448c2ecf20Sopenharmony_ci	default:
7458c2ecf20Sopenharmony_ci		pr_err("%s: csk %p; state %d\n",
7468c2ecf20Sopenharmony_ci		       __func__, csk, csk->com.state);
7478c2ecf20Sopenharmony_ci	}
7488c2ecf20Sopenharmony_ci	spin_unlock_bh(&csk->lock);
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	if (release)
7518c2ecf20Sopenharmony_ci		cxgbit_put_csk(csk);
7528c2ecf20Sopenharmony_ci}
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_civoid cxgbit_free_conn(struct iscsi_conn *conn)
7558c2ecf20Sopenharmony_ci{
7568c2ecf20Sopenharmony_ci	__cxgbit_free_conn(conn->context);
7578c2ecf20Sopenharmony_ci}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_cistatic void cxgbit_set_emss(struct cxgbit_sock *csk, u16 opt)
7608c2ecf20Sopenharmony_ci{
7618c2ecf20Sopenharmony_ci	csk->emss = csk->com.cdev->lldi.mtus[TCPOPT_MSS_G(opt)] -
7628c2ecf20Sopenharmony_ci			((csk->com.remote_addr.ss_family == AF_INET) ?
7638c2ecf20Sopenharmony_ci			sizeof(struct iphdr) : sizeof(struct ipv6hdr)) -
7648c2ecf20Sopenharmony_ci			sizeof(struct tcphdr);
7658c2ecf20Sopenharmony_ci	csk->mss = csk->emss;
7668c2ecf20Sopenharmony_ci	if (TCPOPT_TSTAMP_G(opt))
7678c2ecf20Sopenharmony_ci		csk->emss -= round_up(TCPOLEN_TIMESTAMP, 4);
7688c2ecf20Sopenharmony_ci	if (csk->emss < 128)
7698c2ecf20Sopenharmony_ci		csk->emss = 128;
7708c2ecf20Sopenharmony_ci	if (csk->emss & 7)
7718c2ecf20Sopenharmony_ci		pr_info("Warning: misaligned mtu idx %u mss %u emss=%u\n",
7728c2ecf20Sopenharmony_ci			TCPOPT_MSS_G(opt), csk->mss, csk->emss);
7738c2ecf20Sopenharmony_ci	pr_debug("%s mss_idx %u mss %u emss=%u\n", __func__, TCPOPT_MSS_G(opt),
7748c2ecf20Sopenharmony_ci		 csk->mss, csk->emss);
7758c2ecf20Sopenharmony_ci}
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_cistatic void cxgbit_free_skb(struct cxgbit_sock *csk)
7788c2ecf20Sopenharmony_ci{
7798c2ecf20Sopenharmony_ci	struct sk_buff *skb;
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	__skb_queue_purge(&csk->txq);
7828c2ecf20Sopenharmony_ci	__skb_queue_purge(&csk->rxq);
7838c2ecf20Sopenharmony_ci	__skb_queue_purge(&csk->backlogq);
7848c2ecf20Sopenharmony_ci	__skb_queue_purge(&csk->ppodq);
7858c2ecf20Sopenharmony_ci	__skb_queue_purge(&csk->skbq);
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	while ((skb = cxgbit_sock_dequeue_wr(csk)))
7888c2ecf20Sopenharmony_ci		kfree_skb(skb);
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	__kfree_skb(csk->lro_hskb);
7918c2ecf20Sopenharmony_ci}
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_civoid _cxgbit_free_csk(struct kref *kref)
7948c2ecf20Sopenharmony_ci{
7958c2ecf20Sopenharmony_ci	struct cxgbit_sock *csk;
7968c2ecf20Sopenharmony_ci	struct cxgbit_device *cdev;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	csk = container_of(kref, struct cxgbit_sock, kref);
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	pr_debug("%s csk %p state %d\n", __func__, csk, csk->com.state);
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	if (csk->com.local_addr.ss_family == AF_INET6) {
8038c2ecf20Sopenharmony_ci		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)
8048c2ecf20Sopenharmony_ci					     &csk->com.local_addr;
8058c2ecf20Sopenharmony_ci		cxgb4_clip_release(csk->com.cdev->lldi.ports[0],
8068c2ecf20Sopenharmony_ci				   (const u32 *)
8078c2ecf20Sopenharmony_ci				   &sin6->sin6_addr.s6_addr, 1);
8088c2ecf20Sopenharmony_ci	}
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	cxgb4_remove_tid(csk->com.cdev->lldi.tids, 0, csk->tid,
8118c2ecf20Sopenharmony_ci			 csk->com.local_addr.ss_family);
8128c2ecf20Sopenharmony_ci	dst_release(csk->dst);
8138c2ecf20Sopenharmony_ci	cxgb4_l2t_release(csk->l2t);
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	cdev = csk->com.cdev;
8168c2ecf20Sopenharmony_ci	spin_lock_bh(&cdev->cskq.lock);
8178c2ecf20Sopenharmony_ci	list_del(&csk->list);
8188c2ecf20Sopenharmony_ci	spin_unlock_bh(&cdev->cskq.lock);
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	cxgbit_free_skb(csk);
8218c2ecf20Sopenharmony_ci	cxgbit_put_cnp(csk->cnp);
8228c2ecf20Sopenharmony_ci	cxgbit_put_cdev(cdev);
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	kfree(csk);
8258c2ecf20Sopenharmony_ci}
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_cistatic void cxgbit_set_tcp_window(struct cxgbit_sock *csk, struct port_info *pi)
8288c2ecf20Sopenharmony_ci{
8298c2ecf20Sopenharmony_ci	unsigned int linkspeed;
8308c2ecf20Sopenharmony_ci	u8 scale;
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	linkspeed = pi->link_cfg.speed;
8338c2ecf20Sopenharmony_ci	scale = linkspeed / SPEED_10000;
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci#define CXGBIT_10G_RCV_WIN (256 * 1024)
8368c2ecf20Sopenharmony_ci	csk->rcv_win = CXGBIT_10G_RCV_WIN;
8378c2ecf20Sopenharmony_ci	if (scale)
8388c2ecf20Sopenharmony_ci		csk->rcv_win *= scale;
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci#define CXGBIT_10G_SND_WIN (256 * 1024)
8418c2ecf20Sopenharmony_ci	csk->snd_win = CXGBIT_10G_SND_WIN;
8428c2ecf20Sopenharmony_ci	if (scale)
8438c2ecf20Sopenharmony_ci		csk->snd_win *= scale;
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	pr_debug("%s snd_win %d rcv_win %d\n",
8468c2ecf20Sopenharmony_ci		 __func__, csk->snd_win, csk->rcv_win);
8478c2ecf20Sopenharmony_ci}
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB
8508c2ecf20Sopenharmony_cistatic u8 cxgbit_get_iscsi_dcb_state(struct net_device *ndev)
8518c2ecf20Sopenharmony_ci{
8528c2ecf20Sopenharmony_ci	return ndev->dcbnl_ops->getstate(ndev);
8538c2ecf20Sopenharmony_ci}
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_cistatic int cxgbit_select_priority(int pri_mask)
8568c2ecf20Sopenharmony_ci{
8578c2ecf20Sopenharmony_ci	if (!pri_mask)
8588c2ecf20Sopenharmony_ci		return 0;
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	return (ffs(pri_mask) - 1);
8618c2ecf20Sopenharmony_ci}
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_cistatic u8 cxgbit_get_iscsi_dcb_priority(struct net_device *ndev, u16 local_port)
8648c2ecf20Sopenharmony_ci{
8658c2ecf20Sopenharmony_ci	int ret;
8668c2ecf20Sopenharmony_ci	u8 caps;
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	struct dcb_app iscsi_dcb_app = {
8698c2ecf20Sopenharmony_ci		.protocol = local_port
8708c2ecf20Sopenharmony_ci	};
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	ret = (int)ndev->dcbnl_ops->getcap(ndev, DCB_CAP_ATTR_DCBX, &caps);
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	if (ret)
8758c2ecf20Sopenharmony_ci		return 0;
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	if (caps & DCB_CAP_DCBX_VER_IEEE) {
8788c2ecf20Sopenharmony_ci		iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_STREAM;
8798c2ecf20Sopenharmony_ci		ret = dcb_ieee_getapp_mask(ndev, &iscsi_dcb_app);
8808c2ecf20Sopenharmony_ci		if (!ret) {
8818c2ecf20Sopenharmony_ci			iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_ANY;
8828c2ecf20Sopenharmony_ci			ret = dcb_ieee_getapp_mask(ndev, &iscsi_dcb_app);
8838c2ecf20Sopenharmony_ci		}
8848c2ecf20Sopenharmony_ci	} else if (caps & DCB_CAP_DCBX_VER_CEE) {
8858c2ecf20Sopenharmony_ci		iscsi_dcb_app.selector = DCB_APP_IDTYPE_PORTNUM;
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci		ret = dcb_getapp(ndev, &iscsi_dcb_app);
8888c2ecf20Sopenharmony_ci	}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	pr_info("iSCSI priority is set to %u\n", cxgbit_select_priority(ret));
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	return cxgbit_select_priority(ret);
8938c2ecf20Sopenharmony_ci}
8948c2ecf20Sopenharmony_ci#endif
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_cistatic int
8978c2ecf20Sopenharmony_cicxgbit_offload_init(struct cxgbit_sock *csk, int iptype, __u8 *peer_ip,
8988c2ecf20Sopenharmony_ci		    u16 local_port, struct dst_entry *dst,
8998c2ecf20Sopenharmony_ci		    struct cxgbit_device *cdev)
9008c2ecf20Sopenharmony_ci{
9018c2ecf20Sopenharmony_ci	struct neighbour *n;
9028c2ecf20Sopenharmony_ci	int ret, step;
9038c2ecf20Sopenharmony_ci	struct net_device *ndev;
9048c2ecf20Sopenharmony_ci	u16 rxq_idx, port_id;
9058c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB
9068c2ecf20Sopenharmony_ci	u8 priority = 0;
9078c2ecf20Sopenharmony_ci#endif
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	n = dst_neigh_lookup(dst, peer_ip);
9108c2ecf20Sopenharmony_ci	if (!n)
9118c2ecf20Sopenharmony_ci		return -ENODEV;
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci	rcu_read_lock();
9148c2ecf20Sopenharmony_ci	if (!(n->nud_state & NUD_VALID))
9158c2ecf20Sopenharmony_ci		neigh_event_send(n, NULL);
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci	ret = -ENOMEM;
9188c2ecf20Sopenharmony_ci	if (n->dev->flags & IFF_LOOPBACK) {
9198c2ecf20Sopenharmony_ci		if (iptype == 4)
9208c2ecf20Sopenharmony_ci			ndev = cxgbit_ipv4_netdev(*(__be32 *)peer_ip);
9218c2ecf20Sopenharmony_ci		else if (IS_ENABLED(CONFIG_IPV6))
9228c2ecf20Sopenharmony_ci			ndev = cxgbit_ipv6_netdev((struct in6_addr *)peer_ip);
9238c2ecf20Sopenharmony_ci		else
9248c2ecf20Sopenharmony_ci			ndev = NULL;
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci		if (!ndev) {
9278c2ecf20Sopenharmony_ci			ret = -ENODEV;
9288c2ecf20Sopenharmony_ci			goto out;
9298c2ecf20Sopenharmony_ci		}
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci		csk->l2t = cxgb4_l2t_get(cdev->lldi.l2t,
9328c2ecf20Sopenharmony_ci					 n, ndev, 0);
9338c2ecf20Sopenharmony_ci		if (!csk->l2t)
9348c2ecf20Sopenharmony_ci			goto out;
9358c2ecf20Sopenharmony_ci		csk->mtu = ndev->mtu;
9368c2ecf20Sopenharmony_ci		csk->tx_chan = cxgb4_port_chan(ndev);
9378c2ecf20Sopenharmony_ci		csk->smac_idx =
9388c2ecf20Sopenharmony_ci			       ((struct port_info *)netdev_priv(ndev))->smt_idx;
9398c2ecf20Sopenharmony_ci		step = cdev->lldi.ntxq /
9408c2ecf20Sopenharmony_ci			cdev->lldi.nchan;
9418c2ecf20Sopenharmony_ci		csk->txq_idx = cxgb4_port_idx(ndev) * step;
9428c2ecf20Sopenharmony_ci		step = cdev->lldi.nrxq /
9438c2ecf20Sopenharmony_ci			cdev->lldi.nchan;
9448c2ecf20Sopenharmony_ci		csk->ctrlq_idx = cxgb4_port_idx(ndev);
9458c2ecf20Sopenharmony_ci		csk->rss_qid = cdev->lldi.rxq_ids[
9468c2ecf20Sopenharmony_ci				cxgb4_port_idx(ndev) * step];
9478c2ecf20Sopenharmony_ci		csk->port_id = cxgb4_port_idx(ndev);
9488c2ecf20Sopenharmony_ci		cxgbit_set_tcp_window(csk,
9498c2ecf20Sopenharmony_ci				      (struct port_info *)netdev_priv(ndev));
9508c2ecf20Sopenharmony_ci	} else {
9518c2ecf20Sopenharmony_ci		ndev = cxgbit_get_real_dev(n->dev);
9528c2ecf20Sopenharmony_ci		if (!ndev) {
9538c2ecf20Sopenharmony_ci			ret = -ENODEV;
9548c2ecf20Sopenharmony_ci			goto out;
9558c2ecf20Sopenharmony_ci		}
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB
9588c2ecf20Sopenharmony_ci		if (cxgbit_get_iscsi_dcb_state(ndev))
9598c2ecf20Sopenharmony_ci			priority = cxgbit_get_iscsi_dcb_priority(ndev,
9608c2ecf20Sopenharmony_ci								 local_port);
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci		csk->dcb_priority = priority;
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci		csk->l2t = cxgb4_l2t_get(cdev->lldi.l2t, n, ndev, priority);
9658c2ecf20Sopenharmony_ci#else
9668c2ecf20Sopenharmony_ci		csk->l2t = cxgb4_l2t_get(cdev->lldi.l2t, n, ndev, 0);
9678c2ecf20Sopenharmony_ci#endif
9688c2ecf20Sopenharmony_ci		if (!csk->l2t)
9698c2ecf20Sopenharmony_ci			goto out;
9708c2ecf20Sopenharmony_ci		port_id = cxgb4_port_idx(ndev);
9718c2ecf20Sopenharmony_ci		csk->mtu = dst_mtu(dst);
9728c2ecf20Sopenharmony_ci		csk->tx_chan = cxgb4_port_chan(ndev);
9738c2ecf20Sopenharmony_ci		csk->smac_idx =
9748c2ecf20Sopenharmony_ci			       ((struct port_info *)netdev_priv(ndev))->smt_idx;
9758c2ecf20Sopenharmony_ci		step = cdev->lldi.ntxq /
9768c2ecf20Sopenharmony_ci			cdev->lldi.nports;
9778c2ecf20Sopenharmony_ci		csk->txq_idx = (port_id * step) +
9788c2ecf20Sopenharmony_ci				(cdev->selectq[port_id][0]++ % step);
9798c2ecf20Sopenharmony_ci		csk->ctrlq_idx = cxgb4_port_idx(ndev);
9808c2ecf20Sopenharmony_ci		step = cdev->lldi.nrxq /
9818c2ecf20Sopenharmony_ci			cdev->lldi.nports;
9828c2ecf20Sopenharmony_ci		rxq_idx = (port_id * step) +
9838c2ecf20Sopenharmony_ci				(cdev->selectq[port_id][1]++ % step);
9848c2ecf20Sopenharmony_ci		csk->rss_qid = cdev->lldi.rxq_ids[rxq_idx];
9858c2ecf20Sopenharmony_ci		csk->port_id = port_id;
9868c2ecf20Sopenharmony_ci		cxgbit_set_tcp_window(csk,
9878c2ecf20Sopenharmony_ci				      (struct port_info *)netdev_priv(ndev));
9888c2ecf20Sopenharmony_ci	}
9898c2ecf20Sopenharmony_ci	ret = 0;
9908c2ecf20Sopenharmony_ciout:
9918c2ecf20Sopenharmony_ci	rcu_read_unlock();
9928c2ecf20Sopenharmony_ci	neigh_release(n);
9938c2ecf20Sopenharmony_ci	return ret;
9948c2ecf20Sopenharmony_ci}
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ciint cxgbit_ofld_send(struct cxgbit_device *cdev, struct sk_buff *skb)
9978c2ecf20Sopenharmony_ci{
9988c2ecf20Sopenharmony_ci	int ret = 0;
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	if (!test_bit(CDEV_STATE_UP, &cdev->flags)) {
10018c2ecf20Sopenharmony_ci		kfree_skb(skb);
10028c2ecf20Sopenharmony_ci		pr_err("%s - device not up - dropping\n", __func__);
10038c2ecf20Sopenharmony_ci		return -EIO;
10048c2ecf20Sopenharmony_ci	}
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	ret = cxgb4_ofld_send(cdev->lldi.ports[0], skb);
10078c2ecf20Sopenharmony_ci	if (ret < 0)
10088c2ecf20Sopenharmony_ci		kfree_skb(skb);
10098c2ecf20Sopenharmony_ci	return ret < 0 ? ret : 0;
10108c2ecf20Sopenharmony_ci}
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_cistatic void cxgbit_release_tid(struct cxgbit_device *cdev, u32 tid)
10138c2ecf20Sopenharmony_ci{
10148c2ecf20Sopenharmony_ci	u32 len = roundup(sizeof(struct cpl_tid_release), 16);
10158c2ecf20Sopenharmony_ci	struct sk_buff *skb;
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	skb = alloc_skb(len, GFP_ATOMIC);
10188c2ecf20Sopenharmony_ci	if (!skb)
10198c2ecf20Sopenharmony_ci		return;
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	cxgb_mk_tid_release(skb, len, tid, 0);
10228c2ecf20Sopenharmony_ci	cxgbit_ofld_send(cdev, skb);
10238c2ecf20Sopenharmony_ci}
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ciint
10268c2ecf20Sopenharmony_cicxgbit_l2t_send(struct cxgbit_device *cdev, struct sk_buff *skb,
10278c2ecf20Sopenharmony_ci		struct l2t_entry *l2e)
10288c2ecf20Sopenharmony_ci{
10298c2ecf20Sopenharmony_ci	int ret = 0;
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci	if (!test_bit(CDEV_STATE_UP, &cdev->flags)) {
10328c2ecf20Sopenharmony_ci		kfree_skb(skb);
10338c2ecf20Sopenharmony_ci		pr_err("%s - device not up - dropping\n", __func__);
10348c2ecf20Sopenharmony_ci		return -EIO;
10358c2ecf20Sopenharmony_ci	}
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci	ret = cxgb4_l2t_send(cdev->lldi.ports[0], skb, l2e);
10388c2ecf20Sopenharmony_ci	if (ret < 0)
10398c2ecf20Sopenharmony_ci		kfree_skb(skb);
10408c2ecf20Sopenharmony_ci	return ret < 0 ? ret : 0;
10418c2ecf20Sopenharmony_ci}
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_cistatic void cxgbit_send_rx_credits(struct cxgbit_sock *csk, struct sk_buff *skb)
10448c2ecf20Sopenharmony_ci{
10458c2ecf20Sopenharmony_ci	if (csk->com.state != CSK_STATE_ESTABLISHED) {
10468c2ecf20Sopenharmony_ci		__kfree_skb(skb);
10478c2ecf20Sopenharmony_ci		return;
10488c2ecf20Sopenharmony_ci	}
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci	cxgbit_ofld_send(csk->com.cdev, skb);
10518c2ecf20Sopenharmony_ci}
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci/*
10548c2ecf20Sopenharmony_ci * CPL connection rx data ack: host ->
10558c2ecf20Sopenharmony_ci * Send RX credits through an RX_DATA_ACK CPL message.
10568c2ecf20Sopenharmony_ci * Returns the number of credits sent.
10578c2ecf20Sopenharmony_ci */
10588c2ecf20Sopenharmony_ciint cxgbit_rx_data_ack(struct cxgbit_sock *csk)
10598c2ecf20Sopenharmony_ci{
10608c2ecf20Sopenharmony_ci	struct sk_buff *skb;
10618c2ecf20Sopenharmony_ci	u32 len = roundup(sizeof(struct cpl_rx_data_ack), 16);
10628c2ecf20Sopenharmony_ci	u32 credit_dack;
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	skb = alloc_skb(len, GFP_KERNEL);
10658c2ecf20Sopenharmony_ci	if (!skb)
10668c2ecf20Sopenharmony_ci		return -1;
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	credit_dack = RX_DACK_CHANGE_F | RX_DACK_MODE_V(1) |
10698c2ecf20Sopenharmony_ci		      RX_CREDITS_V(csk->rx_credits);
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	cxgb_mk_rx_data_ack(skb, len, csk->tid, csk->ctrlq_idx,
10728c2ecf20Sopenharmony_ci			    credit_dack);
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci	csk->rx_credits = 0;
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	spin_lock_bh(&csk->lock);
10778c2ecf20Sopenharmony_ci	if (csk->lock_owner) {
10788c2ecf20Sopenharmony_ci		cxgbit_skcb_rx_backlog_fn(skb) = cxgbit_send_rx_credits;
10798c2ecf20Sopenharmony_ci		__skb_queue_tail(&csk->backlogq, skb);
10808c2ecf20Sopenharmony_ci		spin_unlock_bh(&csk->lock);
10818c2ecf20Sopenharmony_ci		return 0;
10828c2ecf20Sopenharmony_ci	}
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	cxgbit_send_rx_credits(csk, skb);
10858c2ecf20Sopenharmony_ci	spin_unlock_bh(&csk->lock);
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	return 0;
10888c2ecf20Sopenharmony_ci}
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci#define FLOWC_WR_NPARAMS_MIN    9
10918c2ecf20Sopenharmony_ci#define FLOWC_WR_NPARAMS_MAX	11
10928c2ecf20Sopenharmony_cistatic int cxgbit_alloc_csk_skb(struct cxgbit_sock *csk)
10938c2ecf20Sopenharmony_ci{
10948c2ecf20Sopenharmony_ci	struct sk_buff *skb;
10958c2ecf20Sopenharmony_ci	u32 len, flowclen;
10968c2ecf20Sopenharmony_ci	u8 i;
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	flowclen = offsetof(struct fw_flowc_wr,
10998c2ecf20Sopenharmony_ci			    mnemval[FLOWC_WR_NPARAMS_MAX]);
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	len = max_t(u32, sizeof(struct cpl_abort_req),
11028c2ecf20Sopenharmony_ci		    sizeof(struct cpl_abort_rpl));
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	len = max(len, flowclen);
11058c2ecf20Sopenharmony_ci	len = roundup(len, 16);
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci	for (i = 0; i < 3; i++) {
11088c2ecf20Sopenharmony_ci		skb = alloc_skb(len, GFP_ATOMIC);
11098c2ecf20Sopenharmony_ci		if (!skb)
11108c2ecf20Sopenharmony_ci			goto out;
11118c2ecf20Sopenharmony_ci		__skb_queue_tail(&csk->skbq, skb);
11128c2ecf20Sopenharmony_ci	}
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	skb = alloc_skb(LRO_SKB_MIN_HEADROOM, GFP_ATOMIC);
11158c2ecf20Sopenharmony_ci	if (!skb)
11168c2ecf20Sopenharmony_ci		goto out;
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci	memset(skb->data, 0, LRO_SKB_MIN_HEADROOM);
11198c2ecf20Sopenharmony_ci	csk->lro_hskb = skb;
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	return 0;
11228c2ecf20Sopenharmony_ciout:
11238c2ecf20Sopenharmony_ci	__skb_queue_purge(&csk->skbq);
11248c2ecf20Sopenharmony_ci	return -ENOMEM;
11258c2ecf20Sopenharmony_ci}
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_cistatic void
11288c2ecf20Sopenharmony_cicxgbit_pass_accept_rpl(struct cxgbit_sock *csk, struct cpl_pass_accept_req *req)
11298c2ecf20Sopenharmony_ci{
11308c2ecf20Sopenharmony_ci	struct sk_buff *skb;
11318c2ecf20Sopenharmony_ci	const struct tcphdr *tcph;
11328c2ecf20Sopenharmony_ci	struct cpl_t5_pass_accept_rpl *rpl5;
11338c2ecf20Sopenharmony_ci	struct cxgb4_lld_info *lldi = &csk->com.cdev->lldi;
11348c2ecf20Sopenharmony_ci	unsigned int len = roundup(sizeof(*rpl5), 16);
11358c2ecf20Sopenharmony_ci	unsigned int mtu_idx;
11368c2ecf20Sopenharmony_ci	u64 opt0;
11378c2ecf20Sopenharmony_ci	u32 opt2, hlen;
11388c2ecf20Sopenharmony_ci	u32 wscale;
11398c2ecf20Sopenharmony_ci	u32 win;
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci	pr_debug("%s csk %p tid %u\n", __func__, csk, csk->tid);
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_ci	skb = alloc_skb(len, GFP_ATOMIC);
11448c2ecf20Sopenharmony_ci	if (!skb) {
11458c2ecf20Sopenharmony_ci		cxgbit_put_csk(csk);
11468c2ecf20Sopenharmony_ci		return;
11478c2ecf20Sopenharmony_ci	}
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	rpl5 = __skb_put_zero(skb, len);
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	INIT_TP_WR(rpl5, csk->tid);
11528c2ecf20Sopenharmony_ci	OPCODE_TID(rpl5) = cpu_to_be32(MK_OPCODE_TID(CPL_PASS_ACCEPT_RPL,
11538c2ecf20Sopenharmony_ci						     csk->tid));
11548c2ecf20Sopenharmony_ci	cxgb_best_mtu(csk->com.cdev->lldi.mtus, csk->mtu, &mtu_idx,
11558c2ecf20Sopenharmony_ci		      req->tcpopt.tstamp,
11568c2ecf20Sopenharmony_ci		      (csk->com.remote_addr.ss_family == AF_INET) ? 0 : 1);
11578c2ecf20Sopenharmony_ci	wscale = cxgb_compute_wscale(csk->rcv_win);
11588c2ecf20Sopenharmony_ci	/*
11598c2ecf20Sopenharmony_ci	 * Specify the largest window that will fit in opt0. The
11608c2ecf20Sopenharmony_ci	 * remainder will be specified in the rx_data_ack.
11618c2ecf20Sopenharmony_ci	 */
11628c2ecf20Sopenharmony_ci	win = csk->rcv_win >> 10;
11638c2ecf20Sopenharmony_ci	if (win > RCV_BUFSIZ_M)
11648c2ecf20Sopenharmony_ci		win = RCV_BUFSIZ_M;
11658c2ecf20Sopenharmony_ci	opt0 =  TCAM_BYPASS_F |
11668c2ecf20Sopenharmony_ci		WND_SCALE_V(wscale) |
11678c2ecf20Sopenharmony_ci		MSS_IDX_V(mtu_idx) |
11688c2ecf20Sopenharmony_ci		L2T_IDX_V(csk->l2t->idx) |
11698c2ecf20Sopenharmony_ci		TX_CHAN_V(csk->tx_chan) |
11708c2ecf20Sopenharmony_ci		SMAC_SEL_V(csk->smac_idx) |
11718c2ecf20Sopenharmony_ci		DSCP_V(csk->tos >> 2) |
11728c2ecf20Sopenharmony_ci		ULP_MODE_V(ULP_MODE_ISCSI) |
11738c2ecf20Sopenharmony_ci		RCV_BUFSIZ_V(win);
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci	opt2 = RX_CHANNEL_V(0) |
11768c2ecf20Sopenharmony_ci		RSS_QUEUE_VALID_F | RSS_QUEUE_V(csk->rss_qid);
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	if (!is_t5(lldi->adapter_type))
11798c2ecf20Sopenharmony_ci		opt2 |= RX_FC_DISABLE_F;
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	if (req->tcpopt.tstamp)
11828c2ecf20Sopenharmony_ci		opt2 |= TSTAMPS_EN_F;
11838c2ecf20Sopenharmony_ci	if (req->tcpopt.sack)
11848c2ecf20Sopenharmony_ci		opt2 |= SACK_EN_F;
11858c2ecf20Sopenharmony_ci	if (wscale)
11868c2ecf20Sopenharmony_ci		opt2 |= WND_SCALE_EN_F;
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	hlen = ntohl(req->hdr_len);
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	if (is_t5(lldi->adapter_type))
11918c2ecf20Sopenharmony_ci		tcph = (struct tcphdr *)((u8 *)(req + 1) +
11928c2ecf20Sopenharmony_ci		       ETH_HDR_LEN_G(hlen) + IP_HDR_LEN_G(hlen));
11938c2ecf20Sopenharmony_ci	else
11948c2ecf20Sopenharmony_ci		tcph = (struct tcphdr *)((u8 *)(req + 1) +
11958c2ecf20Sopenharmony_ci		       T6_ETH_HDR_LEN_G(hlen) + T6_IP_HDR_LEN_G(hlen));
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	if (tcph->ece && tcph->cwr)
11988c2ecf20Sopenharmony_ci		opt2 |= CCTRL_ECN_V(1);
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	opt2 |= RX_COALESCE_V(3);
12018c2ecf20Sopenharmony_ci	opt2 |= CONG_CNTRL_V(CONG_ALG_NEWRENO);
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	opt2 |= T5_ISS_F;
12048c2ecf20Sopenharmony_ci	rpl5->iss = cpu_to_be32((prandom_u32() & ~7UL) - 1);
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	opt2 |= T5_OPT_2_VALID_F;
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	rpl5->opt0 = cpu_to_be64(opt0);
12098c2ecf20Sopenharmony_ci	rpl5->opt2 = cpu_to_be32(opt2);
12108c2ecf20Sopenharmony_ci	set_wr_txq(skb, CPL_PRIORITY_SETUP, csk->ctrlq_idx);
12118c2ecf20Sopenharmony_ci	t4_set_arp_err_handler(skb, csk, cxgbit_arp_failure_discard);
12128c2ecf20Sopenharmony_ci	cxgbit_l2t_send(csk->com.cdev, skb, csk->l2t);
12138c2ecf20Sopenharmony_ci}
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_cistatic void
12168c2ecf20Sopenharmony_cicxgbit_pass_accept_req(struct cxgbit_device *cdev, struct sk_buff *skb)
12178c2ecf20Sopenharmony_ci{
12188c2ecf20Sopenharmony_ci	struct cxgbit_sock *csk = NULL;
12198c2ecf20Sopenharmony_ci	struct cxgbit_np *cnp;
12208c2ecf20Sopenharmony_ci	struct cpl_pass_accept_req *req = cplhdr(skb);
12218c2ecf20Sopenharmony_ci	unsigned int stid = PASS_OPEN_TID_G(ntohl(req->tos_stid));
12228c2ecf20Sopenharmony_ci	struct tid_info *t = cdev->lldi.tids;
12238c2ecf20Sopenharmony_ci	unsigned int tid = GET_TID(req);
12248c2ecf20Sopenharmony_ci	u16 peer_mss = ntohs(req->tcpopt.mss);
12258c2ecf20Sopenharmony_ci	unsigned short hdrs;
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	struct dst_entry *dst;
12288c2ecf20Sopenharmony_ci	__u8 local_ip[16], peer_ip[16];
12298c2ecf20Sopenharmony_ci	__be16 local_port, peer_port;
12308c2ecf20Sopenharmony_ci	int ret;
12318c2ecf20Sopenharmony_ci	int iptype;
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	pr_debug("%s: cdev = %p; stid = %u; tid = %u\n",
12348c2ecf20Sopenharmony_ci		 __func__, cdev, stid, tid);
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ci	cnp = lookup_stid(t, stid);
12378c2ecf20Sopenharmony_ci	if (!cnp) {
12388c2ecf20Sopenharmony_ci		pr_err("%s connect request on invalid stid %d\n",
12398c2ecf20Sopenharmony_ci		       __func__, stid);
12408c2ecf20Sopenharmony_ci		goto rel_skb;
12418c2ecf20Sopenharmony_ci	}
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	if (cnp->com.state != CSK_STATE_LISTEN) {
12448c2ecf20Sopenharmony_ci		pr_err("%s - listening parent not in CSK_STATE_LISTEN\n",
12458c2ecf20Sopenharmony_ci		       __func__);
12468c2ecf20Sopenharmony_ci		goto reject;
12478c2ecf20Sopenharmony_ci	}
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_ci	csk = lookup_tid(t, tid);
12508c2ecf20Sopenharmony_ci	if (csk) {
12518c2ecf20Sopenharmony_ci		pr_err("%s csk not null tid %u\n",
12528c2ecf20Sopenharmony_ci		       __func__, tid);
12538c2ecf20Sopenharmony_ci		goto rel_skb;
12548c2ecf20Sopenharmony_ci	}
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	cxgb_get_4tuple(req, cdev->lldi.adapter_type, &iptype, local_ip,
12578c2ecf20Sopenharmony_ci			peer_ip, &local_port, &peer_port);
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	/* Find output route */
12608c2ecf20Sopenharmony_ci	if (iptype == 4)  {
12618c2ecf20Sopenharmony_ci		pr_debug("%s parent sock %p tid %u laddr %pI4 raddr %pI4 "
12628c2ecf20Sopenharmony_ci			 "lport %d rport %d peer_mss %d\n"
12638c2ecf20Sopenharmony_ci			 , __func__, cnp, tid,
12648c2ecf20Sopenharmony_ci			 local_ip, peer_ip, ntohs(local_port),
12658c2ecf20Sopenharmony_ci			 ntohs(peer_port), peer_mss);
12668c2ecf20Sopenharmony_ci		dst = cxgb_find_route(&cdev->lldi, cxgbit_get_real_dev,
12678c2ecf20Sopenharmony_ci				      *(__be32 *)local_ip,
12688c2ecf20Sopenharmony_ci				      *(__be32 *)peer_ip,
12698c2ecf20Sopenharmony_ci				      local_port, peer_port,
12708c2ecf20Sopenharmony_ci				      PASS_OPEN_TOS_G(ntohl(req->tos_stid)));
12718c2ecf20Sopenharmony_ci	} else {
12728c2ecf20Sopenharmony_ci		pr_debug("%s parent sock %p tid %u laddr %pI6 raddr %pI6 "
12738c2ecf20Sopenharmony_ci			 "lport %d rport %d peer_mss %d\n"
12748c2ecf20Sopenharmony_ci			 , __func__, cnp, tid,
12758c2ecf20Sopenharmony_ci			 local_ip, peer_ip, ntohs(local_port),
12768c2ecf20Sopenharmony_ci			 ntohs(peer_port), peer_mss);
12778c2ecf20Sopenharmony_ci		dst = cxgb_find_route6(&cdev->lldi, cxgbit_get_real_dev,
12788c2ecf20Sopenharmony_ci				       local_ip, peer_ip,
12798c2ecf20Sopenharmony_ci				       local_port, peer_port,
12808c2ecf20Sopenharmony_ci				       PASS_OPEN_TOS_G(ntohl(req->tos_stid)),
12818c2ecf20Sopenharmony_ci				       ((struct sockaddr_in6 *)
12828c2ecf20Sopenharmony_ci					&cnp->com.local_addr)->sin6_scope_id);
12838c2ecf20Sopenharmony_ci	}
12848c2ecf20Sopenharmony_ci	if (!dst) {
12858c2ecf20Sopenharmony_ci		pr_err("%s - failed to find dst entry!\n",
12868c2ecf20Sopenharmony_ci		       __func__);
12878c2ecf20Sopenharmony_ci		goto reject;
12888c2ecf20Sopenharmony_ci	}
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci	csk = kzalloc(sizeof(*csk), GFP_ATOMIC);
12918c2ecf20Sopenharmony_ci	if (!csk) {
12928c2ecf20Sopenharmony_ci		dst_release(dst);
12938c2ecf20Sopenharmony_ci		goto rel_skb;
12948c2ecf20Sopenharmony_ci	}
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci	ret = cxgbit_offload_init(csk, iptype, peer_ip, ntohs(local_port),
12978c2ecf20Sopenharmony_ci				  dst, cdev);
12988c2ecf20Sopenharmony_ci	if (ret) {
12998c2ecf20Sopenharmony_ci		pr_err("%s - failed to allocate l2t entry!\n",
13008c2ecf20Sopenharmony_ci		       __func__);
13018c2ecf20Sopenharmony_ci		dst_release(dst);
13028c2ecf20Sopenharmony_ci		kfree(csk);
13038c2ecf20Sopenharmony_ci		goto reject;
13048c2ecf20Sopenharmony_ci	}
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci	kref_init(&csk->kref);
13078c2ecf20Sopenharmony_ci	init_completion(&csk->com.wr_wait.completion);
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&csk->accept_node);
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci	hdrs = (iptype == 4 ? sizeof(struct iphdr) : sizeof(struct ipv6hdr)) +
13128c2ecf20Sopenharmony_ci		sizeof(struct tcphdr) +	(req->tcpopt.tstamp ? 12 : 0);
13138c2ecf20Sopenharmony_ci	if (peer_mss && csk->mtu > (peer_mss + hdrs))
13148c2ecf20Sopenharmony_ci		csk->mtu = peer_mss + hdrs;
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci	csk->com.state = CSK_STATE_CONNECTING;
13178c2ecf20Sopenharmony_ci	csk->com.cdev = cdev;
13188c2ecf20Sopenharmony_ci	csk->cnp = cnp;
13198c2ecf20Sopenharmony_ci	csk->tos = PASS_OPEN_TOS_G(ntohl(req->tos_stid));
13208c2ecf20Sopenharmony_ci	csk->dst = dst;
13218c2ecf20Sopenharmony_ci	csk->tid = tid;
13228c2ecf20Sopenharmony_ci	csk->wr_cred = cdev->lldi.wr_cred -
13238c2ecf20Sopenharmony_ci			DIV_ROUND_UP(sizeof(struct cpl_abort_req), 16);
13248c2ecf20Sopenharmony_ci	csk->wr_max_cred = csk->wr_cred;
13258c2ecf20Sopenharmony_ci	csk->wr_una_cred = 0;
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci	if (iptype == 4) {
13288c2ecf20Sopenharmony_ci		struct sockaddr_in *sin = (struct sockaddr_in *)
13298c2ecf20Sopenharmony_ci					  &csk->com.local_addr;
13308c2ecf20Sopenharmony_ci		sin->sin_family = AF_INET;
13318c2ecf20Sopenharmony_ci		sin->sin_port = local_port;
13328c2ecf20Sopenharmony_ci		sin->sin_addr.s_addr = *(__be32 *)local_ip;
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci		sin = (struct sockaddr_in *)&csk->com.remote_addr;
13358c2ecf20Sopenharmony_ci		sin->sin_family = AF_INET;
13368c2ecf20Sopenharmony_ci		sin->sin_port = peer_port;
13378c2ecf20Sopenharmony_ci		sin->sin_addr.s_addr = *(__be32 *)peer_ip;
13388c2ecf20Sopenharmony_ci	} else {
13398c2ecf20Sopenharmony_ci		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)
13408c2ecf20Sopenharmony_ci					    &csk->com.local_addr;
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci		sin6->sin6_family = PF_INET6;
13438c2ecf20Sopenharmony_ci		sin6->sin6_port = local_port;
13448c2ecf20Sopenharmony_ci		memcpy(sin6->sin6_addr.s6_addr, local_ip, 16);
13458c2ecf20Sopenharmony_ci		cxgb4_clip_get(cdev->lldi.ports[0],
13468c2ecf20Sopenharmony_ci			       (const u32 *)&sin6->sin6_addr.s6_addr,
13478c2ecf20Sopenharmony_ci			       1);
13488c2ecf20Sopenharmony_ci
13498c2ecf20Sopenharmony_ci		sin6 = (struct sockaddr_in6 *)&csk->com.remote_addr;
13508c2ecf20Sopenharmony_ci		sin6->sin6_family = PF_INET6;
13518c2ecf20Sopenharmony_ci		sin6->sin6_port = peer_port;
13528c2ecf20Sopenharmony_ci		memcpy(sin6->sin6_addr.s6_addr, peer_ip, 16);
13538c2ecf20Sopenharmony_ci	}
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci	skb_queue_head_init(&csk->rxq);
13568c2ecf20Sopenharmony_ci	skb_queue_head_init(&csk->txq);
13578c2ecf20Sopenharmony_ci	skb_queue_head_init(&csk->ppodq);
13588c2ecf20Sopenharmony_ci	skb_queue_head_init(&csk->backlogq);
13598c2ecf20Sopenharmony_ci	skb_queue_head_init(&csk->skbq);
13608c2ecf20Sopenharmony_ci	cxgbit_sock_reset_wr_list(csk);
13618c2ecf20Sopenharmony_ci	spin_lock_init(&csk->lock);
13628c2ecf20Sopenharmony_ci	init_waitqueue_head(&csk->waitq);
13638c2ecf20Sopenharmony_ci	csk->lock_owner = false;
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	if (cxgbit_alloc_csk_skb(csk)) {
13668c2ecf20Sopenharmony_ci		dst_release(dst);
13678c2ecf20Sopenharmony_ci		kfree(csk);
13688c2ecf20Sopenharmony_ci		goto rel_skb;
13698c2ecf20Sopenharmony_ci	}
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_ci	cxgbit_get_cnp(cnp);
13728c2ecf20Sopenharmony_ci	cxgbit_get_cdev(cdev);
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	spin_lock(&cdev->cskq.lock);
13758c2ecf20Sopenharmony_ci	list_add_tail(&csk->list, &cdev->cskq.list);
13768c2ecf20Sopenharmony_ci	spin_unlock(&cdev->cskq.lock);
13778c2ecf20Sopenharmony_ci	cxgb4_insert_tid(t, csk, tid, csk->com.local_addr.ss_family);
13788c2ecf20Sopenharmony_ci	cxgbit_pass_accept_rpl(csk, req);
13798c2ecf20Sopenharmony_ci	goto rel_skb;
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_cireject:
13828c2ecf20Sopenharmony_ci	cxgbit_release_tid(cdev, tid);
13838c2ecf20Sopenharmony_cirel_skb:
13848c2ecf20Sopenharmony_ci	__kfree_skb(skb);
13858c2ecf20Sopenharmony_ci}
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_cistatic u32
13888c2ecf20Sopenharmony_cicxgbit_tx_flowc_wr_credits(struct cxgbit_sock *csk, u32 *nparamsp,
13898c2ecf20Sopenharmony_ci			   u32 *flowclenp)
13908c2ecf20Sopenharmony_ci{
13918c2ecf20Sopenharmony_ci	u32 nparams, flowclen16, flowclen;
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_ci	nparams = FLOWC_WR_NPARAMS_MIN;
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci	if (csk->snd_wscale)
13968c2ecf20Sopenharmony_ci		nparams++;
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB
13998c2ecf20Sopenharmony_ci	nparams++;
14008c2ecf20Sopenharmony_ci#endif
14018c2ecf20Sopenharmony_ci	flowclen = offsetof(struct fw_flowc_wr, mnemval[nparams]);
14028c2ecf20Sopenharmony_ci	flowclen16 = DIV_ROUND_UP(flowclen, 16);
14038c2ecf20Sopenharmony_ci	flowclen = flowclen16 * 16;
14048c2ecf20Sopenharmony_ci	/*
14058c2ecf20Sopenharmony_ci	 * Return the number of 16-byte credits used by the flowc request.
14068c2ecf20Sopenharmony_ci	 * Pass back the nparams and actual flowc length if requested.
14078c2ecf20Sopenharmony_ci	 */
14088c2ecf20Sopenharmony_ci	if (nparamsp)
14098c2ecf20Sopenharmony_ci		*nparamsp = nparams;
14108c2ecf20Sopenharmony_ci	if (flowclenp)
14118c2ecf20Sopenharmony_ci		*flowclenp = flowclen;
14128c2ecf20Sopenharmony_ci	return flowclen16;
14138c2ecf20Sopenharmony_ci}
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ciu32 cxgbit_send_tx_flowc_wr(struct cxgbit_sock *csk)
14168c2ecf20Sopenharmony_ci{
14178c2ecf20Sopenharmony_ci	struct cxgbit_device *cdev = csk->com.cdev;
14188c2ecf20Sopenharmony_ci	struct fw_flowc_wr *flowc;
14198c2ecf20Sopenharmony_ci	u32 nparams, flowclen16, flowclen;
14208c2ecf20Sopenharmony_ci	struct sk_buff *skb;
14218c2ecf20Sopenharmony_ci	u8 index;
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB
14248c2ecf20Sopenharmony_ci	u16 vlan = ((struct l2t_entry *)csk->l2t)->vlan;
14258c2ecf20Sopenharmony_ci#endif
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_ci	flowclen16 = cxgbit_tx_flowc_wr_credits(csk, &nparams, &flowclen);
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci	skb = __skb_dequeue(&csk->skbq);
14308c2ecf20Sopenharmony_ci	flowc = __skb_put_zero(skb, flowclen);
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci	flowc->op_to_nparams = cpu_to_be32(FW_WR_OP_V(FW_FLOWC_WR) |
14338c2ecf20Sopenharmony_ci					   FW_FLOWC_WR_NPARAMS_V(nparams));
14348c2ecf20Sopenharmony_ci	flowc->flowid_len16 = cpu_to_be32(FW_WR_LEN16_V(flowclen16) |
14358c2ecf20Sopenharmony_ci					  FW_WR_FLOWID_V(csk->tid));
14368c2ecf20Sopenharmony_ci	flowc->mnemval[0].mnemonic = FW_FLOWC_MNEM_PFNVFN;
14378c2ecf20Sopenharmony_ci	flowc->mnemval[0].val = cpu_to_be32(FW_PFVF_CMD_PFN_V
14388c2ecf20Sopenharmony_ci					    (csk->com.cdev->lldi.pf));
14398c2ecf20Sopenharmony_ci	flowc->mnemval[1].mnemonic = FW_FLOWC_MNEM_CH;
14408c2ecf20Sopenharmony_ci	flowc->mnemval[1].val = cpu_to_be32(csk->tx_chan);
14418c2ecf20Sopenharmony_ci	flowc->mnemval[2].mnemonic = FW_FLOWC_MNEM_PORT;
14428c2ecf20Sopenharmony_ci	flowc->mnemval[2].val = cpu_to_be32(csk->tx_chan);
14438c2ecf20Sopenharmony_ci	flowc->mnemval[3].mnemonic = FW_FLOWC_MNEM_IQID;
14448c2ecf20Sopenharmony_ci	flowc->mnemval[3].val = cpu_to_be32(csk->rss_qid);
14458c2ecf20Sopenharmony_ci	flowc->mnemval[4].mnemonic = FW_FLOWC_MNEM_SNDNXT;
14468c2ecf20Sopenharmony_ci	flowc->mnemval[4].val = cpu_to_be32(csk->snd_nxt);
14478c2ecf20Sopenharmony_ci	flowc->mnemval[5].mnemonic = FW_FLOWC_MNEM_RCVNXT;
14488c2ecf20Sopenharmony_ci	flowc->mnemval[5].val = cpu_to_be32(csk->rcv_nxt);
14498c2ecf20Sopenharmony_ci	flowc->mnemval[6].mnemonic = FW_FLOWC_MNEM_SNDBUF;
14508c2ecf20Sopenharmony_ci	flowc->mnemval[6].val = cpu_to_be32(csk->snd_win);
14518c2ecf20Sopenharmony_ci	flowc->mnemval[7].mnemonic = FW_FLOWC_MNEM_MSS;
14528c2ecf20Sopenharmony_ci	flowc->mnemval[7].val = cpu_to_be32(csk->emss);
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci	flowc->mnemval[8].mnemonic = FW_FLOWC_MNEM_TXDATAPLEN_MAX;
14558c2ecf20Sopenharmony_ci	if (test_bit(CDEV_ISO_ENABLE, &cdev->flags))
14568c2ecf20Sopenharmony_ci		flowc->mnemval[8].val = cpu_to_be32(CXGBIT_MAX_ISO_PAYLOAD);
14578c2ecf20Sopenharmony_ci	else
14588c2ecf20Sopenharmony_ci		flowc->mnemval[8].val = cpu_to_be32(16384);
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci	index = 9;
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_ci	if (csk->snd_wscale) {
14638c2ecf20Sopenharmony_ci		flowc->mnemval[index].mnemonic = FW_FLOWC_MNEM_RCV_SCALE;
14648c2ecf20Sopenharmony_ci		flowc->mnemval[index].val = cpu_to_be32(csk->snd_wscale);
14658c2ecf20Sopenharmony_ci		index++;
14668c2ecf20Sopenharmony_ci	}
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB
14698c2ecf20Sopenharmony_ci	flowc->mnemval[index].mnemonic = FW_FLOWC_MNEM_DCBPRIO;
14708c2ecf20Sopenharmony_ci	if (vlan == VLAN_NONE) {
14718c2ecf20Sopenharmony_ci		pr_warn("csk %u without VLAN Tag on DCB Link\n", csk->tid);
14728c2ecf20Sopenharmony_ci		flowc->mnemval[index].val = cpu_to_be32(0);
14738c2ecf20Sopenharmony_ci	} else
14748c2ecf20Sopenharmony_ci		flowc->mnemval[index].val = cpu_to_be32(
14758c2ecf20Sopenharmony_ci				(vlan & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT);
14768c2ecf20Sopenharmony_ci#endif
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci	pr_debug("%s: csk %p; tx_chan = %u; rss_qid = %u; snd_seq = %u;"
14798c2ecf20Sopenharmony_ci		 " rcv_seq = %u; snd_win = %u; emss = %u\n",
14808c2ecf20Sopenharmony_ci		 __func__, csk, csk->tx_chan, csk->rss_qid, csk->snd_nxt,
14818c2ecf20Sopenharmony_ci		 csk->rcv_nxt, csk->snd_win, csk->emss);
14828c2ecf20Sopenharmony_ci	set_wr_txq(skb, CPL_PRIORITY_DATA, csk->txq_idx);
14838c2ecf20Sopenharmony_ci	cxgbit_ofld_send(csk->com.cdev, skb);
14848c2ecf20Sopenharmony_ci	return flowclen16;
14858c2ecf20Sopenharmony_ci}
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_cistatic int
14888c2ecf20Sopenharmony_cicxgbit_send_tcb_skb(struct cxgbit_sock *csk, struct sk_buff *skb)
14898c2ecf20Sopenharmony_ci{
14908c2ecf20Sopenharmony_ci	spin_lock_bh(&csk->lock);
14918c2ecf20Sopenharmony_ci	if (unlikely(csk->com.state != CSK_STATE_ESTABLISHED)) {
14928c2ecf20Sopenharmony_ci		spin_unlock_bh(&csk->lock);
14938c2ecf20Sopenharmony_ci		pr_err("%s: csk 0x%p, tid %u, state %u\n",
14948c2ecf20Sopenharmony_ci		       __func__, csk, csk->tid, csk->com.state);
14958c2ecf20Sopenharmony_ci		__kfree_skb(skb);
14968c2ecf20Sopenharmony_ci		return -1;
14978c2ecf20Sopenharmony_ci	}
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_ci	cxgbit_get_csk(csk);
15008c2ecf20Sopenharmony_ci	cxgbit_init_wr_wait(&csk->com.wr_wait);
15018c2ecf20Sopenharmony_ci	cxgbit_ofld_send(csk->com.cdev, skb);
15028c2ecf20Sopenharmony_ci	spin_unlock_bh(&csk->lock);
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci	return 0;
15058c2ecf20Sopenharmony_ci}
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_ciint cxgbit_setup_conn_digest(struct cxgbit_sock *csk)
15088c2ecf20Sopenharmony_ci{
15098c2ecf20Sopenharmony_ci	struct sk_buff *skb;
15108c2ecf20Sopenharmony_ci	struct cpl_set_tcb_field *req;
15118c2ecf20Sopenharmony_ci	u8 hcrc = csk->submode & CXGBIT_SUBMODE_HCRC;
15128c2ecf20Sopenharmony_ci	u8 dcrc = csk->submode & CXGBIT_SUBMODE_DCRC;
15138c2ecf20Sopenharmony_ci	unsigned int len = roundup(sizeof(*req), 16);
15148c2ecf20Sopenharmony_ci	int ret;
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci	skb = alloc_skb(len, GFP_KERNEL);
15178c2ecf20Sopenharmony_ci	if (!skb)
15188c2ecf20Sopenharmony_ci		return -ENOMEM;
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_ci	/*  set up ulp submode */
15218c2ecf20Sopenharmony_ci	req = __skb_put_zero(skb, len);
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci	INIT_TP_WR(req, csk->tid);
15248c2ecf20Sopenharmony_ci	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, csk->tid));
15258c2ecf20Sopenharmony_ci	req->reply_ctrl = htons(NO_REPLY_V(0) | QUEUENO_V(csk->rss_qid));
15268c2ecf20Sopenharmony_ci	req->word_cookie = htons(0);
15278c2ecf20Sopenharmony_ci	req->mask = cpu_to_be64(0x3 << 4);
15288c2ecf20Sopenharmony_ci	req->val = cpu_to_be64(((hcrc ? ULP_CRC_HEADER : 0) |
15298c2ecf20Sopenharmony_ci				(dcrc ? ULP_CRC_DATA : 0)) << 4);
15308c2ecf20Sopenharmony_ci	set_wr_txq(skb, CPL_PRIORITY_CONTROL, csk->ctrlq_idx);
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_ci	if (cxgbit_send_tcb_skb(csk, skb))
15338c2ecf20Sopenharmony_ci		return -1;
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci	ret = cxgbit_wait_for_reply(csk->com.cdev,
15368c2ecf20Sopenharmony_ci				    &csk->com.wr_wait,
15378c2ecf20Sopenharmony_ci				    csk->tid, 5, __func__);
15388c2ecf20Sopenharmony_ci	if (ret)
15398c2ecf20Sopenharmony_ci		return -1;
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci	return 0;
15428c2ecf20Sopenharmony_ci}
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_ciint cxgbit_setup_conn_pgidx(struct cxgbit_sock *csk, u32 pg_idx)
15458c2ecf20Sopenharmony_ci{
15468c2ecf20Sopenharmony_ci	struct sk_buff *skb;
15478c2ecf20Sopenharmony_ci	struct cpl_set_tcb_field *req;
15488c2ecf20Sopenharmony_ci	unsigned int len = roundup(sizeof(*req), 16);
15498c2ecf20Sopenharmony_ci	int ret;
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_ci	skb = alloc_skb(len, GFP_KERNEL);
15528c2ecf20Sopenharmony_ci	if (!skb)
15538c2ecf20Sopenharmony_ci		return -ENOMEM;
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci	req = __skb_put_zero(skb, len);
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_ci	INIT_TP_WR(req, csk->tid);
15588c2ecf20Sopenharmony_ci	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, csk->tid));
15598c2ecf20Sopenharmony_ci	req->reply_ctrl = htons(NO_REPLY_V(0) | QUEUENO_V(csk->rss_qid));
15608c2ecf20Sopenharmony_ci	req->word_cookie = htons(0);
15618c2ecf20Sopenharmony_ci	req->mask = cpu_to_be64(0x3 << 8);
15628c2ecf20Sopenharmony_ci	req->val = cpu_to_be64(pg_idx << 8);
15638c2ecf20Sopenharmony_ci	set_wr_txq(skb, CPL_PRIORITY_CONTROL, csk->ctrlq_idx);
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_ci	if (cxgbit_send_tcb_skb(csk, skb))
15668c2ecf20Sopenharmony_ci		return -1;
15678c2ecf20Sopenharmony_ci
15688c2ecf20Sopenharmony_ci	ret = cxgbit_wait_for_reply(csk->com.cdev,
15698c2ecf20Sopenharmony_ci				    &csk->com.wr_wait,
15708c2ecf20Sopenharmony_ci				    csk->tid, 5, __func__);
15718c2ecf20Sopenharmony_ci	if (ret)
15728c2ecf20Sopenharmony_ci		return -1;
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci	return 0;
15758c2ecf20Sopenharmony_ci}
15768c2ecf20Sopenharmony_ci
15778c2ecf20Sopenharmony_cistatic void
15788c2ecf20Sopenharmony_cicxgbit_pass_open_rpl(struct cxgbit_device *cdev, struct sk_buff *skb)
15798c2ecf20Sopenharmony_ci{
15808c2ecf20Sopenharmony_ci	struct cpl_pass_open_rpl *rpl = cplhdr(skb);
15818c2ecf20Sopenharmony_ci	struct tid_info *t = cdev->lldi.tids;
15828c2ecf20Sopenharmony_ci	unsigned int stid = GET_TID(rpl);
15838c2ecf20Sopenharmony_ci	struct cxgbit_np *cnp = lookup_stid(t, stid);
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci	pr_debug("%s: cnp = %p; stid = %u; status = %d\n",
15868c2ecf20Sopenharmony_ci		 __func__, cnp, stid, rpl->status);
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_ci	if (!cnp) {
15898c2ecf20Sopenharmony_ci		pr_info("%s stid %d lookup failure\n", __func__, stid);
15908c2ecf20Sopenharmony_ci		goto rel_skb;
15918c2ecf20Sopenharmony_ci	}
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci	cxgbit_wake_up(&cnp->com.wr_wait, __func__, rpl->status);
15948c2ecf20Sopenharmony_ci	cxgbit_put_cnp(cnp);
15958c2ecf20Sopenharmony_cirel_skb:
15968c2ecf20Sopenharmony_ci	__kfree_skb(skb);
15978c2ecf20Sopenharmony_ci}
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_cistatic void
16008c2ecf20Sopenharmony_cicxgbit_close_listsrv_rpl(struct cxgbit_device *cdev, struct sk_buff *skb)
16018c2ecf20Sopenharmony_ci{
16028c2ecf20Sopenharmony_ci	struct cpl_close_listsvr_rpl *rpl = cplhdr(skb);
16038c2ecf20Sopenharmony_ci	struct tid_info *t = cdev->lldi.tids;
16048c2ecf20Sopenharmony_ci	unsigned int stid = GET_TID(rpl);
16058c2ecf20Sopenharmony_ci	struct cxgbit_np *cnp = lookup_stid(t, stid);
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci	pr_debug("%s: cnp = %p; stid = %u; status = %d\n",
16088c2ecf20Sopenharmony_ci		 __func__, cnp, stid, rpl->status);
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ci	if (!cnp) {
16118c2ecf20Sopenharmony_ci		pr_info("%s stid %d lookup failure\n", __func__, stid);
16128c2ecf20Sopenharmony_ci		goto rel_skb;
16138c2ecf20Sopenharmony_ci	}
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci	cxgbit_wake_up(&cnp->com.wr_wait, __func__, rpl->status);
16168c2ecf20Sopenharmony_ci	cxgbit_put_cnp(cnp);
16178c2ecf20Sopenharmony_cirel_skb:
16188c2ecf20Sopenharmony_ci	__kfree_skb(skb);
16198c2ecf20Sopenharmony_ci}
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_cistatic void
16228c2ecf20Sopenharmony_cicxgbit_pass_establish(struct cxgbit_device *cdev, struct sk_buff *skb)
16238c2ecf20Sopenharmony_ci{
16248c2ecf20Sopenharmony_ci	struct cpl_pass_establish *req = cplhdr(skb);
16258c2ecf20Sopenharmony_ci	struct tid_info *t = cdev->lldi.tids;
16268c2ecf20Sopenharmony_ci	unsigned int tid = GET_TID(req);
16278c2ecf20Sopenharmony_ci	struct cxgbit_sock *csk;
16288c2ecf20Sopenharmony_ci	struct cxgbit_np *cnp;
16298c2ecf20Sopenharmony_ci	u16 tcp_opt = be16_to_cpu(req->tcp_opt);
16308c2ecf20Sopenharmony_ci	u32 snd_isn = be32_to_cpu(req->snd_isn);
16318c2ecf20Sopenharmony_ci	u32 rcv_isn = be32_to_cpu(req->rcv_isn);
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_ci	csk = lookup_tid(t, tid);
16348c2ecf20Sopenharmony_ci	if (unlikely(!csk)) {
16358c2ecf20Sopenharmony_ci		pr_err("can't find connection for tid %u.\n", tid);
16368c2ecf20Sopenharmony_ci		goto rel_skb;
16378c2ecf20Sopenharmony_ci	}
16388c2ecf20Sopenharmony_ci	cnp = csk->cnp;
16398c2ecf20Sopenharmony_ci
16408c2ecf20Sopenharmony_ci	pr_debug("%s: csk %p; tid %u; cnp %p\n",
16418c2ecf20Sopenharmony_ci		 __func__, csk, tid, cnp);
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_ci	csk->write_seq = snd_isn;
16448c2ecf20Sopenharmony_ci	csk->snd_una = snd_isn;
16458c2ecf20Sopenharmony_ci	csk->snd_nxt = snd_isn;
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci	csk->rcv_nxt = rcv_isn;
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci	if (csk->rcv_win > (RCV_BUFSIZ_M << 10))
16508c2ecf20Sopenharmony_ci		csk->rx_credits = (csk->rcv_win - (RCV_BUFSIZ_M << 10));
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_ci	csk->snd_wscale = TCPOPT_SND_WSCALE_G(tcp_opt);
16538c2ecf20Sopenharmony_ci	cxgbit_set_emss(csk, tcp_opt);
16548c2ecf20Sopenharmony_ci	dst_confirm(csk->dst);
16558c2ecf20Sopenharmony_ci	csk->com.state = CSK_STATE_ESTABLISHED;
16568c2ecf20Sopenharmony_ci	spin_lock_bh(&cnp->np_accept_lock);
16578c2ecf20Sopenharmony_ci	list_add_tail(&csk->accept_node, &cnp->np_accept_list);
16588c2ecf20Sopenharmony_ci	spin_unlock_bh(&cnp->np_accept_lock);
16598c2ecf20Sopenharmony_ci	complete(&cnp->accept_comp);
16608c2ecf20Sopenharmony_cirel_skb:
16618c2ecf20Sopenharmony_ci	__kfree_skb(skb);
16628c2ecf20Sopenharmony_ci}
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_cistatic void cxgbit_queue_rx_skb(struct cxgbit_sock *csk, struct sk_buff *skb)
16658c2ecf20Sopenharmony_ci{
16668c2ecf20Sopenharmony_ci	cxgbit_skcb_flags(skb) = 0;
16678c2ecf20Sopenharmony_ci	spin_lock_bh(&csk->rxq.lock);
16688c2ecf20Sopenharmony_ci	__skb_queue_tail(&csk->rxq, skb);
16698c2ecf20Sopenharmony_ci	spin_unlock_bh(&csk->rxq.lock);
16708c2ecf20Sopenharmony_ci	wake_up(&csk->waitq);
16718c2ecf20Sopenharmony_ci}
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_cistatic void cxgbit_peer_close(struct cxgbit_sock *csk, struct sk_buff *skb)
16748c2ecf20Sopenharmony_ci{
16758c2ecf20Sopenharmony_ci	pr_debug("%s: csk %p; tid %u; state %d\n",
16768c2ecf20Sopenharmony_ci		 __func__, csk, csk->tid, csk->com.state);
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ci	switch (csk->com.state) {
16798c2ecf20Sopenharmony_ci	case CSK_STATE_ESTABLISHED:
16808c2ecf20Sopenharmony_ci		csk->com.state = CSK_STATE_CLOSING;
16818c2ecf20Sopenharmony_ci		cxgbit_queue_rx_skb(csk, skb);
16828c2ecf20Sopenharmony_ci		return;
16838c2ecf20Sopenharmony_ci	case CSK_STATE_CLOSING:
16848c2ecf20Sopenharmony_ci		/* simultaneous close */
16858c2ecf20Sopenharmony_ci		csk->com.state = CSK_STATE_MORIBUND;
16868c2ecf20Sopenharmony_ci		break;
16878c2ecf20Sopenharmony_ci	case CSK_STATE_MORIBUND:
16888c2ecf20Sopenharmony_ci		csk->com.state = CSK_STATE_DEAD;
16898c2ecf20Sopenharmony_ci		cxgbit_put_csk(csk);
16908c2ecf20Sopenharmony_ci		break;
16918c2ecf20Sopenharmony_ci	case CSK_STATE_ABORTING:
16928c2ecf20Sopenharmony_ci		break;
16938c2ecf20Sopenharmony_ci	default:
16948c2ecf20Sopenharmony_ci		pr_info("%s: cpl_peer_close in bad state %d\n",
16958c2ecf20Sopenharmony_ci			__func__, csk->com.state);
16968c2ecf20Sopenharmony_ci	}
16978c2ecf20Sopenharmony_ci
16988c2ecf20Sopenharmony_ci	__kfree_skb(skb);
16998c2ecf20Sopenharmony_ci}
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_cistatic void cxgbit_close_con_rpl(struct cxgbit_sock *csk, struct sk_buff *skb)
17028c2ecf20Sopenharmony_ci{
17038c2ecf20Sopenharmony_ci	pr_debug("%s: csk %p; tid %u; state %d\n",
17048c2ecf20Sopenharmony_ci		 __func__, csk, csk->tid, csk->com.state);
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_ci	switch (csk->com.state) {
17078c2ecf20Sopenharmony_ci	case CSK_STATE_CLOSING:
17088c2ecf20Sopenharmony_ci		csk->com.state = CSK_STATE_MORIBUND;
17098c2ecf20Sopenharmony_ci		break;
17108c2ecf20Sopenharmony_ci	case CSK_STATE_MORIBUND:
17118c2ecf20Sopenharmony_ci		csk->com.state = CSK_STATE_DEAD;
17128c2ecf20Sopenharmony_ci		cxgbit_put_csk(csk);
17138c2ecf20Sopenharmony_ci		break;
17148c2ecf20Sopenharmony_ci	case CSK_STATE_ABORTING:
17158c2ecf20Sopenharmony_ci	case CSK_STATE_DEAD:
17168c2ecf20Sopenharmony_ci		break;
17178c2ecf20Sopenharmony_ci	default:
17188c2ecf20Sopenharmony_ci		pr_info("%s: cpl_close_con_rpl in bad state %d\n",
17198c2ecf20Sopenharmony_ci			__func__, csk->com.state);
17208c2ecf20Sopenharmony_ci	}
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci	__kfree_skb(skb);
17238c2ecf20Sopenharmony_ci}
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_cistatic void cxgbit_abort_req_rss(struct cxgbit_sock *csk, struct sk_buff *skb)
17268c2ecf20Sopenharmony_ci{
17278c2ecf20Sopenharmony_ci	struct cpl_abort_req_rss *hdr = cplhdr(skb);
17288c2ecf20Sopenharmony_ci	unsigned int tid = GET_TID(hdr);
17298c2ecf20Sopenharmony_ci	struct sk_buff *rpl_skb;
17308c2ecf20Sopenharmony_ci	bool release = false;
17318c2ecf20Sopenharmony_ci	bool wakeup_thread = false;
17328c2ecf20Sopenharmony_ci	u32 len = roundup(sizeof(struct cpl_abort_rpl), 16);
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci	pr_debug("%s: csk %p; tid %u; state %d\n",
17358c2ecf20Sopenharmony_ci		 __func__, csk, tid, csk->com.state);
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_ci	if (cxgb_is_neg_adv(hdr->status)) {
17388c2ecf20Sopenharmony_ci		pr_err("%s: got neg advise %d on tid %u\n",
17398c2ecf20Sopenharmony_ci		       __func__, hdr->status, tid);
17408c2ecf20Sopenharmony_ci		goto rel_skb;
17418c2ecf20Sopenharmony_ci	}
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_ci	switch (csk->com.state) {
17448c2ecf20Sopenharmony_ci	case CSK_STATE_CONNECTING:
17458c2ecf20Sopenharmony_ci	case CSK_STATE_MORIBUND:
17468c2ecf20Sopenharmony_ci		csk->com.state = CSK_STATE_DEAD;
17478c2ecf20Sopenharmony_ci		release = true;
17488c2ecf20Sopenharmony_ci		break;
17498c2ecf20Sopenharmony_ci	case CSK_STATE_ESTABLISHED:
17508c2ecf20Sopenharmony_ci		csk->com.state = CSK_STATE_DEAD;
17518c2ecf20Sopenharmony_ci		wakeup_thread = true;
17528c2ecf20Sopenharmony_ci		break;
17538c2ecf20Sopenharmony_ci	case CSK_STATE_CLOSING:
17548c2ecf20Sopenharmony_ci		csk->com.state = CSK_STATE_DEAD;
17558c2ecf20Sopenharmony_ci		if (!csk->conn)
17568c2ecf20Sopenharmony_ci			release = true;
17578c2ecf20Sopenharmony_ci		break;
17588c2ecf20Sopenharmony_ci	case CSK_STATE_ABORTING:
17598c2ecf20Sopenharmony_ci		break;
17608c2ecf20Sopenharmony_ci	default:
17618c2ecf20Sopenharmony_ci		pr_info("%s: cpl_abort_req_rss in bad state %d\n",
17628c2ecf20Sopenharmony_ci			__func__, csk->com.state);
17638c2ecf20Sopenharmony_ci		csk->com.state = CSK_STATE_DEAD;
17648c2ecf20Sopenharmony_ci	}
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_ci	__skb_queue_purge(&csk->txq);
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_ci	if (!test_and_set_bit(CSK_TX_DATA_SENT, &csk->com.flags))
17698c2ecf20Sopenharmony_ci		cxgbit_send_tx_flowc_wr(csk);
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_ci	rpl_skb = __skb_dequeue(&csk->skbq);
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci	cxgb_mk_abort_rpl(rpl_skb, len, csk->tid, csk->txq_idx);
17748c2ecf20Sopenharmony_ci	cxgbit_ofld_send(csk->com.cdev, rpl_skb);
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_ci	if (wakeup_thread) {
17778c2ecf20Sopenharmony_ci		cxgbit_queue_rx_skb(csk, skb);
17788c2ecf20Sopenharmony_ci		return;
17798c2ecf20Sopenharmony_ci	}
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci	if (release)
17828c2ecf20Sopenharmony_ci		cxgbit_put_csk(csk);
17838c2ecf20Sopenharmony_cirel_skb:
17848c2ecf20Sopenharmony_ci	__kfree_skb(skb);
17858c2ecf20Sopenharmony_ci}
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_cistatic void cxgbit_abort_rpl_rss(struct cxgbit_sock *csk, struct sk_buff *skb)
17888c2ecf20Sopenharmony_ci{
17898c2ecf20Sopenharmony_ci	struct cpl_abort_rpl_rss *rpl = cplhdr(skb);
17908c2ecf20Sopenharmony_ci
17918c2ecf20Sopenharmony_ci	pr_debug("%s: csk %p; tid %u; state %d\n",
17928c2ecf20Sopenharmony_ci		 __func__, csk, csk->tid, csk->com.state);
17938c2ecf20Sopenharmony_ci
17948c2ecf20Sopenharmony_ci	switch (csk->com.state) {
17958c2ecf20Sopenharmony_ci	case CSK_STATE_ABORTING:
17968c2ecf20Sopenharmony_ci		csk->com.state = CSK_STATE_DEAD;
17978c2ecf20Sopenharmony_ci		if (test_bit(CSK_ABORT_RPL_WAIT, &csk->com.flags))
17988c2ecf20Sopenharmony_ci			cxgbit_wake_up(&csk->com.wr_wait, __func__,
17998c2ecf20Sopenharmony_ci				       rpl->status);
18008c2ecf20Sopenharmony_ci		cxgbit_put_csk(csk);
18018c2ecf20Sopenharmony_ci		break;
18028c2ecf20Sopenharmony_ci	default:
18038c2ecf20Sopenharmony_ci		pr_info("%s: cpl_abort_rpl_rss in state %d\n",
18048c2ecf20Sopenharmony_ci			__func__, csk->com.state);
18058c2ecf20Sopenharmony_ci	}
18068c2ecf20Sopenharmony_ci
18078c2ecf20Sopenharmony_ci	__kfree_skb(skb);
18088c2ecf20Sopenharmony_ci}
18098c2ecf20Sopenharmony_ci
18108c2ecf20Sopenharmony_cistatic bool cxgbit_credit_err(const struct cxgbit_sock *csk)
18118c2ecf20Sopenharmony_ci{
18128c2ecf20Sopenharmony_ci	const struct sk_buff *skb = csk->wr_pending_head;
18138c2ecf20Sopenharmony_ci	u32 credit = 0;
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_ci	if (unlikely(csk->wr_cred > csk->wr_max_cred)) {
18168c2ecf20Sopenharmony_ci		pr_err("csk 0x%p, tid %u, credit %u > %u\n",
18178c2ecf20Sopenharmony_ci		       csk, csk->tid, csk->wr_cred, csk->wr_max_cred);
18188c2ecf20Sopenharmony_ci		return true;
18198c2ecf20Sopenharmony_ci	}
18208c2ecf20Sopenharmony_ci
18218c2ecf20Sopenharmony_ci	while (skb) {
18228c2ecf20Sopenharmony_ci		credit += (__force u32)skb->csum;
18238c2ecf20Sopenharmony_ci		skb = cxgbit_skcb_tx_wr_next(skb);
18248c2ecf20Sopenharmony_ci	}
18258c2ecf20Sopenharmony_ci
18268c2ecf20Sopenharmony_ci	if (unlikely((csk->wr_cred + credit) != csk->wr_max_cred)) {
18278c2ecf20Sopenharmony_ci		pr_err("csk 0x%p, tid %u, credit %u + %u != %u.\n",
18288c2ecf20Sopenharmony_ci		       csk, csk->tid, csk->wr_cred,
18298c2ecf20Sopenharmony_ci		       credit, csk->wr_max_cred);
18308c2ecf20Sopenharmony_ci
18318c2ecf20Sopenharmony_ci		return true;
18328c2ecf20Sopenharmony_ci	}
18338c2ecf20Sopenharmony_ci
18348c2ecf20Sopenharmony_ci	return false;
18358c2ecf20Sopenharmony_ci}
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_cistatic void cxgbit_fw4_ack(struct cxgbit_sock *csk, struct sk_buff *skb)
18388c2ecf20Sopenharmony_ci{
18398c2ecf20Sopenharmony_ci	struct cpl_fw4_ack *rpl = (struct cpl_fw4_ack *)cplhdr(skb);
18408c2ecf20Sopenharmony_ci	u32 credits = rpl->credits;
18418c2ecf20Sopenharmony_ci	u32 snd_una = ntohl(rpl->snd_una);
18428c2ecf20Sopenharmony_ci
18438c2ecf20Sopenharmony_ci	csk->wr_cred += credits;
18448c2ecf20Sopenharmony_ci	if (csk->wr_una_cred > (csk->wr_max_cred - csk->wr_cred))
18458c2ecf20Sopenharmony_ci		csk->wr_una_cred = csk->wr_max_cred - csk->wr_cred;
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_ci	while (credits) {
18488c2ecf20Sopenharmony_ci		struct sk_buff *p = cxgbit_sock_peek_wr(csk);
18498c2ecf20Sopenharmony_ci		u32 csum;
18508c2ecf20Sopenharmony_ci
18518c2ecf20Sopenharmony_ci		if (unlikely(!p)) {
18528c2ecf20Sopenharmony_ci			pr_err("csk 0x%p,%u, cr %u,%u+%u, empty.\n",
18538c2ecf20Sopenharmony_ci			       csk, csk->tid, credits,
18548c2ecf20Sopenharmony_ci			       csk->wr_cred, csk->wr_una_cred);
18558c2ecf20Sopenharmony_ci			break;
18568c2ecf20Sopenharmony_ci		}
18578c2ecf20Sopenharmony_ci
18588c2ecf20Sopenharmony_ci		csum = (__force u32)p->csum;
18598c2ecf20Sopenharmony_ci		if (unlikely(credits < csum)) {
18608c2ecf20Sopenharmony_ci			pr_warn("csk 0x%p,%u, cr %u,%u+%u, < %u.\n",
18618c2ecf20Sopenharmony_ci				csk,  csk->tid,
18628c2ecf20Sopenharmony_ci				credits, csk->wr_cred, csk->wr_una_cred,
18638c2ecf20Sopenharmony_ci				csum);
18648c2ecf20Sopenharmony_ci			p->csum = (__force __wsum)(csum - credits);
18658c2ecf20Sopenharmony_ci			break;
18668c2ecf20Sopenharmony_ci		}
18678c2ecf20Sopenharmony_ci
18688c2ecf20Sopenharmony_ci		cxgbit_sock_dequeue_wr(csk);
18698c2ecf20Sopenharmony_ci		credits -= csum;
18708c2ecf20Sopenharmony_ci		kfree_skb(p);
18718c2ecf20Sopenharmony_ci	}
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci	if (unlikely(cxgbit_credit_err(csk))) {
18748c2ecf20Sopenharmony_ci		cxgbit_queue_rx_skb(csk, skb);
18758c2ecf20Sopenharmony_ci		return;
18768c2ecf20Sopenharmony_ci	}
18778c2ecf20Sopenharmony_ci
18788c2ecf20Sopenharmony_ci	if (rpl->seq_vld & CPL_FW4_ACK_FLAGS_SEQVAL) {
18798c2ecf20Sopenharmony_ci		if (unlikely(before(snd_una, csk->snd_una))) {
18808c2ecf20Sopenharmony_ci			pr_warn("csk 0x%p,%u, snd_una %u/%u.",
18818c2ecf20Sopenharmony_ci				csk, csk->tid, snd_una,
18828c2ecf20Sopenharmony_ci				csk->snd_una);
18838c2ecf20Sopenharmony_ci			goto rel_skb;
18848c2ecf20Sopenharmony_ci		}
18858c2ecf20Sopenharmony_ci
18868c2ecf20Sopenharmony_ci		if (csk->snd_una != snd_una) {
18878c2ecf20Sopenharmony_ci			csk->snd_una = snd_una;
18888c2ecf20Sopenharmony_ci			dst_confirm(csk->dst);
18898c2ecf20Sopenharmony_ci		}
18908c2ecf20Sopenharmony_ci	}
18918c2ecf20Sopenharmony_ci
18928c2ecf20Sopenharmony_ci	if (skb_queue_len(&csk->txq))
18938c2ecf20Sopenharmony_ci		cxgbit_push_tx_frames(csk);
18948c2ecf20Sopenharmony_ci
18958c2ecf20Sopenharmony_cirel_skb:
18968c2ecf20Sopenharmony_ci	__kfree_skb(skb);
18978c2ecf20Sopenharmony_ci}
18988c2ecf20Sopenharmony_ci
18998c2ecf20Sopenharmony_cistatic void cxgbit_set_tcb_rpl(struct cxgbit_device *cdev, struct sk_buff *skb)
19008c2ecf20Sopenharmony_ci{
19018c2ecf20Sopenharmony_ci	struct cxgbit_sock *csk;
19028c2ecf20Sopenharmony_ci	struct cpl_set_tcb_rpl *rpl = (struct cpl_set_tcb_rpl *)skb->data;
19038c2ecf20Sopenharmony_ci	unsigned int tid = GET_TID(rpl);
19048c2ecf20Sopenharmony_ci	struct cxgb4_lld_info *lldi = &cdev->lldi;
19058c2ecf20Sopenharmony_ci	struct tid_info *t = lldi->tids;
19068c2ecf20Sopenharmony_ci
19078c2ecf20Sopenharmony_ci	csk = lookup_tid(t, tid);
19088c2ecf20Sopenharmony_ci	if (unlikely(!csk)) {
19098c2ecf20Sopenharmony_ci		pr_err("can't find connection for tid %u.\n", tid);
19108c2ecf20Sopenharmony_ci		goto rel_skb;
19118c2ecf20Sopenharmony_ci	} else {
19128c2ecf20Sopenharmony_ci		cxgbit_wake_up(&csk->com.wr_wait, __func__, rpl->status);
19138c2ecf20Sopenharmony_ci	}
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_ci	cxgbit_put_csk(csk);
19168c2ecf20Sopenharmony_cirel_skb:
19178c2ecf20Sopenharmony_ci	__kfree_skb(skb);
19188c2ecf20Sopenharmony_ci}
19198c2ecf20Sopenharmony_ci
19208c2ecf20Sopenharmony_cistatic void cxgbit_rx_data(struct cxgbit_device *cdev, struct sk_buff *skb)
19218c2ecf20Sopenharmony_ci{
19228c2ecf20Sopenharmony_ci	struct cxgbit_sock *csk;
19238c2ecf20Sopenharmony_ci	struct cpl_rx_data *cpl = cplhdr(skb);
19248c2ecf20Sopenharmony_ci	unsigned int tid = GET_TID(cpl);
19258c2ecf20Sopenharmony_ci	struct cxgb4_lld_info *lldi = &cdev->lldi;
19268c2ecf20Sopenharmony_ci	struct tid_info *t = lldi->tids;
19278c2ecf20Sopenharmony_ci
19288c2ecf20Sopenharmony_ci	csk = lookup_tid(t, tid);
19298c2ecf20Sopenharmony_ci	if (unlikely(!csk)) {
19308c2ecf20Sopenharmony_ci		pr_err("can't find conn. for tid %u.\n", tid);
19318c2ecf20Sopenharmony_ci		goto rel_skb;
19328c2ecf20Sopenharmony_ci	}
19338c2ecf20Sopenharmony_ci
19348c2ecf20Sopenharmony_ci	cxgbit_queue_rx_skb(csk, skb);
19358c2ecf20Sopenharmony_ci	return;
19368c2ecf20Sopenharmony_cirel_skb:
19378c2ecf20Sopenharmony_ci	__kfree_skb(skb);
19388c2ecf20Sopenharmony_ci}
19398c2ecf20Sopenharmony_ci
19408c2ecf20Sopenharmony_cistatic void
19418c2ecf20Sopenharmony_ci__cxgbit_process_rx_cpl(struct cxgbit_sock *csk, struct sk_buff *skb)
19428c2ecf20Sopenharmony_ci{
19438c2ecf20Sopenharmony_ci	spin_lock(&csk->lock);
19448c2ecf20Sopenharmony_ci	if (csk->lock_owner) {
19458c2ecf20Sopenharmony_ci		__skb_queue_tail(&csk->backlogq, skb);
19468c2ecf20Sopenharmony_ci		spin_unlock(&csk->lock);
19478c2ecf20Sopenharmony_ci		return;
19488c2ecf20Sopenharmony_ci	}
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_ci	cxgbit_skcb_rx_backlog_fn(skb)(csk, skb);
19518c2ecf20Sopenharmony_ci	spin_unlock(&csk->lock);
19528c2ecf20Sopenharmony_ci}
19538c2ecf20Sopenharmony_ci
19548c2ecf20Sopenharmony_cistatic void cxgbit_process_rx_cpl(struct cxgbit_sock *csk, struct sk_buff *skb)
19558c2ecf20Sopenharmony_ci{
19568c2ecf20Sopenharmony_ci	cxgbit_get_csk(csk);
19578c2ecf20Sopenharmony_ci	__cxgbit_process_rx_cpl(csk, skb);
19588c2ecf20Sopenharmony_ci	cxgbit_put_csk(csk);
19598c2ecf20Sopenharmony_ci}
19608c2ecf20Sopenharmony_ci
19618c2ecf20Sopenharmony_cistatic void cxgbit_rx_cpl(struct cxgbit_device *cdev, struct sk_buff *skb)
19628c2ecf20Sopenharmony_ci{
19638c2ecf20Sopenharmony_ci	struct cxgbit_sock *csk;
19648c2ecf20Sopenharmony_ci	struct cpl_tx_data *cpl = cplhdr(skb);
19658c2ecf20Sopenharmony_ci	struct cxgb4_lld_info *lldi = &cdev->lldi;
19668c2ecf20Sopenharmony_ci	struct tid_info *t = lldi->tids;
19678c2ecf20Sopenharmony_ci	unsigned int tid = GET_TID(cpl);
19688c2ecf20Sopenharmony_ci	u8 opcode = cxgbit_skcb_rx_opcode(skb);
19698c2ecf20Sopenharmony_ci	bool ref = true;
19708c2ecf20Sopenharmony_ci
19718c2ecf20Sopenharmony_ci	switch (opcode) {
19728c2ecf20Sopenharmony_ci	case CPL_FW4_ACK:
19738c2ecf20Sopenharmony_ci			cxgbit_skcb_rx_backlog_fn(skb) = cxgbit_fw4_ack;
19748c2ecf20Sopenharmony_ci			ref = false;
19758c2ecf20Sopenharmony_ci			break;
19768c2ecf20Sopenharmony_ci	case CPL_PEER_CLOSE:
19778c2ecf20Sopenharmony_ci			cxgbit_skcb_rx_backlog_fn(skb) = cxgbit_peer_close;
19788c2ecf20Sopenharmony_ci			break;
19798c2ecf20Sopenharmony_ci	case CPL_CLOSE_CON_RPL:
19808c2ecf20Sopenharmony_ci			cxgbit_skcb_rx_backlog_fn(skb) = cxgbit_close_con_rpl;
19818c2ecf20Sopenharmony_ci			break;
19828c2ecf20Sopenharmony_ci	case CPL_ABORT_REQ_RSS:
19838c2ecf20Sopenharmony_ci			cxgbit_skcb_rx_backlog_fn(skb) = cxgbit_abort_req_rss;
19848c2ecf20Sopenharmony_ci			break;
19858c2ecf20Sopenharmony_ci	case CPL_ABORT_RPL_RSS:
19868c2ecf20Sopenharmony_ci			cxgbit_skcb_rx_backlog_fn(skb) = cxgbit_abort_rpl_rss;
19878c2ecf20Sopenharmony_ci			break;
19888c2ecf20Sopenharmony_ci	default:
19898c2ecf20Sopenharmony_ci		goto rel_skb;
19908c2ecf20Sopenharmony_ci	}
19918c2ecf20Sopenharmony_ci
19928c2ecf20Sopenharmony_ci	csk = lookup_tid(t, tid);
19938c2ecf20Sopenharmony_ci	if (unlikely(!csk)) {
19948c2ecf20Sopenharmony_ci		pr_err("can't find conn. for tid %u.\n", tid);
19958c2ecf20Sopenharmony_ci		goto rel_skb;
19968c2ecf20Sopenharmony_ci	}
19978c2ecf20Sopenharmony_ci
19988c2ecf20Sopenharmony_ci	if (ref)
19998c2ecf20Sopenharmony_ci		cxgbit_process_rx_cpl(csk, skb);
20008c2ecf20Sopenharmony_ci	else
20018c2ecf20Sopenharmony_ci		__cxgbit_process_rx_cpl(csk, skb);
20028c2ecf20Sopenharmony_ci
20038c2ecf20Sopenharmony_ci	return;
20048c2ecf20Sopenharmony_cirel_skb:
20058c2ecf20Sopenharmony_ci	__kfree_skb(skb);
20068c2ecf20Sopenharmony_ci}
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_cicxgbit_cplhandler_func cxgbit_cplhandlers[NUM_CPL_CMDS] = {
20098c2ecf20Sopenharmony_ci	[CPL_PASS_OPEN_RPL]	= cxgbit_pass_open_rpl,
20108c2ecf20Sopenharmony_ci	[CPL_CLOSE_LISTSRV_RPL] = cxgbit_close_listsrv_rpl,
20118c2ecf20Sopenharmony_ci	[CPL_PASS_ACCEPT_REQ]	= cxgbit_pass_accept_req,
20128c2ecf20Sopenharmony_ci	[CPL_PASS_ESTABLISH]	= cxgbit_pass_establish,
20138c2ecf20Sopenharmony_ci	[CPL_SET_TCB_RPL]	= cxgbit_set_tcb_rpl,
20148c2ecf20Sopenharmony_ci	[CPL_RX_DATA]		= cxgbit_rx_data,
20158c2ecf20Sopenharmony_ci	[CPL_FW4_ACK]		= cxgbit_rx_cpl,
20168c2ecf20Sopenharmony_ci	[CPL_PEER_CLOSE]	= cxgbit_rx_cpl,
20178c2ecf20Sopenharmony_ci	[CPL_CLOSE_CON_RPL]	= cxgbit_rx_cpl,
20188c2ecf20Sopenharmony_ci	[CPL_ABORT_REQ_RSS]	= cxgbit_rx_cpl,
20198c2ecf20Sopenharmony_ci	[CPL_ABORT_RPL_RSS]	= cxgbit_rx_cpl,
20208c2ecf20Sopenharmony_ci};
2021