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