162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2016 Chelsio Communications, Inc.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/module.h>
762306a36Sopenharmony_ci#include <linux/list.h>
862306a36Sopenharmony_ci#include <linux/workqueue.h>
962306a36Sopenharmony_ci#include <linux/skbuff.h>
1062306a36Sopenharmony_ci#include <linux/timer.h>
1162306a36Sopenharmony_ci#include <linux/notifier.h>
1262306a36Sopenharmony_ci#include <linux/inetdevice.h>
1362306a36Sopenharmony_ci#include <linux/ip.h>
1462306a36Sopenharmony_ci#include <linux/tcp.h>
1562306a36Sopenharmony_ci#include <linux/if_vlan.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <net/neighbour.h>
1862306a36Sopenharmony_ci#include <net/netevent.h>
1962306a36Sopenharmony_ci#include <net/route.h>
2062306a36Sopenharmony_ci#include <net/tcp.h>
2162306a36Sopenharmony_ci#include <net/ip6_route.h>
2262306a36Sopenharmony_ci#include <net/addrconf.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include <libcxgb_cm.h>
2562306a36Sopenharmony_ci#include "cxgbit.h"
2662306a36Sopenharmony_ci#include "clip_tbl.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic void cxgbit_init_wr_wait(struct cxgbit_wr_wait *wr_waitp)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	wr_waitp->ret = 0;
3162306a36Sopenharmony_ci	reinit_completion(&wr_waitp->completion);
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic void
3562306a36Sopenharmony_cicxgbit_wake_up(struct cxgbit_wr_wait *wr_waitp, const char *func, u8 ret)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	if (ret == CPL_ERR_NONE)
3862306a36Sopenharmony_ci		wr_waitp->ret = 0;
3962306a36Sopenharmony_ci	else
4062306a36Sopenharmony_ci		wr_waitp->ret = -EIO;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	if (wr_waitp->ret)
4362306a36Sopenharmony_ci		pr_err("%s: err:%u", func, ret);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	complete(&wr_waitp->completion);
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic int
4962306a36Sopenharmony_cicxgbit_wait_for_reply(struct cxgbit_device *cdev,
5062306a36Sopenharmony_ci		      struct cxgbit_wr_wait *wr_waitp, u32 tid, u32 timeout,
5162306a36Sopenharmony_ci		      const char *func)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	int ret;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	if (!test_bit(CDEV_STATE_UP, &cdev->flags)) {
5662306a36Sopenharmony_ci		wr_waitp->ret = -EIO;
5762306a36Sopenharmony_ci		goto out;
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	ret = wait_for_completion_timeout(&wr_waitp->completion, timeout * HZ);
6162306a36Sopenharmony_ci	if (!ret) {
6262306a36Sopenharmony_ci		pr_info("%s - Device %s not responding tid %u\n",
6362306a36Sopenharmony_ci			func, pci_name(cdev->lldi.pdev), tid);
6462306a36Sopenharmony_ci		wr_waitp->ret = -ETIMEDOUT;
6562306a36Sopenharmony_ci	}
6662306a36Sopenharmony_ciout:
6762306a36Sopenharmony_ci	if (wr_waitp->ret)
6862306a36Sopenharmony_ci		pr_info("%s: FW reply %d tid %u\n",
6962306a36Sopenharmony_ci			pci_name(cdev->lldi.pdev), wr_waitp->ret, tid);
7062306a36Sopenharmony_ci	return wr_waitp->ret;
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic int cxgbit_np_hashfn(const struct cxgbit_np *cnp)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	return ((unsigned long)cnp >> 10) & (NP_INFO_HASH_SIZE - 1);
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic struct np_info *
7962306a36Sopenharmony_cicxgbit_np_hash_add(struct cxgbit_device *cdev, struct cxgbit_np *cnp,
8062306a36Sopenharmony_ci		   unsigned int stid)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	struct np_info *p = kzalloc(sizeof(*p), GFP_KERNEL);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	if (p) {
8562306a36Sopenharmony_ci		int bucket = cxgbit_np_hashfn(cnp);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci		p->cnp = cnp;
8862306a36Sopenharmony_ci		p->stid = stid;
8962306a36Sopenharmony_ci		spin_lock(&cdev->np_lock);
9062306a36Sopenharmony_ci		p->next = cdev->np_hash_tab[bucket];
9162306a36Sopenharmony_ci		cdev->np_hash_tab[bucket] = p;
9262306a36Sopenharmony_ci		spin_unlock(&cdev->np_lock);
9362306a36Sopenharmony_ci	}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	return p;
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic int
9962306a36Sopenharmony_cicxgbit_np_hash_find(struct cxgbit_device *cdev, struct cxgbit_np *cnp)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	int stid = -1, bucket = cxgbit_np_hashfn(cnp);
10262306a36Sopenharmony_ci	struct np_info *p;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	spin_lock(&cdev->np_lock);
10562306a36Sopenharmony_ci	for (p = cdev->np_hash_tab[bucket]; p; p = p->next) {
10662306a36Sopenharmony_ci		if (p->cnp == cnp) {
10762306a36Sopenharmony_ci			stid = p->stid;
10862306a36Sopenharmony_ci			break;
10962306a36Sopenharmony_ci		}
11062306a36Sopenharmony_ci	}
11162306a36Sopenharmony_ci	spin_unlock(&cdev->np_lock);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	return stid;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic int cxgbit_np_hash_del(struct cxgbit_device *cdev, struct cxgbit_np *cnp)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	int stid = -1, bucket = cxgbit_np_hashfn(cnp);
11962306a36Sopenharmony_ci	struct np_info *p, **prev = &cdev->np_hash_tab[bucket];
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	spin_lock(&cdev->np_lock);
12262306a36Sopenharmony_ci	for (p = *prev; p; prev = &p->next, p = p->next) {
12362306a36Sopenharmony_ci		if (p->cnp == cnp) {
12462306a36Sopenharmony_ci			stid = p->stid;
12562306a36Sopenharmony_ci			*prev = p->next;
12662306a36Sopenharmony_ci			kfree(p);
12762306a36Sopenharmony_ci			break;
12862306a36Sopenharmony_ci		}
12962306a36Sopenharmony_ci	}
13062306a36Sopenharmony_ci	spin_unlock(&cdev->np_lock);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	return stid;
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_civoid _cxgbit_free_cnp(struct kref *kref)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	struct cxgbit_np *cnp;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	cnp = container_of(kref, struct cxgbit_np, kref);
14062306a36Sopenharmony_ci	kfree(cnp);
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic int
14462306a36Sopenharmony_cicxgbit_create_server6(struct cxgbit_device *cdev, unsigned int stid,
14562306a36Sopenharmony_ci		      struct cxgbit_np *cnp)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)
14862306a36Sopenharmony_ci				     &cnp->com.local_addr;
14962306a36Sopenharmony_ci	int addr_type;
15062306a36Sopenharmony_ci	int ret;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	pr_debug("%s: dev = %s; stid = %u; sin6_port = %u\n",
15362306a36Sopenharmony_ci		 __func__, cdev->lldi.ports[0]->name, stid, sin6->sin6_port);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	addr_type = ipv6_addr_type((const struct in6_addr *)
15662306a36Sopenharmony_ci				   &sin6->sin6_addr);
15762306a36Sopenharmony_ci	if (addr_type != IPV6_ADDR_ANY) {
15862306a36Sopenharmony_ci		ret = cxgb4_clip_get(cdev->lldi.ports[0],
15962306a36Sopenharmony_ci				     (const u32 *)&sin6->sin6_addr.s6_addr, 1);
16062306a36Sopenharmony_ci		if (ret) {
16162306a36Sopenharmony_ci			pr_err("Unable to find clip table entry. laddr %pI6. Error:%d.\n",
16262306a36Sopenharmony_ci			       sin6->sin6_addr.s6_addr, ret);
16362306a36Sopenharmony_ci			return -ENOMEM;
16462306a36Sopenharmony_ci		}
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	cxgbit_get_cnp(cnp);
16862306a36Sopenharmony_ci	cxgbit_init_wr_wait(&cnp->com.wr_wait);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	ret = cxgb4_create_server6(cdev->lldi.ports[0],
17162306a36Sopenharmony_ci				   stid, &sin6->sin6_addr,
17262306a36Sopenharmony_ci				   sin6->sin6_port,
17362306a36Sopenharmony_ci				   cdev->lldi.rxq_ids[0]);
17462306a36Sopenharmony_ci	if (!ret)
17562306a36Sopenharmony_ci		ret = cxgbit_wait_for_reply(cdev, &cnp->com.wr_wait,
17662306a36Sopenharmony_ci					    0, 10, __func__);
17762306a36Sopenharmony_ci	else if (ret > 0)
17862306a36Sopenharmony_ci		ret = net_xmit_errno(ret);
17962306a36Sopenharmony_ci	else
18062306a36Sopenharmony_ci		cxgbit_put_cnp(cnp);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	if (ret) {
18362306a36Sopenharmony_ci		if (ret != -ETIMEDOUT)
18462306a36Sopenharmony_ci			cxgb4_clip_release(cdev->lldi.ports[0],
18562306a36Sopenharmony_ci				   (const u32 *)&sin6->sin6_addr.s6_addr, 1);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci		pr_err("create server6 err %d stid %d laddr %pI6 lport %d\n",
18862306a36Sopenharmony_ci		       ret, stid, sin6->sin6_addr.s6_addr,
18962306a36Sopenharmony_ci		       ntohs(sin6->sin6_port));
19062306a36Sopenharmony_ci	}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	return ret;
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic int
19662306a36Sopenharmony_cicxgbit_create_server4(struct cxgbit_device *cdev, unsigned int stid,
19762306a36Sopenharmony_ci		      struct cxgbit_np *cnp)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	struct sockaddr_in *sin = (struct sockaddr_in *)
20062306a36Sopenharmony_ci				   &cnp->com.local_addr;
20162306a36Sopenharmony_ci	int ret;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	pr_debug("%s: dev = %s; stid = %u; sin_port = %u\n",
20462306a36Sopenharmony_ci		 __func__, cdev->lldi.ports[0]->name, stid, sin->sin_port);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	cxgbit_get_cnp(cnp);
20762306a36Sopenharmony_ci	cxgbit_init_wr_wait(&cnp->com.wr_wait);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	ret = cxgb4_create_server(cdev->lldi.ports[0],
21062306a36Sopenharmony_ci				  stid, sin->sin_addr.s_addr,
21162306a36Sopenharmony_ci				  sin->sin_port, 0,
21262306a36Sopenharmony_ci				  cdev->lldi.rxq_ids[0]);
21362306a36Sopenharmony_ci	if (!ret)
21462306a36Sopenharmony_ci		ret = cxgbit_wait_for_reply(cdev,
21562306a36Sopenharmony_ci					    &cnp->com.wr_wait,
21662306a36Sopenharmony_ci					    0, 10, __func__);
21762306a36Sopenharmony_ci	else if (ret > 0)
21862306a36Sopenharmony_ci		ret = net_xmit_errno(ret);
21962306a36Sopenharmony_ci	else
22062306a36Sopenharmony_ci		cxgbit_put_cnp(cnp);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	if (ret)
22362306a36Sopenharmony_ci		pr_err("create server failed err %d stid %d laddr %pI4 lport %d\n",
22462306a36Sopenharmony_ci		       ret, stid, &sin->sin_addr, ntohs(sin->sin_port));
22562306a36Sopenharmony_ci	return ret;
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistruct cxgbit_device *cxgbit_find_device(struct net_device *ndev, u8 *port_id)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	struct cxgbit_device *cdev;
23162306a36Sopenharmony_ci	u8 i;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	list_for_each_entry(cdev, &cdev_list_head, list) {
23462306a36Sopenharmony_ci		struct cxgb4_lld_info *lldi = &cdev->lldi;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci		for (i = 0; i < lldi->nports; i++) {
23762306a36Sopenharmony_ci			if (lldi->ports[i] == ndev) {
23862306a36Sopenharmony_ci				if (port_id)
23962306a36Sopenharmony_ci					*port_id = i;
24062306a36Sopenharmony_ci				return cdev;
24162306a36Sopenharmony_ci			}
24262306a36Sopenharmony_ci		}
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	return NULL;
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic struct net_device *cxgbit_get_real_dev(struct net_device *ndev)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	if (ndev->priv_flags & IFF_BONDING) {
25162306a36Sopenharmony_ci		pr_err("Bond devices are not supported. Interface:%s\n",
25262306a36Sopenharmony_ci		       ndev->name);
25362306a36Sopenharmony_ci		return NULL;
25462306a36Sopenharmony_ci	}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	if (is_vlan_dev(ndev))
25762306a36Sopenharmony_ci		return vlan_dev_real_dev(ndev);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	return ndev;
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic struct net_device *cxgbit_ipv4_netdev(__be32 saddr)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	struct net_device *ndev;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	ndev = __ip_dev_find(&init_net, saddr, false);
26762306a36Sopenharmony_ci	if (!ndev)
26862306a36Sopenharmony_ci		return NULL;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	return cxgbit_get_real_dev(ndev);
27162306a36Sopenharmony_ci}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_cistatic struct net_device *cxgbit_ipv6_netdev(struct in6_addr *addr6)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	struct net_device *ndev = NULL;
27662306a36Sopenharmony_ci	bool found = false;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_IPV6)) {
27962306a36Sopenharmony_ci		for_each_netdev_rcu(&init_net, ndev)
28062306a36Sopenharmony_ci			if (ipv6_chk_addr(&init_net, addr6, ndev, 1)) {
28162306a36Sopenharmony_ci				found = true;
28262306a36Sopenharmony_ci				break;
28362306a36Sopenharmony_ci			}
28462306a36Sopenharmony_ci	}
28562306a36Sopenharmony_ci	if (!found)
28662306a36Sopenharmony_ci		return NULL;
28762306a36Sopenharmony_ci	return cxgbit_get_real_dev(ndev);
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistatic struct cxgbit_device *cxgbit_find_np_cdev(struct cxgbit_np *cnp)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	struct sockaddr_storage *sockaddr = &cnp->com.local_addr;
29362306a36Sopenharmony_ci	int ss_family = sockaddr->ss_family;
29462306a36Sopenharmony_ci	struct net_device *ndev = NULL;
29562306a36Sopenharmony_ci	struct cxgbit_device *cdev = NULL;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	rcu_read_lock();
29862306a36Sopenharmony_ci	if (ss_family == AF_INET) {
29962306a36Sopenharmony_ci		struct sockaddr_in *sin;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci		sin = (struct sockaddr_in *)sockaddr;
30262306a36Sopenharmony_ci		ndev = cxgbit_ipv4_netdev(sin->sin_addr.s_addr);
30362306a36Sopenharmony_ci	} else if (ss_family == AF_INET6) {
30462306a36Sopenharmony_ci		struct sockaddr_in6 *sin6;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci		sin6 = (struct sockaddr_in6 *)sockaddr;
30762306a36Sopenharmony_ci		ndev = cxgbit_ipv6_netdev(&sin6->sin6_addr);
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci	if (!ndev)
31062306a36Sopenharmony_ci		goto out;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	cdev = cxgbit_find_device(ndev, NULL);
31362306a36Sopenharmony_ciout:
31462306a36Sopenharmony_ci	rcu_read_unlock();
31562306a36Sopenharmony_ci	return cdev;
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic bool cxgbit_inaddr_any(struct cxgbit_np *cnp)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	struct sockaddr_storage *sockaddr = &cnp->com.local_addr;
32162306a36Sopenharmony_ci	int ss_family = sockaddr->ss_family;
32262306a36Sopenharmony_ci	int addr_type;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	if (ss_family == AF_INET) {
32562306a36Sopenharmony_ci		struct sockaddr_in *sin;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci		sin = (struct sockaddr_in *)sockaddr;
32862306a36Sopenharmony_ci		if (sin->sin_addr.s_addr == htonl(INADDR_ANY))
32962306a36Sopenharmony_ci			return true;
33062306a36Sopenharmony_ci	} else if (ss_family == AF_INET6) {
33162306a36Sopenharmony_ci		struct sockaddr_in6 *sin6;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci		sin6 = (struct sockaddr_in6 *)sockaddr;
33462306a36Sopenharmony_ci		addr_type = ipv6_addr_type((const struct in6_addr *)
33562306a36Sopenharmony_ci				&sin6->sin6_addr);
33662306a36Sopenharmony_ci		if (addr_type == IPV6_ADDR_ANY)
33762306a36Sopenharmony_ci			return true;
33862306a36Sopenharmony_ci	}
33962306a36Sopenharmony_ci	return false;
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_cistatic int
34362306a36Sopenharmony_ci__cxgbit_setup_cdev_np(struct cxgbit_device *cdev, struct cxgbit_np *cnp)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	int stid, ret;
34662306a36Sopenharmony_ci	int ss_family = cnp->com.local_addr.ss_family;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	if (!test_bit(CDEV_STATE_UP, &cdev->flags))
34962306a36Sopenharmony_ci		return -EINVAL;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	stid = cxgb4_alloc_stid(cdev->lldi.tids, ss_family, cnp);
35262306a36Sopenharmony_ci	if (stid < 0)
35362306a36Sopenharmony_ci		return -EINVAL;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	if (!cxgbit_np_hash_add(cdev, cnp, stid)) {
35662306a36Sopenharmony_ci		cxgb4_free_stid(cdev->lldi.tids, stid, ss_family);
35762306a36Sopenharmony_ci		return -EINVAL;
35862306a36Sopenharmony_ci	}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	if (ss_family == AF_INET)
36162306a36Sopenharmony_ci		ret = cxgbit_create_server4(cdev, stid, cnp);
36262306a36Sopenharmony_ci	else
36362306a36Sopenharmony_ci		ret = cxgbit_create_server6(cdev, stid, cnp);
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	if (ret) {
36662306a36Sopenharmony_ci		if (ret != -ETIMEDOUT)
36762306a36Sopenharmony_ci			cxgb4_free_stid(cdev->lldi.tids, stid,
36862306a36Sopenharmony_ci					ss_family);
36962306a36Sopenharmony_ci		cxgbit_np_hash_del(cdev, cnp);
37062306a36Sopenharmony_ci		return ret;
37162306a36Sopenharmony_ci	}
37262306a36Sopenharmony_ci	return ret;
37362306a36Sopenharmony_ci}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_cistatic int cxgbit_setup_cdev_np(struct cxgbit_np *cnp)
37662306a36Sopenharmony_ci{
37762306a36Sopenharmony_ci	struct cxgbit_device *cdev;
37862306a36Sopenharmony_ci	int ret = -1;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	mutex_lock(&cdev_list_lock);
38162306a36Sopenharmony_ci	cdev = cxgbit_find_np_cdev(cnp);
38262306a36Sopenharmony_ci	if (!cdev)
38362306a36Sopenharmony_ci		goto out;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	if (cxgbit_np_hash_find(cdev, cnp) >= 0)
38662306a36Sopenharmony_ci		goto out;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	if (__cxgbit_setup_cdev_np(cdev, cnp))
38962306a36Sopenharmony_ci		goto out;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	cnp->com.cdev = cdev;
39262306a36Sopenharmony_ci	ret = 0;
39362306a36Sopenharmony_ciout:
39462306a36Sopenharmony_ci	mutex_unlock(&cdev_list_lock);
39562306a36Sopenharmony_ci	return ret;
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic int cxgbit_setup_all_np(struct cxgbit_np *cnp)
39962306a36Sopenharmony_ci{
40062306a36Sopenharmony_ci	struct cxgbit_device *cdev;
40162306a36Sopenharmony_ci	int ret;
40262306a36Sopenharmony_ci	u32 count = 0;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	mutex_lock(&cdev_list_lock);
40562306a36Sopenharmony_ci	list_for_each_entry(cdev, &cdev_list_head, list) {
40662306a36Sopenharmony_ci		if (cxgbit_np_hash_find(cdev, cnp) >= 0) {
40762306a36Sopenharmony_ci			mutex_unlock(&cdev_list_lock);
40862306a36Sopenharmony_ci			return -1;
40962306a36Sopenharmony_ci		}
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	list_for_each_entry(cdev, &cdev_list_head, list) {
41362306a36Sopenharmony_ci		ret = __cxgbit_setup_cdev_np(cdev, cnp);
41462306a36Sopenharmony_ci		if (ret == -ETIMEDOUT)
41562306a36Sopenharmony_ci			break;
41662306a36Sopenharmony_ci		if (ret != 0)
41762306a36Sopenharmony_ci			continue;
41862306a36Sopenharmony_ci		count++;
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci	mutex_unlock(&cdev_list_lock);
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	return count ? 0 : -1;
42362306a36Sopenharmony_ci}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ciint cxgbit_setup_np(struct iscsi_np *np, struct sockaddr_storage *ksockaddr)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	struct cxgbit_np *cnp;
42862306a36Sopenharmony_ci	int ret;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	if ((ksockaddr->ss_family != AF_INET) &&
43162306a36Sopenharmony_ci	    (ksockaddr->ss_family != AF_INET6))
43262306a36Sopenharmony_ci		return -EINVAL;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	cnp = kzalloc(sizeof(*cnp), GFP_KERNEL);
43562306a36Sopenharmony_ci	if (!cnp)
43662306a36Sopenharmony_ci		return -ENOMEM;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	init_waitqueue_head(&cnp->accept_wait);
43962306a36Sopenharmony_ci	init_completion(&cnp->com.wr_wait.completion);
44062306a36Sopenharmony_ci	init_completion(&cnp->accept_comp);
44162306a36Sopenharmony_ci	INIT_LIST_HEAD(&cnp->np_accept_list);
44262306a36Sopenharmony_ci	spin_lock_init(&cnp->np_accept_lock);
44362306a36Sopenharmony_ci	kref_init(&cnp->kref);
44462306a36Sopenharmony_ci	memcpy(&np->np_sockaddr, ksockaddr,
44562306a36Sopenharmony_ci	       sizeof(struct sockaddr_storage));
44662306a36Sopenharmony_ci	memcpy(&cnp->com.local_addr, &np->np_sockaddr,
44762306a36Sopenharmony_ci	       sizeof(cnp->com.local_addr));
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	cnp->np = np;
45062306a36Sopenharmony_ci	cnp->com.cdev = NULL;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	if (cxgbit_inaddr_any(cnp))
45362306a36Sopenharmony_ci		ret = cxgbit_setup_all_np(cnp);
45462306a36Sopenharmony_ci	else
45562306a36Sopenharmony_ci		ret = cxgbit_setup_cdev_np(cnp);
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	if (ret) {
45862306a36Sopenharmony_ci		cxgbit_put_cnp(cnp);
45962306a36Sopenharmony_ci		return -EINVAL;
46062306a36Sopenharmony_ci	}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	np->np_context = cnp;
46362306a36Sopenharmony_ci	cnp->com.state = CSK_STATE_LISTEN;
46462306a36Sopenharmony_ci	return 0;
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_cistatic void
46862306a36Sopenharmony_cicxgbit_set_conn_info(struct iscsi_np *np, struct iscsit_conn *conn,
46962306a36Sopenharmony_ci		     struct cxgbit_sock *csk)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	conn->login_family = np->np_sockaddr.ss_family;
47262306a36Sopenharmony_ci	conn->login_sockaddr = csk->com.remote_addr;
47362306a36Sopenharmony_ci	conn->local_sockaddr = csk->com.local_addr;
47462306a36Sopenharmony_ci}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ciint cxgbit_accept_np(struct iscsi_np *np, struct iscsit_conn *conn)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	struct cxgbit_np *cnp = np->np_context;
47962306a36Sopenharmony_ci	struct cxgbit_sock *csk;
48062306a36Sopenharmony_ci	int ret = 0;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ciaccept_wait:
48362306a36Sopenharmony_ci	ret = wait_for_completion_interruptible(&cnp->accept_comp);
48462306a36Sopenharmony_ci	if (ret)
48562306a36Sopenharmony_ci		return -ENODEV;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	spin_lock_bh(&np->np_thread_lock);
48862306a36Sopenharmony_ci	if (np->np_thread_state >= ISCSI_NP_THREAD_RESET) {
48962306a36Sopenharmony_ci		spin_unlock_bh(&np->np_thread_lock);
49062306a36Sopenharmony_ci		/**
49162306a36Sopenharmony_ci		 * No point in stalling here when np_thread
49262306a36Sopenharmony_ci		 * is in state RESET/SHUTDOWN/EXIT - bail
49362306a36Sopenharmony_ci		 **/
49462306a36Sopenharmony_ci		return -ENODEV;
49562306a36Sopenharmony_ci	}
49662306a36Sopenharmony_ci	spin_unlock_bh(&np->np_thread_lock);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	spin_lock_bh(&cnp->np_accept_lock);
49962306a36Sopenharmony_ci	if (list_empty(&cnp->np_accept_list)) {
50062306a36Sopenharmony_ci		spin_unlock_bh(&cnp->np_accept_lock);
50162306a36Sopenharmony_ci		goto accept_wait;
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	csk = list_first_entry(&cnp->np_accept_list,
50562306a36Sopenharmony_ci			       struct cxgbit_sock,
50662306a36Sopenharmony_ci			       accept_node);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	list_del_init(&csk->accept_node);
50962306a36Sopenharmony_ci	spin_unlock_bh(&cnp->np_accept_lock);
51062306a36Sopenharmony_ci	conn->context = csk;
51162306a36Sopenharmony_ci	csk->conn = conn;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	cxgbit_set_conn_info(np, conn, csk);
51462306a36Sopenharmony_ci	return 0;
51562306a36Sopenharmony_ci}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_cistatic int
51862306a36Sopenharmony_ci__cxgbit_free_cdev_np(struct cxgbit_device *cdev, struct cxgbit_np *cnp)
51962306a36Sopenharmony_ci{
52062306a36Sopenharmony_ci	int stid, ret;
52162306a36Sopenharmony_ci	bool ipv6 = false;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	stid = cxgbit_np_hash_del(cdev, cnp);
52462306a36Sopenharmony_ci	if (stid < 0)
52562306a36Sopenharmony_ci		return -EINVAL;
52662306a36Sopenharmony_ci	if (!test_bit(CDEV_STATE_UP, &cdev->flags))
52762306a36Sopenharmony_ci		return -EINVAL;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	if (cnp->np->np_sockaddr.ss_family == AF_INET6)
53062306a36Sopenharmony_ci		ipv6 = true;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	cxgbit_get_cnp(cnp);
53362306a36Sopenharmony_ci	cxgbit_init_wr_wait(&cnp->com.wr_wait);
53462306a36Sopenharmony_ci	ret = cxgb4_remove_server(cdev->lldi.ports[0], stid,
53562306a36Sopenharmony_ci				  cdev->lldi.rxq_ids[0], ipv6);
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	if (ret > 0)
53862306a36Sopenharmony_ci		ret = net_xmit_errno(ret);
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	if (ret) {
54162306a36Sopenharmony_ci		cxgbit_put_cnp(cnp);
54262306a36Sopenharmony_ci		return ret;
54362306a36Sopenharmony_ci	}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	ret = cxgbit_wait_for_reply(cdev, &cnp->com.wr_wait,
54662306a36Sopenharmony_ci				    0, 10, __func__);
54762306a36Sopenharmony_ci	if (ret == -ETIMEDOUT)
54862306a36Sopenharmony_ci		return ret;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	if (ipv6 && cnp->com.cdev) {
55162306a36Sopenharmony_ci		struct sockaddr_in6 *sin6;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci		sin6 = (struct sockaddr_in6 *)&cnp->com.local_addr;
55462306a36Sopenharmony_ci		cxgb4_clip_release(cdev->lldi.ports[0],
55562306a36Sopenharmony_ci				   (const u32 *)&sin6->sin6_addr.s6_addr,
55662306a36Sopenharmony_ci				   1);
55762306a36Sopenharmony_ci	}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	cxgb4_free_stid(cdev->lldi.tids, stid,
56062306a36Sopenharmony_ci			cnp->com.local_addr.ss_family);
56162306a36Sopenharmony_ci	return 0;
56262306a36Sopenharmony_ci}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_cistatic void cxgbit_free_all_np(struct cxgbit_np *cnp)
56562306a36Sopenharmony_ci{
56662306a36Sopenharmony_ci	struct cxgbit_device *cdev;
56762306a36Sopenharmony_ci	int ret;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	mutex_lock(&cdev_list_lock);
57062306a36Sopenharmony_ci	list_for_each_entry(cdev, &cdev_list_head, list) {
57162306a36Sopenharmony_ci		ret = __cxgbit_free_cdev_np(cdev, cnp);
57262306a36Sopenharmony_ci		if (ret == -ETIMEDOUT)
57362306a36Sopenharmony_ci			break;
57462306a36Sopenharmony_ci	}
57562306a36Sopenharmony_ci	mutex_unlock(&cdev_list_lock);
57662306a36Sopenharmony_ci}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_cistatic void cxgbit_free_cdev_np(struct cxgbit_np *cnp)
57962306a36Sopenharmony_ci{
58062306a36Sopenharmony_ci	struct cxgbit_device *cdev;
58162306a36Sopenharmony_ci	bool found = false;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	mutex_lock(&cdev_list_lock);
58462306a36Sopenharmony_ci	list_for_each_entry(cdev, &cdev_list_head, list) {
58562306a36Sopenharmony_ci		if (cdev == cnp->com.cdev) {
58662306a36Sopenharmony_ci			found = true;
58762306a36Sopenharmony_ci			break;
58862306a36Sopenharmony_ci		}
58962306a36Sopenharmony_ci	}
59062306a36Sopenharmony_ci	if (!found)
59162306a36Sopenharmony_ci		goto out;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	__cxgbit_free_cdev_np(cdev, cnp);
59462306a36Sopenharmony_ciout:
59562306a36Sopenharmony_ci	mutex_unlock(&cdev_list_lock);
59662306a36Sopenharmony_ci}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_cistatic void __cxgbit_free_conn(struct cxgbit_sock *csk);
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_civoid cxgbit_free_np(struct iscsi_np *np)
60162306a36Sopenharmony_ci{
60262306a36Sopenharmony_ci	struct cxgbit_np *cnp = np->np_context;
60362306a36Sopenharmony_ci	struct cxgbit_sock *csk, *tmp;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	cnp->com.state = CSK_STATE_DEAD;
60662306a36Sopenharmony_ci	if (cnp->com.cdev)
60762306a36Sopenharmony_ci		cxgbit_free_cdev_np(cnp);
60862306a36Sopenharmony_ci	else
60962306a36Sopenharmony_ci		cxgbit_free_all_np(cnp);
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	spin_lock_bh(&cnp->np_accept_lock);
61262306a36Sopenharmony_ci	list_for_each_entry_safe(csk, tmp, &cnp->np_accept_list, accept_node) {
61362306a36Sopenharmony_ci		list_del_init(&csk->accept_node);
61462306a36Sopenharmony_ci		__cxgbit_free_conn(csk);
61562306a36Sopenharmony_ci	}
61662306a36Sopenharmony_ci	spin_unlock_bh(&cnp->np_accept_lock);
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	np->np_context = NULL;
61962306a36Sopenharmony_ci	cxgbit_put_cnp(cnp);
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_cistatic void cxgbit_send_halfclose(struct cxgbit_sock *csk)
62362306a36Sopenharmony_ci{
62462306a36Sopenharmony_ci	struct sk_buff *skb;
62562306a36Sopenharmony_ci	u32 len = roundup(sizeof(struct cpl_close_con_req), 16);
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	skb = alloc_skb(len, GFP_ATOMIC);
62862306a36Sopenharmony_ci	if (!skb)
62962306a36Sopenharmony_ci		return;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	cxgb_mk_close_con_req(skb, len, csk->tid, csk->txq_idx,
63262306a36Sopenharmony_ci			      NULL, NULL);
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	cxgbit_skcb_flags(skb) |= SKCBF_TX_FLAG_COMPL;
63562306a36Sopenharmony_ci	__skb_queue_tail(&csk->txq, skb);
63662306a36Sopenharmony_ci	cxgbit_push_tx_frames(csk);
63762306a36Sopenharmony_ci}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_cistatic void cxgbit_arp_failure_discard(void *handle, struct sk_buff *skb)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	struct cxgbit_sock *csk = handle;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	pr_debug("%s cxgbit_device %p\n", __func__, handle);
64462306a36Sopenharmony_ci	kfree_skb(skb);
64562306a36Sopenharmony_ci	cxgbit_put_csk(csk);
64662306a36Sopenharmony_ci}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_cistatic void cxgbit_abort_arp_failure(void *handle, struct sk_buff *skb)
64962306a36Sopenharmony_ci{
65062306a36Sopenharmony_ci	struct cxgbit_device *cdev = handle;
65162306a36Sopenharmony_ci	struct cpl_abort_req *req = cplhdr(skb);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	pr_debug("%s cdev %p\n", __func__, cdev);
65462306a36Sopenharmony_ci	req->cmd = CPL_ABORT_NO_RST;
65562306a36Sopenharmony_ci	cxgbit_ofld_send(cdev, skb);
65662306a36Sopenharmony_ci}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_cistatic int cxgbit_send_abort_req(struct cxgbit_sock *csk)
65962306a36Sopenharmony_ci{
66062306a36Sopenharmony_ci	struct sk_buff *skb;
66162306a36Sopenharmony_ci	u32 len = roundup(sizeof(struct cpl_abort_req), 16);
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	pr_debug("%s: csk %p tid %u; state %d\n",
66462306a36Sopenharmony_ci		 __func__, csk, csk->tid, csk->com.state);
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	__skb_queue_purge(&csk->txq);
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	if (!test_and_set_bit(CSK_TX_DATA_SENT, &csk->com.flags))
66962306a36Sopenharmony_ci		cxgbit_send_tx_flowc_wr(csk);
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	skb = __skb_dequeue(&csk->skbq);
67262306a36Sopenharmony_ci	cxgb_mk_abort_req(skb, len, csk->tid, csk->txq_idx,
67362306a36Sopenharmony_ci			  csk->com.cdev, cxgbit_abort_arp_failure);
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	return cxgbit_l2t_send(csk->com.cdev, skb, csk->l2t);
67662306a36Sopenharmony_ci}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_cistatic void
67962306a36Sopenharmony_ci__cxgbit_abort_conn(struct cxgbit_sock *csk, struct sk_buff *skb)
68062306a36Sopenharmony_ci{
68162306a36Sopenharmony_ci	__kfree_skb(skb);
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	if (csk->com.state != CSK_STATE_ESTABLISHED)
68462306a36Sopenharmony_ci		goto no_abort;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	set_bit(CSK_ABORT_RPL_WAIT, &csk->com.flags);
68762306a36Sopenharmony_ci	csk->com.state = CSK_STATE_ABORTING;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	cxgbit_send_abort_req(csk);
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	return;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_cino_abort:
69462306a36Sopenharmony_ci	cxgbit_wake_up(&csk->com.wr_wait, __func__, CPL_ERR_NONE);
69562306a36Sopenharmony_ci	cxgbit_put_csk(csk);
69662306a36Sopenharmony_ci}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_civoid cxgbit_abort_conn(struct cxgbit_sock *csk)
69962306a36Sopenharmony_ci{
70062306a36Sopenharmony_ci	struct sk_buff *skb = alloc_skb(0, GFP_KERNEL | __GFP_NOFAIL);
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	cxgbit_get_csk(csk);
70362306a36Sopenharmony_ci	cxgbit_init_wr_wait(&csk->com.wr_wait);
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	spin_lock_bh(&csk->lock);
70662306a36Sopenharmony_ci	if (csk->lock_owner) {
70762306a36Sopenharmony_ci		cxgbit_skcb_rx_backlog_fn(skb) = __cxgbit_abort_conn;
70862306a36Sopenharmony_ci		__skb_queue_tail(&csk->backlogq, skb);
70962306a36Sopenharmony_ci	} else {
71062306a36Sopenharmony_ci		__cxgbit_abort_conn(csk, skb);
71162306a36Sopenharmony_ci	}
71262306a36Sopenharmony_ci	spin_unlock_bh(&csk->lock);
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	cxgbit_wait_for_reply(csk->com.cdev, &csk->com.wr_wait,
71562306a36Sopenharmony_ci			      csk->tid, 600, __func__);
71662306a36Sopenharmony_ci}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_cistatic void __cxgbit_free_conn(struct cxgbit_sock *csk)
71962306a36Sopenharmony_ci{
72062306a36Sopenharmony_ci	struct iscsit_conn *conn = csk->conn;
72162306a36Sopenharmony_ci	bool release = false;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	pr_debug("%s: state %d\n",
72462306a36Sopenharmony_ci		 __func__, csk->com.state);
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	spin_lock_bh(&csk->lock);
72762306a36Sopenharmony_ci	switch (csk->com.state) {
72862306a36Sopenharmony_ci	case CSK_STATE_ESTABLISHED:
72962306a36Sopenharmony_ci		if (conn && (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT)) {
73062306a36Sopenharmony_ci			csk->com.state = CSK_STATE_CLOSING;
73162306a36Sopenharmony_ci			cxgbit_send_halfclose(csk);
73262306a36Sopenharmony_ci		} else {
73362306a36Sopenharmony_ci			csk->com.state = CSK_STATE_ABORTING;
73462306a36Sopenharmony_ci			cxgbit_send_abort_req(csk);
73562306a36Sopenharmony_ci		}
73662306a36Sopenharmony_ci		break;
73762306a36Sopenharmony_ci	case CSK_STATE_CLOSING:
73862306a36Sopenharmony_ci		csk->com.state = CSK_STATE_MORIBUND;
73962306a36Sopenharmony_ci		cxgbit_send_halfclose(csk);
74062306a36Sopenharmony_ci		break;
74162306a36Sopenharmony_ci	case CSK_STATE_DEAD:
74262306a36Sopenharmony_ci		release = true;
74362306a36Sopenharmony_ci		break;
74462306a36Sopenharmony_ci	default:
74562306a36Sopenharmony_ci		pr_err("%s: csk %p; state %d\n",
74662306a36Sopenharmony_ci		       __func__, csk, csk->com.state);
74762306a36Sopenharmony_ci	}
74862306a36Sopenharmony_ci	spin_unlock_bh(&csk->lock);
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	if (release)
75162306a36Sopenharmony_ci		cxgbit_put_csk(csk);
75262306a36Sopenharmony_ci}
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_civoid cxgbit_free_conn(struct iscsit_conn *conn)
75562306a36Sopenharmony_ci{
75662306a36Sopenharmony_ci	__cxgbit_free_conn(conn->context);
75762306a36Sopenharmony_ci}
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_cistatic void cxgbit_set_emss(struct cxgbit_sock *csk, u16 opt)
76062306a36Sopenharmony_ci{
76162306a36Sopenharmony_ci	csk->emss = csk->com.cdev->lldi.mtus[TCPOPT_MSS_G(opt)] -
76262306a36Sopenharmony_ci			((csk->com.remote_addr.ss_family == AF_INET) ?
76362306a36Sopenharmony_ci			sizeof(struct iphdr) : sizeof(struct ipv6hdr)) -
76462306a36Sopenharmony_ci			sizeof(struct tcphdr);
76562306a36Sopenharmony_ci	csk->mss = csk->emss;
76662306a36Sopenharmony_ci	if (TCPOPT_TSTAMP_G(opt))
76762306a36Sopenharmony_ci		csk->emss -= round_up(TCPOLEN_TIMESTAMP, 4);
76862306a36Sopenharmony_ci	if (csk->emss < 128)
76962306a36Sopenharmony_ci		csk->emss = 128;
77062306a36Sopenharmony_ci	if (csk->emss & 7)
77162306a36Sopenharmony_ci		pr_info("Warning: misaligned mtu idx %u mss %u emss=%u\n",
77262306a36Sopenharmony_ci			TCPOPT_MSS_G(opt), csk->mss, csk->emss);
77362306a36Sopenharmony_ci	pr_debug("%s mss_idx %u mss %u emss=%u\n", __func__, TCPOPT_MSS_G(opt),
77462306a36Sopenharmony_ci		 csk->mss, csk->emss);
77562306a36Sopenharmony_ci}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_cistatic void cxgbit_free_skb(struct cxgbit_sock *csk)
77862306a36Sopenharmony_ci{
77962306a36Sopenharmony_ci	struct sk_buff *skb;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	__skb_queue_purge(&csk->txq);
78262306a36Sopenharmony_ci	__skb_queue_purge(&csk->rxq);
78362306a36Sopenharmony_ci	__skb_queue_purge(&csk->backlogq);
78462306a36Sopenharmony_ci	__skb_queue_purge(&csk->ppodq);
78562306a36Sopenharmony_ci	__skb_queue_purge(&csk->skbq);
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	while ((skb = cxgbit_sock_dequeue_wr(csk)))
78862306a36Sopenharmony_ci		kfree_skb(skb);
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	__kfree_skb(csk->lro_hskb);
79162306a36Sopenharmony_ci}
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_civoid _cxgbit_free_csk(struct kref *kref)
79462306a36Sopenharmony_ci{
79562306a36Sopenharmony_ci	struct cxgbit_sock *csk;
79662306a36Sopenharmony_ci	struct cxgbit_device *cdev;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	csk = container_of(kref, struct cxgbit_sock, kref);
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	pr_debug("%s csk %p state %d\n", __func__, csk, csk->com.state);
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	if (csk->com.local_addr.ss_family == AF_INET6) {
80362306a36Sopenharmony_ci		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)
80462306a36Sopenharmony_ci					     &csk->com.local_addr;
80562306a36Sopenharmony_ci		cxgb4_clip_release(csk->com.cdev->lldi.ports[0],
80662306a36Sopenharmony_ci				   (const u32 *)
80762306a36Sopenharmony_ci				   &sin6->sin6_addr.s6_addr, 1);
80862306a36Sopenharmony_ci	}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	cxgb4_remove_tid(csk->com.cdev->lldi.tids, 0, csk->tid,
81162306a36Sopenharmony_ci			 csk->com.local_addr.ss_family);
81262306a36Sopenharmony_ci	dst_release(csk->dst);
81362306a36Sopenharmony_ci	cxgb4_l2t_release(csk->l2t);
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	cdev = csk->com.cdev;
81662306a36Sopenharmony_ci	spin_lock_bh(&cdev->cskq.lock);
81762306a36Sopenharmony_ci	list_del(&csk->list);
81862306a36Sopenharmony_ci	spin_unlock_bh(&cdev->cskq.lock);
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	cxgbit_free_skb(csk);
82162306a36Sopenharmony_ci	cxgbit_put_cnp(csk->cnp);
82262306a36Sopenharmony_ci	cxgbit_put_cdev(cdev);
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	kfree(csk);
82562306a36Sopenharmony_ci}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_cistatic void cxgbit_set_tcp_window(struct cxgbit_sock *csk, struct port_info *pi)
82862306a36Sopenharmony_ci{
82962306a36Sopenharmony_ci	unsigned int linkspeed;
83062306a36Sopenharmony_ci	u8 scale;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	linkspeed = pi->link_cfg.speed;
83362306a36Sopenharmony_ci	scale = linkspeed / SPEED_10000;
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci#define CXGBIT_10G_RCV_WIN (256 * 1024)
83662306a36Sopenharmony_ci	csk->rcv_win = CXGBIT_10G_RCV_WIN;
83762306a36Sopenharmony_ci	if (scale)
83862306a36Sopenharmony_ci		csk->rcv_win *= scale;
83962306a36Sopenharmony_ci	csk->rcv_win = min(csk->rcv_win, RCV_BUFSIZ_M << 10);
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci#define CXGBIT_10G_SND_WIN (256 * 1024)
84262306a36Sopenharmony_ci	csk->snd_win = CXGBIT_10G_SND_WIN;
84362306a36Sopenharmony_ci	if (scale)
84462306a36Sopenharmony_ci		csk->snd_win *= scale;
84562306a36Sopenharmony_ci	csk->snd_win = min(csk->snd_win, 512U * 1024);
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	pr_debug("%s snd_win %d rcv_win %d\n",
84862306a36Sopenharmony_ci		 __func__, csk->snd_win, csk->rcv_win);
84962306a36Sopenharmony_ci}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB
85262306a36Sopenharmony_cistatic u8 cxgbit_get_iscsi_dcb_state(struct net_device *ndev)
85362306a36Sopenharmony_ci{
85462306a36Sopenharmony_ci	return ndev->dcbnl_ops->getstate(ndev);
85562306a36Sopenharmony_ci}
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_cistatic int cxgbit_select_priority(int pri_mask)
85862306a36Sopenharmony_ci{
85962306a36Sopenharmony_ci	if (!pri_mask)
86062306a36Sopenharmony_ci		return 0;
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	return (ffs(pri_mask) - 1);
86362306a36Sopenharmony_ci}
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_cistatic u8 cxgbit_get_iscsi_dcb_priority(struct net_device *ndev, u16 local_port)
86662306a36Sopenharmony_ci{
86762306a36Sopenharmony_ci	int ret;
86862306a36Sopenharmony_ci	u8 caps;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	struct dcb_app iscsi_dcb_app = {
87162306a36Sopenharmony_ci		.protocol = local_port
87262306a36Sopenharmony_ci	};
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	ret = (int)ndev->dcbnl_ops->getcap(ndev, DCB_CAP_ATTR_DCBX, &caps);
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	if (ret)
87762306a36Sopenharmony_ci		return 0;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	if (caps & DCB_CAP_DCBX_VER_IEEE) {
88062306a36Sopenharmony_ci		iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_STREAM;
88162306a36Sopenharmony_ci		ret = dcb_ieee_getapp_mask(ndev, &iscsi_dcb_app);
88262306a36Sopenharmony_ci		if (!ret) {
88362306a36Sopenharmony_ci			iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_ANY;
88462306a36Sopenharmony_ci			ret = dcb_ieee_getapp_mask(ndev, &iscsi_dcb_app);
88562306a36Sopenharmony_ci		}
88662306a36Sopenharmony_ci	} else if (caps & DCB_CAP_DCBX_VER_CEE) {
88762306a36Sopenharmony_ci		iscsi_dcb_app.selector = DCB_APP_IDTYPE_PORTNUM;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci		ret = dcb_getapp(ndev, &iscsi_dcb_app);
89062306a36Sopenharmony_ci	}
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	pr_info("iSCSI priority is set to %u\n", cxgbit_select_priority(ret));
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	return cxgbit_select_priority(ret);
89562306a36Sopenharmony_ci}
89662306a36Sopenharmony_ci#endif
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_cistatic int
89962306a36Sopenharmony_cicxgbit_offload_init(struct cxgbit_sock *csk, int iptype, __u8 *peer_ip,
90062306a36Sopenharmony_ci		    u16 local_port, struct dst_entry *dst,
90162306a36Sopenharmony_ci		    struct cxgbit_device *cdev)
90262306a36Sopenharmony_ci{
90362306a36Sopenharmony_ci	struct neighbour *n;
90462306a36Sopenharmony_ci	int ret, step;
90562306a36Sopenharmony_ci	struct net_device *ndev;
90662306a36Sopenharmony_ci	u16 rxq_idx, port_id;
90762306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB
90862306a36Sopenharmony_ci	u8 priority = 0;
90962306a36Sopenharmony_ci#endif
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	n = dst_neigh_lookup(dst, peer_ip);
91262306a36Sopenharmony_ci	if (!n)
91362306a36Sopenharmony_ci		return -ENODEV;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	rcu_read_lock();
91662306a36Sopenharmony_ci	if (!(n->nud_state & NUD_VALID))
91762306a36Sopenharmony_ci		neigh_event_send(n, NULL);
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	ret = -ENOMEM;
92062306a36Sopenharmony_ci	if (n->dev->flags & IFF_LOOPBACK) {
92162306a36Sopenharmony_ci		if (iptype == 4)
92262306a36Sopenharmony_ci			ndev = cxgbit_ipv4_netdev(*(__be32 *)peer_ip);
92362306a36Sopenharmony_ci		else if (IS_ENABLED(CONFIG_IPV6))
92462306a36Sopenharmony_ci			ndev = cxgbit_ipv6_netdev((struct in6_addr *)peer_ip);
92562306a36Sopenharmony_ci		else
92662306a36Sopenharmony_ci			ndev = NULL;
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci		if (!ndev) {
92962306a36Sopenharmony_ci			ret = -ENODEV;
93062306a36Sopenharmony_ci			goto out;
93162306a36Sopenharmony_ci		}
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci		csk->l2t = cxgb4_l2t_get(cdev->lldi.l2t,
93462306a36Sopenharmony_ci					 n, ndev, 0);
93562306a36Sopenharmony_ci		if (!csk->l2t)
93662306a36Sopenharmony_ci			goto out;
93762306a36Sopenharmony_ci		csk->mtu = ndev->mtu;
93862306a36Sopenharmony_ci		csk->tx_chan = cxgb4_port_chan(ndev);
93962306a36Sopenharmony_ci		csk->smac_idx =
94062306a36Sopenharmony_ci			       ((struct port_info *)netdev_priv(ndev))->smt_idx;
94162306a36Sopenharmony_ci		step = cdev->lldi.ntxq /
94262306a36Sopenharmony_ci			cdev->lldi.nchan;
94362306a36Sopenharmony_ci		csk->txq_idx = cxgb4_port_idx(ndev) * step;
94462306a36Sopenharmony_ci		step = cdev->lldi.nrxq /
94562306a36Sopenharmony_ci			cdev->lldi.nchan;
94662306a36Sopenharmony_ci		csk->ctrlq_idx = cxgb4_port_idx(ndev);
94762306a36Sopenharmony_ci		csk->rss_qid = cdev->lldi.rxq_ids[
94862306a36Sopenharmony_ci				cxgb4_port_idx(ndev) * step];
94962306a36Sopenharmony_ci		csk->port_id = cxgb4_port_idx(ndev);
95062306a36Sopenharmony_ci		cxgbit_set_tcp_window(csk,
95162306a36Sopenharmony_ci				      (struct port_info *)netdev_priv(ndev));
95262306a36Sopenharmony_ci	} else {
95362306a36Sopenharmony_ci		ndev = cxgbit_get_real_dev(n->dev);
95462306a36Sopenharmony_ci		if (!ndev) {
95562306a36Sopenharmony_ci			ret = -ENODEV;
95662306a36Sopenharmony_ci			goto out;
95762306a36Sopenharmony_ci		}
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB
96062306a36Sopenharmony_ci		if (cxgbit_get_iscsi_dcb_state(ndev))
96162306a36Sopenharmony_ci			priority = cxgbit_get_iscsi_dcb_priority(ndev,
96262306a36Sopenharmony_ci								 local_port);
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci		csk->dcb_priority = priority;
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci		csk->l2t = cxgb4_l2t_get(cdev->lldi.l2t, n, ndev, priority);
96762306a36Sopenharmony_ci#else
96862306a36Sopenharmony_ci		csk->l2t = cxgb4_l2t_get(cdev->lldi.l2t, n, ndev, 0);
96962306a36Sopenharmony_ci#endif
97062306a36Sopenharmony_ci		if (!csk->l2t)
97162306a36Sopenharmony_ci			goto out;
97262306a36Sopenharmony_ci		port_id = cxgb4_port_idx(ndev);
97362306a36Sopenharmony_ci		csk->mtu = dst_mtu(dst);
97462306a36Sopenharmony_ci		csk->tx_chan = cxgb4_port_chan(ndev);
97562306a36Sopenharmony_ci		csk->smac_idx =
97662306a36Sopenharmony_ci			       ((struct port_info *)netdev_priv(ndev))->smt_idx;
97762306a36Sopenharmony_ci		step = cdev->lldi.ntxq /
97862306a36Sopenharmony_ci			cdev->lldi.nports;
97962306a36Sopenharmony_ci		csk->txq_idx = (port_id * step) +
98062306a36Sopenharmony_ci				(cdev->selectq[port_id][0]++ % step);
98162306a36Sopenharmony_ci		csk->ctrlq_idx = cxgb4_port_idx(ndev);
98262306a36Sopenharmony_ci		step = cdev->lldi.nrxq /
98362306a36Sopenharmony_ci			cdev->lldi.nports;
98462306a36Sopenharmony_ci		rxq_idx = (port_id * step) +
98562306a36Sopenharmony_ci				(cdev->selectq[port_id][1]++ % step);
98662306a36Sopenharmony_ci		csk->rss_qid = cdev->lldi.rxq_ids[rxq_idx];
98762306a36Sopenharmony_ci		csk->port_id = port_id;
98862306a36Sopenharmony_ci		cxgbit_set_tcp_window(csk,
98962306a36Sopenharmony_ci				      (struct port_info *)netdev_priv(ndev));
99062306a36Sopenharmony_ci	}
99162306a36Sopenharmony_ci	ret = 0;
99262306a36Sopenharmony_ciout:
99362306a36Sopenharmony_ci	rcu_read_unlock();
99462306a36Sopenharmony_ci	neigh_release(n);
99562306a36Sopenharmony_ci	return ret;
99662306a36Sopenharmony_ci}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ciint cxgbit_ofld_send(struct cxgbit_device *cdev, struct sk_buff *skb)
99962306a36Sopenharmony_ci{
100062306a36Sopenharmony_ci	int ret = 0;
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	if (!test_bit(CDEV_STATE_UP, &cdev->flags)) {
100362306a36Sopenharmony_ci		kfree_skb(skb);
100462306a36Sopenharmony_ci		pr_err("%s - device not up - dropping\n", __func__);
100562306a36Sopenharmony_ci		return -EIO;
100662306a36Sopenharmony_ci	}
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	ret = cxgb4_ofld_send(cdev->lldi.ports[0], skb);
100962306a36Sopenharmony_ci	if (ret < 0)
101062306a36Sopenharmony_ci		kfree_skb(skb);
101162306a36Sopenharmony_ci	return ret < 0 ? ret : 0;
101262306a36Sopenharmony_ci}
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_cistatic void cxgbit_release_tid(struct cxgbit_device *cdev, u32 tid)
101562306a36Sopenharmony_ci{
101662306a36Sopenharmony_ci	u32 len = roundup(sizeof(struct cpl_tid_release), 16);
101762306a36Sopenharmony_ci	struct sk_buff *skb;
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	skb = alloc_skb(len, GFP_ATOMIC);
102062306a36Sopenharmony_ci	if (!skb)
102162306a36Sopenharmony_ci		return;
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	cxgb_mk_tid_release(skb, len, tid, 0);
102462306a36Sopenharmony_ci	cxgbit_ofld_send(cdev, skb);
102562306a36Sopenharmony_ci}
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ciint
102862306a36Sopenharmony_cicxgbit_l2t_send(struct cxgbit_device *cdev, struct sk_buff *skb,
102962306a36Sopenharmony_ci		struct l2t_entry *l2e)
103062306a36Sopenharmony_ci{
103162306a36Sopenharmony_ci	int ret = 0;
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	if (!test_bit(CDEV_STATE_UP, &cdev->flags)) {
103462306a36Sopenharmony_ci		kfree_skb(skb);
103562306a36Sopenharmony_ci		pr_err("%s - device not up - dropping\n", __func__);
103662306a36Sopenharmony_ci		return -EIO;
103762306a36Sopenharmony_ci	}
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	ret = cxgb4_l2t_send(cdev->lldi.ports[0], skb, l2e);
104062306a36Sopenharmony_ci	if (ret < 0)
104162306a36Sopenharmony_ci		kfree_skb(skb);
104262306a36Sopenharmony_ci	return ret < 0 ? ret : 0;
104362306a36Sopenharmony_ci}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_cistatic void cxgbit_send_rx_credits(struct cxgbit_sock *csk, struct sk_buff *skb)
104662306a36Sopenharmony_ci{
104762306a36Sopenharmony_ci	if (csk->com.state != CSK_STATE_ESTABLISHED) {
104862306a36Sopenharmony_ci		__kfree_skb(skb);
104962306a36Sopenharmony_ci		return;
105062306a36Sopenharmony_ci	}
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	cxgbit_ofld_send(csk->com.cdev, skb);
105362306a36Sopenharmony_ci}
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci/*
105662306a36Sopenharmony_ci * CPL connection rx data ack: host ->
105762306a36Sopenharmony_ci * Send RX credits through an RX_DATA_ACK CPL message.
105862306a36Sopenharmony_ci * Returns the number of credits sent.
105962306a36Sopenharmony_ci */
106062306a36Sopenharmony_ciint cxgbit_rx_data_ack(struct cxgbit_sock *csk)
106162306a36Sopenharmony_ci{
106262306a36Sopenharmony_ci	struct sk_buff *skb;
106362306a36Sopenharmony_ci	u32 len = roundup(sizeof(struct cpl_rx_data_ack), 16);
106462306a36Sopenharmony_ci	u32 credit_dack;
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	skb = alloc_skb(len, GFP_KERNEL);
106762306a36Sopenharmony_ci	if (!skb)
106862306a36Sopenharmony_ci		return -1;
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	credit_dack = RX_DACK_CHANGE_F | RX_DACK_MODE_V(3) |
107162306a36Sopenharmony_ci		      RX_CREDITS_V(csk->rx_credits);
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	cxgb_mk_rx_data_ack(skb, len, csk->tid, csk->ctrlq_idx,
107462306a36Sopenharmony_ci			    credit_dack);
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	csk->rx_credits = 0;
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	spin_lock_bh(&csk->lock);
107962306a36Sopenharmony_ci	if (csk->lock_owner) {
108062306a36Sopenharmony_ci		cxgbit_skcb_rx_backlog_fn(skb) = cxgbit_send_rx_credits;
108162306a36Sopenharmony_ci		__skb_queue_tail(&csk->backlogq, skb);
108262306a36Sopenharmony_ci		spin_unlock_bh(&csk->lock);
108362306a36Sopenharmony_ci		return 0;
108462306a36Sopenharmony_ci	}
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	cxgbit_send_rx_credits(csk, skb);
108762306a36Sopenharmony_ci	spin_unlock_bh(&csk->lock);
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	return 0;
109062306a36Sopenharmony_ci}
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci#define FLOWC_WR_NPARAMS_MIN    9
109362306a36Sopenharmony_ci#define FLOWC_WR_NPARAMS_MAX	11
109462306a36Sopenharmony_cistatic int cxgbit_alloc_csk_skb(struct cxgbit_sock *csk)
109562306a36Sopenharmony_ci{
109662306a36Sopenharmony_ci	struct sk_buff *skb;
109762306a36Sopenharmony_ci	u32 len, flowclen;
109862306a36Sopenharmony_ci	u8 i;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	flowclen = offsetof(struct fw_flowc_wr,
110162306a36Sopenharmony_ci			    mnemval[FLOWC_WR_NPARAMS_MAX]);
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	len = max_t(u32, sizeof(struct cpl_abort_req),
110462306a36Sopenharmony_ci		    sizeof(struct cpl_abort_rpl));
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	len = max(len, flowclen);
110762306a36Sopenharmony_ci	len = roundup(len, 16);
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	for (i = 0; i < 3; i++) {
111062306a36Sopenharmony_ci		skb = alloc_skb(len, GFP_ATOMIC);
111162306a36Sopenharmony_ci		if (!skb)
111262306a36Sopenharmony_ci			goto out;
111362306a36Sopenharmony_ci		__skb_queue_tail(&csk->skbq, skb);
111462306a36Sopenharmony_ci	}
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	skb = alloc_skb(LRO_SKB_MIN_HEADROOM, GFP_ATOMIC);
111762306a36Sopenharmony_ci	if (!skb)
111862306a36Sopenharmony_ci		goto out;
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	memset(skb->data, 0, LRO_SKB_MIN_HEADROOM);
112162306a36Sopenharmony_ci	csk->lro_hskb = skb;
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	return 0;
112462306a36Sopenharmony_ciout:
112562306a36Sopenharmony_ci	__skb_queue_purge(&csk->skbq);
112662306a36Sopenharmony_ci	return -ENOMEM;
112762306a36Sopenharmony_ci}
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_cistatic void
113062306a36Sopenharmony_cicxgbit_pass_accept_rpl(struct cxgbit_sock *csk, struct cpl_pass_accept_req *req)
113162306a36Sopenharmony_ci{
113262306a36Sopenharmony_ci	struct sk_buff *skb;
113362306a36Sopenharmony_ci	const struct tcphdr *tcph;
113462306a36Sopenharmony_ci	struct cpl_t5_pass_accept_rpl *rpl5;
113562306a36Sopenharmony_ci	struct cxgb4_lld_info *lldi = &csk->com.cdev->lldi;
113662306a36Sopenharmony_ci	unsigned int len = roundup(sizeof(*rpl5), 16);
113762306a36Sopenharmony_ci	unsigned int mtu_idx;
113862306a36Sopenharmony_ci	u64 opt0;
113962306a36Sopenharmony_ci	u32 opt2, hlen;
114062306a36Sopenharmony_ci	u32 wscale;
114162306a36Sopenharmony_ci	u32 win;
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	pr_debug("%s csk %p tid %u\n", __func__, csk, csk->tid);
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	skb = alloc_skb(len, GFP_ATOMIC);
114662306a36Sopenharmony_ci	if (!skb) {
114762306a36Sopenharmony_ci		cxgbit_put_csk(csk);
114862306a36Sopenharmony_ci		return;
114962306a36Sopenharmony_ci	}
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	rpl5 = __skb_put_zero(skb, len);
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	INIT_TP_WR(rpl5, csk->tid);
115462306a36Sopenharmony_ci	OPCODE_TID(rpl5) = cpu_to_be32(MK_OPCODE_TID(CPL_PASS_ACCEPT_RPL,
115562306a36Sopenharmony_ci						     csk->tid));
115662306a36Sopenharmony_ci	cxgb_best_mtu(csk->com.cdev->lldi.mtus, csk->mtu, &mtu_idx,
115762306a36Sopenharmony_ci		      req->tcpopt.tstamp,
115862306a36Sopenharmony_ci		      (csk->com.remote_addr.ss_family == AF_INET) ? 0 : 1);
115962306a36Sopenharmony_ci	wscale = cxgb_compute_wscale(csk->rcv_win);
116062306a36Sopenharmony_ci	/*
116162306a36Sopenharmony_ci	 * Specify the largest window that will fit in opt0. The
116262306a36Sopenharmony_ci	 * remainder will be specified in the rx_data_ack.
116362306a36Sopenharmony_ci	 */
116462306a36Sopenharmony_ci	win = csk->rcv_win >> 10;
116562306a36Sopenharmony_ci	if (win > RCV_BUFSIZ_M)
116662306a36Sopenharmony_ci		win = RCV_BUFSIZ_M;
116762306a36Sopenharmony_ci	opt0 =  TCAM_BYPASS_F |
116862306a36Sopenharmony_ci		WND_SCALE_V(wscale) |
116962306a36Sopenharmony_ci		MSS_IDX_V(mtu_idx) |
117062306a36Sopenharmony_ci		L2T_IDX_V(csk->l2t->idx) |
117162306a36Sopenharmony_ci		TX_CHAN_V(csk->tx_chan) |
117262306a36Sopenharmony_ci		SMAC_SEL_V(csk->smac_idx) |
117362306a36Sopenharmony_ci		DSCP_V(csk->tos >> 2) |
117462306a36Sopenharmony_ci		ULP_MODE_V(ULP_MODE_ISCSI) |
117562306a36Sopenharmony_ci		RCV_BUFSIZ_V(win);
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	opt2 = RX_CHANNEL_V(0) |
117862306a36Sopenharmony_ci		RSS_QUEUE_VALID_F | RSS_QUEUE_V(csk->rss_qid);
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	if (!is_t5(lldi->adapter_type))
118162306a36Sopenharmony_ci		opt2 |= RX_FC_DISABLE_F;
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	if (req->tcpopt.tstamp)
118462306a36Sopenharmony_ci		opt2 |= TSTAMPS_EN_F;
118562306a36Sopenharmony_ci	if (req->tcpopt.sack)
118662306a36Sopenharmony_ci		opt2 |= SACK_EN_F;
118762306a36Sopenharmony_ci	if (wscale)
118862306a36Sopenharmony_ci		opt2 |= WND_SCALE_EN_F;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	hlen = ntohl(req->hdr_len);
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	if (is_t5(lldi->adapter_type))
119362306a36Sopenharmony_ci		tcph = (struct tcphdr *)((u8 *)(req + 1) +
119462306a36Sopenharmony_ci		       ETH_HDR_LEN_G(hlen) + IP_HDR_LEN_G(hlen));
119562306a36Sopenharmony_ci	else
119662306a36Sopenharmony_ci		tcph = (struct tcphdr *)((u8 *)(req + 1) +
119762306a36Sopenharmony_ci		       T6_ETH_HDR_LEN_G(hlen) + T6_IP_HDR_LEN_G(hlen));
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	if (tcph->ece && tcph->cwr)
120062306a36Sopenharmony_ci		opt2 |= CCTRL_ECN_V(1);
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	opt2 |= CONG_CNTRL_V(CONG_ALG_NEWRENO);
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	opt2 |= T5_ISS_F;
120562306a36Sopenharmony_ci	rpl5->iss = cpu_to_be32((get_random_u32() & ~7UL) - 1);
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	opt2 |= T5_OPT_2_VALID_F;
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	rpl5->opt0 = cpu_to_be64(opt0);
121062306a36Sopenharmony_ci	rpl5->opt2 = cpu_to_be32(opt2);
121162306a36Sopenharmony_ci	set_wr_txq(skb, CPL_PRIORITY_SETUP, csk->ctrlq_idx);
121262306a36Sopenharmony_ci	t4_set_arp_err_handler(skb, csk, cxgbit_arp_failure_discard);
121362306a36Sopenharmony_ci	cxgbit_l2t_send(csk->com.cdev, skb, csk->l2t);
121462306a36Sopenharmony_ci}
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_cistatic void
121762306a36Sopenharmony_cicxgbit_pass_accept_req(struct cxgbit_device *cdev, struct sk_buff *skb)
121862306a36Sopenharmony_ci{
121962306a36Sopenharmony_ci	struct cxgbit_sock *csk = NULL;
122062306a36Sopenharmony_ci	struct cxgbit_np *cnp;
122162306a36Sopenharmony_ci	struct cpl_pass_accept_req *req = cplhdr(skb);
122262306a36Sopenharmony_ci	unsigned int stid = PASS_OPEN_TID_G(ntohl(req->tos_stid));
122362306a36Sopenharmony_ci	struct tid_info *t = cdev->lldi.tids;
122462306a36Sopenharmony_ci	unsigned int tid = GET_TID(req);
122562306a36Sopenharmony_ci	u16 peer_mss = ntohs(req->tcpopt.mss);
122662306a36Sopenharmony_ci	unsigned short hdrs;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	struct dst_entry *dst;
122962306a36Sopenharmony_ci	__u8 local_ip[16], peer_ip[16];
123062306a36Sopenharmony_ci	__be16 local_port, peer_port;
123162306a36Sopenharmony_ci	int ret;
123262306a36Sopenharmony_ci	int iptype;
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	pr_debug("%s: cdev = %p; stid = %u; tid = %u\n",
123562306a36Sopenharmony_ci		 __func__, cdev, stid, tid);
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	cnp = lookup_stid(t, stid);
123862306a36Sopenharmony_ci	if (!cnp) {
123962306a36Sopenharmony_ci		pr_err("%s connect request on invalid stid %d\n",
124062306a36Sopenharmony_ci		       __func__, stid);
124162306a36Sopenharmony_ci		goto rel_skb;
124262306a36Sopenharmony_ci	}
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	if (cnp->com.state != CSK_STATE_LISTEN) {
124562306a36Sopenharmony_ci		pr_err("%s - listening parent not in CSK_STATE_LISTEN\n",
124662306a36Sopenharmony_ci		       __func__);
124762306a36Sopenharmony_ci		goto reject;
124862306a36Sopenharmony_ci	}
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	csk = lookup_tid(t, tid);
125162306a36Sopenharmony_ci	if (csk) {
125262306a36Sopenharmony_ci		pr_err("%s csk not null tid %u\n",
125362306a36Sopenharmony_ci		       __func__, tid);
125462306a36Sopenharmony_ci		goto rel_skb;
125562306a36Sopenharmony_ci	}
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	cxgb_get_4tuple(req, cdev->lldi.adapter_type, &iptype, local_ip,
125862306a36Sopenharmony_ci			peer_ip, &local_port, &peer_port);
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	/* Find output route */
126162306a36Sopenharmony_ci	if (iptype == 4)  {
126262306a36Sopenharmony_ci		pr_debug("%s parent sock %p tid %u laddr %pI4 raddr %pI4 "
126362306a36Sopenharmony_ci			 "lport %d rport %d peer_mss %d\n"
126462306a36Sopenharmony_ci			 , __func__, cnp, tid,
126562306a36Sopenharmony_ci			 local_ip, peer_ip, ntohs(local_port),
126662306a36Sopenharmony_ci			 ntohs(peer_port), peer_mss);
126762306a36Sopenharmony_ci		dst = cxgb_find_route(&cdev->lldi, cxgbit_get_real_dev,
126862306a36Sopenharmony_ci				      *(__be32 *)local_ip,
126962306a36Sopenharmony_ci				      *(__be32 *)peer_ip,
127062306a36Sopenharmony_ci				      local_port, peer_port,
127162306a36Sopenharmony_ci				      PASS_OPEN_TOS_G(ntohl(req->tos_stid)));
127262306a36Sopenharmony_ci	} else {
127362306a36Sopenharmony_ci		pr_debug("%s parent sock %p tid %u laddr %pI6 raddr %pI6 "
127462306a36Sopenharmony_ci			 "lport %d rport %d peer_mss %d\n"
127562306a36Sopenharmony_ci			 , __func__, cnp, tid,
127662306a36Sopenharmony_ci			 local_ip, peer_ip, ntohs(local_port),
127762306a36Sopenharmony_ci			 ntohs(peer_port), peer_mss);
127862306a36Sopenharmony_ci		dst = cxgb_find_route6(&cdev->lldi, cxgbit_get_real_dev,
127962306a36Sopenharmony_ci				       local_ip, peer_ip,
128062306a36Sopenharmony_ci				       local_port, peer_port,
128162306a36Sopenharmony_ci				       PASS_OPEN_TOS_G(ntohl(req->tos_stid)),
128262306a36Sopenharmony_ci				       ((struct sockaddr_in6 *)
128362306a36Sopenharmony_ci					&cnp->com.local_addr)->sin6_scope_id);
128462306a36Sopenharmony_ci	}
128562306a36Sopenharmony_ci	if (!dst) {
128662306a36Sopenharmony_ci		pr_err("%s - failed to find dst entry!\n",
128762306a36Sopenharmony_ci		       __func__);
128862306a36Sopenharmony_ci		goto reject;
128962306a36Sopenharmony_ci	}
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	csk = kzalloc(sizeof(*csk), GFP_ATOMIC);
129262306a36Sopenharmony_ci	if (!csk) {
129362306a36Sopenharmony_ci		dst_release(dst);
129462306a36Sopenharmony_ci		goto rel_skb;
129562306a36Sopenharmony_ci	}
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	ret = cxgbit_offload_init(csk, iptype, peer_ip, ntohs(local_port),
129862306a36Sopenharmony_ci				  dst, cdev);
129962306a36Sopenharmony_ci	if (ret) {
130062306a36Sopenharmony_ci		pr_err("%s - failed to allocate l2t entry!\n",
130162306a36Sopenharmony_ci		       __func__);
130262306a36Sopenharmony_ci		dst_release(dst);
130362306a36Sopenharmony_ci		kfree(csk);
130462306a36Sopenharmony_ci		goto reject;
130562306a36Sopenharmony_ci	}
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	kref_init(&csk->kref);
130862306a36Sopenharmony_ci	init_completion(&csk->com.wr_wait.completion);
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	INIT_LIST_HEAD(&csk->accept_node);
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	hdrs = (iptype == 4 ? sizeof(struct iphdr) : sizeof(struct ipv6hdr)) +
131362306a36Sopenharmony_ci		sizeof(struct tcphdr) +	(req->tcpopt.tstamp ? 12 : 0);
131462306a36Sopenharmony_ci	if (peer_mss && csk->mtu > (peer_mss + hdrs))
131562306a36Sopenharmony_ci		csk->mtu = peer_mss + hdrs;
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	csk->com.state = CSK_STATE_CONNECTING;
131862306a36Sopenharmony_ci	csk->com.cdev = cdev;
131962306a36Sopenharmony_ci	csk->cnp = cnp;
132062306a36Sopenharmony_ci	csk->tos = PASS_OPEN_TOS_G(ntohl(req->tos_stid));
132162306a36Sopenharmony_ci	csk->dst = dst;
132262306a36Sopenharmony_ci	csk->tid = tid;
132362306a36Sopenharmony_ci	csk->wr_cred = cdev->lldi.wr_cred -
132462306a36Sopenharmony_ci			DIV_ROUND_UP(sizeof(struct cpl_abort_req), 16);
132562306a36Sopenharmony_ci	csk->wr_max_cred = csk->wr_cred;
132662306a36Sopenharmony_ci	csk->wr_una_cred = 0;
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	if (iptype == 4) {
132962306a36Sopenharmony_ci		struct sockaddr_in *sin = (struct sockaddr_in *)
133062306a36Sopenharmony_ci					  &csk->com.local_addr;
133162306a36Sopenharmony_ci		sin->sin_family = AF_INET;
133262306a36Sopenharmony_ci		sin->sin_port = local_port;
133362306a36Sopenharmony_ci		sin->sin_addr.s_addr = *(__be32 *)local_ip;
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci		sin = (struct sockaddr_in *)&csk->com.remote_addr;
133662306a36Sopenharmony_ci		sin->sin_family = AF_INET;
133762306a36Sopenharmony_ci		sin->sin_port = peer_port;
133862306a36Sopenharmony_ci		sin->sin_addr.s_addr = *(__be32 *)peer_ip;
133962306a36Sopenharmony_ci	} else {
134062306a36Sopenharmony_ci		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)
134162306a36Sopenharmony_ci					    &csk->com.local_addr;
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci		sin6->sin6_family = PF_INET6;
134462306a36Sopenharmony_ci		sin6->sin6_port = local_port;
134562306a36Sopenharmony_ci		memcpy(sin6->sin6_addr.s6_addr, local_ip, 16);
134662306a36Sopenharmony_ci		cxgb4_clip_get(cdev->lldi.ports[0],
134762306a36Sopenharmony_ci			       (const u32 *)&sin6->sin6_addr.s6_addr,
134862306a36Sopenharmony_ci			       1);
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci		sin6 = (struct sockaddr_in6 *)&csk->com.remote_addr;
135162306a36Sopenharmony_ci		sin6->sin6_family = PF_INET6;
135262306a36Sopenharmony_ci		sin6->sin6_port = peer_port;
135362306a36Sopenharmony_ci		memcpy(sin6->sin6_addr.s6_addr, peer_ip, 16);
135462306a36Sopenharmony_ci	}
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	skb_queue_head_init(&csk->rxq);
135762306a36Sopenharmony_ci	skb_queue_head_init(&csk->txq);
135862306a36Sopenharmony_ci	skb_queue_head_init(&csk->ppodq);
135962306a36Sopenharmony_ci	skb_queue_head_init(&csk->backlogq);
136062306a36Sopenharmony_ci	skb_queue_head_init(&csk->skbq);
136162306a36Sopenharmony_ci	cxgbit_sock_reset_wr_list(csk);
136262306a36Sopenharmony_ci	spin_lock_init(&csk->lock);
136362306a36Sopenharmony_ci	init_waitqueue_head(&csk->waitq);
136462306a36Sopenharmony_ci	csk->lock_owner = false;
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	if (cxgbit_alloc_csk_skb(csk)) {
136762306a36Sopenharmony_ci		dst_release(dst);
136862306a36Sopenharmony_ci		kfree(csk);
136962306a36Sopenharmony_ci		goto rel_skb;
137062306a36Sopenharmony_ci	}
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	cxgbit_get_cnp(cnp);
137362306a36Sopenharmony_ci	cxgbit_get_cdev(cdev);
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	spin_lock(&cdev->cskq.lock);
137662306a36Sopenharmony_ci	list_add_tail(&csk->list, &cdev->cskq.list);
137762306a36Sopenharmony_ci	spin_unlock(&cdev->cskq.lock);
137862306a36Sopenharmony_ci	cxgb4_insert_tid(t, csk, tid, csk->com.local_addr.ss_family);
137962306a36Sopenharmony_ci	cxgbit_pass_accept_rpl(csk, req);
138062306a36Sopenharmony_ci	goto rel_skb;
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_cireject:
138362306a36Sopenharmony_ci	cxgbit_release_tid(cdev, tid);
138462306a36Sopenharmony_cirel_skb:
138562306a36Sopenharmony_ci	__kfree_skb(skb);
138662306a36Sopenharmony_ci}
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_cistatic u32
138962306a36Sopenharmony_cicxgbit_tx_flowc_wr_credits(struct cxgbit_sock *csk, u32 *nparamsp,
139062306a36Sopenharmony_ci			   u32 *flowclenp)
139162306a36Sopenharmony_ci{
139262306a36Sopenharmony_ci	u32 nparams, flowclen16, flowclen;
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	nparams = FLOWC_WR_NPARAMS_MIN;
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	if (csk->snd_wscale)
139762306a36Sopenharmony_ci		nparams++;
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB
140062306a36Sopenharmony_ci	nparams++;
140162306a36Sopenharmony_ci#endif
140262306a36Sopenharmony_ci	flowclen = offsetof(struct fw_flowc_wr, mnemval[nparams]);
140362306a36Sopenharmony_ci	flowclen16 = DIV_ROUND_UP(flowclen, 16);
140462306a36Sopenharmony_ci	flowclen = flowclen16 * 16;
140562306a36Sopenharmony_ci	/*
140662306a36Sopenharmony_ci	 * Return the number of 16-byte credits used by the flowc request.
140762306a36Sopenharmony_ci	 * Pass back the nparams and actual flowc length if requested.
140862306a36Sopenharmony_ci	 */
140962306a36Sopenharmony_ci	if (nparamsp)
141062306a36Sopenharmony_ci		*nparamsp = nparams;
141162306a36Sopenharmony_ci	if (flowclenp)
141262306a36Sopenharmony_ci		*flowclenp = flowclen;
141362306a36Sopenharmony_ci	return flowclen16;
141462306a36Sopenharmony_ci}
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ciu32 cxgbit_send_tx_flowc_wr(struct cxgbit_sock *csk)
141762306a36Sopenharmony_ci{
141862306a36Sopenharmony_ci	struct cxgbit_device *cdev = csk->com.cdev;
141962306a36Sopenharmony_ci	struct fw_flowc_wr *flowc;
142062306a36Sopenharmony_ci	u32 nparams, flowclen16, flowclen;
142162306a36Sopenharmony_ci	struct sk_buff *skb;
142262306a36Sopenharmony_ci	u8 index;
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB
142562306a36Sopenharmony_ci	u16 vlan = ((struct l2t_entry *)csk->l2t)->vlan;
142662306a36Sopenharmony_ci#endif
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci	flowclen16 = cxgbit_tx_flowc_wr_credits(csk, &nparams, &flowclen);
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci	skb = __skb_dequeue(&csk->skbq);
143162306a36Sopenharmony_ci	flowc = __skb_put_zero(skb, flowclen);
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci	flowc->op_to_nparams = cpu_to_be32(FW_WR_OP_V(FW_FLOWC_WR) |
143462306a36Sopenharmony_ci					   FW_FLOWC_WR_NPARAMS_V(nparams));
143562306a36Sopenharmony_ci	flowc->flowid_len16 = cpu_to_be32(FW_WR_LEN16_V(flowclen16) |
143662306a36Sopenharmony_ci					  FW_WR_FLOWID_V(csk->tid));
143762306a36Sopenharmony_ci	flowc->mnemval[0].mnemonic = FW_FLOWC_MNEM_PFNVFN;
143862306a36Sopenharmony_ci	flowc->mnemval[0].val = cpu_to_be32(FW_PFVF_CMD_PFN_V
143962306a36Sopenharmony_ci					    (csk->com.cdev->lldi.pf));
144062306a36Sopenharmony_ci	flowc->mnemval[1].mnemonic = FW_FLOWC_MNEM_CH;
144162306a36Sopenharmony_ci	flowc->mnemval[1].val = cpu_to_be32(csk->tx_chan);
144262306a36Sopenharmony_ci	flowc->mnemval[2].mnemonic = FW_FLOWC_MNEM_PORT;
144362306a36Sopenharmony_ci	flowc->mnemval[2].val = cpu_to_be32(csk->tx_chan);
144462306a36Sopenharmony_ci	flowc->mnemval[3].mnemonic = FW_FLOWC_MNEM_IQID;
144562306a36Sopenharmony_ci	flowc->mnemval[3].val = cpu_to_be32(csk->rss_qid);
144662306a36Sopenharmony_ci	flowc->mnemval[4].mnemonic = FW_FLOWC_MNEM_SNDNXT;
144762306a36Sopenharmony_ci	flowc->mnemval[4].val = cpu_to_be32(csk->snd_nxt);
144862306a36Sopenharmony_ci	flowc->mnemval[5].mnemonic = FW_FLOWC_MNEM_RCVNXT;
144962306a36Sopenharmony_ci	flowc->mnemval[5].val = cpu_to_be32(csk->rcv_nxt);
145062306a36Sopenharmony_ci	flowc->mnemval[6].mnemonic = FW_FLOWC_MNEM_SNDBUF;
145162306a36Sopenharmony_ci	flowc->mnemval[6].val = cpu_to_be32(csk->snd_win);
145262306a36Sopenharmony_ci	flowc->mnemval[7].mnemonic = FW_FLOWC_MNEM_MSS;
145362306a36Sopenharmony_ci	flowc->mnemval[7].val = cpu_to_be32(csk->emss);
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	flowc->mnemval[8].mnemonic = FW_FLOWC_MNEM_TXDATAPLEN_MAX;
145662306a36Sopenharmony_ci	if (test_bit(CDEV_ISO_ENABLE, &cdev->flags))
145762306a36Sopenharmony_ci		flowc->mnemval[8].val = cpu_to_be32(CXGBIT_MAX_ISO_PAYLOAD);
145862306a36Sopenharmony_ci	else
145962306a36Sopenharmony_ci		flowc->mnemval[8].val = cpu_to_be32(16384);
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	index = 9;
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	if (csk->snd_wscale) {
146462306a36Sopenharmony_ci		flowc->mnemval[index].mnemonic = FW_FLOWC_MNEM_RCV_SCALE;
146562306a36Sopenharmony_ci		flowc->mnemval[index].val = cpu_to_be32(csk->snd_wscale);
146662306a36Sopenharmony_ci		index++;
146762306a36Sopenharmony_ci	}
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB
147062306a36Sopenharmony_ci	flowc->mnemval[index].mnemonic = FW_FLOWC_MNEM_DCBPRIO;
147162306a36Sopenharmony_ci	if (vlan == VLAN_NONE) {
147262306a36Sopenharmony_ci		pr_warn("csk %u without VLAN Tag on DCB Link\n", csk->tid);
147362306a36Sopenharmony_ci		flowc->mnemval[index].val = cpu_to_be32(0);
147462306a36Sopenharmony_ci	} else
147562306a36Sopenharmony_ci		flowc->mnemval[index].val = cpu_to_be32(
147662306a36Sopenharmony_ci				(vlan & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT);
147762306a36Sopenharmony_ci#endif
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	pr_debug("%s: csk %p; tx_chan = %u; rss_qid = %u; snd_seq = %u;"
148062306a36Sopenharmony_ci		 " rcv_seq = %u; snd_win = %u; emss = %u\n",
148162306a36Sopenharmony_ci		 __func__, csk, csk->tx_chan, csk->rss_qid, csk->snd_nxt,
148262306a36Sopenharmony_ci		 csk->rcv_nxt, csk->snd_win, csk->emss);
148362306a36Sopenharmony_ci	set_wr_txq(skb, CPL_PRIORITY_DATA, csk->txq_idx);
148462306a36Sopenharmony_ci	cxgbit_ofld_send(csk->com.cdev, skb);
148562306a36Sopenharmony_ci	return flowclen16;
148662306a36Sopenharmony_ci}
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_cistatic int
148962306a36Sopenharmony_cicxgbit_send_tcb_skb(struct cxgbit_sock *csk, struct sk_buff *skb)
149062306a36Sopenharmony_ci{
149162306a36Sopenharmony_ci	spin_lock_bh(&csk->lock);
149262306a36Sopenharmony_ci	if (unlikely(csk->com.state != CSK_STATE_ESTABLISHED)) {
149362306a36Sopenharmony_ci		spin_unlock_bh(&csk->lock);
149462306a36Sopenharmony_ci		pr_err("%s: csk 0x%p, tid %u, state %u\n",
149562306a36Sopenharmony_ci		       __func__, csk, csk->tid, csk->com.state);
149662306a36Sopenharmony_ci		__kfree_skb(skb);
149762306a36Sopenharmony_ci		return -1;
149862306a36Sopenharmony_ci	}
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	cxgbit_get_csk(csk);
150162306a36Sopenharmony_ci	cxgbit_init_wr_wait(&csk->com.wr_wait);
150262306a36Sopenharmony_ci	cxgbit_ofld_send(csk->com.cdev, skb);
150362306a36Sopenharmony_ci	spin_unlock_bh(&csk->lock);
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	return 0;
150662306a36Sopenharmony_ci}
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ciint cxgbit_setup_conn_digest(struct cxgbit_sock *csk)
150962306a36Sopenharmony_ci{
151062306a36Sopenharmony_ci	struct sk_buff *skb;
151162306a36Sopenharmony_ci	struct cpl_set_tcb_field *req;
151262306a36Sopenharmony_ci	u8 hcrc = csk->submode & CXGBIT_SUBMODE_HCRC;
151362306a36Sopenharmony_ci	u8 dcrc = csk->submode & CXGBIT_SUBMODE_DCRC;
151462306a36Sopenharmony_ci	unsigned int len = roundup(sizeof(*req), 16);
151562306a36Sopenharmony_ci	int ret;
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	skb = alloc_skb(len, GFP_KERNEL);
151862306a36Sopenharmony_ci	if (!skb)
151962306a36Sopenharmony_ci		return -ENOMEM;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	/*  set up ulp submode */
152262306a36Sopenharmony_ci	req = __skb_put_zero(skb, len);
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	INIT_TP_WR(req, csk->tid);
152562306a36Sopenharmony_ci	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, csk->tid));
152662306a36Sopenharmony_ci	req->reply_ctrl = htons(NO_REPLY_V(0) | QUEUENO_V(csk->rss_qid));
152762306a36Sopenharmony_ci	req->word_cookie = htons(0);
152862306a36Sopenharmony_ci	req->mask = cpu_to_be64(0x3 << 4);
152962306a36Sopenharmony_ci	req->val = cpu_to_be64(((hcrc ? ULP_CRC_HEADER : 0) |
153062306a36Sopenharmony_ci				(dcrc ? ULP_CRC_DATA : 0)) << 4);
153162306a36Sopenharmony_ci	set_wr_txq(skb, CPL_PRIORITY_CONTROL, csk->ctrlq_idx);
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	if (cxgbit_send_tcb_skb(csk, skb))
153462306a36Sopenharmony_ci		return -1;
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci	ret = cxgbit_wait_for_reply(csk->com.cdev,
153762306a36Sopenharmony_ci				    &csk->com.wr_wait,
153862306a36Sopenharmony_ci				    csk->tid, 5, __func__);
153962306a36Sopenharmony_ci	if (ret)
154062306a36Sopenharmony_ci		return -1;
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	return 0;
154362306a36Sopenharmony_ci}
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ciint cxgbit_setup_conn_pgidx(struct cxgbit_sock *csk, u32 pg_idx)
154662306a36Sopenharmony_ci{
154762306a36Sopenharmony_ci	struct sk_buff *skb;
154862306a36Sopenharmony_ci	struct cpl_set_tcb_field *req;
154962306a36Sopenharmony_ci	unsigned int len = roundup(sizeof(*req), 16);
155062306a36Sopenharmony_ci	int ret;
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	skb = alloc_skb(len, GFP_KERNEL);
155362306a36Sopenharmony_ci	if (!skb)
155462306a36Sopenharmony_ci		return -ENOMEM;
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	req = __skb_put_zero(skb, len);
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	INIT_TP_WR(req, csk->tid);
155962306a36Sopenharmony_ci	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, csk->tid));
156062306a36Sopenharmony_ci	req->reply_ctrl = htons(NO_REPLY_V(0) | QUEUENO_V(csk->rss_qid));
156162306a36Sopenharmony_ci	req->word_cookie = htons(0);
156262306a36Sopenharmony_ci	req->mask = cpu_to_be64(0x3 << 8);
156362306a36Sopenharmony_ci	req->val = cpu_to_be64(pg_idx << 8);
156462306a36Sopenharmony_ci	set_wr_txq(skb, CPL_PRIORITY_CONTROL, csk->ctrlq_idx);
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	if (cxgbit_send_tcb_skb(csk, skb))
156762306a36Sopenharmony_ci		return -1;
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci	ret = cxgbit_wait_for_reply(csk->com.cdev,
157062306a36Sopenharmony_ci				    &csk->com.wr_wait,
157162306a36Sopenharmony_ci				    csk->tid, 5, __func__);
157262306a36Sopenharmony_ci	if (ret)
157362306a36Sopenharmony_ci		return -1;
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	return 0;
157662306a36Sopenharmony_ci}
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_cistatic void
157962306a36Sopenharmony_cicxgbit_pass_open_rpl(struct cxgbit_device *cdev, struct sk_buff *skb)
158062306a36Sopenharmony_ci{
158162306a36Sopenharmony_ci	struct cpl_pass_open_rpl *rpl = cplhdr(skb);
158262306a36Sopenharmony_ci	struct tid_info *t = cdev->lldi.tids;
158362306a36Sopenharmony_ci	unsigned int stid = GET_TID(rpl);
158462306a36Sopenharmony_ci	struct cxgbit_np *cnp = lookup_stid(t, stid);
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	pr_debug("%s: cnp = %p; stid = %u; status = %d\n",
158762306a36Sopenharmony_ci		 __func__, cnp, stid, rpl->status);
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	if (!cnp) {
159062306a36Sopenharmony_ci		pr_info("%s stid %d lookup failure\n", __func__, stid);
159162306a36Sopenharmony_ci		goto rel_skb;
159262306a36Sopenharmony_ci	}
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	cxgbit_wake_up(&cnp->com.wr_wait, __func__, rpl->status);
159562306a36Sopenharmony_ci	cxgbit_put_cnp(cnp);
159662306a36Sopenharmony_cirel_skb:
159762306a36Sopenharmony_ci	__kfree_skb(skb);
159862306a36Sopenharmony_ci}
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_cistatic void
160162306a36Sopenharmony_cicxgbit_close_listsrv_rpl(struct cxgbit_device *cdev, struct sk_buff *skb)
160262306a36Sopenharmony_ci{
160362306a36Sopenharmony_ci	struct cpl_close_listsvr_rpl *rpl = cplhdr(skb);
160462306a36Sopenharmony_ci	struct tid_info *t = cdev->lldi.tids;
160562306a36Sopenharmony_ci	unsigned int stid = GET_TID(rpl);
160662306a36Sopenharmony_ci	struct cxgbit_np *cnp = lookup_stid(t, stid);
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci	pr_debug("%s: cnp = %p; stid = %u; status = %d\n",
160962306a36Sopenharmony_ci		 __func__, cnp, stid, rpl->status);
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	if (!cnp) {
161262306a36Sopenharmony_ci		pr_info("%s stid %d lookup failure\n", __func__, stid);
161362306a36Sopenharmony_ci		goto rel_skb;
161462306a36Sopenharmony_ci	}
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci	cxgbit_wake_up(&cnp->com.wr_wait, __func__, rpl->status);
161762306a36Sopenharmony_ci	cxgbit_put_cnp(cnp);
161862306a36Sopenharmony_cirel_skb:
161962306a36Sopenharmony_ci	__kfree_skb(skb);
162062306a36Sopenharmony_ci}
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_cistatic void
162362306a36Sopenharmony_cicxgbit_pass_establish(struct cxgbit_device *cdev, struct sk_buff *skb)
162462306a36Sopenharmony_ci{
162562306a36Sopenharmony_ci	struct cpl_pass_establish *req = cplhdr(skb);
162662306a36Sopenharmony_ci	struct tid_info *t = cdev->lldi.tids;
162762306a36Sopenharmony_ci	unsigned int tid = GET_TID(req);
162862306a36Sopenharmony_ci	struct cxgbit_sock *csk;
162962306a36Sopenharmony_ci	struct cxgbit_np *cnp;
163062306a36Sopenharmony_ci	u16 tcp_opt = be16_to_cpu(req->tcp_opt);
163162306a36Sopenharmony_ci	u32 snd_isn = be32_to_cpu(req->snd_isn);
163262306a36Sopenharmony_ci	u32 rcv_isn = be32_to_cpu(req->rcv_isn);
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	csk = lookup_tid(t, tid);
163562306a36Sopenharmony_ci	if (unlikely(!csk)) {
163662306a36Sopenharmony_ci		pr_err("can't find connection for tid %u.\n", tid);
163762306a36Sopenharmony_ci		goto rel_skb;
163862306a36Sopenharmony_ci	}
163962306a36Sopenharmony_ci	cnp = csk->cnp;
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_ci	pr_debug("%s: csk %p; tid %u; cnp %p\n",
164262306a36Sopenharmony_ci		 __func__, csk, tid, cnp);
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci	csk->write_seq = snd_isn;
164562306a36Sopenharmony_ci	csk->snd_una = snd_isn;
164662306a36Sopenharmony_ci	csk->snd_nxt = snd_isn;
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	csk->rcv_nxt = rcv_isn;
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci	csk->snd_wscale = TCPOPT_SND_WSCALE_G(tcp_opt);
165162306a36Sopenharmony_ci	cxgbit_set_emss(csk, tcp_opt);
165262306a36Sopenharmony_ci	dst_confirm(csk->dst);
165362306a36Sopenharmony_ci	csk->com.state = CSK_STATE_ESTABLISHED;
165462306a36Sopenharmony_ci	spin_lock_bh(&cnp->np_accept_lock);
165562306a36Sopenharmony_ci	list_add_tail(&csk->accept_node, &cnp->np_accept_list);
165662306a36Sopenharmony_ci	spin_unlock_bh(&cnp->np_accept_lock);
165762306a36Sopenharmony_ci	complete(&cnp->accept_comp);
165862306a36Sopenharmony_cirel_skb:
165962306a36Sopenharmony_ci	__kfree_skb(skb);
166062306a36Sopenharmony_ci}
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_cistatic void cxgbit_queue_rx_skb(struct cxgbit_sock *csk, struct sk_buff *skb)
166362306a36Sopenharmony_ci{
166462306a36Sopenharmony_ci	cxgbit_skcb_flags(skb) = 0;
166562306a36Sopenharmony_ci	spin_lock_bh(&csk->rxq.lock);
166662306a36Sopenharmony_ci	__skb_queue_tail(&csk->rxq, skb);
166762306a36Sopenharmony_ci	spin_unlock_bh(&csk->rxq.lock);
166862306a36Sopenharmony_ci	wake_up(&csk->waitq);
166962306a36Sopenharmony_ci}
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_cistatic void cxgbit_peer_close(struct cxgbit_sock *csk, struct sk_buff *skb)
167262306a36Sopenharmony_ci{
167362306a36Sopenharmony_ci	pr_debug("%s: csk %p; tid %u; state %d\n",
167462306a36Sopenharmony_ci		 __func__, csk, csk->tid, csk->com.state);
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	switch (csk->com.state) {
167762306a36Sopenharmony_ci	case CSK_STATE_ESTABLISHED:
167862306a36Sopenharmony_ci		csk->com.state = CSK_STATE_CLOSING;
167962306a36Sopenharmony_ci		cxgbit_queue_rx_skb(csk, skb);
168062306a36Sopenharmony_ci		return;
168162306a36Sopenharmony_ci	case CSK_STATE_CLOSING:
168262306a36Sopenharmony_ci		/* simultaneous close */
168362306a36Sopenharmony_ci		csk->com.state = CSK_STATE_MORIBUND;
168462306a36Sopenharmony_ci		break;
168562306a36Sopenharmony_ci	case CSK_STATE_MORIBUND:
168662306a36Sopenharmony_ci		csk->com.state = CSK_STATE_DEAD;
168762306a36Sopenharmony_ci		cxgbit_put_csk(csk);
168862306a36Sopenharmony_ci		break;
168962306a36Sopenharmony_ci	case CSK_STATE_ABORTING:
169062306a36Sopenharmony_ci		break;
169162306a36Sopenharmony_ci	default:
169262306a36Sopenharmony_ci		pr_info("%s: cpl_peer_close in bad state %d\n",
169362306a36Sopenharmony_ci			__func__, csk->com.state);
169462306a36Sopenharmony_ci	}
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci	__kfree_skb(skb);
169762306a36Sopenharmony_ci}
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_cistatic void cxgbit_close_con_rpl(struct cxgbit_sock *csk, struct sk_buff *skb)
170062306a36Sopenharmony_ci{
170162306a36Sopenharmony_ci	pr_debug("%s: csk %p; tid %u; state %d\n",
170262306a36Sopenharmony_ci		 __func__, csk, csk->tid, csk->com.state);
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	switch (csk->com.state) {
170562306a36Sopenharmony_ci	case CSK_STATE_CLOSING:
170662306a36Sopenharmony_ci		csk->com.state = CSK_STATE_MORIBUND;
170762306a36Sopenharmony_ci		break;
170862306a36Sopenharmony_ci	case CSK_STATE_MORIBUND:
170962306a36Sopenharmony_ci		csk->com.state = CSK_STATE_DEAD;
171062306a36Sopenharmony_ci		cxgbit_put_csk(csk);
171162306a36Sopenharmony_ci		break;
171262306a36Sopenharmony_ci	case CSK_STATE_ABORTING:
171362306a36Sopenharmony_ci	case CSK_STATE_DEAD:
171462306a36Sopenharmony_ci		break;
171562306a36Sopenharmony_ci	default:
171662306a36Sopenharmony_ci		pr_info("%s: cpl_close_con_rpl in bad state %d\n",
171762306a36Sopenharmony_ci			__func__, csk->com.state);
171862306a36Sopenharmony_ci	}
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci	__kfree_skb(skb);
172162306a36Sopenharmony_ci}
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_cistatic void cxgbit_abort_req_rss(struct cxgbit_sock *csk, struct sk_buff *skb)
172462306a36Sopenharmony_ci{
172562306a36Sopenharmony_ci	struct cpl_abort_req_rss *hdr = cplhdr(skb);
172662306a36Sopenharmony_ci	unsigned int tid = GET_TID(hdr);
172762306a36Sopenharmony_ci	struct sk_buff *rpl_skb;
172862306a36Sopenharmony_ci	bool release = false;
172962306a36Sopenharmony_ci	bool wakeup_thread = false;
173062306a36Sopenharmony_ci	u32 len = roundup(sizeof(struct cpl_abort_rpl), 16);
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	pr_debug("%s: csk %p; tid %u; state %d\n",
173362306a36Sopenharmony_ci		 __func__, csk, tid, csk->com.state);
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci	if (cxgb_is_neg_adv(hdr->status)) {
173662306a36Sopenharmony_ci		pr_err("%s: got neg advise %d on tid %u\n",
173762306a36Sopenharmony_ci		       __func__, hdr->status, tid);
173862306a36Sopenharmony_ci		goto rel_skb;
173962306a36Sopenharmony_ci	}
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci	switch (csk->com.state) {
174262306a36Sopenharmony_ci	case CSK_STATE_CONNECTING:
174362306a36Sopenharmony_ci	case CSK_STATE_MORIBUND:
174462306a36Sopenharmony_ci		csk->com.state = CSK_STATE_DEAD;
174562306a36Sopenharmony_ci		release = true;
174662306a36Sopenharmony_ci		break;
174762306a36Sopenharmony_ci	case CSK_STATE_ESTABLISHED:
174862306a36Sopenharmony_ci		csk->com.state = CSK_STATE_DEAD;
174962306a36Sopenharmony_ci		wakeup_thread = true;
175062306a36Sopenharmony_ci		break;
175162306a36Sopenharmony_ci	case CSK_STATE_CLOSING:
175262306a36Sopenharmony_ci		csk->com.state = CSK_STATE_DEAD;
175362306a36Sopenharmony_ci		if (!csk->conn)
175462306a36Sopenharmony_ci			release = true;
175562306a36Sopenharmony_ci		break;
175662306a36Sopenharmony_ci	case CSK_STATE_ABORTING:
175762306a36Sopenharmony_ci		break;
175862306a36Sopenharmony_ci	default:
175962306a36Sopenharmony_ci		pr_info("%s: cpl_abort_req_rss in bad state %d\n",
176062306a36Sopenharmony_ci			__func__, csk->com.state);
176162306a36Sopenharmony_ci		csk->com.state = CSK_STATE_DEAD;
176262306a36Sopenharmony_ci	}
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci	__skb_queue_purge(&csk->txq);
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci	if (!test_and_set_bit(CSK_TX_DATA_SENT, &csk->com.flags))
176762306a36Sopenharmony_ci		cxgbit_send_tx_flowc_wr(csk);
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	rpl_skb = __skb_dequeue(&csk->skbq);
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	cxgb_mk_abort_rpl(rpl_skb, len, csk->tid, csk->txq_idx);
177262306a36Sopenharmony_ci	cxgbit_ofld_send(csk->com.cdev, rpl_skb);
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci	if (wakeup_thread) {
177562306a36Sopenharmony_ci		cxgbit_queue_rx_skb(csk, skb);
177662306a36Sopenharmony_ci		return;
177762306a36Sopenharmony_ci	}
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci	if (release)
178062306a36Sopenharmony_ci		cxgbit_put_csk(csk);
178162306a36Sopenharmony_cirel_skb:
178262306a36Sopenharmony_ci	__kfree_skb(skb);
178362306a36Sopenharmony_ci}
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_cistatic void cxgbit_abort_rpl_rss(struct cxgbit_sock *csk, struct sk_buff *skb)
178662306a36Sopenharmony_ci{
178762306a36Sopenharmony_ci	struct cpl_abort_rpl_rss *rpl = cplhdr(skb);
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci	pr_debug("%s: csk %p; tid %u; state %d\n",
179062306a36Sopenharmony_ci		 __func__, csk, csk->tid, csk->com.state);
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	switch (csk->com.state) {
179362306a36Sopenharmony_ci	case CSK_STATE_ABORTING:
179462306a36Sopenharmony_ci		csk->com.state = CSK_STATE_DEAD;
179562306a36Sopenharmony_ci		if (test_bit(CSK_ABORT_RPL_WAIT, &csk->com.flags))
179662306a36Sopenharmony_ci			cxgbit_wake_up(&csk->com.wr_wait, __func__,
179762306a36Sopenharmony_ci				       rpl->status);
179862306a36Sopenharmony_ci		cxgbit_put_csk(csk);
179962306a36Sopenharmony_ci		break;
180062306a36Sopenharmony_ci	default:
180162306a36Sopenharmony_ci		pr_info("%s: cpl_abort_rpl_rss in state %d\n",
180262306a36Sopenharmony_ci			__func__, csk->com.state);
180362306a36Sopenharmony_ci	}
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	__kfree_skb(skb);
180662306a36Sopenharmony_ci}
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_cistatic bool cxgbit_credit_err(const struct cxgbit_sock *csk)
180962306a36Sopenharmony_ci{
181062306a36Sopenharmony_ci	const struct sk_buff *skb = csk->wr_pending_head;
181162306a36Sopenharmony_ci	u32 credit = 0;
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci	if (unlikely(csk->wr_cred > csk->wr_max_cred)) {
181462306a36Sopenharmony_ci		pr_err("csk 0x%p, tid %u, credit %u > %u\n",
181562306a36Sopenharmony_ci		       csk, csk->tid, csk->wr_cred, csk->wr_max_cred);
181662306a36Sopenharmony_ci		return true;
181762306a36Sopenharmony_ci	}
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	while (skb) {
182062306a36Sopenharmony_ci		credit += (__force u32)skb->csum;
182162306a36Sopenharmony_ci		skb = cxgbit_skcb_tx_wr_next(skb);
182262306a36Sopenharmony_ci	}
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ci	if (unlikely((csk->wr_cred + credit) != csk->wr_max_cred)) {
182562306a36Sopenharmony_ci		pr_err("csk 0x%p, tid %u, credit %u + %u != %u.\n",
182662306a36Sopenharmony_ci		       csk, csk->tid, csk->wr_cred,
182762306a36Sopenharmony_ci		       credit, csk->wr_max_cred);
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci		return true;
183062306a36Sopenharmony_ci	}
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci	return false;
183362306a36Sopenharmony_ci}
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_cistatic void cxgbit_fw4_ack(struct cxgbit_sock *csk, struct sk_buff *skb)
183662306a36Sopenharmony_ci{
183762306a36Sopenharmony_ci	struct cpl_fw4_ack *rpl = (struct cpl_fw4_ack *)cplhdr(skb);
183862306a36Sopenharmony_ci	u32 credits = rpl->credits;
183962306a36Sopenharmony_ci	u32 snd_una = ntohl(rpl->snd_una);
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	csk->wr_cred += credits;
184262306a36Sopenharmony_ci	if (csk->wr_una_cred > (csk->wr_max_cred - csk->wr_cred))
184362306a36Sopenharmony_ci		csk->wr_una_cred = csk->wr_max_cred - csk->wr_cred;
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci	while (credits) {
184662306a36Sopenharmony_ci		struct sk_buff *p = cxgbit_sock_peek_wr(csk);
184762306a36Sopenharmony_ci		u32 csum;
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci		if (unlikely(!p)) {
185062306a36Sopenharmony_ci			pr_err("csk 0x%p,%u, cr %u,%u+%u, empty.\n",
185162306a36Sopenharmony_ci			       csk, csk->tid, credits,
185262306a36Sopenharmony_ci			       csk->wr_cred, csk->wr_una_cred);
185362306a36Sopenharmony_ci			break;
185462306a36Sopenharmony_ci		}
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci		csum = (__force u32)p->csum;
185762306a36Sopenharmony_ci		if (unlikely(credits < csum)) {
185862306a36Sopenharmony_ci			pr_warn("csk 0x%p,%u, cr %u,%u+%u, < %u.\n",
185962306a36Sopenharmony_ci				csk,  csk->tid,
186062306a36Sopenharmony_ci				credits, csk->wr_cred, csk->wr_una_cred,
186162306a36Sopenharmony_ci				csum);
186262306a36Sopenharmony_ci			p->csum = (__force __wsum)(csum - credits);
186362306a36Sopenharmony_ci			break;
186462306a36Sopenharmony_ci		}
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci		cxgbit_sock_dequeue_wr(csk);
186762306a36Sopenharmony_ci		credits -= csum;
186862306a36Sopenharmony_ci		kfree_skb(p);
186962306a36Sopenharmony_ci	}
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	if (unlikely(cxgbit_credit_err(csk))) {
187262306a36Sopenharmony_ci		cxgbit_queue_rx_skb(csk, skb);
187362306a36Sopenharmony_ci		return;
187462306a36Sopenharmony_ci	}
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci	if (rpl->seq_vld & CPL_FW4_ACK_FLAGS_SEQVAL) {
187762306a36Sopenharmony_ci		if (unlikely(before(snd_una, csk->snd_una))) {
187862306a36Sopenharmony_ci			pr_warn("csk 0x%p,%u, snd_una %u/%u.",
187962306a36Sopenharmony_ci				csk, csk->tid, snd_una,
188062306a36Sopenharmony_ci				csk->snd_una);
188162306a36Sopenharmony_ci			goto rel_skb;
188262306a36Sopenharmony_ci		}
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci		if (csk->snd_una != snd_una) {
188562306a36Sopenharmony_ci			csk->snd_una = snd_una;
188662306a36Sopenharmony_ci			dst_confirm(csk->dst);
188762306a36Sopenharmony_ci		}
188862306a36Sopenharmony_ci	}
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci	if (skb_queue_len(&csk->txq))
189162306a36Sopenharmony_ci		cxgbit_push_tx_frames(csk);
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_cirel_skb:
189462306a36Sopenharmony_ci	__kfree_skb(skb);
189562306a36Sopenharmony_ci}
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_cistatic void cxgbit_set_tcb_rpl(struct cxgbit_device *cdev, struct sk_buff *skb)
189862306a36Sopenharmony_ci{
189962306a36Sopenharmony_ci	struct cxgbit_sock *csk;
190062306a36Sopenharmony_ci	struct cpl_set_tcb_rpl *rpl = (struct cpl_set_tcb_rpl *)skb->data;
190162306a36Sopenharmony_ci	unsigned int tid = GET_TID(rpl);
190262306a36Sopenharmony_ci	struct cxgb4_lld_info *lldi = &cdev->lldi;
190362306a36Sopenharmony_ci	struct tid_info *t = lldi->tids;
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	csk = lookup_tid(t, tid);
190662306a36Sopenharmony_ci	if (unlikely(!csk)) {
190762306a36Sopenharmony_ci		pr_err("can't find connection for tid %u.\n", tid);
190862306a36Sopenharmony_ci		goto rel_skb;
190962306a36Sopenharmony_ci	} else {
191062306a36Sopenharmony_ci		cxgbit_wake_up(&csk->com.wr_wait, __func__, rpl->status);
191162306a36Sopenharmony_ci	}
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	cxgbit_put_csk(csk);
191462306a36Sopenharmony_cirel_skb:
191562306a36Sopenharmony_ci	__kfree_skb(skb);
191662306a36Sopenharmony_ci}
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_cistatic void cxgbit_rx_data(struct cxgbit_device *cdev, struct sk_buff *skb)
191962306a36Sopenharmony_ci{
192062306a36Sopenharmony_ci	struct cxgbit_sock *csk;
192162306a36Sopenharmony_ci	struct cpl_rx_data *cpl = cplhdr(skb);
192262306a36Sopenharmony_ci	unsigned int tid = GET_TID(cpl);
192362306a36Sopenharmony_ci	struct cxgb4_lld_info *lldi = &cdev->lldi;
192462306a36Sopenharmony_ci	struct tid_info *t = lldi->tids;
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci	csk = lookup_tid(t, tid);
192762306a36Sopenharmony_ci	if (unlikely(!csk)) {
192862306a36Sopenharmony_ci		pr_err("can't find conn. for tid %u.\n", tid);
192962306a36Sopenharmony_ci		goto rel_skb;
193062306a36Sopenharmony_ci	}
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci	cxgbit_queue_rx_skb(csk, skb);
193362306a36Sopenharmony_ci	return;
193462306a36Sopenharmony_cirel_skb:
193562306a36Sopenharmony_ci	__kfree_skb(skb);
193662306a36Sopenharmony_ci}
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_cistatic void
193962306a36Sopenharmony_ci__cxgbit_process_rx_cpl(struct cxgbit_sock *csk, struct sk_buff *skb)
194062306a36Sopenharmony_ci{
194162306a36Sopenharmony_ci	spin_lock(&csk->lock);
194262306a36Sopenharmony_ci	if (csk->lock_owner) {
194362306a36Sopenharmony_ci		__skb_queue_tail(&csk->backlogq, skb);
194462306a36Sopenharmony_ci		spin_unlock(&csk->lock);
194562306a36Sopenharmony_ci		return;
194662306a36Sopenharmony_ci	}
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ci	cxgbit_skcb_rx_backlog_fn(skb)(csk, skb);
194962306a36Sopenharmony_ci	spin_unlock(&csk->lock);
195062306a36Sopenharmony_ci}
195162306a36Sopenharmony_ci
195262306a36Sopenharmony_cistatic void cxgbit_process_rx_cpl(struct cxgbit_sock *csk, struct sk_buff *skb)
195362306a36Sopenharmony_ci{
195462306a36Sopenharmony_ci	cxgbit_get_csk(csk);
195562306a36Sopenharmony_ci	__cxgbit_process_rx_cpl(csk, skb);
195662306a36Sopenharmony_ci	cxgbit_put_csk(csk);
195762306a36Sopenharmony_ci}
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_cistatic void cxgbit_rx_cpl(struct cxgbit_device *cdev, struct sk_buff *skb)
196062306a36Sopenharmony_ci{
196162306a36Sopenharmony_ci	struct cxgbit_sock *csk;
196262306a36Sopenharmony_ci	struct cpl_tx_data *cpl = cplhdr(skb);
196362306a36Sopenharmony_ci	struct cxgb4_lld_info *lldi = &cdev->lldi;
196462306a36Sopenharmony_ci	struct tid_info *t = lldi->tids;
196562306a36Sopenharmony_ci	unsigned int tid = GET_TID(cpl);
196662306a36Sopenharmony_ci	u8 opcode = cxgbit_skcb_rx_opcode(skb);
196762306a36Sopenharmony_ci	bool ref = true;
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_ci	switch (opcode) {
197062306a36Sopenharmony_ci	case CPL_FW4_ACK:
197162306a36Sopenharmony_ci			cxgbit_skcb_rx_backlog_fn(skb) = cxgbit_fw4_ack;
197262306a36Sopenharmony_ci			ref = false;
197362306a36Sopenharmony_ci			break;
197462306a36Sopenharmony_ci	case CPL_PEER_CLOSE:
197562306a36Sopenharmony_ci			cxgbit_skcb_rx_backlog_fn(skb) = cxgbit_peer_close;
197662306a36Sopenharmony_ci			break;
197762306a36Sopenharmony_ci	case CPL_CLOSE_CON_RPL:
197862306a36Sopenharmony_ci			cxgbit_skcb_rx_backlog_fn(skb) = cxgbit_close_con_rpl;
197962306a36Sopenharmony_ci			break;
198062306a36Sopenharmony_ci	case CPL_ABORT_REQ_RSS:
198162306a36Sopenharmony_ci			cxgbit_skcb_rx_backlog_fn(skb) = cxgbit_abort_req_rss;
198262306a36Sopenharmony_ci			break;
198362306a36Sopenharmony_ci	case CPL_ABORT_RPL_RSS:
198462306a36Sopenharmony_ci			cxgbit_skcb_rx_backlog_fn(skb) = cxgbit_abort_rpl_rss;
198562306a36Sopenharmony_ci			break;
198662306a36Sopenharmony_ci	default:
198762306a36Sopenharmony_ci		goto rel_skb;
198862306a36Sopenharmony_ci	}
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci	csk = lookup_tid(t, tid);
199162306a36Sopenharmony_ci	if (unlikely(!csk)) {
199262306a36Sopenharmony_ci		pr_err("can't find conn. for tid %u.\n", tid);
199362306a36Sopenharmony_ci		goto rel_skb;
199462306a36Sopenharmony_ci	}
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	if (ref)
199762306a36Sopenharmony_ci		cxgbit_process_rx_cpl(csk, skb);
199862306a36Sopenharmony_ci	else
199962306a36Sopenharmony_ci		__cxgbit_process_rx_cpl(csk, skb);
200062306a36Sopenharmony_ci
200162306a36Sopenharmony_ci	return;
200262306a36Sopenharmony_cirel_skb:
200362306a36Sopenharmony_ci	__kfree_skb(skb);
200462306a36Sopenharmony_ci}
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_cicxgbit_cplhandler_func cxgbit_cplhandlers[NUM_CPL_CMDS] = {
200762306a36Sopenharmony_ci	[CPL_PASS_OPEN_RPL]	= cxgbit_pass_open_rpl,
200862306a36Sopenharmony_ci	[CPL_CLOSE_LISTSRV_RPL] = cxgbit_close_listsrv_rpl,
200962306a36Sopenharmony_ci	[CPL_PASS_ACCEPT_REQ]	= cxgbit_pass_accept_req,
201062306a36Sopenharmony_ci	[CPL_PASS_ESTABLISH]	= cxgbit_pass_establish,
201162306a36Sopenharmony_ci	[CPL_SET_TCB_RPL]	= cxgbit_set_tcb_rpl,
201262306a36Sopenharmony_ci	[CPL_RX_DATA]		= cxgbit_rx_data,
201362306a36Sopenharmony_ci	[CPL_FW4_ACK]		= cxgbit_rx_cpl,
201462306a36Sopenharmony_ci	[CPL_PEER_CLOSE]	= cxgbit_rx_cpl,
201562306a36Sopenharmony_ci	[CPL_CLOSE_CON_RPL]	= cxgbit_rx_cpl,
201662306a36Sopenharmony_ci	[CPL_ABORT_REQ_RSS]	= cxgbit_rx_cpl,
201762306a36Sopenharmony_ci	[CPL_ABORT_RPL_RSS]	= cxgbit_rx_cpl,
201862306a36Sopenharmony_ci};
2019