18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * libcxgbi.c: Chelsio common library for T3/T4 iSCSI driver. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2010-2015 Chelsio Communications, Inc. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 78c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 88c2ecf20Sopenharmony_ci * the Free Software Foundation. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Written by: Karen Xie (kxie@chelsio.com) 118c2ecf20Sopenharmony_ci * Written by: Rakesh Ranjan (rranjan@chelsio.com) 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 178c2ecf20Sopenharmony_ci#include <linux/crypto.h> 188c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 198c2ecf20Sopenharmony_ci#include <linux/pci.h> 208c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 218c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 228c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 238c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 248c2ecf20Sopenharmony_ci#include <linux/inet.h> 258c2ecf20Sopenharmony_ci#include <net/dst.h> 268c2ecf20Sopenharmony_ci#include <net/route.h> 278c2ecf20Sopenharmony_ci#include <net/ipv6.h> 288c2ecf20Sopenharmony_ci#include <net/ip6_route.h> 298c2ecf20Sopenharmony_ci#include <net/addrconf.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include <linux/inetdevice.h> /* ip_dev_find */ 328c2ecf20Sopenharmony_ci#include <linux/module.h> 338c2ecf20Sopenharmony_ci#include <net/tcp.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic unsigned int dbg_level; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include "libcxgbi.h" 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define DRV_MODULE_NAME "libcxgbi" 408c2ecf20Sopenharmony_ci#define DRV_MODULE_DESC "Chelsio iSCSI driver library" 418c2ecf20Sopenharmony_ci#define DRV_MODULE_VERSION "0.9.1-ko" 428c2ecf20Sopenharmony_ci#define DRV_MODULE_RELDATE "Apr. 2015" 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic char version[] = 458c2ecf20Sopenharmony_ci DRV_MODULE_DESC " " DRV_MODULE_NAME 468c2ecf20Sopenharmony_ci " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ciMODULE_AUTHOR("Chelsio Communications, Inc."); 498c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRV_MODULE_DESC); 508c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_MODULE_VERSION); 518c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cimodule_param(dbg_level, uint, 0644); 548c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dbg_level, "libiscsi debug level (default=0)"); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* 588c2ecf20Sopenharmony_ci * cxgbi device management 598c2ecf20Sopenharmony_ci * maintains a list of the cxgbi devices 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_cistatic LIST_HEAD(cdev_list); 628c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(cdev_mutex); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic LIST_HEAD(cdev_rcu_list); 658c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(cdev_rcu_lock); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic inline void cxgbi_decode_sw_tag(u32 sw_tag, int *idx, int *age) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci if (age) 708c2ecf20Sopenharmony_ci *age = sw_tag & 0x7FFF; 718c2ecf20Sopenharmony_ci if (idx) 728c2ecf20Sopenharmony_ci *idx = (sw_tag >> 16) & 0x7FFF; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ciint cxgbi_device_portmap_create(struct cxgbi_device *cdev, unsigned int base, 768c2ecf20Sopenharmony_ci unsigned int max_conn) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci struct cxgbi_ports_map *pmap = &cdev->pmap; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci pmap->port_csk = kvzalloc(array_size(max_conn, 818c2ecf20Sopenharmony_ci sizeof(struct cxgbi_sock *)), 828c2ecf20Sopenharmony_ci GFP_KERNEL | __GFP_NOWARN); 838c2ecf20Sopenharmony_ci if (!pmap->port_csk) { 848c2ecf20Sopenharmony_ci pr_warn("cdev 0x%p, portmap OOM %u.\n", cdev, max_conn); 858c2ecf20Sopenharmony_ci return -ENOMEM; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci pmap->max_connect = max_conn; 898c2ecf20Sopenharmony_ci pmap->sport_base = base; 908c2ecf20Sopenharmony_ci spin_lock_init(&pmap->lock); 918c2ecf20Sopenharmony_ci return 0; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_device_portmap_create); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_civoid cxgbi_device_portmap_cleanup(struct cxgbi_device *cdev) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci struct cxgbi_ports_map *pmap = &cdev->pmap; 988c2ecf20Sopenharmony_ci struct cxgbi_sock *csk; 998c2ecf20Sopenharmony_ci int i; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci for (i = 0; i < pmap->max_connect; i++) { 1028c2ecf20Sopenharmony_ci if (pmap->port_csk[i]) { 1038c2ecf20Sopenharmony_ci csk = pmap->port_csk[i]; 1048c2ecf20Sopenharmony_ci pmap->port_csk[i] = NULL; 1058c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, 1068c2ecf20Sopenharmony_ci "csk 0x%p, cdev 0x%p, offload down.\n", 1078c2ecf20Sopenharmony_ci csk, cdev); 1088c2ecf20Sopenharmony_ci spin_lock_bh(&csk->lock); 1098c2ecf20Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_OFFLOAD_DOWN); 1108c2ecf20Sopenharmony_ci cxgbi_sock_closed(csk); 1118c2ecf20Sopenharmony_ci spin_unlock_bh(&csk->lock); 1128c2ecf20Sopenharmony_ci cxgbi_sock_put(csk); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_device_portmap_cleanup); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic inline void cxgbi_device_destroy(struct cxgbi_device *cdev) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_DEV, 1218c2ecf20Sopenharmony_ci "cdev 0x%p, p# %u.\n", cdev, cdev->nports); 1228c2ecf20Sopenharmony_ci cxgbi_hbas_remove(cdev); 1238c2ecf20Sopenharmony_ci cxgbi_device_portmap_cleanup(cdev); 1248c2ecf20Sopenharmony_ci if (cdev->cdev2ppm) 1258c2ecf20Sopenharmony_ci cxgbi_ppm_release(cdev->cdev2ppm(cdev)); 1268c2ecf20Sopenharmony_ci if (cdev->pmap.max_connect) 1278c2ecf20Sopenharmony_ci kvfree(cdev->pmap.port_csk); 1288c2ecf20Sopenharmony_ci kfree(cdev); 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistruct cxgbi_device *cxgbi_device_register(unsigned int extra, 1328c2ecf20Sopenharmony_ci unsigned int nports) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci struct cxgbi_device *cdev; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci cdev = kzalloc(sizeof(*cdev) + extra + nports * 1378c2ecf20Sopenharmony_ci (sizeof(struct cxgbi_hba *) + 1388c2ecf20Sopenharmony_ci sizeof(struct net_device *)), 1398c2ecf20Sopenharmony_ci GFP_KERNEL); 1408c2ecf20Sopenharmony_ci if (!cdev) { 1418c2ecf20Sopenharmony_ci pr_warn("nport %d, OOM.\n", nports); 1428c2ecf20Sopenharmony_ci return NULL; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci cdev->ports = (struct net_device **)(cdev + 1); 1458c2ecf20Sopenharmony_ci cdev->hbas = (struct cxgbi_hba **)(((char*)cdev->ports) + nports * 1468c2ecf20Sopenharmony_ci sizeof(struct net_device *)); 1478c2ecf20Sopenharmony_ci if (extra) 1488c2ecf20Sopenharmony_ci cdev->dd_data = ((char *)cdev->hbas) + 1498c2ecf20Sopenharmony_ci nports * sizeof(struct cxgbi_hba *); 1508c2ecf20Sopenharmony_ci spin_lock_init(&cdev->pmap.lock); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci mutex_lock(&cdev_mutex); 1538c2ecf20Sopenharmony_ci list_add_tail(&cdev->list_head, &cdev_list); 1548c2ecf20Sopenharmony_ci mutex_unlock(&cdev_mutex); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci spin_lock(&cdev_rcu_lock); 1578c2ecf20Sopenharmony_ci list_add_tail_rcu(&cdev->rcu_node, &cdev_rcu_list); 1588c2ecf20Sopenharmony_ci spin_unlock(&cdev_rcu_lock); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_DEV, 1618c2ecf20Sopenharmony_ci "cdev 0x%p, p# %u.\n", cdev, nports); 1628c2ecf20Sopenharmony_ci return cdev; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_device_register); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_civoid cxgbi_device_unregister(struct cxgbi_device *cdev) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_DEV, 1698c2ecf20Sopenharmony_ci "cdev 0x%p, p# %u,%s.\n", 1708c2ecf20Sopenharmony_ci cdev, cdev->nports, cdev->nports ? cdev->ports[0]->name : ""); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci mutex_lock(&cdev_mutex); 1738c2ecf20Sopenharmony_ci list_del(&cdev->list_head); 1748c2ecf20Sopenharmony_ci mutex_unlock(&cdev_mutex); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci spin_lock(&cdev_rcu_lock); 1778c2ecf20Sopenharmony_ci list_del_rcu(&cdev->rcu_node); 1788c2ecf20Sopenharmony_ci spin_unlock(&cdev_rcu_lock); 1798c2ecf20Sopenharmony_ci synchronize_rcu(); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci cxgbi_device_destroy(cdev); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_device_unregister); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_civoid cxgbi_device_unregister_all(unsigned int flag) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci struct cxgbi_device *cdev, *tmp; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci mutex_lock(&cdev_mutex); 1908c2ecf20Sopenharmony_ci list_for_each_entry_safe(cdev, tmp, &cdev_list, list_head) { 1918c2ecf20Sopenharmony_ci if ((cdev->flags & flag) == flag) { 1928c2ecf20Sopenharmony_ci mutex_unlock(&cdev_mutex); 1938c2ecf20Sopenharmony_ci cxgbi_device_unregister(cdev); 1948c2ecf20Sopenharmony_ci mutex_lock(&cdev_mutex); 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci mutex_unlock(&cdev_mutex); 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_device_unregister_all); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistruct cxgbi_device *cxgbi_device_find_by_lldev(void *lldev) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci struct cxgbi_device *cdev, *tmp; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci mutex_lock(&cdev_mutex); 2068c2ecf20Sopenharmony_ci list_for_each_entry_safe(cdev, tmp, &cdev_list, list_head) { 2078c2ecf20Sopenharmony_ci if (cdev->lldev == lldev) { 2088c2ecf20Sopenharmony_ci mutex_unlock(&cdev_mutex); 2098c2ecf20Sopenharmony_ci return cdev; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci mutex_unlock(&cdev_mutex); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_DEV, 2158c2ecf20Sopenharmony_ci "lldev 0x%p, NO match found.\n", lldev); 2168c2ecf20Sopenharmony_ci return NULL; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_device_find_by_lldev); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistruct cxgbi_device *cxgbi_device_find_by_netdev(struct net_device *ndev, 2218c2ecf20Sopenharmony_ci int *port) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct net_device *vdev = NULL; 2248c2ecf20Sopenharmony_ci struct cxgbi_device *cdev, *tmp; 2258c2ecf20Sopenharmony_ci int i; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci if (is_vlan_dev(ndev)) { 2288c2ecf20Sopenharmony_ci vdev = ndev; 2298c2ecf20Sopenharmony_ci ndev = vlan_dev_real_dev(ndev); 2308c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_DEV, 2318c2ecf20Sopenharmony_ci "vlan dev %s -> %s.\n", vdev->name, ndev->name); 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci mutex_lock(&cdev_mutex); 2358c2ecf20Sopenharmony_ci list_for_each_entry_safe(cdev, tmp, &cdev_list, list_head) { 2368c2ecf20Sopenharmony_ci for (i = 0; i < cdev->nports; i++) { 2378c2ecf20Sopenharmony_ci if (ndev == cdev->ports[i]) { 2388c2ecf20Sopenharmony_ci cdev->hbas[i]->vdev = vdev; 2398c2ecf20Sopenharmony_ci mutex_unlock(&cdev_mutex); 2408c2ecf20Sopenharmony_ci if (port) 2418c2ecf20Sopenharmony_ci *port = i; 2428c2ecf20Sopenharmony_ci return cdev; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci mutex_unlock(&cdev_mutex); 2478c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_DEV, 2488c2ecf20Sopenharmony_ci "ndev 0x%p, %s, NO match found.\n", ndev, ndev->name); 2498c2ecf20Sopenharmony_ci return NULL; 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_device_find_by_netdev); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistruct cxgbi_device *cxgbi_device_find_by_netdev_rcu(struct net_device *ndev, 2548c2ecf20Sopenharmony_ci int *port) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci struct net_device *vdev = NULL; 2578c2ecf20Sopenharmony_ci struct cxgbi_device *cdev; 2588c2ecf20Sopenharmony_ci int i; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (is_vlan_dev(ndev)) { 2618c2ecf20Sopenharmony_ci vdev = ndev; 2628c2ecf20Sopenharmony_ci ndev = vlan_dev_real_dev(ndev); 2638c2ecf20Sopenharmony_ci pr_info("vlan dev %s -> %s.\n", vdev->name, ndev->name); 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci rcu_read_lock(); 2678c2ecf20Sopenharmony_ci list_for_each_entry_rcu(cdev, &cdev_rcu_list, rcu_node) { 2688c2ecf20Sopenharmony_ci for (i = 0; i < cdev->nports; i++) { 2698c2ecf20Sopenharmony_ci if (ndev == cdev->ports[i]) { 2708c2ecf20Sopenharmony_ci cdev->hbas[i]->vdev = vdev; 2718c2ecf20Sopenharmony_ci rcu_read_unlock(); 2728c2ecf20Sopenharmony_ci if (port) 2738c2ecf20Sopenharmony_ci *port = i; 2748c2ecf20Sopenharmony_ci return cdev; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci rcu_read_unlock(); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_DEV, 2818c2ecf20Sopenharmony_ci "ndev 0x%p, %s, NO match found.\n", ndev, ndev->name); 2828c2ecf20Sopenharmony_ci return NULL; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_device_find_by_netdev_rcu); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic struct cxgbi_device *cxgbi_device_find_by_mac(struct net_device *ndev, 2878c2ecf20Sopenharmony_ci int *port) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci struct net_device *vdev = NULL; 2908c2ecf20Sopenharmony_ci struct cxgbi_device *cdev, *tmp; 2918c2ecf20Sopenharmony_ci int i; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (is_vlan_dev(ndev)) { 2948c2ecf20Sopenharmony_ci vdev = ndev; 2958c2ecf20Sopenharmony_ci ndev = vlan_dev_real_dev(ndev); 2968c2ecf20Sopenharmony_ci pr_info("vlan dev %s -> %s.\n", vdev->name, ndev->name); 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci mutex_lock(&cdev_mutex); 3008c2ecf20Sopenharmony_ci list_for_each_entry_safe(cdev, tmp, &cdev_list, list_head) { 3018c2ecf20Sopenharmony_ci for (i = 0; i < cdev->nports; i++) { 3028c2ecf20Sopenharmony_ci if (!memcmp(ndev->dev_addr, cdev->ports[i]->dev_addr, 3038c2ecf20Sopenharmony_ci MAX_ADDR_LEN)) { 3048c2ecf20Sopenharmony_ci cdev->hbas[i]->vdev = vdev; 3058c2ecf20Sopenharmony_ci mutex_unlock(&cdev_mutex); 3068c2ecf20Sopenharmony_ci if (port) 3078c2ecf20Sopenharmony_ci *port = i; 3088c2ecf20Sopenharmony_ci return cdev; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci mutex_unlock(&cdev_mutex); 3138c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_DEV, 3148c2ecf20Sopenharmony_ci "ndev 0x%p, %s, NO match mac found.\n", 3158c2ecf20Sopenharmony_ci ndev, ndev->name); 3168c2ecf20Sopenharmony_ci return NULL; 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_civoid cxgbi_hbas_remove(struct cxgbi_device *cdev) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci int i; 3228c2ecf20Sopenharmony_ci struct cxgbi_hba *chba; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_DEV, 3258c2ecf20Sopenharmony_ci "cdev 0x%p, p#%u.\n", cdev, cdev->nports); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci for (i = 0; i < cdev->nports; i++) { 3288c2ecf20Sopenharmony_ci chba = cdev->hbas[i]; 3298c2ecf20Sopenharmony_ci if (chba) { 3308c2ecf20Sopenharmony_ci cdev->hbas[i] = NULL; 3318c2ecf20Sopenharmony_ci iscsi_host_remove(chba->shost); 3328c2ecf20Sopenharmony_ci pci_dev_put(cdev->pdev); 3338c2ecf20Sopenharmony_ci iscsi_host_free(chba->shost); 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_hbas_remove); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ciint cxgbi_hbas_add(struct cxgbi_device *cdev, u64 max_lun, 3408c2ecf20Sopenharmony_ci unsigned int max_conns, struct scsi_host_template *sht, 3418c2ecf20Sopenharmony_ci struct scsi_transport_template *stt) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci struct cxgbi_hba *chba; 3448c2ecf20Sopenharmony_ci struct Scsi_Host *shost; 3458c2ecf20Sopenharmony_ci int i, err; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_DEV, "cdev 0x%p, p#%u.\n", cdev, cdev->nports); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci for (i = 0; i < cdev->nports; i++) { 3508c2ecf20Sopenharmony_ci shost = iscsi_host_alloc(sht, sizeof(*chba), 1); 3518c2ecf20Sopenharmony_ci if (!shost) { 3528c2ecf20Sopenharmony_ci pr_info("0x%p, p%d, %s, host alloc failed.\n", 3538c2ecf20Sopenharmony_ci cdev, i, cdev->ports[i]->name); 3548c2ecf20Sopenharmony_ci err = -ENOMEM; 3558c2ecf20Sopenharmony_ci goto err_out; 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci shost->transportt = stt; 3598c2ecf20Sopenharmony_ci shost->max_lun = max_lun; 3608c2ecf20Sopenharmony_ci shost->max_id = max_conns - 1; 3618c2ecf20Sopenharmony_ci shost->max_channel = 0; 3628c2ecf20Sopenharmony_ci shost->max_cmd_len = SCSI_MAX_VARLEN_CDB_SIZE; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci chba = iscsi_host_priv(shost); 3658c2ecf20Sopenharmony_ci chba->cdev = cdev; 3668c2ecf20Sopenharmony_ci chba->ndev = cdev->ports[i]; 3678c2ecf20Sopenharmony_ci chba->shost = shost; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci shost->can_queue = sht->can_queue - ISCSI_MGMT_CMDS_MAX; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_DEV, 3728c2ecf20Sopenharmony_ci "cdev 0x%p, p#%d %s: chba 0x%p.\n", 3738c2ecf20Sopenharmony_ci cdev, i, cdev->ports[i]->name, chba); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci pci_dev_get(cdev->pdev); 3768c2ecf20Sopenharmony_ci err = iscsi_host_add(shost, &cdev->pdev->dev); 3778c2ecf20Sopenharmony_ci if (err) { 3788c2ecf20Sopenharmony_ci pr_info("cdev 0x%p, p#%d %s, host add failed.\n", 3798c2ecf20Sopenharmony_ci cdev, i, cdev->ports[i]->name); 3808c2ecf20Sopenharmony_ci pci_dev_put(cdev->pdev); 3818c2ecf20Sopenharmony_ci scsi_host_put(shost); 3828c2ecf20Sopenharmony_ci goto err_out; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci cdev->hbas[i] = chba; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci return 0; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cierr_out: 3918c2ecf20Sopenharmony_ci cxgbi_hbas_remove(cdev); 3928c2ecf20Sopenharmony_ci return err; 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_hbas_add); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci/* 3978c2ecf20Sopenharmony_ci * iSCSI offload 3988c2ecf20Sopenharmony_ci * 3998c2ecf20Sopenharmony_ci * - source port management 4008c2ecf20Sopenharmony_ci * To find a free source port in the port allocation map we use a very simple 4018c2ecf20Sopenharmony_ci * rotor scheme to look for the next free port. 4028c2ecf20Sopenharmony_ci * 4038c2ecf20Sopenharmony_ci * If a source port has been specified make sure that it doesn't collide with 4048c2ecf20Sopenharmony_ci * our normal source port allocation map. If it's outside the range of our 4058c2ecf20Sopenharmony_ci * allocation/deallocation scheme just let them use it. 4068c2ecf20Sopenharmony_ci * 4078c2ecf20Sopenharmony_ci * If the source port is outside our allocation range, the caller is 4088c2ecf20Sopenharmony_ci * responsible for keeping track of their port usage. 4098c2ecf20Sopenharmony_ci */ 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cistatic struct cxgbi_sock *find_sock_on_port(struct cxgbi_device *cdev, 4128c2ecf20Sopenharmony_ci unsigned char port_id) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci struct cxgbi_ports_map *pmap = &cdev->pmap; 4158c2ecf20Sopenharmony_ci unsigned int i; 4168c2ecf20Sopenharmony_ci unsigned int used; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (!pmap->max_connect || !pmap->used) 4198c2ecf20Sopenharmony_ci return NULL; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci spin_lock_bh(&pmap->lock); 4228c2ecf20Sopenharmony_ci used = pmap->used; 4238c2ecf20Sopenharmony_ci for (i = 0; used && i < pmap->max_connect; i++) { 4248c2ecf20Sopenharmony_ci struct cxgbi_sock *csk = pmap->port_csk[i]; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (csk) { 4278c2ecf20Sopenharmony_ci if (csk->port_id == port_id) { 4288c2ecf20Sopenharmony_ci spin_unlock_bh(&pmap->lock); 4298c2ecf20Sopenharmony_ci return csk; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci used--; 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci spin_unlock_bh(&pmap->lock); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci return NULL; 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic int sock_get_port(struct cxgbi_sock *csk) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci struct cxgbi_device *cdev = csk->cdev; 4428c2ecf20Sopenharmony_ci struct cxgbi_ports_map *pmap = &cdev->pmap; 4438c2ecf20Sopenharmony_ci unsigned int start; 4448c2ecf20Sopenharmony_ci int idx; 4458c2ecf20Sopenharmony_ci __be16 *port; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (!pmap->max_connect) { 4488c2ecf20Sopenharmony_ci pr_err("cdev 0x%p, p#%u %s, NO port map.\n", 4498c2ecf20Sopenharmony_ci cdev, csk->port_id, cdev->ports[csk->port_id]->name); 4508c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (csk->csk_family == AF_INET) 4548c2ecf20Sopenharmony_ci port = &csk->saddr.sin_port; 4558c2ecf20Sopenharmony_ci else /* ipv6 */ 4568c2ecf20Sopenharmony_ci port = &csk->saddr6.sin6_port; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (*port) { 4598c2ecf20Sopenharmony_ci pr_err("source port NON-ZERO %u.\n", 4608c2ecf20Sopenharmony_ci ntohs(*port)); 4618c2ecf20Sopenharmony_ci return -EADDRINUSE; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci spin_lock_bh(&pmap->lock); 4658c2ecf20Sopenharmony_ci if (pmap->used >= pmap->max_connect) { 4668c2ecf20Sopenharmony_ci spin_unlock_bh(&pmap->lock); 4678c2ecf20Sopenharmony_ci pr_info("cdev 0x%p, p#%u %s, ALL ports used.\n", 4688c2ecf20Sopenharmony_ci cdev, csk->port_id, cdev->ports[csk->port_id]->name); 4698c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci start = idx = pmap->next; 4738c2ecf20Sopenharmony_ci do { 4748c2ecf20Sopenharmony_ci if (++idx >= pmap->max_connect) 4758c2ecf20Sopenharmony_ci idx = 0; 4768c2ecf20Sopenharmony_ci if (!pmap->port_csk[idx]) { 4778c2ecf20Sopenharmony_ci pmap->used++; 4788c2ecf20Sopenharmony_ci *port = htons(pmap->sport_base + idx); 4798c2ecf20Sopenharmony_ci pmap->next = idx; 4808c2ecf20Sopenharmony_ci pmap->port_csk[idx] = csk; 4818c2ecf20Sopenharmony_ci spin_unlock_bh(&pmap->lock); 4828c2ecf20Sopenharmony_ci cxgbi_sock_get(csk); 4838c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, 4848c2ecf20Sopenharmony_ci "cdev 0x%p, p#%u %s, p %u, %u.\n", 4858c2ecf20Sopenharmony_ci cdev, csk->port_id, 4868c2ecf20Sopenharmony_ci cdev->ports[csk->port_id]->name, 4878c2ecf20Sopenharmony_ci pmap->sport_base + idx, pmap->next); 4888c2ecf20Sopenharmony_ci return 0; 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci } while (idx != start); 4918c2ecf20Sopenharmony_ci spin_unlock_bh(&pmap->lock); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci /* should not happen */ 4948c2ecf20Sopenharmony_ci pr_warn("cdev 0x%p, p#%u %s, next %u?\n", 4958c2ecf20Sopenharmony_ci cdev, csk->port_id, cdev->ports[csk->port_id]->name, 4968c2ecf20Sopenharmony_ci pmap->next); 4978c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_cistatic void sock_put_port(struct cxgbi_sock *csk) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci struct cxgbi_device *cdev = csk->cdev; 5038c2ecf20Sopenharmony_ci struct cxgbi_ports_map *pmap = &cdev->pmap; 5048c2ecf20Sopenharmony_ci __be16 *port; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci if (csk->csk_family == AF_INET) 5078c2ecf20Sopenharmony_ci port = &csk->saddr.sin_port; 5088c2ecf20Sopenharmony_ci else /* ipv6 */ 5098c2ecf20Sopenharmony_ci port = &csk->saddr6.sin6_port; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci if (*port) { 5128c2ecf20Sopenharmony_ci int idx = ntohs(*port) - pmap->sport_base; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci *port = 0; 5158c2ecf20Sopenharmony_ci if (idx < 0 || idx >= pmap->max_connect) { 5168c2ecf20Sopenharmony_ci pr_err("cdev 0x%p, p#%u %s, port %u OOR.\n", 5178c2ecf20Sopenharmony_ci cdev, csk->port_id, 5188c2ecf20Sopenharmony_ci cdev->ports[csk->port_id]->name, 5198c2ecf20Sopenharmony_ci ntohs(*port)); 5208c2ecf20Sopenharmony_ci return; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci spin_lock_bh(&pmap->lock); 5248c2ecf20Sopenharmony_ci pmap->port_csk[idx] = NULL; 5258c2ecf20Sopenharmony_ci pmap->used--; 5268c2ecf20Sopenharmony_ci spin_unlock_bh(&pmap->lock); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, 5298c2ecf20Sopenharmony_ci "cdev 0x%p, p#%u %s, release %u.\n", 5308c2ecf20Sopenharmony_ci cdev, csk->port_id, cdev->ports[csk->port_id]->name, 5318c2ecf20Sopenharmony_ci pmap->sport_base + idx); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci cxgbi_sock_put(csk); 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci} 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci/* 5388c2ecf20Sopenharmony_ci * iscsi tcp connection 5398c2ecf20Sopenharmony_ci */ 5408c2ecf20Sopenharmony_civoid cxgbi_sock_free_cpl_skbs(struct cxgbi_sock *csk) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci if (csk->cpl_close) { 5438c2ecf20Sopenharmony_ci kfree_skb(csk->cpl_close); 5448c2ecf20Sopenharmony_ci csk->cpl_close = NULL; 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci if (csk->cpl_abort_req) { 5478c2ecf20Sopenharmony_ci kfree_skb(csk->cpl_abort_req); 5488c2ecf20Sopenharmony_ci csk->cpl_abort_req = NULL; 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci if (csk->cpl_abort_rpl) { 5518c2ecf20Sopenharmony_ci kfree_skb(csk->cpl_abort_rpl); 5528c2ecf20Sopenharmony_ci csk->cpl_abort_rpl = NULL; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_free_cpl_skbs); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistatic struct cxgbi_sock *cxgbi_sock_create(struct cxgbi_device *cdev) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci struct cxgbi_sock *csk = kzalloc(sizeof(*csk), GFP_NOIO); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci if (!csk) { 5628c2ecf20Sopenharmony_ci pr_info("alloc csk %zu failed.\n", sizeof(*csk)); 5638c2ecf20Sopenharmony_ci return NULL; 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci if (cdev->csk_alloc_cpls(csk) < 0) { 5678c2ecf20Sopenharmony_ci pr_info("csk 0x%p, alloc cpls failed.\n", csk); 5688c2ecf20Sopenharmony_ci kfree(csk); 5698c2ecf20Sopenharmony_ci return NULL; 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci spin_lock_init(&csk->lock); 5738c2ecf20Sopenharmony_ci kref_init(&csk->refcnt); 5748c2ecf20Sopenharmony_ci skb_queue_head_init(&csk->receive_queue); 5758c2ecf20Sopenharmony_ci skb_queue_head_init(&csk->write_queue); 5768c2ecf20Sopenharmony_ci timer_setup(&csk->retry_timer, NULL, 0); 5778c2ecf20Sopenharmony_ci init_completion(&csk->cmpl); 5788c2ecf20Sopenharmony_ci rwlock_init(&csk->callback_lock); 5798c2ecf20Sopenharmony_ci csk->cdev = cdev; 5808c2ecf20Sopenharmony_ci csk->flags = 0; 5818c2ecf20Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_CLOSED); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, "cdev 0x%p, new csk 0x%p.\n", cdev, csk); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci return csk; 5868c2ecf20Sopenharmony_ci} 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_cistatic struct rtable *find_route_ipv4(struct flowi4 *fl4, 5898c2ecf20Sopenharmony_ci __be32 saddr, __be32 daddr, 5908c2ecf20Sopenharmony_ci __be16 sport, __be16 dport, u8 tos, 5918c2ecf20Sopenharmony_ci int ifindex) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci struct rtable *rt; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci rt = ip_route_output_ports(&init_net, fl4, NULL, daddr, saddr, 5968c2ecf20Sopenharmony_ci dport, sport, IPPROTO_TCP, tos, ifindex); 5978c2ecf20Sopenharmony_ci if (IS_ERR(rt)) 5988c2ecf20Sopenharmony_ci return NULL; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci return rt; 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_cistatic struct cxgbi_sock * 6048c2ecf20Sopenharmony_cicxgbi_check_route(struct sockaddr *dst_addr, int ifindex) 6058c2ecf20Sopenharmony_ci{ 6068c2ecf20Sopenharmony_ci struct sockaddr_in *daddr = (struct sockaddr_in *)dst_addr; 6078c2ecf20Sopenharmony_ci struct dst_entry *dst; 6088c2ecf20Sopenharmony_ci struct net_device *ndev; 6098c2ecf20Sopenharmony_ci struct cxgbi_device *cdev; 6108c2ecf20Sopenharmony_ci struct rtable *rt = NULL; 6118c2ecf20Sopenharmony_ci struct neighbour *n; 6128c2ecf20Sopenharmony_ci struct flowi4 fl4; 6138c2ecf20Sopenharmony_ci struct cxgbi_sock *csk = NULL; 6148c2ecf20Sopenharmony_ci unsigned int mtu = 0; 6158c2ecf20Sopenharmony_ci int port = 0xFFFF; 6168c2ecf20Sopenharmony_ci int err = 0; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci rt = find_route_ipv4(&fl4, 0, daddr->sin_addr.s_addr, 0, 6198c2ecf20Sopenharmony_ci daddr->sin_port, 0, ifindex); 6208c2ecf20Sopenharmony_ci if (!rt) { 6218c2ecf20Sopenharmony_ci pr_info("no route to ipv4 0x%x, port %u.\n", 6228c2ecf20Sopenharmony_ci be32_to_cpu(daddr->sin_addr.s_addr), 6238c2ecf20Sopenharmony_ci be16_to_cpu(daddr->sin_port)); 6248c2ecf20Sopenharmony_ci err = -ENETUNREACH; 6258c2ecf20Sopenharmony_ci goto err_out; 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci dst = &rt->dst; 6288c2ecf20Sopenharmony_ci n = dst_neigh_lookup(dst, &daddr->sin_addr.s_addr); 6298c2ecf20Sopenharmony_ci if (!n) { 6308c2ecf20Sopenharmony_ci err = -ENODEV; 6318c2ecf20Sopenharmony_ci goto rel_rt; 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci ndev = n->dev; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { 6368c2ecf20Sopenharmony_ci pr_info("multi-cast route %pI4, port %u, dev %s.\n", 6378c2ecf20Sopenharmony_ci &daddr->sin_addr.s_addr, ntohs(daddr->sin_port), 6388c2ecf20Sopenharmony_ci ndev->name); 6398c2ecf20Sopenharmony_ci err = -ENETUNREACH; 6408c2ecf20Sopenharmony_ci goto rel_neigh; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci if (ndev->flags & IFF_LOOPBACK) { 6448c2ecf20Sopenharmony_ci ndev = ip_dev_find(&init_net, daddr->sin_addr.s_addr); 6458c2ecf20Sopenharmony_ci if (!ndev) { 6468c2ecf20Sopenharmony_ci err = -ENETUNREACH; 6478c2ecf20Sopenharmony_ci goto rel_neigh; 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci mtu = ndev->mtu; 6508c2ecf20Sopenharmony_ci pr_info("rt dev %s, loopback -> %s, mtu %u.\n", 6518c2ecf20Sopenharmony_ci n->dev->name, ndev->name, mtu); 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci if (!(ndev->flags & IFF_UP) || !netif_carrier_ok(ndev)) { 6558c2ecf20Sopenharmony_ci pr_info("%s interface not up.\n", ndev->name); 6568c2ecf20Sopenharmony_ci err = -ENETDOWN; 6578c2ecf20Sopenharmony_ci goto rel_neigh; 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci cdev = cxgbi_device_find_by_netdev(ndev, &port); 6618c2ecf20Sopenharmony_ci if (!cdev) 6628c2ecf20Sopenharmony_ci cdev = cxgbi_device_find_by_mac(ndev, &port); 6638c2ecf20Sopenharmony_ci if (!cdev) { 6648c2ecf20Sopenharmony_ci pr_info("dst %pI4, %s, NOT cxgbi device.\n", 6658c2ecf20Sopenharmony_ci &daddr->sin_addr.s_addr, ndev->name); 6668c2ecf20Sopenharmony_ci err = -ENETUNREACH; 6678c2ecf20Sopenharmony_ci goto rel_neigh; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, 6708c2ecf20Sopenharmony_ci "route to %pI4 :%u, ndev p#%d,%s, cdev 0x%p.\n", 6718c2ecf20Sopenharmony_ci &daddr->sin_addr.s_addr, ntohs(daddr->sin_port), 6728c2ecf20Sopenharmony_ci port, ndev->name, cdev); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci csk = cxgbi_sock_create(cdev); 6758c2ecf20Sopenharmony_ci if (!csk) { 6768c2ecf20Sopenharmony_ci err = -ENOMEM; 6778c2ecf20Sopenharmony_ci goto rel_neigh; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci csk->cdev = cdev; 6808c2ecf20Sopenharmony_ci csk->port_id = port; 6818c2ecf20Sopenharmony_ci csk->mtu = mtu; 6828c2ecf20Sopenharmony_ci csk->dst = dst; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci csk->csk_family = AF_INET; 6858c2ecf20Sopenharmony_ci csk->daddr.sin_addr.s_addr = daddr->sin_addr.s_addr; 6868c2ecf20Sopenharmony_ci csk->daddr.sin_port = daddr->sin_port; 6878c2ecf20Sopenharmony_ci csk->daddr.sin_family = daddr->sin_family; 6888c2ecf20Sopenharmony_ci csk->saddr.sin_family = daddr->sin_family; 6898c2ecf20Sopenharmony_ci csk->saddr.sin_addr.s_addr = fl4.saddr; 6908c2ecf20Sopenharmony_ci neigh_release(n); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci return csk; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_cirel_neigh: 6958c2ecf20Sopenharmony_ci neigh_release(n); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_cirel_rt: 6988c2ecf20Sopenharmony_ci ip_rt_put(rt); 6998c2ecf20Sopenharmony_cierr_out: 7008c2ecf20Sopenharmony_ci return ERR_PTR(err); 7018c2ecf20Sopenharmony_ci} 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 7048c2ecf20Sopenharmony_cistatic struct rt6_info *find_route_ipv6(const struct in6_addr *saddr, 7058c2ecf20Sopenharmony_ci const struct in6_addr *daddr, 7068c2ecf20Sopenharmony_ci int ifindex) 7078c2ecf20Sopenharmony_ci{ 7088c2ecf20Sopenharmony_ci struct flowi6 fl; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci memset(&fl, 0, sizeof(fl)); 7118c2ecf20Sopenharmony_ci fl.flowi6_oif = ifindex; 7128c2ecf20Sopenharmony_ci if (saddr) 7138c2ecf20Sopenharmony_ci memcpy(&fl.saddr, saddr, sizeof(struct in6_addr)); 7148c2ecf20Sopenharmony_ci if (daddr) 7158c2ecf20Sopenharmony_ci memcpy(&fl.daddr, daddr, sizeof(struct in6_addr)); 7168c2ecf20Sopenharmony_ci return (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl); 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_cistatic struct cxgbi_sock * 7208c2ecf20Sopenharmony_cicxgbi_check_route6(struct sockaddr *dst_addr, int ifindex) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci struct sockaddr_in6 *daddr6 = (struct sockaddr_in6 *)dst_addr; 7238c2ecf20Sopenharmony_ci struct dst_entry *dst; 7248c2ecf20Sopenharmony_ci struct net_device *ndev; 7258c2ecf20Sopenharmony_ci struct cxgbi_device *cdev; 7268c2ecf20Sopenharmony_ci struct rt6_info *rt = NULL; 7278c2ecf20Sopenharmony_ci struct neighbour *n; 7288c2ecf20Sopenharmony_ci struct in6_addr pref_saddr; 7298c2ecf20Sopenharmony_ci struct cxgbi_sock *csk = NULL; 7308c2ecf20Sopenharmony_ci unsigned int mtu = 0; 7318c2ecf20Sopenharmony_ci int port = 0xFFFF; 7328c2ecf20Sopenharmony_ci int err = 0; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci rt = find_route_ipv6(NULL, &daddr6->sin6_addr, ifindex); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci if (!rt) { 7378c2ecf20Sopenharmony_ci pr_info("no route to ipv6 %pI6 port %u\n", 7388c2ecf20Sopenharmony_ci daddr6->sin6_addr.s6_addr, 7398c2ecf20Sopenharmony_ci be16_to_cpu(daddr6->sin6_port)); 7408c2ecf20Sopenharmony_ci err = -ENETUNREACH; 7418c2ecf20Sopenharmony_ci goto err_out; 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci dst = &rt->dst; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci n = dst_neigh_lookup(dst, &daddr6->sin6_addr); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci if (!n) { 7498c2ecf20Sopenharmony_ci pr_info("%pI6, port %u, dst no neighbour.\n", 7508c2ecf20Sopenharmony_ci daddr6->sin6_addr.s6_addr, 7518c2ecf20Sopenharmony_ci be16_to_cpu(daddr6->sin6_port)); 7528c2ecf20Sopenharmony_ci err = -ENETUNREACH; 7538c2ecf20Sopenharmony_ci goto rel_rt; 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci ndev = n->dev; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci if (!(ndev->flags & IFF_UP) || !netif_carrier_ok(ndev)) { 7588c2ecf20Sopenharmony_ci pr_info("%s interface not up.\n", ndev->name); 7598c2ecf20Sopenharmony_ci err = -ENETDOWN; 7608c2ecf20Sopenharmony_ci goto rel_rt; 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci if (ipv6_addr_is_multicast(&daddr6->sin6_addr)) { 7648c2ecf20Sopenharmony_ci pr_info("multi-cast route %pI6 port %u, dev %s.\n", 7658c2ecf20Sopenharmony_ci daddr6->sin6_addr.s6_addr, 7668c2ecf20Sopenharmony_ci ntohs(daddr6->sin6_port), ndev->name); 7678c2ecf20Sopenharmony_ci err = -ENETUNREACH; 7688c2ecf20Sopenharmony_ci goto rel_rt; 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci cdev = cxgbi_device_find_by_netdev(ndev, &port); 7728c2ecf20Sopenharmony_ci if (!cdev) 7738c2ecf20Sopenharmony_ci cdev = cxgbi_device_find_by_mac(ndev, &port); 7748c2ecf20Sopenharmony_ci if (!cdev) { 7758c2ecf20Sopenharmony_ci pr_info("dst %pI6 %s, NOT cxgbi device.\n", 7768c2ecf20Sopenharmony_ci daddr6->sin6_addr.s6_addr, ndev->name); 7778c2ecf20Sopenharmony_ci err = -ENETUNREACH; 7788c2ecf20Sopenharmony_ci goto rel_rt; 7798c2ecf20Sopenharmony_ci } 7808c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, 7818c2ecf20Sopenharmony_ci "route to %pI6 :%u, ndev p#%d,%s, cdev 0x%p.\n", 7828c2ecf20Sopenharmony_ci daddr6->sin6_addr.s6_addr, ntohs(daddr6->sin6_port), port, 7838c2ecf20Sopenharmony_ci ndev->name, cdev); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci csk = cxgbi_sock_create(cdev); 7868c2ecf20Sopenharmony_ci if (!csk) { 7878c2ecf20Sopenharmony_ci err = -ENOMEM; 7888c2ecf20Sopenharmony_ci goto rel_rt; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci csk->cdev = cdev; 7918c2ecf20Sopenharmony_ci csk->port_id = port; 7928c2ecf20Sopenharmony_ci csk->mtu = mtu; 7938c2ecf20Sopenharmony_ci csk->dst = dst; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci rt6_get_prefsrc(rt, &pref_saddr); 7968c2ecf20Sopenharmony_ci if (ipv6_addr_any(&pref_saddr)) { 7978c2ecf20Sopenharmony_ci struct inet6_dev *idev = ip6_dst_idev((struct dst_entry *)rt); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci err = ipv6_dev_get_saddr(&init_net, idev ? idev->dev : NULL, 8008c2ecf20Sopenharmony_ci &daddr6->sin6_addr, 0, &pref_saddr); 8018c2ecf20Sopenharmony_ci if (err) { 8028c2ecf20Sopenharmony_ci pr_info("failed to get source address to reach %pI6\n", 8038c2ecf20Sopenharmony_ci &daddr6->sin6_addr); 8048c2ecf20Sopenharmony_ci goto rel_rt; 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci csk->csk_family = AF_INET6; 8098c2ecf20Sopenharmony_ci csk->daddr6.sin6_addr = daddr6->sin6_addr; 8108c2ecf20Sopenharmony_ci csk->daddr6.sin6_port = daddr6->sin6_port; 8118c2ecf20Sopenharmony_ci csk->daddr6.sin6_family = daddr6->sin6_family; 8128c2ecf20Sopenharmony_ci csk->saddr6.sin6_family = daddr6->sin6_family; 8138c2ecf20Sopenharmony_ci csk->saddr6.sin6_addr = pref_saddr; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci neigh_release(n); 8168c2ecf20Sopenharmony_ci return csk; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_cirel_rt: 8198c2ecf20Sopenharmony_ci if (n) 8208c2ecf20Sopenharmony_ci neigh_release(n); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci ip6_rt_put(rt); 8238c2ecf20Sopenharmony_ci if (csk) 8248c2ecf20Sopenharmony_ci cxgbi_sock_closed(csk); 8258c2ecf20Sopenharmony_cierr_out: 8268c2ecf20Sopenharmony_ci return ERR_PTR(err); 8278c2ecf20Sopenharmony_ci} 8288c2ecf20Sopenharmony_ci#endif /* IS_ENABLED(CONFIG_IPV6) */ 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_civoid cxgbi_sock_established(struct cxgbi_sock *csk, unsigned int snd_isn, 8318c2ecf20Sopenharmony_ci unsigned int opt) 8328c2ecf20Sopenharmony_ci{ 8338c2ecf20Sopenharmony_ci csk->write_seq = csk->snd_nxt = csk->snd_una = snd_isn; 8348c2ecf20Sopenharmony_ci dst_confirm(csk->dst); 8358c2ecf20Sopenharmony_ci smp_mb(); 8368c2ecf20Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_ESTABLISHED); 8378c2ecf20Sopenharmony_ci} 8388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_established); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_cistatic void cxgbi_inform_iscsi_conn_closing(struct cxgbi_sock *csk) 8418c2ecf20Sopenharmony_ci{ 8428c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, 8438c2ecf20Sopenharmony_ci "csk 0x%p, state %u, flags 0x%lx, conn 0x%p.\n", 8448c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->user_data); 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci if (csk->state != CTP_ESTABLISHED) { 8478c2ecf20Sopenharmony_ci read_lock_bh(&csk->callback_lock); 8488c2ecf20Sopenharmony_ci if (csk->user_data) 8498c2ecf20Sopenharmony_ci iscsi_conn_failure(csk->user_data, 8508c2ecf20Sopenharmony_ci ISCSI_ERR_TCP_CONN_CLOSE); 8518c2ecf20Sopenharmony_ci read_unlock_bh(&csk->callback_lock); 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci} 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_civoid cxgbi_sock_closed(struct cxgbi_sock *csk) 8568c2ecf20Sopenharmony_ci{ 8578c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", 8588c2ecf20Sopenharmony_ci csk, (csk)->state, (csk)->flags, (csk)->tid); 8598c2ecf20Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_ACTIVE_CLOSE_NEEDED); 8608c2ecf20Sopenharmony_ci if (csk->state == CTP_ACTIVE_OPEN || csk->state == CTP_CLOSED) 8618c2ecf20Sopenharmony_ci return; 8628c2ecf20Sopenharmony_ci if (csk->saddr.sin_port) 8638c2ecf20Sopenharmony_ci sock_put_port(csk); 8648c2ecf20Sopenharmony_ci if (csk->dst) 8658c2ecf20Sopenharmony_ci dst_release(csk->dst); 8668c2ecf20Sopenharmony_ci csk->cdev->csk_release_offload_resources(csk); 8678c2ecf20Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_CLOSED); 8688c2ecf20Sopenharmony_ci cxgbi_inform_iscsi_conn_closing(csk); 8698c2ecf20Sopenharmony_ci cxgbi_sock_put(csk); 8708c2ecf20Sopenharmony_ci} 8718c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_closed); 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_cistatic void need_active_close(struct cxgbi_sock *csk) 8748c2ecf20Sopenharmony_ci{ 8758c2ecf20Sopenharmony_ci int data_lost; 8768c2ecf20Sopenharmony_ci int close_req = 0; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", 8798c2ecf20Sopenharmony_ci csk, (csk)->state, (csk)->flags, (csk)->tid); 8808c2ecf20Sopenharmony_ci spin_lock_bh(&csk->lock); 8818c2ecf20Sopenharmony_ci if (csk->dst) 8828c2ecf20Sopenharmony_ci dst_confirm(csk->dst); 8838c2ecf20Sopenharmony_ci data_lost = skb_queue_len(&csk->receive_queue); 8848c2ecf20Sopenharmony_ci __skb_queue_purge(&csk->receive_queue); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci if (csk->state == CTP_ACTIVE_OPEN) 8878c2ecf20Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_ACTIVE_CLOSE_NEEDED); 8888c2ecf20Sopenharmony_ci else if (csk->state == CTP_ESTABLISHED) { 8898c2ecf20Sopenharmony_ci close_req = 1; 8908c2ecf20Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_ACTIVE_CLOSE); 8918c2ecf20Sopenharmony_ci } else if (csk->state == CTP_PASSIVE_CLOSE) { 8928c2ecf20Sopenharmony_ci close_req = 1; 8938c2ecf20Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_CLOSE_WAIT_2); 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci if (close_req) { 8978c2ecf20Sopenharmony_ci if (!cxgbi_sock_flag(csk, CTPF_LOGOUT_RSP_RCVD) || 8988c2ecf20Sopenharmony_ci data_lost) 8998c2ecf20Sopenharmony_ci csk->cdev->csk_send_abort_req(csk); 9008c2ecf20Sopenharmony_ci else 9018c2ecf20Sopenharmony_ci csk->cdev->csk_send_close_req(csk); 9028c2ecf20Sopenharmony_ci } 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci spin_unlock_bh(&csk->lock); 9058c2ecf20Sopenharmony_ci} 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_civoid cxgbi_sock_fail_act_open(struct cxgbi_sock *csk, int errno) 9088c2ecf20Sopenharmony_ci{ 9098c2ecf20Sopenharmony_ci pr_info("csk 0x%p,%u,%lx, %pI4:%u-%pI4:%u, err %d.\n", 9108c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, 9118c2ecf20Sopenharmony_ci &csk->saddr.sin_addr.s_addr, csk->saddr.sin_port, 9128c2ecf20Sopenharmony_ci &csk->daddr.sin_addr.s_addr, csk->daddr.sin_port, 9138c2ecf20Sopenharmony_ci errno); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_CONNECTING); 9168c2ecf20Sopenharmony_ci csk->err = errno; 9178c2ecf20Sopenharmony_ci cxgbi_sock_closed(csk); 9188c2ecf20Sopenharmony_ci} 9198c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_fail_act_open); 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_civoid cxgbi_sock_act_open_req_arp_failure(void *handle, struct sk_buff *skb) 9228c2ecf20Sopenharmony_ci{ 9238c2ecf20Sopenharmony_ci struct cxgbi_sock *csk = (struct cxgbi_sock *)skb->sk; 9248c2ecf20Sopenharmony_ci struct module *owner = csk->cdev->owner; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", 9278c2ecf20Sopenharmony_ci csk, (csk)->state, (csk)->flags, (csk)->tid); 9288c2ecf20Sopenharmony_ci cxgbi_sock_get(csk); 9298c2ecf20Sopenharmony_ci spin_lock_bh(&csk->lock); 9308c2ecf20Sopenharmony_ci if (csk->state == CTP_ACTIVE_OPEN) 9318c2ecf20Sopenharmony_ci cxgbi_sock_fail_act_open(csk, -EHOSTUNREACH); 9328c2ecf20Sopenharmony_ci spin_unlock_bh(&csk->lock); 9338c2ecf20Sopenharmony_ci cxgbi_sock_put(csk); 9348c2ecf20Sopenharmony_ci __kfree_skb(skb); 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci module_put(owner); 9378c2ecf20Sopenharmony_ci} 9388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_act_open_req_arp_failure); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_civoid cxgbi_sock_rcv_abort_rpl(struct cxgbi_sock *csk) 9418c2ecf20Sopenharmony_ci{ 9428c2ecf20Sopenharmony_ci cxgbi_sock_get(csk); 9438c2ecf20Sopenharmony_ci spin_lock_bh(&csk->lock); 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_ABORT_RPL_RCVD); 9468c2ecf20Sopenharmony_ci if (cxgbi_sock_flag(csk, CTPF_ABORT_RPL_PENDING)) { 9478c2ecf20Sopenharmony_ci cxgbi_sock_clear_flag(csk, CTPF_ABORT_RPL_PENDING); 9488c2ecf20Sopenharmony_ci if (cxgbi_sock_flag(csk, CTPF_ABORT_REQ_RCVD)) 9498c2ecf20Sopenharmony_ci pr_err("csk 0x%p,%u,0x%lx,%u,ABT_RPL_RSS.\n", 9508c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 9518c2ecf20Sopenharmony_ci cxgbi_sock_closed(csk); 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci spin_unlock_bh(&csk->lock); 9558c2ecf20Sopenharmony_ci cxgbi_sock_put(csk); 9568c2ecf20Sopenharmony_ci} 9578c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_rcv_abort_rpl); 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_civoid cxgbi_sock_rcv_peer_close(struct cxgbi_sock *csk) 9608c2ecf20Sopenharmony_ci{ 9618c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", 9628c2ecf20Sopenharmony_ci csk, (csk)->state, (csk)->flags, (csk)->tid); 9638c2ecf20Sopenharmony_ci cxgbi_sock_get(csk); 9648c2ecf20Sopenharmony_ci spin_lock_bh(&csk->lock); 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci if (cxgbi_sock_flag(csk, CTPF_ABORT_RPL_PENDING)) 9678c2ecf20Sopenharmony_ci goto done; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci switch (csk->state) { 9708c2ecf20Sopenharmony_ci case CTP_ESTABLISHED: 9718c2ecf20Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_PASSIVE_CLOSE); 9728c2ecf20Sopenharmony_ci break; 9738c2ecf20Sopenharmony_ci case CTP_ACTIVE_CLOSE: 9748c2ecf20Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_CLOSE_WAIT_2); 9758c2ecf20Sopenharmony_ci break; 9768c2ecf20Sopenharmony_ci case CTP_CLOSE_WAIT_1: 9778c2ecf20Sopenharmony_ci cxgbi_sock_closed(csk); 9788c2ecf20Sopenharmony_ci break; 9798c2ecf20Sopenharmony_ci case CTP_ABORTING: 9808c2ecf20Sopenharmony_ci break; 9818c2ecf20Sopenharmony_ci default: 9828c2ecf20Sopenharmony_ci pr_err("csk 0x%p,%u,0x%lx,%u, bad state.\n", 9838c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci cxgbi_inform_iscsi_conn_closing(csk); 9868c2ecf20Sopenharmony_cidone: 9878c2ecf20Sopenharmony_ci spin_unlock_bh(&csk->lock); 9888c2ecf20Sopenharmony_ci cxgbi_sock_put(csk); 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_rcv_peer_close); 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_civoid cxgbi_sock_rcv_close_conn_rpl(struct cxgbi_sock *csk, u32 snd_nxt) 9938c2ecf20Sopenharmony_ci{ 9948c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", 9958c2ecf20Sopenharmony_ci csk, (csk)->state, (csk)->flags, (csk)->tid); 9968c2ecf20Sopenharmony_ci cxgbi_sock_get(csk); 9978c2ecf20Sopenharmony_ci spin_lock_bh(&csk->lock); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci csk->snd_una = snd_nxt - 1; 10008c2ecf20Sopenharmony_ci if (cxgbi_sock_flag(csk, CTPF_ABORT_RPL_PENDING)) 10018c2ecf20Sopenharmony_ci goto done; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci switch (csk->state) { 10048c2ecf20Sopenharmony_ci case CTP_ACTIVE_CLOSE: 10058c2ecf20Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_CLOSE_WAIT_1); 10068c2ecf20Sopenharmony_ci break; 10078c2ecf20Sopenharmony_ci case CTP_CLOSE_WAIT_1: 10088c2ecf20Sopenharmony_ci case CTP_CLOSE_WAIT_2: 10098c2ecf20Sopenharmony_ci cxgbi_sock_closed(csk); 10108c2ecf20Sopenharmony_ci break; 10118c2ecf20Sopenharmony_ci case CTP_ABORTING: 10128c2ecf20Sopenharmony_ci break; 10138c2ecf20Sopenharmony_ci default: 10148c2ecf20Sopenharmony_ci pr_err("csk 0x%p,%u,0x%lx,%u, bad state.\n", 10158c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 10168c2ecf20Sopenharmony_ci } 10178c2ecf20Sopenharmony_cidone: 10188c2ecf20Sopenharmony_ci spin_unlock_bh(&csk->lock); 10198c2ecf20Sopenharmony_ci cxgbi_sock_put(csk); 10208c2ecf20Sopenharmony_ci} 10218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_rcv_close_conn_rpl); 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_civoid cxgbi_sock_rcv_wr_ack(struct cxgbi_sock *csk, unsigned int credits, 10248c2ecf20Sopenharmony_ci unsigned int snd_una, int seq_chk) 10258c2ecf20Sopenharmony_ci{ 10268c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 10278c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, cr %u,%u+%u, snd_una %u,%d.\n", 10288c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, credits, 10298c2ecf20Sopenharmony_ci csk->wr_cred, csk->wr_una_cred, snd_una, seq_chk); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci spin_lock_bh(&csk->lock); 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci csk->wr_cred += credits; 10348c2ecf20Sopenharmony_ci if (csk->wr_una_cred > csk->wr_max_cred - csk->wr_cred) 10358c2ecf20Sopenharmony_ci csk->wr_una_cred = csk->wr_max_cred - csk->wr_cred; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci while (credits) { 10388c2ecf20Sopenharmony_ci struct sk_buff *p = cxgbi_sock_peek_wr(csk); 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci if (unlikely(!p)) { 10418c2ecf20Sopenharmony_ci pr_err("csk 0x%p,%u,0x%lx,%u, cr %u,%u+%u, empty.\n", 10428c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, credits, 10438c2ecf20Sopenharmony_ci csk->wr_cred, csk->wr_una_cred); 10448c2ecf20Sopenharmony_ci break; 10458c2ecf20Sopenharmony_ci } 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci if (unlikely(credits < p->csum)) { 10488c2ecf20Sopenharmony_ci pr_warn("csk 0x%p,%u,0x%lx,%u, cr %u,%u+%u, < %u.\n", 10498c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, 10508c2ecf20Sopenharmony_ci credits, csk->wr_cred, csk->wr_una_cred, 10518c2ecf20Sopenharmony_ci p->csum); 10528c2ecf20Sopenharmony_ci p->csum -= credits; 10538c2ecf20Sopenharmony_ci break; 10548c2ecf20Sopenharmony_ci } else { 10558c2ecf20Sopenharmony_ci cxgbi_sock_dequeue_wr(csk); 10568c2ecf20Sopenharmony_ci credits -= p->csum; 10578c2ecf20Sopenharmony_ci kfree_skb(p); 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci } 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci cxgbi_sock_check_wr_invariants(csk); 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci if (seq_chk) { 10648c2ecf20Sopenharmony_ci if (unlikely(before(snd_una, csk->snd_una))) { 10658c2ecf20Sopenharmony_ci pr_warn("csk 0x%p,%u,0x%lx,%u, snd_una %u/%u.", 10668c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, snd_una, 10678c2ecf20Sopenharmony_ci csk->snd_una); 10688c2ecf20Sopenharmony_ci goto done; 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci if (csk->snd_una != snd_una) { 10728c2ecf20Sopenharmony_ci csk->snd_una = snd_una; 10738c2ecf20Sopenharmony_ci dst_confirm(csk->dst); 10748c2ecf20Sopenharmony_ci } 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci if (skb_queue_len(&csk->write_queue)) { 10788c2ecf20Sopenharmony_ci if (csk->cdev->csk_push_tx_frames(csk, 0)) 10798c2ecf20Sopenharmony_ci cxgbi_conn_tx_open(csk); 10808c2ecf20Sopenharmony_ci } else 10818c2ecf20Sopenharmony_ci cxgbi_conn_tx_open(csk); 10828c2ecf20Sopenharmony_cidone: 10838c2ecf20Sopenharmony_ci spin_unlock_bh(&csk->lock); 10848c2ecf20Sopenharmony_ci} 10858c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_rcv_wr_ack); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_cistatic unsigned int cxgbi_sock_find_best_mtu(struct cxgbi_sock *csk, 10888c2ecf20Sopenharmony_ci unsigned short mtu) 10898c2ecf20Sopenharmony_ci{ 10908c2ecf20Sopenharmony_ci int i = 0; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci while (i < csk->cdev->nmtus - 1 && csk->cdev->mtus[i + 1] <= mtu) 10938c2ecf20Sopenharmony_ci ++i; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci return i; 10968c2ecf20Sopenharmony_ci} 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ciunsigned int cxgbi_sock_select_mss(struct cxgbi_sock *csk, unsigned int pmtu) 10998c2ecf20Sopenharmony_ci{ 11008c2ecf20Sopenharmony_ci unsigned int idx; 11018c2ecf20Sopenharmony_ci struct dst_entry *dst = csk->dst; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci csk->advmss = dst_metric_advmss(dst); 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci if (csk->advmss > pmtu - 40) 11068c2ecf20Sopenharmony_ci csk->advmss = pmtu - 40; 11078c2ecf20Sopenharmony_ci if (csk->advmss < csk->cdev->mtus[0] - 40) 11088c2ecf20Sopenharmony_ci csk->advmss = csk->cdev->mtus[0] - 40; 11098c2ecf20Sopenharmony_ci idx = cxgbi_sock_find_best_mtu(csk, csk->advmss + 40); 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci return idx; 11128c2ecf20Sopenharmony_ci} 11138c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_select_mss); 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_civoid cxgbi_sock_skb_entail(struct cxgbi_sock *csk, struct sk_buff *skb) 11168c2ecf20Sopenharmony_ci{ 11178c2ecf20Sopenharmony_ci cxgbi_skcb_tcp_seq(skb) = csk->write_seq; 11188c2ecf20Sopenharmony_ci __skb_queue_tail(&csk->write_queue, skb); 11198c2ecf20Sopenharmony_ci} 11208c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_skb_entail); 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_civoid cxgbi_sock_purge_wr_queue(struct cxgbi_sock *csk) 11238c2ecf20Sopenharmony_ci{ 11248c2ecf20Sopenharmony_ci struct sk_buff *skb; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci while ((skb = cxgbi_sock_dequeue_wr(csk)) != NULL) 11278c2ecf20Sopenharmony_ci kfree_skb(skb); 11288c2ecf20Sopenharmony_ci} 11298c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_purge_wr_queue); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_civoid cxgbi_sock_check_wr_invariants(const struct cxgbi_sock *csk) 11328c2ecf20Sopenharmony_ci{ 11338c2ecf20Sopenharmony_ci int pending = cxgbi_sock_count_pending_wrs(csk); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci if (unlikely(csk->wr_cred + pending != csk->wr_max_cred)) 11368c2ecf20Sopenharmony_ci pr_err("csk 0x%p, tid %u, credit %u + %u != %u.\n", 11378c2ecf20Sopenharmony_ci csk, csk->tid, csk->wr_cred, pending, csk->wr_max_cred); 11388c2ecf20Sopenharmony_ci} 11398c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_check_wr_invariants); 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_cistatic inline void 11428c2ecf20Sopenharmony_ciscmd_get_params(struct scsi_cmnd *sc, struct scatterlist **sgl, 11438c2ecf20Sopenharmony_ci unsigned int *sgcnt, unsigned int *dlen, 11448c2ecf20Sopenharmony_ci unsigned int prot) 11458c2ecf20Sopenharmony_ci{ 11468c2ecf20Sopenharmony_ci struct scsi_data_buffer *sdb = prot ? scsi_prot(sc) : &sc->sdb; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci *sgl = sdb->table.sgl; 11498c2ecf20Sopenharmony_ci *sgcnt = sdb->table.nents; 11508c2ecf20Sopenharmony_ci *dlen = sdb->length; 11518c2ecf20Sopenharmony_ci /* Caution: for protection sdb, sdb->length is invalid */ 11528c2ecf20Sopenharmony_ci} 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_civoid cxgbi_ddp_set_one_ppod(struct cxgbi_pagepod *ppod, 11558c2ecf20Sopenharmony_ci struct cxgbi_task_tag_info *ttinfo, 11568c2ecf20Sopenharmony_ci struct scatterlist **sg_pp, unsigned int *sg_off) 11578c2ecf20Sopenharmony_ci{ 11588c2ecf20Sopenharmony_ci struct scatterlist *sg = sg_pp ? *sg_pp : NULL; 11598c2ecf20Sopenharmony_ci unsigned int offset = sg_off ? *sg_off : 0; 11608c2ecf20Sopenharmony_ci dma_addr_t addr = 0UL; 11618c2ecf20Sopenharmony_ci unsigned int len = 0; 11628c2ecf20Sopenharmony_ci int i; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci memcpy(ppod, &ttinfo->hdr, sizeof(struct cxgbi_pagepod_hdr)); 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci if (sg) { 11678c2ecf20Sopenharmony_ci addr = sg_dma_address(sg); 11688c2ecf20Sopenharmony_ci len = sg_dma_len(sg); 11698c2ecf20Sopenharmony_ci } 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci for (i = 0; i < PPOD_PAGES_MAX; i++) { 11728c2ecf20Sopenharmony_ci if (sg) { 11738c2ecf20Sopenharmony_ci ppod->addr[i] = cpu_to_be64(addr + offset); 11748c2ecf20Sopenharmony_ci offset += PAGE_SIZE; 11758c2ecf20Sopenharmony_ci if (offset == (len + sg->offset)) { 11768c2ecf20Sopenharmony_ci offset = 0; 11778c2ecf20Sopenharmony_ci sg = sg_next(sg); 11788c2ecf20Sopenharmony_ci if (sg) { 11798c2ecf20Sopenharmony_ci addr = sg_dma_address(sg); 11808c2ecf20Sopenharmony_ci len = sg_dma_len(sg); 11818c2ecf20Sopenharmony_ci } 11828c2ecf20Sopenharmony_ci } 11838c2ecf20Sopenharmony_ci } else { 11848c2ecf20Sopenharmony_ci ppod->addr[i] = 0ULL; 11858c2ecf20Sopenharmony_ci } 11868c2ecf20Sopenharmony_ci } 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci /* 11898c2ecf20Sopenharmony_ci * the fifth address needs to be repeated in the next ppod, so do 11908c2ecf20Sopenharmony_ci * not move sg 11918c2ecf20Sopenharmony_ci */ 11928c2ecf20Sopenharmony_ci if (sg_pp) { 11938c2ecf20Sopenharmony_ci *sg_pp = sg; 11948c2ecf20Sopenharmony_ci *sg_off = offset; 11958c2ecf20Sopenharmony_ci } 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci if (offset == len) { 11988c2ecf20Sopenharmony_ci offset = 0; 11998c2ecf20Sopenharmony_ci sg = sg_next(sg); 12008c2ecf20Sopenharmony_ci if (sg) { 12018c2ecf20Sopenharmony_ci addr = sg_dma_address(sg); 12028c2ecf20Sopenharmony_ci len = sg_dma_len(sg); 12038c2ecf20Sopenharmony_ci } 12048c2ecf20Sopenharmony_ci } 12058c2ecf20Sopenharmony_ci ppod->addr[i] = sg ? cpu_to_be64(addr + offset) : 0ULL; 12068c2ecf20Sopenharmony_ci} 12078c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_ddp_set_one_ppod); 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci/* 12108c2ecf20Sopenharmony_ci * APIs interacting with open-iscsi libraries 12118c2ecf20Sopenharmony_ci */ 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ciint cxgbi_ddp_ppm_setup(void **ppm_pp, struct cxgbi_device *cdev, 12148c2ecf20Sopenharmony_ci struct cxgbi_tag_format *tformat, 12158c2ecf20Sopenharmony_ci unsigned int iscsi_size, unsigned int llimit, 12168c2ecf20Sopenharmony_ci unsigned int start, unsigned int rsvd_factor, 12178c2ecf20Sopenharmony_ci unsigned int edram_start, unsigned int edram_size) 12188c2ecf20Sopenharmony_ci{ 12198c2ecf20Sopenharmony_ci int err = cxgbi_ppm_init(ppm_pp, cdev->ports[0], cdev->pdev, 12208c2ecf20Sopenharmony_ci cdev->lldev, tformat, iscsi_size, llimit, start, 12218c2ecf20Sopenharmony_ci rsvd_factor, edram_start, edram_size); 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci if (err >= 0) { 12248c2ecf20Sopenharmony_ci struct cxgbi_ppm *ppm = (struct cxgbi_ppm *)(*ppm_pp); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci if (ppm->ppmax < 1024 || 12278c2ecf20Sopenharmony_ci ppm->tformat.pgsz_idx_dflt >= DDP_PGIDX_MAX) 12288c2ecf20Sopenharmony_ci cdev->flags |= CXGBI_FLAG_DDP_OFF; 12298c2ecf20Sopenharmony_ci err = 0; 12308c2ecf20Sopenharmony_ci } else { 12318c2ecf20Sopenharmony_ci cdev->flags |= CXGBI_FLAG_DDP_OFF; 12328c2ecf20Sopenharmony_ci } 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci return err; 12358c2ecf20Sopenharmony_ci} 12368c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_ddp_ppm_setup); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_cistatic int cxgbi_ddp_sgl_check(struct scatterlist *sgl, int nents) 12398c2ecf20Sopenharmony_ci{ 12408c2ecf20Sopenharmony_ci int i; 12418c2ecf20Sopenharmony_ci int last_sgidx = nents - 1; 12428c2ecf20Sopenharmony_ci struct scatterlist *sg = sgl; 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci for (i = 0; i < nents; i++, sg = sg_next(sg)) { 12458c2ecf20Sopenharmony_ci unsigned int len = sg->length + sg->offset; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci if ((sg->offset & 0x3) || (i && sg->offset) || 12488c2ecf20Sopenharmony_ci ((i != last_sgidx) && len != PAGE_SIZE)) { 12498c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_DDP, 12508c2ecf20Sopenharmony_ci "sg %u/%u, %u,%u, not aligned.\n", 12518c2ecf20Sopenharmony_ci i, nents, sg->offset, sg->length); 12528c2ecf20Sopenharmony_ci goto err_out; 12538c2ecf20Sopenharmony_ci } 12548c2ecf20Sopenharmony_ci } 12558c2ecf20Sopenharmony_ci return 0; 12568c2ecf20Sopenharmony_cierr_out: 12578c2ecf20Sopenharmony_ci return -EINVAL; 12588c2ecf20Sopenharmony_ci} 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_cistatic int cxgbi_ddp_reserve(struct cxgbi_conn *cconn, 12618c2ecf20Sopenharmony_ci struct cxgbi_task_data *tdata, u32 sw_tag, 12628c2ecf20Sopenharmony_ci unsigned int xferlen) 12638c2ecf20Sopenharmony_ci{ 12648c2ecf20Sopenharmony_ci struct cxgbi_sock *csk = cconn->cep->csk; 12658c2ecf20Sopenharmony_ci struct cxgbi_device *cdev = csk->cdev; 12668c2ecf20Sopenharmony_ci struct cxgbi_ppm *ppm = cdev->cdev2ppm(cdev); 12678c2ecf20Sopenharmony_ci struct cxgbi_task_tag_info *ttinfo = &tdata->ttinfo; 12688c2ecf20Sopenharmony_ci struct scatterlist *sgl = ttinfo->sgl; 12698c2ecf20Sopenharmony_ci unsigned int sgcnt = ttinfo->nents; 12708c2ecf20Sopenharmony_ci unsigned int sg_offset = sgl->offset; 12718c2ecf20Sopenharmony_ci int err; 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci if (cdev->flags & CXGBI_FLAG_DDP_OFF) { 12748c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_DDP, 12758c2ecf20Sopenharmony_ci "cdev 0x%p DDP off.\n", cdev); 12768c2ecf20Sopenharmony_ci return -EINVAL; 12778c2ecf20Sopenharmony_ci } 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci if (!ppm || xferlen < DDP_THRESHOLD || !sgcnt || 12808c2ecf20Sopenharmony_ci ppm->tformat.pgsz_idx_dflt >= DDP_PGIDX_MAX) { 12818c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_DDP, 12828c2ecf20Sopenharmony_ci "ppm 0x%p, pgidx %u, xfer %u, sgcnt %u, NO ddp.\n", 12838c2ecf20Sopenharmony_ci ppm, ppm ? ppm->tformat.pgsz_idx_dflt : DDP_PGIDX_MAX, 12848c2ecf20Sopenharmony_ci xferlen, ttinfo->nents); 12858c2ecf20Sopenharmony_ci return -EINVAL; 12868c2ecf20Sopenharmony_ci } 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci /* make sure the buffer is suitable for ddp */ 12898c2ecf20Sopenharmony_ci if (cxgbi_ddp_sgl_check(sgl, sgcnt) < 0) 12908c2ecf20Sopenharmony_ci return -EINVAL; 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci ttinfo->nr_pages = (xferlen + sgl->offset + (1 << PAGE_SHIFT) - 1) >> 12938c2ecf20Sopenharmony_ci PAGE_SHIFT; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci /* 12968c2ecf20Sopenharmony_ci * the ddp tag will be used for the itt in the outgoing pdu, 12978c2ecf20Sopenharmony_ci * the itt genrated by libiscsi is saved in the ppm and can be 12988c2ecf20Sopenharmony_ci * retrieved via the ddp tag 12998c2ecf20Sopenharmony_ci */ 13008c2ecf20Sopenharmony_ci err = cxgbi_ppm_ppods_reserve(ppm, ttinfo->nr_pages, 0, &ttinfo->idx, 13018c2ecf20Sopenharmony_ci &ttinfo->tag, (unsigned long)sw_tag); 13028c2ecf20Sopenharmony_ci if (err < 0) { 13038c2ecf20Sopenharmony_ci cconn->ddp_full++; 13048c2ecf20Sopenharmony_ci return err; 13058c2ecf20Sopenharmony_ci } 13068c2ecf20Sopenharmony_ci ttinfo->npods = err; 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci /* setup dma from scsi command sgl */ 13098c2ecf20Sopenharmony_ci sgl->offset = 0; 13108c2ecf20Sopenharmony_ci err = dma_map_sg(&ppm->pdev->dev, sgl, sgcnt, DMA_FROM_DEVICE); 13118c2ecf20Sopenharmony_ci sgl->offset = sg_offset; 13128c2ecf20Sopenharmony_ci if (err == 0) { 13138c2ecf20Sopenharmony_ci pr_info("%s: 0x%x, xfer %u, sgl %u dma mapping err.\n", 13148c2ecf20Sopenharmony_ci __func__, sw_tag, xferlen, sgcnt); 13158c2ecf20Sopenharmony_ci goto rel_ppods; 13168c2ecf20Sopenharmony_ci } 13178c2ecf20Sopenharmony_ci if (err != ttinfo->nr_pages) { 13188c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_DDP, 13198c2ecf20Sopenharmony_ci "%s: sw tag 0x%x, xfer %u, sgl %u, dma count %d.\n", 13208c2ecf20Sopenharmony_ci __func__, sw_tag, xferlen, sgcnt, err); 13218c2ecf20Sopenharmony_ci } 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci ttinfo->flags |= CXGBI_PPOD_INFO_FLAG_MAPPED; 13248c2ecf20Sopenharmony_ci ttinfo->cid = csk->port_id; 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci cxgbi_ppm_make_ppod_hdr(ppm, ttinfo->tag, csk->tid, sgl->offset, 13278c2ecf20Sopenharmony_ci xferlen, &ttinfo->hdr); 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci if (cdev->flags & CXGBI_FLAG_USE_PPOD_OFLDQ) { 13308c2ecf20Sopenharmony_ci /* write ppod from xmit_pdu (of iscsi_scsi_command pdu) */ 13318c2ecf20Sopenharmony_ci ttinfo->flags |= CXGBI_PPOD_INFO_FLAG_VALID; 13328c2ecf20Sopenharmony_ci } else { 13338c2ecf20Sopenharmony_ci /* write ppod from control queue now */ 13348c2ecf20Sopenharmony_ci err = cdev->csk_ddp_set_map(ppm, csk, ttinfo); 13358c2ecf20Sopenharmony_ci if (err < 0) 13368c2ecf20Sopenharmony_ci goto rel_ppods; 13378c2ecf20Sopenharmony_ci } 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci return 0; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_cirel_ppods: 13428c2ecf20Sopenharmony_ci cxgbi_ppm_ppod_release(ppm, ttinfo->idx); 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci if (ttinfo->flags & CXGBI_PPOD_INFO_FLAG_MAPPED) { 13458c2ecf20Sopenharmony_ci ttinfo->flags &= ~CXGBI_PPOD_INFO_FLAG_MAPPED; 13468c2ecf20Sopenharmony_ci dma_unmap_sg(&ppm->pdev->dev, sgl, sgcnt, DMA_FROM_DEVICE); 13478c2ecf20Sopenharmony_ci } 13488c2ecf20Sopenharmony_ci return -EINVAL; 13498c2ecf20Sopenharmony_ci} 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_cistatic void task_release_itt(struct iscsi_task *task, itt_t hdr_itt) 13528c2ecf20Sopenharmony_ci{ 13538c2ecf20Sopenharmony_ci struct scsi_cmnd *sc = task->sc; 13548c2ecf20Sopenharmony_ci struct iscsi_tcp_conn *tcp_conn = task->conn->dd_data; 13558c2ecf20Sopenharmony_ci struct cxgbi_conn *cconn = tcp_conn->dd_data; 13568c2ecf20Sopenharmony_ci struct cxgbi_device *cdev = cconn->chba->cdev; 13578c2ecf20Sopenharmony_ci struct cxgbi_ppm *ppm = cdev->cdev2ppm(cdev); 13588c2ecf20Sopenharmony_ci u32 tag = ntohl((__force u32)hdr_itt); 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_DDP, 13618c2ecf20Sopenharmony_ci "cdev 0x%p, task 0x%p, release tag 0x%x.\n", 13628c2ecf20Sopenharmony_ci cdev, task, tag); 13638c2ecf20Sopenharmony_ci if (sc && sc->sc_data_direction == DMA_FROM_DEVICE && 13648c2ecf20Sopenharmony_ci cxgbi_ppm_is_ddp_tag(ppm, tag)) { 13658c2ecf20Sopenharmony_ci struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); 13668c2ecf20Sopenharmony_ci struct cxgbi_task_tag_info *ttinfo = &tdata->ttinfo; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci if (!(cdev->flags & CXGBI_FLAG_USE_PPOD_OFLDQ)) 13698c2ecf20Sopenharmony_ci cdev->csk_ddp_clear_map(cdev, ppm, ttinfo); 13708c2ecf20Sopenharmony_ci cxgbi_ppm_ppod_release(ppm, ttinfo->idx); 13718c2ecf20Sopenharmony_ci dma_unmap_sg(&ppm->pdev->dev, ttinfo->sgl, ttinfo->nents, 13728c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 13738c2ecf20Sopenharmony_ci } 13748c2ecf20Sopenharmony_ci} 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_cistatic inline u32 cxgbi_build_sw_tag(u32 idx, u32 age) 13778c2ecf20Sopenharmony_ci{ 13788c2ecf20Sopenharmony_ci /* assume idx and age both are < 0x7FFF (32767) */ 13798c2ecf20Sopenharmony_ci return (idx << 16) | age; 13808c2ecf20Sopenharmony_ci} 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_cistatic int task_reserve_itt(struct iscsi_task *task, itt_t *hdr_itt) 13838c2ecf20Sopenharmony_ci{ 13848c2ecf20Sopenharmony_ci struct scsi_cmnd *sc = task->sc; 13858c2ecf20Sopenharmony_ci struct iscsi_conn *conn = task->conn; 13868c2ecf20Sopenharmony_ci struct iscsi_session *sess = conn->session; 13878c2ecf20Sopenharmony_ci struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 13888c2ecf20Sopenharmony_ci struct cxgbi_conn *cconn = tcp_conn->dd_data; 13898c2ecf20Sopenharmony_ci struct cxgbi_device *cdev = cconn->chba->cdev; 13908c2ecf20Sopenharmony_ci struct cxgbi_ppm *ppm = cdev->cdev2ppm(cdev); 13918c2ecf20Sopenharmony_ci u32 sw_tag = cxgbi_build_sw_tag(task->itt, sess->age); 13928c2ecf20Sopenharmony_ci u32 tag = 0; 13938c2ecf20Sopenharmony_ci int err = -EINVAL; 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci if (sc && sc->sc_data_direction == DMA_FROM_DEVICE) { 13968c2ecf20Sopenharmony_ci struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); 13978c2ecf20Sopenharmony_ci struct cxgbi_task_tag_info *ttinfo = &tdata->ttinfo; 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci scmd_get_params(sc, &ttinfo->sgl, &ttinfo->nents, 14008c2ecf20Sopenharmony_ci &tdata->dlen, 0); 14018c2ecf20Sopenharmony_ci err = cxgbi_ddp_reserve(cconn, tdata, sw_tag, tdata->dlen); 14028c2ecf20Sopenharmony_ci if (!err) 14038c2ecf20Sopenharmony_ci tag = ttinfo->tag; 14048c2ecf20Sopenharmony_ci else 14058c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_DDP, 14068c2ecf20Sopenharmony_ci "csk 0x%p, R task 0x%p, %u,%u, no ddp.\n", 14078c2ecf20Sopenharmony_ci cconn->cep->csk, task, tdata->dlen, 14088c2ecf20Sopenharmony_ci ttinfo->nents); 14098c2ecf20Sopenharmony_ci } 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci if (err < 0) { 14128c2ecf20Sopenharmony_ci err = cxgbi_ppm_make_non_ddp_tag(ppm, sw_tag, &tag); 14138c2ecf20Sopenharmony_ci if (err < 0) 14148c2ecf20Sopenharmony_ci return err; 14158c2ecf20Sopenharmony_ci } 14168c2ecf20Sopenharmony_ci /* the itt need to sent in big-endian order */ 14178c2ecf20Sopenharmony_ci *hdr_itt = (__force itt_t)htonl(tag); 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_DDP, 14208c2ecf20Sopenharmony_ci "cdev 0x%p, task 0x%p, 0x%x(0x%x,0x%x)->0x%x/0x%x.\n", 14218c2ecf20Sopenharmony_ci cdev, task, sw_tag, task->itt, sess->age, tag, *hdr_itt); 14228c2ecf20Sopenharmony_ci return 0; 14238c2ecf20Sopenharmony_ci} 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_civoid cxgbi_parse_pdu_itt(struct iscsi_conn *conn, itt_t itt, int *idx, int *age) 14268c2ecf20Sopenharmony_ci{ 14278c2ecf20Sopenharmony_ci struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 14288c2ecf20Sopenharmony_ci struct cxgbi_conn *cconn = tcp_conn->dd_data; 14298c2ecf20Sopenharmony_ci struct cxgbi_device *cdev = cconn->chba->cdev; 14308c2ecf20Sopenharmony_ci struct cxgbi_ppm *ppm = cdev->cdev2ppm(cdev); 14318c2ecf20Sopenharmony_ci u32 tag = ntohl((__force u32)itt); 14328c2ecf20Sopenharmony_ci u32 sw_bits; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci if (ppm) { 14358c2ecf20Sopenharmony_ci if (cxgbi_ppm_is_ddp_tag(ppm, tag)) 14368c2ecf20Sopenharmony_ci sw_bits = cxgbi_ppm_get_tag_caller_data(ppm, tag); 14378c2ecf20Sopenharmony_ci else 14388c2ecf20Sopenharmony_ci sw_bits = cxgbi_ppm_decode_non_ddp_tag(ppm, tag); 14398c2ecf20Sopenharmony_ci } else { 14408c2ecf20Sopenharmony_ci sw_bits = tag; 14418c2ecf20Sopenharmony_ci } 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci cxgbi_decode_sw_tag(sw_bits, idx, age); 14448c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_DDP, 14458c2ecf20Sopenharmony_ci "cdev 0x%p, tag 0x%x/0x%x, -> 0x%x(0x%x,0x%x).\n", 14468c2ecf20Sopenharmony_ci cdev, tag, itt, sw_bits, idx ? *idx : 0xFFFFF, 14478c2ecf20Sopenharmony_ci age ? *age : 0xFF); 14488c2ecf20Sopenharmony_ci} 14498c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_parse_pdu_itt); 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_civoid cxgbi_conn_tx_open(struct cxgbi_sock *csk) 14528c2ecf20Sopenharmony_ci{ 14538c2ecf20Sopenharmony_ci struct iscsi_conn *conn = csk->user_data; 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci if (conn) { 14568c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, 14578c2ecf20Sopenharmony_ci "csk 0x%p, cid %d.\n", csk, conn->id); 14588c2ecf20Sopenharmony_ci iscsi_conn_queue_work(conn); 14598c2ecf20Sopenharmony_ci } 14608c2ecf20Sopenharmony_ci} 14618c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_conn_tx_open); 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci/* 14648c2ecf20Sopenharmony_ci * pdu receive, interact with libiscsi_tcp 14658c2ecf20Sopenharmony_ci */ 14668c2ecf20Sopenharmony_cistatic inline int read_pdu_skb(struct iscsi_conn *conn, 14678c2ecf20Sopenharmony_ci struct sk_buff *skb, 14688c2ecf20Sopenharmony_ci unsigned int offset, 14698c2ecf20Sopenharmony_ci int offloaded) 14708c2ecf20Sopenharmony_ci{ 14718c2ecf20Sopenharmony_ci int status = 0; 14728c2ecf20Sopenharmony_ci int bytes_read; 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci bytes_read = iscsi_tcp_recv_skb(conn, skb, offset, offloaded, &status); 14758c2ecf20Sopenharmony_ci switch (status) { 14768c2ecf20Sopenharmony_ci case ISCSI_TCP_CONN_ERR: 14778c2ecf20Sopenharmony_ci pr_info("skb 0x%p, off %u, %d, TCP_ERR.\n", 14788c2ecf20Sopenharmony_ci skb, offset, offloaded); 14798c2ecf20Sopenharmony_ci return -EIO; 14808c2ecf20Sopenharmony_ci case ISCSI_TCP_SUSPENDED: 14818c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 14828c2ecf20Sopenharmony_ci "skb 0x%p, off %u, %d, TCP_SUSPEND, rc %d.\n", 14838c2ecf20Sopenharmony_ci skb, offset, offloaded, bytes_read); 14848c2ecf20Sopenharmony_ci /* no transfer - just have caller flush queue */ 14858c2ecf20Sopenharmony_ci return bytes_read; 14868c2ecf20Sopenharmony_ci case ISCSI_TCP_SKB_DONE: 14878c2ecf20Sopenharmony_ci pr_info("skb 0x%p, off %u, %d, TCP_SKB_DONE.\n", 14888c2ecf20Sopenharmony_ci skb, offset, offloaded); 14898c2ecf20Sopenharmony_ci /* 14908c2ecf20Sopenharmony_ci * pdus should always fit in the skb and we should get 14918c2ecf20Sopenharmony_ci * segment done notifcation. 14928c2ecf20Sopenharmony_ci */ 14938c2ecf20Sopenharmony_ci iscsi_conn_printk(KERN_ERR, conn, "Invalid pdu or skb."); 14948c2ecf20Sopenharmony_ci return -EFAULT; 14958c2ecf20Sopenharmony_ci case ISCSI_TCP_SEGMENT_DONE: 14968c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 14978c2ecf20Sopenharmony_ci "skb 0x%p, off %u, %d, TCP_SEG_DONE, rc %d.\n", 14988c2ecf20Sopenharmony_ci skb, offset, offloaded, bytes_read); 14998c2ecf20Sopenharmony_ci return bytes_read; 15008c2ecf20Sopenharmony_ci default: 15018c2ecf20Sopenharmony_ci pr_info("skb 0x%p, off %u, %d, invalid status %d.\n", 15028c2ecf20Sopenharmony_ci skb, offset, offloaded, status); 15038c2ecf20Sopenharmony_ci return -EINVAL; 15048c2ecf20Sopenharmony_ci } 15058c2ecf20Sopenharmony_ci} 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_cistatic int 15088c2ecf20Sopenharmony_ciskb_read_pdu_bhs(struct cxgbi_sock *csk, struct iscsi_conn *conn, 15098c2ecf20Sopenharmony_ci struct sk_buff *skb) 15108c2ecf20Sopenharmony_ci{ 15118c2ecf20Sopenharmony_ci struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 15128c2ecf20Sopenharmony_ci int err; 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 15158c2ecf20Sopenharmony_ci "conn 0x%p, skb 0x%p, len %u, flag 0x%lx.\n", 15168c2ecf20Sopenharmony_ci conn, skb, skb->len, cxgbi_skcb_flags(skb)); 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci if (!iscsi_tcp_recv_segment_is_hdr(tcp_conn)) { 15198c2ecf20Sopenharmony_ci pr_info("conn 0x%p, skb 0x%p, not hdr.\n", conn, skb); 15208c2ecf20Sopenharmony_ci iscsi_conn_failure(conn, ISCSI_ERR_PROTO); 15218c2ecf20Sopenharmony_ci return -EIO; 15228c2ecf20Sopenharmony_ci } 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci if (conn->hdrdgst_en && 15258c2ecf20Sopenharmony_ci cxgbi_skcb_test_flag(skb, SKCBF_RX_HCRC_ERR)) { 15268c2ecf20Sopenharmony_ci pr_info("conn 0x%p, skb 0x%p, hcrc.\n", conn, skb); 15278c2ecf20Sopenharmony_ci iscsi_conn_failure(conn, ISCSI_ERR_HDR_DGST); 15288c2ecf20Sopenharmony_ci return -EIO; 15298c2ecf20Sopenharmony_ci } 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci if (cxgbi_skcb_test_flag(skb, SKCBF_RX_ISCSI_COMPL) && 15328c2ecf20Sopenharmony_ci cxgbi_skcb_test_flag(skb, SKCBF_RX_DATA_DDPD)) { 15338c2ecf20Sopenharmony_ci /* If completion flag is set and data is directly 15348c2ecf20Sopenharmony_ci * placed in to the host memory then update 15358c2ecf20Sopenharmony_ci * task->exp_datasn to the datasn in completion 15368c2ecf20Sopenharmony_ci * iSCSI hdr as T6 adapter generates completion only 15378c2ecf20Sopenharmony_ci * for the last pdu of a sequence. 15388c2ecf20Sopenharmony_ci */ 15398c2ecf20Sopenharmony_ci itt_t itt = ((struct iscsi_data *)skb->data)->itt; 15408c2ecf20Sopenharmony_ci struct iscsi_task *task = iscsi_itt_to_ctask(conn, itt); 15418c2ecf20Sopenharmony_ci u32 data_sn = be32_to_cpu(((struct iscsi_data *) 15428c2ecf20Sopenharmony_ci skb->data)->datasn); 15438c2ecf20Sopenharmony_ci if (task && task->sc) { 15448c2ecf20Sopenharmony_ci struct iscsi_tcp_task *tcp_task = task->dd_data; 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci tcp_task->exp_datasn = data_sn; 15478c2ecf20Sopenharmony_ci } 15488c2ecf20Sopenharmony_ci } 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci err = read_pdu_skb(conn, skb, 0, 0); 15518c2ecf20Sopenharmony_ci if (likely(err >= 0)) { 15528c2ecf20Sopenharmony_ci struct iscsi_hdr *hdr = (struct iscsi_hdr *)skb->data; 15538c2ecf20Sopenharmony_ci u8 opcode = hdr->opcode & ISCSI_OPCODE_MASK; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci if (unlikely(opcode == ISCSI_OP_LOGOUT_RSP)) 15568c2ecf20Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_LOGOUT_RSP_RCVD); 15578c2ecf20Sopenharmony_ci } 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci return err; 15608c2ecf20Sopenharmony_ci} 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_cistatic int skb_read_pdu_data(struct iscsi_conn *conn, struct sk_buff *lskb, 15638c2ecf20Sopenharmony_ci struct sk_buff *skb, unsigned int offset) 15648c2ecf20Sopenharmony_ci{ 15658c2ecf20Sopenharmony_ci struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 15668c2ecf20Sopenharmony_ci bool offloaded = 0; 15678c2ecf20Sopenharmony_ci int opcode = tcp_conn->in.hdr->opcode & ISCSI_OPCODE_MASK; 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 15708c2ecf20Sopenharmony_ci "conn 0x%p, skb 0x%p, len %u, flag 0x%lx.\n", 15718c2ecf20Sopenharmony_ci conn, skb, skb->len, cxgbi_skcb_flags(skb)); 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci if (conn->datadgst_en && 15748c2ecf20Sopenharmony_ci cxgbi_skcb_test_flag(lskb, SKCBF_RX_DCRC_ERR)) { 15758c2ecf20Sopenharmony_ci pr_info("conn 0x%p, skb 0x%p, dcrc 0x%lx.\n", 15768c2ecf20Sopenharmony_ci conn, lskb, cxgbi_skcb_flags(lskb)); 15778c2ecf20Sopenharmony_ci iscsi_conn_failure(conn, ISCSI_ERR_DATA_DGST); 15788c2ecf20Sopenharmony_ci return -EIO; 15798c2ecf20Sopenharmony_ci } 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci if (iscsi_tcp_recv_segment_is_hdr(tcp_conn)) 15828c2ecf20Sopenharmony_ci return 0; 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci /* coalesced, add header digest length */ 15858c2ecf20Sopenharmony_ci if (lskb == skb && conn->hdrdgst_en) 15868c2ecf20Sopenharmony_ci offset += ISCSI_DIGEST_SIZE; 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci if (cxgbi_skcb_test_flag(lskb, SKCBF_RX_DATA_DDPD)) 15898c2ecf20Sopenharmony_ci offloaded = 1; 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci if (opcode == ISCSI_OP_SCSI_DATA_IN) 15928c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 15938c2ecf20Sopenharmony_ci "skb 0x%p, op 0x%x, itt 0x%x, %u %s ddp'ed.\n", 15948c2ecf20Sopenharmony_ci skb, opcode, ntohl(tcp_conn->in.hdr->itt), 15958c2ecf20Sopenharmony_ci tcp_conn->in.datalen, offloaded ? "is" : "not"); 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci return read_pdu_skb(conn, skb, offset, offloaded); 15988c2ecf20Sopenharmony_ci} 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_cistatic void csk_return_rx_credits(struct cxgbi_sock *csk, int copied) 16018c2ecf20Sopenharmony_ci{ 16028c2ecf20Sopenharmony_ci struct cxgbi_device *cdev = csk->cdev; 16038c2ecf20Sopenharmony_ci int must_send; 16048c2ecf20Sopenharmony_ci u32 credits; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 16078c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, seq %u, wup %u, thre %u, %u.\n", 16088c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, csk->copied_seq, 16098c2ecf20Sopenharmony_ci csk->rcv_wup, cdev->rx_credit_thres, 16108c2ecf20Sopenharmony_ci csk->rcv_win); 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci if (!cdev->rx_credit_thres) 16138c2ecf20Sopenharmony_ci return; 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci if (csk->state != CTP_ESTABLISHED) 16168c2ecf20Sopenharmony_ci return; 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ci credits = csk->copied_seq - csk->rcv_wup; 16198c2ecf20Sopenharmony_ci if (unlikely(!credits)) 16208c2ecf20Sopenharmony_ci return; 16218c2ecf20Sopenharmony_ci must_send = credits + 16384 >= csk->rcv_win; 16228c2ecf20Sopenharmony_ci if (must_send || credits >= cdev->rx_credit_thres) 16238c2ecf20Sopenharmony_ci csk->rcv_wup += cdev->csk_send_rx_credits(csk, credits); 16248c2ecf20Sopenharmony_ci} 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_civoid cxgbi_conn_pdu_ready(struct cxgbi_sock *csk) 16278c2ecf20Sopenharmony_ci{ 16288c2ecf20Sopenharmony_ci struct cxgbi_device *cdev = csk->cdev; 16298c2ecf20Sopenharmony_ci struct iscsi_conn *conn = csk->user_data; 16308c2ecf20Sopenharmony_ci struct sk_buff *skb; 16318c2ecf20Sopenharmony_ci unsigned int read = 0; 16328c2ecf20Sopenharmony_ci int err = 0; 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 16358c2ecf20Sopenharmony_ci "csk 0x%p, conn 0x%p.\n", csk, conn); 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci if (unlikely(!conn || conn->suspend_rx)) { 16388c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 16398c2ecf20Sopenharmony_ci "csk 0x%p, conn 0x%p, id %d, suspend_rx %lu!\n", 16408c2ecf20Sopenharmony_ci csk, conn, conn ? conn->id : 0xFF, 16418c2ecf20Sopenharmony_ci conn ? conn->suspend_rx : 0xFF); 16428c2ecf20Sopenharmony_ci return; 16438c2ecf20Sopenharmony_ci } 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci while (!err) { 16468c2ecf20Sopenharmony_ci skb = skb_peek(&csk->receive_queue); 16478c2ecf20Sopenharmony_ci if (!skb || 16488c2ecf20Sopenharmony_ci !(cxgbi_skcb_test_flag(skb, SKCBF_RX_STATUS))) { 16498c2ecf20Sopenharmony_ci if (skb) 16508c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 16518c2ecf20Sopenharmony_ci "skb 0x%p, NOT ready 0x%lx.\n", 16528c2ecf20Sopenharmony_ci skb, cxgbi_skcb_flags(skb)); 16538c2ecf20Sopenharmony_ci break; 16548c2ecf20Sopenharmony_ci } 16558c2ecf20Sopenharmony_ci __skb_unlink(skb, &csk->receive_queue); 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci read += cxgbi_skcb_rx_pdulen(skb); 16588c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 16598c2ecf20Sopenharmony_ci "csk 0x%p, skb 0x%p,%u,f 0x%lx, pdu len %u.\n", 16608c2ecf20Sopenharmony_ci csk, skb, skb->len, cxgbi_skcb_flags(skb), 16618c2ecf20Sopenharmony_ci cxgbi_skcb_rx_pdulen(skb)); 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci if (cxgbi_skcb_test_flag(skb, SKCBF_RX_COALESCED)) { 16648c2ecf20Sopenharmony_ci err = skb_read_pdu_bhs(csk, conn, skb); 16658c2ecf20Sopenharmony_ci if (err < 0) { 16668c2ecf20Sopenharmony_ci pr_err("coalesced bhs, csk 0x%p, skb 0x%p,%u, " 16678c2ecf20Sopenharmony_ci "f 0x%lx, plen %u.\n", 16688c2ecf20Sopenharmony_ci csk, skb, skb->len, 16698c2ecf20Sopenharmony_ci cxgbi_skcb_flags(skb), 16708c2ecf20Sopenharmony_ci cxgbi_skcb_rx_pdulen(skb)); 16718c2ecf20Sopenharmony_ci goto skb_done; 16728c2ecf20Sopenharmony_ci } 16738c2ecf20Sopenharmony_ci err = skb_read_pdu_data(conn, skb, skb, 16748c2ecf20Sopenharmony_ci err + cdev->skb_rx_extra); 16758c2ecf20Sopenharmony_ci if (err < 0) 16768c2ecf20Sopenharmony_ci pr_err("coalesced data, csk 0x%p, skb 0x%p,%u, " 16778c2ecf20Sopenharmony_ci "f 0x%lx, plen %u.\n", 16788c2ecf20Sopenharmony_ci csk, skb, skb->len, 16798c2ecf20Sopenharmony_ci cxgbi_skcb_flags(skb), 16808c2ecf20Sopenharmony_ci cxgbi_skcb_rx_pdulen(skb)); 16818c2ecf20Sopenharmony_ci } else { 16828c2ecf20Sopenharmony_ci err = skb_read_pdu_bhs(csk, conn, skb); 16838c2ecf20Sopenharmony_ci if (err < 0) { 16848c2ecf20Sopenharmony_ci pr_err("bhs, csk 0x%p, skb 0x%p,%u, " 16858c2ecf20Sopenharmony_ci "f 0x%lx, plen %u.\n", 16868c2ecf20Sopenharmony_ci csk, skb, skb->len, 16878c2ecf20Sopenharmony_ci cxgbi_skcb_flags(skb), 16888c2ecf20Sopenharmony_ci cxgbi_skcb_rx_pdulen(skb)); 16898c2ecf20Sopenharmony_ci goto skb_done; 16908c2ecf20Sopenharmony_ci } 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci if (cxgbi_skcb_test_flag(skb, SKCBF_RX_DATA)) { 16938c2ecf20Sopenharmony_ci struct sk_buff *dskb; 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci dskb = skb_peek(&csk->receive_queue); 16968c2ecf20Sopenharmony_ci if (!dskb) { 16978c2ecf20Sopenharmony_ci pr_err("csk 0x%p, skb 0x%p,%u, f 0x%lx," 16988c2ecf20Sopenharmony_ci " plen %u, NO data.\n", 16998c2ecf20Sopenharmony_ci csk, skb, skb->len, 17008c2ecf20Sopenharmony_ci cxgbi_skcb_flags(skb), 17018c2ecf20Sopenharmony_ci cxgbi_skcb_rx_pdulen(skb)); 17028c2ecf20Sopenharmony_ci err = -EIO; 17038c2ecf20Sopenharmony_ci goto skb_done; 17048c2ecf20Sopenharmony_ci } 17058c2ecf20Sopenharmony_ci __skb_unlink(dskb, &csk->receive_queue); 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci err = skb_read_pdu_data(conn, skb, dskb, 0); 17088c2ecf20Sopenharmony_ci if (err < 0) 17098c2ecf20Sopenharmony_ci pr_err("data, csk 0x%p, skb 0x%p,%u, " 17108c2ecf20Sopenharmony_ci "f 0x%lx, plen %u, dskb 0x%p," 17118c2ecf20Sopenharmony_ci "%u.\n", 17128c2ecf20Sopenharmony_ci csk, skb, skb->len, 17138c2ecf20Sopenharmony_ci cxgbi_skcb_flags(skb), 17148c2ecf20Sopenharmony_ci cxgbi_skcb_rx_pdulen(skb), 17158c2ecf20Sopenharmony_ci dskb, dskb->len); 17168c2ecf20Sopenharmony_ci __kfree_skb(dskb); 17178c2ecf20Sopenharmony_ci } else 17188c2ecf20Sopenharmony_ci err = skb_read_pdu_data(conn, skb, skb, 0); 17198c2ecf20Sopenharmony_ci } 17208c2ecf20Sopenharmony_ciskb_done: 17218c2ecf20Sopenharmony_ci __kfree_skb(skb); 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci if (err < 0) 17248c2ecf20Sopenharmony_ci break; 17258c2ecf20Sopenharmony_ci } 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, "csk 0x%p, read %u.\n", csk, read); 17288c2ecf20Sopenharmony_ci if (read) { 17298c2ecf20Sopenharmony_ci csk->copied_seq += read; 17308c2ecf20Sopenharmony_ci csk_return_rx_credits(csk, read); 17318c2ecf20Sopenharmony_ci conn->rxdata_octets += read; 17328c2ecf20Sopenharmony_ci } 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci if (err < 0) { 17358c2ecf20Sopenharmony_ci pr_info("csk 0x%p, 0x%p, rx failed %d, read %u.\n", 17368c2ecf20Sopenharmony_ci csk, conn, err, read); 17378c2ecf20Sopenharmony_ci iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); 17388c2ecf20Sopenharmony_ci } 17398c2ecf20Sopenharmony_ci} 17408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_conn_pdu_ready); 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_cistatic int sgl_seek_offset(struct scatterlist *sgl, unsigned int sgcnt, 17438c2ecf20Sopenharmony_ci unsigned int offset, unsigned int *off, 17448c2ecf20Sopenharmony_ci struct scatterlist **sgp) 17458c2ecf20Sopenharmony_ci{ 17468c2ecf20Sopenharmony_ci int i; 17478c2ecf20Sopenharmony_ci struct scatterlist *sg; 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci for_each_sg(sgl, sg, sgcnt, i) { 17508c2ecf20Sopenharmony_ci if (offset < sg->length) { 17518c2ecf20Sopenharmony_ci *off = offset; 17528c2ecf20Sopenharmony_ci *sgp = sg; 17538c2ecf20Sopenharmony_ci return 0; 17548c2ecf20Sopenharmony_ci } 17558c2ecf20Sopenharmony_ci offset -= sg->length; 17568c2ecf20Sopenharmony_ci } 17578c2ecf20Sopenharmony_ci return -EFAULT; 17588c2ecf20Sopenharmony_ci} 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_cistatic int 17618c2ecf20Sopenharmony_cisgl_read_to_frags(struct scatterlist *sg, unsigned int sgoffset, 17628c2ecf20Sopenharmony_ci unsigned int dlen, struct page_frag *frags, 17638c2ecf20Sopenharmony_ci int frag_max, u32 *dlimit) 17648c2ecf20Sopenharmony_ci{ 17658c2ecf20Sopenharmony_ci unsigned int datalen = dlen; 17668c2ecf20Sopenharmony_ci unsigned int sglen = sg->length - sgoffset; 17678c2ecf20Sopenharmony_ci struct page *page = sg_page(sg); 17688c2ecf20Sopenharmony_ci int i; 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci i = 0; 17718c2ecf20Sopenharmony_ci do { 17728c2ecf20Sopenharmony_ci unsigned int copy; 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci if (!sglen) { 17758c2ecf20Sopenharmony_ci sg = sg_next(sg); 17768c2ecf20Sopenharmony_ci if (!sg) { 17778c2ecf20Sopenharmony_ci pr_warn("sg %d NULL, len %u/%u.\n", 17788c2ecf20Sopenharmony_ci i, datalen, dlen); 17798c2ecf20Sopenharmony_ci return -EINVAL; 17808c2ecf20Sopenharmony_ci } 17818c2ecf20Sopenharmony_ci sgoffset = 0; 17828c2ecf20Sopenharmony_ci sglen = sg->length; 17838c2ecf20Sopenharmony_ci page = sg_page(sg); 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci } 17868c2ecf20Sopenharmony_ci copy = min(datalen, sglen); 17878c2ecf20Sopenharmony_ci if (i && page == frags[i - 1].page && 17888c2ecf20Sopenharmony_ci sgoffset + sg->offset == 17898c2ecf20Sopenharmony_ci frags[i - 1].offset + frags[i - 1].size) { 17908c2ecf20Sopenharmony_ci frags[i - 1].size += copy; 17918c2ecf20Sopenharmony_ci } else { 17928c2ecf20Sopenharmony_ci if (i >= frag_max) { 17938c2ecf20Sopenharmony_ci pr_warn("too many pages %u, dlen %u.\n", 17948c2ecf20Sopenharmony_ci frag_max, dlen); 17958c2ecf20Sopenharmony_ci *dlimit = dlen - datalen; 17968c2ecf20Sopenharmony_ci return -EINVAL; 17978c2ecf20Sopenharmony_ci } 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci frags[i].page = page; 18008c2ecf20Sopenharmony_ci frags[i].offset = sg->offset + sgoffset; 18018c2ecf20Sopenharmony_ci frags[i].size = copy; 18028c2ecf20Sopenharmony_ci i++; 18038c2ecf20Sopenharmony_ci } 18048c2ecf20Sopenharmony_ci datalen -= copy; 18058c2ecf20Sopenharmony_ci sgoffset += copy; 18068c2ecf20Sopenharmony_ci sglen -= copy; 18078c2ecf20Sopenharmony_ci } while (datalen); 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci return i; 18108c2ecf20Sopenharmony_ci} 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_cistatic void cxgbi_task_data_sgl_check(struct iscsi_task *task) 18138c2ecf20Sopenharmony_ci{ 18148c2ecf20Sopenharmony_ci struct scsi_cmnd *sc = task->sc; 18158c2ecf20Sopenharmony_ci struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); 18168c2ecf20Sopenharmony_ci struct scatterlist *sg, *sgl = NULL; 18178c2ecf20Sopenharmony_ci u32 sgcnt = 0; 18188c2ecf20Sopenharmony_ci int i; 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_ci tdata->flags = CXGBI_TASK_SGL_CHECKED; 18218c2ecf20Sopenharmony_ci if (!sc) 18228c2ecf20Sopenharmony_ci return; 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci scmd_get_params(sc, &sgl, &sgcnt, &tdata->dlen, 0); 18258c2ecf20Sopenharmony_ci if (!sgl || !sgcnt) { 18268c2ecf20Sopenharmony_ci tdata->flags |= CXGBI_TASK_SGL_COPY; 18278c2ecf20Sopenharmony_ci return; 18288c2ecf20Sopenharmony_ci } 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci for_each_sg(sgl, sg, sgcnt, i) { 18318c2ecf20Sopenharmony_ci if (page_count(sg_page(sg)) < 1) { 18328c2ecf20Sopenharmony_ci tdata->flags |= CXGBI_TASK_SGL_COPY; 18338c2ecf20Sopenharmony_ci return; 18348c2ecf20Sopenharmony_ci } 18358c2ecf20Sopenharmony_ci } 18368c2ecf20Sopenharmony_ci} 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_cistatic int 18398c2ecf20Sopenharmony_cicxgbi_task_data_sgl_read(struct iscsi_task *task, u32 offset, u32 count, 18408c2ecf20Sopenharmony_ci u32 *dlimit) 18418c2ecf20Sopenharmony_ci{ 18428c2ecf20Sopenharmony_ci struct scsi_cmnd *sc = task->sc; 18438c2ecf20Sopenharmony_ci struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); 18448c2ecf20Sopenharmony_ci struct scatterlist *sgl = NULL; 18458c2ecf20Sopenharmony_ci struct scatterlist *sg; 18468c2ecf20Sopenharmony_ci u32 dlen = 0; 18478c2ecf20Sopenharmony_ci u32 sgcnt; 18488c2ecf20Sopenharmony_ci int err; 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci if (!sc) 18518c2ecf20Sopenharmony_ci return 0; 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci scmd_get_params(sc, &sgl, &sgcnt, &dlen, 0); 18548c2ecf20Sopenharmony_ci if (!sgl || !sgcnt) 18558c2ecf20Sopenharmony_ci return 0; 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci err = sgl_seek_offset(sgl, sgcnt, offset, &tdata->sgoffset, &sg); 18588c2ecf20Sopenharmony_ci if (err < 0) { 18598c2ecf20Sopenharmony_ci pr_warn("tpdu max, sgl %u, bad offset %u/%u.\n", 18608c2ecf20Sopenharmony_ci sgcnt, offset, tdata->dlen); 18618c2ecf20Sopenharmony_ci return err; 18628c2ecf20Sopenharmony_ci } 18638c2ecf20Sopenharmony_ci err = sgl_read_to_frags(sg, tdata->sgoffset, count, 18648c2ecf20Sopenharmony_ci tdata->frags, MAX_SKB_FRAGS, dlimit); 18658c2ecf20Sopenharmony_ci if (err < 0) { 18668c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 18678c2ecf20Sopenharmony_ci "sgl max limit, sgl %u, offset %u, %u/%u, dlimit %u.\n", 18688c2ecf20Sopenharmony_ci sgcnt, offset, count, tdata->dlen, *dlimit); 18698c2ecf20Sopenharmony_ci return err; 18708c2ecf20Sopenharmony_ci } 18718c2ecf20Sopenharmony_ci tdata->offset = offset; 18728c2ecf20Sopenharmony_ci tdata->count = count; 18738c2ecf20Sopenharmony_ci tdata->nr_frags = err; 18748c2ecf20Sopenharmony_ci tdata->total_count = count; 18758c2ecf20Sopenharmony_ci tdata->total_offset = offset; 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, 18788c2ecf20Sopenharmony_ci "%s: offset %u, count %u,\n" 18798c2ecf20Sopenharmony_ci "err %u, total_count %u, total_offset %u\n", 18808c2ecf20Sopenharmony_ci __func__, offset, count, err, tdata->total_count, tdata->total_offset); 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci return 0; 18838c2ecf20Sopenharmony_ci} 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ciint cxgbi_conn_alloc_pdu(struct iscsi_task *task, u8 op) 18868c2ecf20Sopenharmony_ci{ 18878c2ecf20Sopenharmony_ci struct iscsi_conn *conn = task->conn; 18888c2ecf20Sopenharmony_ci struct iscsi_session *session = task->conn->session; 18898c2ecf20Sopenharmony_ci struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 18908c2ecf20Sopenharmony_ci struct cxgbi_conn *cconn = tcp_conn->dd_data; 18918c2ecf20Sopenharmony_ci struct cxgbi_device *cdev = cconn->chba->cdev; 18928c2ecf20Sopenharmony_ci struct cxgbi_sock *csk = cconn->cep ? cconn->cep->csk : NULL; 18938c2ecf20Sopenharmony_ci struct iscsi_tcp_task *tcp_task = task->dd_data; 18948c2ecf20Sopenharmony_ci struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); 18958c2ecf20Sopenharmony_ci struct scsi_cmnd *sc = task->sc; 18968c2ecf20Sopenharmony_ci u32 headroom = SKB_TX_ISCSI_PDU_HEADER_MAX; 18978c2ecf20Sopenharmony_ci u32 max_txdata_len = conn->max_xmit_dlength; 18988c2ecf20Sopenharmony_ci u32 iso_tx_rsvd = 0, local_iso_info = 0; 18998c2ecf20Sopenharmony_ci u32 last_tdata_offset, last_tdata_count; 19008c2ecf20Sopenharmony_ci int err = 0; 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci if (!tcp_task) { 19038c2ecf20Sopenharmony_ci pr_err("task 0x%p, tcp_task 0x%p, tdata 0x%p.\n", 19048c2ecf20Sopenharmony_ci task, tcp_task, tdata); 19058c2ecf20Sopenharmony_ci return -ENOMEM; 19068c2ecf20Sopenharmony_ci } 19078c2ecf20Sopenharmony_ci if (!csk) { 19088c2ecf20Sopenharmony_ci pr_err("task 0x%p, csk gone.\n", task); 19098c2ecf20Sopenharmony_ci return -EPIPE; 19108c2ecf20Sopenharmony_ci } 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci op &= ISCSI_OPCODE_MASK; 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci tcp_task->dd_data = tdata; 19158c2ecf20Sopenharmony_ci task->hdr = NULL; 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci last_tdata_count = tdata->count; 19188c2ecf20Sopenharmony_ci last_tdata_offset = tdata->offset; 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ci if ((op == ISCSI_OP_SCSI_DATA_OUT) || 19218c2ecf20Sopenharmony_ci ((op == ISCSI_OP_SCSI_CMD) && 19228c2ecf20Sopenharmony_ci (sc->sc_data_direction == DMA_TO_DEVICE))) { 19238c2ecf20Sopenharmony_ci u32 remaining_data_tosend, dlimit = 0; 19248c2ecf20Sopenharmony_ci u32 max_pdu_size, max_num_pdu, num_pdu; 19258c2ecf20Sopenharmony_ci u32 count; 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci /* Preserve conn->max_xmit_dlength because it can get updated to 19288c2ecf20Sopenharmony_ci * ISO data size. 19298c2ecf20Sopenharmony_ci */ 19308c2ecf20Sopenharmony_ci if (task->state == ISCSI_TASK_PENDING) 19318c2ecf20Sopenharmony_ci tdata->max_xmit_dlength = conn->max_xmit_dlength; 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci if (!tdata->offset) 19348c2ecf20Sopenharmony_ci cxgbi_task_data_sgl_check(task); 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci remaining_data_tosend = 19378c2ecf20Sopenharmony_ci tdata->dlen - tdata->offset - tdata->count; 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_cirecalculate_sgl: 19408c2ecf20Sopenharmony_ci max_txdata_len = tdata->max_xmit_dlength; 19418c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, 19428c2ecf20Sopenharmony_ci "tdata->dlen %u, remaining to send %u " 19438c2ecf20Sopenharmony_ci "conn->max_xmit_dlength %u, " 19448c2ecf20Sopenharmony_ci "tdata->max_xmit_dlength %u\n", 19458c2ecf20Sopenharmony_ci tdata->dlen, remaining_data_tosend, 19468c2ecf20Sopenharmony_ci conn->max_xmit_dlength, tdata->max_xmit_dlength); 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci if (cdev->skb_iso_txhdr && !csk->disable_iso && 19498c2ecf20Sopenharmony_ci (remaining_data_tosend > tdata->max_xmit_dlength) && 19508c2ecf20Sopenharmony_ci !(remaining_data_tosend % 4)) { 19518c2ecf20Sopenharmony_ci u32 max_iso_data; 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci if ((op == ISCSI_OP_SCSI_CMD) && 19548c2ecf20Sopenharmony_ci session->initial_r2t_en) 19558c2ecf20Sopenharmony_ci goto no_iso; 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci max_pdu_size = tdata->max_xmit_dlength + 19588c2ecf20Sopenharmony_ci ISCSI_PDU_NONPAYLOAD_LEN; 19598c2ecf20Sopenharmony_ci max_iso_data = rounddown(CXGBI_MAX_ISO_DATA_IN_SKB, 19608c2ecf20Sopenharmony_ci csk->advmss); 19618c2ecf20Sopenharmony_ci max_num_pdu = max_iso_data / max_pdu_size; 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci num_pdu = (remaining_data_tosend + 19648c2ecf20Sopenharmony_ci tdata->max_xmit_dlength - 1) / 19658c2ecf20Sopenharmony_ci tdata->max_xmit_dlength; 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci if (num_pdu > max_num_pdu) 19688c2ecf20Sopenharmony_ci num_pdu = max_num_pdu; 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci conn->max_xmit_dlength = tdata->max_xmit_dlength * num_pdu; 19718c2ecf20Sopenharmony_ci max_txdata_len = conn->max_xmit_dlength; 19728c2ecf20Sopenharmony_ci iso_tx_rsvd = cdev->skb_iso_txhdr; 19738c2ecf20Sopenharmony_ci local_iso_info = sizeof(struct cxgbi_iso_info); 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, 19768c2ecf20Sopenharmony_ci "max_pdu_size %u, max_num_pdu %u, " 19778c2ecf20Sopenharmony_ci "max_txdata %u, num_pdu %u\n", 19788c2ecf20Sopenharmony_ci max_pdu_size, max_num_pdu, 19798c2ecf20Sopenharmony_ci max_txdata_len, num_pdu); 19808c2ecf20Sopenharmony_ci } 19818c2ecf20Sopenharmony_cino_iso: 19828c2ecf20Sopenharmony_ci count = min_t(u32, max_txdata_len, remaining_data_tosend); 19838c2ecf20Sopenharmony_ci err = cxgbi_task_data_sgl_read(task, 19848c2ecf20Sopenharmony_ci tdata->offset + tdata->count, 19858c2ecf20Sopenharmony_ci count, &dlimit); 19868c2ecf20Sopenharmony_ci if (unlikely(err < 0)) { 19878c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 19888c2ecf20Sopenharmony_ci "task 0x%p, tcp_task 0x%p, tdata 0x%p, " 19898c2ecf20Sopenharmony_ci "sgl err %d, count %u, dlimit %u\n", 19908c2ecf20Sopenharmony_ci task, tcp_task, tdata, err, count, dlimit); 19918c2ecf20Sopenharmony_ci if (dlimit) { 19928c2ecf20Sopenharmony_ci remaining_data_tosend = 19938c2ecf20Sopenharmony_ci rounddown(dlimit, 19948c2ecf20Sopenharmony_ci tdata->max_xmit_dlength); 19958c2ecf20Sopenharmony_ci if (!remaining_data_tosend) 19968c2ecf20Sopenharmony_ci remaining_data_tosend = dlimit; 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci dlimit = 0; 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci conn->max_xmit_dlength = remaining_data_tosend; 20018c2ecf20Sopenharmony_ci goto recalculate_sgl; 20028c2ecf20Sopenharmony_ci } 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci pr_err("task 0x%p, tcp_task 0x%p, tdata 0x%p, " 20058c2ecf20Sopenharmony_ci "sgl err %d\n", 20068c2ecf20Sopenharmony_ci task, tcp_task, tdata, err); 20078c2ecf20Sopenharmony_ci goto ret_err; 20088c2ecf20Sopenharmony_ci } 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ci if ((tdata->flags & CXGBI_TASK_SGL_COPY) || 20118c2ecf20Sopenharmony_ci (tdata->nr_frags > MAX_SKB_FRAGS)) 20128c2ecf20Sopenharmony_ci headroom += conn->max_xmit_dlength; 20138c2ecf20Sopenharmony_ci } 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci tdata->skb = alloc_skb(local_iso_info + cdev->skb_tx_rsvd + 20168c2ecf20Sopenharmony_ci iso_tx_rsvd + headroom, GFP_ATOMIC); 20178c2ecf20Sopenharmony_ci if (!tdata->skb) { 20188c2ecf20Sopenharmony_ci tdata->count = last_tdata_count; 20198c2ecf20Sopenharmony_ci tdata->offset = last_tdata_offset; 20208c2ecf20Sopenharmony_ci err = -ENOMEM; 20218c2ecf20Sopenharmony_ci goto ret_err; 20228c2ecf20Sopenharmony_ci } 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci skb_reserve(tdata->skb, local_iso_info + cdev->skb_tx_rsvd + 20258c2ecf20Sopenharmony_ci iso_tx_rsvd); 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci if (task->sc) { 20288c2ecf20Sopenharmony_ci task->hdr = (struct iscsi_hdr *)tdata->skb->data; 20298c2ecf20Sopenharmony_ci } else { 20308c2ecf20Sopenharmony_ci task->hdr = kzalloc(SKB_TX_ISCSI_PDU_HEADER_MAX, GFP_ATOMIC); 20318c2ecf20Sopenharmony_ci if (!task->hdr) { 20328c2ecf20Sopenharmony_ci __kfree_skb(tdata->skb); 20338c2ecf20Sopenharmony_ci tdata->skb = NULL; 20348c2ecf20Sopenharmony_ci return -ENOMEM; 20358c2ecf20Sopenharmony_ci } 20368c2ecf20Sopenharmony_ci } 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci task->hdr_max = SKB_TX_ISCSI_PDU_HEADER_MAX; 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci if (iso_tx_rsvd) 20418c2ecf20Sopenharmony_ci cxgbi_skcb_set_flag(tdata->skb, SKCBF_TX_ISO); 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci /* data_out uses scsi_cmd's itt */ 20448c2ecf20Sopenharmony_ci if (op != ISCSI_OP_SCSI_DATA_OUT) 20458c2ecf20Sopenharmony_ci task_reserve_itt(task, &task->hdr->itt); 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, 20488c2ecf20Sopenharmony_ci "task 0x%p, op 0x%x, skb 0x%p,%u+%u/%u, itt 0x%x.\n", 20498c2ecf20Sopenharmony_ci task, op, tdata->skb, cdev->skb_tx_rsvd, headroom, 20508c2ecf20Sopenharmony_ci conn->max_xmit_dlength, be32_to_cpu(task->hdr->itt)); 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci return 0; 20538c2ecf20Sopenharmony_ci 20548c2ecf20Sopenharmony_ciret_err: 20558c2ecf20Sopenharmony_ci conn->max_xmit_dlength = tdata->max_xmit_dlength; 20568c2ecf20Sopenharmony_ci return err; 20578c2ecf20Sopenharmony_ci} 20588c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_conn_alloc_pdu); 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_cistatic int 20618c2ecf20Sopenharmony_cicxgbi_prep_iso_info(struct iscsi_task *task, struct sk_buff *skb, 20628c2ecf20Sopenharmony_ci u32 count) 20638c2ecf20Sopenharmony_ci{ 20648c2ecf20Sopenharmony_ci struct cxgbi_iso_info *iso_info = (struct cxgbi_iso_info *)skb->head; 20658c2ecf20Sopenharmony_ci struct iscsi_r2t_info *r2t; 20668c2ecf20Sopenharmony_ci struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); 20678c2ecf20Sopenharmony_ci struct iscsi_conn *conn = task->conn; 20688c2ecf20Sopenharmony_ci struct iscsi_session *session = conn->session; 20698c2ecf20Sopenharmony_ci struct iscsi_tcp_task *tcp_task = task->dd_data; 20708c2ecf20Sopenharmony_ci u32 burst_size = 0, r2t_dlength = 0, dlength; 20718c2ecf20Sopenharmony_ci u32 max_pdu_len = tdata->max_xmit_dlength; 20728c2ecf20Sopenharmony_ci u32 segment_offset = 0; 20738c2ecf20Sopenharmony_ci u32 num_pdu; 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci if (unlikely(!cxgbi_skcb_test_flag(skb, SKCBF_TX_ISO))) 20768c2ecf20Sopenharmony_ci return 0; 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci memset(iso_info, 0, sizeof(struct cxgbi_iso_info)); 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci if (task->hdr->opcode == ISCSI_OP_SCSI_CMD && session->imm_data_en) { 20818c2ecf20Sopenharmony_ci iso_info->flags |= CXGBI_ISO_INFO_IMM_ENABLE; 20828c2ecf20Sopenharmony_ci burst_size = count; 20838c2ecf20Sopenharmony_ci } 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ci dlength = ntoh24(task->hdr->dlength); 20868c2ecf20Sopenharmony_ci dlength = min(dlength, max_pdu_len); 20878c2ecf20Sopenharmony_ci hton24(task->hdr->dlength, dlength); 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci num_pdu = (count + max_pdu_len - 1) / max_pdu_len; 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_ci if (iscsi_task_has_unsol_data(task)) 20928c2ecf20Sopenharmony_ci r2t = &task->unsol_r2t; 20938c2ecf20Sopenharmony_ci else 20948c2ecf20Sopenharmony_ci r2t = tcp_task->r2t; 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci if (r2t) { 20978c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, 20988c2ecf20Sopenharmony_ci "count %u, tdata->count %u, num_pdu %u," 20998c2ecf20Sopenharmony_ci "task->hdr_len %u, r2t->data_length %u, r2t->sent %u\n", 21008c2ecf20Sopenharmony_ci count, tdata->count, num_pdu, task->hdr_len, 21018c2ecf20Sopenharmony_ci r2t->data_length, r2t->sent); 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_ci r2t_dlength = r2t->data_length - r2t->sent; 21048c2ecf20Sopenharmony_ci segment_offset = r2t->sent; 21058c2ecf20Sopenharmony_ci r2t->datasn += num_pdu - 1; 21068c2ecf20Sopenharmony_ci } 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci if (!r2t || !r2t->sent) 21098c2ecf20Sopenharmony_ci iso_info->flags |= CXGBI_ISO_INFO_FSLICE; 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci if (task->hdr->flags & ISCSI_FLAG_CMD_FINAL) 21128c2ecf20Sopenharmony_ci iso_info->flags |= CXGBI_ISO_INFO_LSLICE; 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_ci task->hdr->flags &= ~ISCSI_FLAG_CMD_FINAL; 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci iso_info->op = task->hdr->opcode; 21178c2ecf20Sopenharmony_ci iso_info->ahs = task->hdr->hlength; 21188c2ecf20Sopenharmony_ci iso_info->num_pdu = num_pdu; 21198c2ecf20Sopenharmony_ci iso_info->mpdu = max_pdu_len; 21208c2ecf20Sopenharmony_ci iso_info->burst_size = (burst_size + r2t_dlength) >> 2; 21218c2ecf20Sopenharmony_ci iso_info->len = count + task->hdr_len; 21228c2ecf20Sopenharmony_ci iso_info->segment_offset = segment_offset; 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_ci cxgbi_skcb_tx_iscsi_hdrlen(skb) = task->hdr_len; 21258c2ecf20Sopenharmony_ci return 0; 21268c2ecf20Sopenharmony_ci} 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_cistatic inline void tx_skb_setmode(struct sk_buff *skb, int hcrc, int dcrc) 21298c2ecf20Sopenharmony_ci{ 21308c2ecf20Sopenharmony_ci if (hcrc || dcrc) { 21318c2ecf20Sopenharmony_ci u8 submode = 0; 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci if (hcrc) 21348c2ecf20Sopenharmony_ci submode |= 1; 21358c2ecf20Sopenharmony_ci if (dcrc) 21368c2ecf20Sopenharmony_ci submode |= 2; 21378c2ecf20Sopenharmony_ci cxgbi_skcb_tx_ulp_mode(skb) = (ULP2_MODE_ISCSI << 4) | submode; 21388c2ecf20Sopenharmony_ci } else 21398c2ecf20Sopenharmony_ci cxgbi_skcb_tx_ulp_mode(skb) = 0; 21408c2ecf20Sopenharmony_ci} 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_cistatic struct page *rsvd_page; 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ciint cxgbi_conn_init_pdu(struct iscsi_task *task, unsigned int offset, 21458c2ecf20Sopenharmony_ci unsigned int count) 21468c2ecf20Sopenharmony_ci{ 21478c2ecf20Sopenharmony_ci struct iscsi_conn *conn = task->conn; 21488c2ecf20Sopenharmony_ci struct iscsi_tcp_task *tcp_task = task->dd_data; 21498c2ecf20Sopenharmony_ci struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); 21508c2ecf20Sopenharmony_ci struct sk_buff *skb; 21518c2ecf20Sopenharmony_ci struct scsi_cmnd *sc = task->sc; 21528c2ecf20Sopenharmony_ci u32 expected_count, expected_offset; 21538c2ecf20Sopenharmony_ci u32 datalen = count, dlimit = 0; 21548c2ecf20Sopenharmony_ci u32 i, padlen = iscsi_padding(count); 21558c2ecf20Sopenharmony_ci struct page *pg; 21568c2ecf20Sopenharmony_ci int err; 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci if (!tcp_task || (tcp_task->dd_data != tdata)) { 21598c2ecf20Sopenharmony_ci pr_err("task 0x%p,0x%p, tcp_task 0x%p, tdata 0x%p/0x%p.\n", 21608c2ecf20Sopenharmony_ci task, task->sc, tcp_task, 21618c2ecf20Sopenharmony_ci tcp_task ? tcp_task->dd_data : NULL, tdata); 21628c2ecf20Sopenharmony_ci return -EINVAL; 21638c2ecf20Sopenharmony_ci } 21648c2ecf20Sopenharmony_ci skb = tdata->skb; 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, 21678c2ecf20Sopenharmony_ci "task 0x%p,0x%p, skb 0x%p, 0x%x,0x%x,0x%x, %u+%u.\n", 21688c2ecf20Sopenharmony_ci task, task->sc, skb, (*skb->data) & ISCSI_OPCODE_MASK, 21698c2ecf20Sopenharmony_ci be32_to_cpu(task->cmdsn), be32_to_cpu(task->hdr->itt), offset, count); 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci skb_put(skb, task->hdr_len); 21728c2ecf20Sopenharmony_ci tx_skb_setmode(skb, conn->hdrdgst_en, datalen ? conn->datadgst_en : 0); 21738c2ecf20Sopenharmony_ci if (!count) { 21748c2ecf20Sopenharmony_ci tdata->count = count; 21758c2ecf20Sopenharmony_ci tdata->offset = offset; 21768c2ecf20Sopenharmony_ci tdata->nr_frags = 0; 21778c2ecf20Sopenharmony_ci tdata->total_offset = 0; 21788c2ecf20Sopenharmony_ci tdata->total_count = 0; 21798c2ecf20Sopenharmony_ci if (tdata->max_xmit_dlength) 21808c2ecf20Sopenharmony_ci conn->max_xmit_dlength = tdata->max_xmit_dlength; 21818c2ecf20Sopenharmony_ci cxgbi_skcb_clear_flag(skb, SKCBF_TX_ISO); 21828c2ecf20Sopenharmony_ci return 0; 21838c2ecf20Sopenharmony_ci } 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, 21868c2ecf20Sopenharmony_ci "data->total_count %u, tdata->total_offset %u\n", 21878c2ecf20Sopenharmony_ci tdata->total_count, tdata->total_offset); 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_ci expected_count = tdata->total_count; 21908c2ecf20Sopenharmony_ci expected_offset = tdata->total_offset; 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci if ((count != expected_count) || 21938c2ecf20Sopenharmony_ci (offset != expected_offset)) { 21948c2ecf20Sopenharmony_ci err = cxgbi_task_data_sgl_read(task, offset, count, &dlimit); 21958c2ecf20Sopenharmony_ci if (err < 0) { 21968c2ecf20Sopenharmony_ci pr_err("task 0x%p,0x%p, tcp_task 0x%p, tdata 0x%p/0x%p " 21978c2ecf20Sopenharmony_ci "dlimit %u, sgl err %d.\n", task, task->sc, 21988c2ecf20Sopenharmony_ci tcp_task, tcp_task ? tcp_task->dd_data : NULL, 21998c2ecf20Sopenharmony_ci tdata, dlimit, err); 22008c2ecf20Sopenharmony_ci return err; 22018c2ecf20Sopenharmony_ci } 22028c2ecf20Sopenharmony_ci } 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci /* Restore original value of conn->max_xmit_dlength because 22058c2ecf20Sopenharmony_ci * it can get updated to ISO data size. 22068c2ecf20Sopenharmony_ci */ 22078c2ecf20Sopenharmony_ci conn->max_xmit_dlength = tdata->max_xmit_dlength; 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci if (sc) { 22108c2ecf20Sopenharmony_ci struct page_frag *frag = tdata->frags; 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci if ((tdata->flags & CXGBI_TASK_SGL_COPY) || 22138c2ecf20Sopenharmony_ci (tdata->nr_frags > MAX_SKB_FRAGS) || 22148c2ecf20Sopenharmony_ci (padlen && (tdata->nr_frags == 22158c2ecf20Sopenharmony_ci MAX_SKB_FRAGS))) { 22168c2ecf20Sopenharmony_ci char *dst = skb->data + task->hdr_len; 22178c2ecf20Sopenharmony_ci 22188c2ecf20Sopenharmony_ci /* data fits in the skb's headroom */ 22198c2ecf20Sopenharmony_ci for (i = 0; i < tdata->nr_frags; i++, frag++) { 22208c2ecf20Sopenharmony_ci char *src = kmap_atomic(frag->page); 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci memcpy(dst, src + frag->offset, frag->size); 22238c2ecf20Sopenharmony_ci dst += frag->size; 22248c2ecf20Sopenharmony_ci kunmap_atomic(src); 22258c2ecf20Sopenharmony_ci } 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci if (padlen) { 22288c2ecf20Sopenharmony_ci memset(dst, 0, padlen); 22298c2ecf20Sopenharmony_ci padlen = 0; 22308c2ecf20Sopenharmony_ci } 22318c2ecf20Sopenharmony_ci skb_put(skb, count + padlen); 22328c2ecf20Sopenharmony_ci } else { 22338c2ecf20Sopenharmony_ci for (i = 0; i < tdata->nr_frags; i++, frag++) { 22348c2ecf20Sopenharmony_ci get_page(frag->page); 22358c2ecf20Sopenharmony_ci skb_fill_page_desc(skb, i, frag->page, 22368c2ecf20Sopenharmony_ci frag->offset, frag->size); 22378c2ecf20Sopenharmony_ci } 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci skb->len += count; 22408c2ecf20Sopenharmony_ci skb->data_len += count; 22418c2ecf20Sopenharmony_ci skb->truesize += count; 22428c2ecf20Sopenharmony_ci } 22438c2ecf20Sopenharmony_ci } else { 22448c2ecf20Sopenharmony_ci pg = virt_to_head_page(task->data); 22458c2ecf20Sopenharmony_ci get_page(pg); 22468c2ecf20Sopenharmony_ci skb_fill_page_desc(skb, 0, pg, 22478c2ecf20Sopenharmony_ci task->data - (char *)page_address(pg), 22488c2ecf20Sopenharmony_ci count); 22498c2ecf20Sopenharmony_ci skb->len += count; 22508c2ecf20Sopenharmony_ci skb->data_len += count; 22518c2ecf20Sopenharmony_ci skb->truesize += count; 22528c2ecf20Sopenharmony_ci } 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci if (padlen) { 22558c2ecf20Sopenharmony_ci get_page(rsvd_page); 22568c2ecf20Sopenharmony_ci skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, 22578c2ecf20Sopenharmony_ci rsvd_page, 0, padlen); 22588c2ecf20Sopenharmony_ci 22598c2ecf20Sopenharmony_ci skb->data_len += padlen; 22608c2ecf20Sopenharmony_ci skb->truesize += padlen; 22618c2ecf20Sopenharmony_ci skb->len += padlen; 22628c2ecf20Sopenharmony_ci } 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci if (likely(count > tdata->max_xmit_dlength)) 22658c2ecf20Sopenharmony_ci cxgbi_prep_iso_info(task, skb, count); 22668c2ecf20Sopenharmony_ci else 22678c2ecf20Sopenharmony_ci cxgbi_skcb_clear_flag(skb, SKCBF_TX_ISO); 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci return 0; 22708c2ecf20Sopenharmony_ci} 22718c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_conn_init_pdu); 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_cistatic int cxgbi_sock_tx_queue_up(struct cxgbi_sock *csk, struct sk_buff *skb) 22748c2ecf20Sopenharmony_ci{ 22758c2ecf20Sopenharmony_ci struct cxgbi_device *cdev = csk->cdev; 22768c2ecf20Sopenharmony_ci struct cxgbi_iso_info *iso_cpl; 22778c2ecf20Sopenharmony_ci u32 frags = skb_shinfo(skb)->nr_frags; 22788c2ecf20Sopenharmony_ci u32 extra_len, num_pdu, hdr_len; 22798c2ecf20Sopenharmony_ci u32 iso_tx_rsvd = 0; 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ci if (csk->state != CTP_ESTABLISHED) { 22828c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_TX, 22838c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, EAGAIN.\n", 22848c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 22858c2ecf20Sopenharmony_ci return -EPIPE; 22868c2ecf20Sopenharmony_ci } 22878c2ecf20Sopenharmony_ci 22888c2ecf20Sopenharmony_ci if (csk->err) { 22898c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_TX, 22908c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, EPIPE %d.\n", 22918c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, csk->err); 22928c2ecf20Sopenharmony_ci return -EPIPE; 22938c2ecf20Sopenharmony_ci } 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_ci if ((cdev->flags & CXGBI_FLAG_DEV_T3) && 22968c2ecf20Sopenharmony_ci before((csk->snd_win + csk->snd_una), csk->write_seq)) { 22978c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_TX, 22988c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, FULL %u-%u >= %u.\n", 22998c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, csk->write_seq, 23008c2ecf20Sopenharmony_ci csk->snd_una, csk->snd_win); 23018c2ecf20Sopenharmony_ci return -ENOBUFS; 23028c2ecf20Sopenharmony_ci } 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci if (cxgbi_skcb_test_flag(skb, SKCBF_TX_ISO)) 23058c2ecf20Sopenharmony_ci iso_tx_rsvd = cdev->skb_iso_txhdr; 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_ci if (unlikely(skb_headroom(skb) < (cdev->skb_tx_rsvd + iso_tx_rsvd))) { 23088c2ecf20Sopenharmony_ci pr_err("csk 0x%p, skb head %u < %u.\n", 23098c2ecf20Sopenharmony_ci csk, skb_headroom(skb), cdev->skb_tx_rsvd); 23108c2ecf20Sopenharmony_ci return -EINVAL; 23118c2ecf20Sopenharmony_ci } 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_ci if (skb->len != skb->data_len) 23148c2ecf20Sopenharmony_ci frags++; 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci if (frags >= SKB_WR_LIST_SIZE) { 23178c2ecf20Sopenharmony_ci pr_err("csk 0x%p, frags %u, %u,%u >%lu.\n", 23188c2ecf20Sopenharmony_ci csk, skb_shinfo(skb)->nr_frags, skb->len, 23198c2ecf20Sopenharmony_ci skb->data_len, SKB_WR_LIST_SIZE); 23208c2ecf20Sopenharmony_ci return -EINVAL; 23218c2ecf20Sopenharmony_ci } 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_ci cxgbi_skcb_set_flag(skb, SKCBF_TX_NEED_HDR); 23248c2ecf20Sopenharmony_ci skb_reset_transport_header(skb); 23258c2ecf20Sopenharmony_ci cxgbi_sock_skb_entail(csk, skb); 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_ci extra_len = cxgbi_ulp_extra_len(cxgbi_skcb_tx_ulp_mode(skb)); 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_ci if (likely(cxgbi_skcb_test_flag(skb, SKCBF_TX_ISO))) { 23308c2ecf20Sopenharmony_ci iso_cpl = (struct cxgbi_iso_info *)skb->head; 23318c2ecf20Sopenharmony_ci num_pdu = iso_cpl->num_pdu; 23328c2ecf20Sopenharmony_ci hdr_len = cxgbi_skcb_tx_iscsi_hdrlen(skb); 23338c2ecf20Sopenharmony_ci extra_len = (cxgbi_ulp_extra_len(cxgbi_skcb_tx_ulp_mode(skb)) * 23348c2ecf20Sopenharmony_ci num_pdu) + (hdr_len * (num_pdu - 1)); 23358c2ecf20Sopenharmony_ci } 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_ci csk->write_seq += (skb->len + extra_len); 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_ci return 0; 23408c2ecf20Sopenharmony_ci} 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_cistatic int cxgbi_sock_send_skb(struct cxgbi_sock *csk, struct sk_buff *skb) 23438c2ecf20Sopenharmony_ci{ 23448c2ecf20Sopenharmony_ci struct cxgbi_device *cdev = csk->cdev; 23458c2ecf20Sopenharmony_ci int len = skb->len; 23468c2ecf20Sopenharmony_ci int err; 23478c2ecf20Sopenharmony_ci 23488c2ecf20Sopenharmony_ci spin_lock_bh(&csk->lock); 23498c2ecf20Sopenharmony_ci err = cxgbi_sock_tx_queue_up(csk, skb); 23508c2ecf20Sopenharmony_ci if (err < 0) { 23518c2ecf20Sopenharmony_ci spin_unlock_bh(&csk->lock); 23528c2ecf20Sopenharmony_ci return err; 23538c2ecf20Sopenharmony_ci } 23548c2ecf20Sopenharmony_ci 23558c2ecf20Sopenharmony_ci if (likely(skb_queue_len(&csk->write_queue))) 23568c2ecf20Sopenharmony_ci cdev->csk_push_tx_frames(csk, 0); 23578c2ecf20Sopenharmony_ci spin_unlock_bh(&csk->lock); 23588c2ecf20Sopenharmony_ci return len; 23598c2ecf20Sopenharmony_ci} 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_ciint cxgbi_conn_xmit_pdu(struct iscsi_task *task) 23628c2ecf20Sopenharmony_ci{ 23638c2ecf20Sopenharmony_ci struct iscsi_tcp_conn *tcp_conn = task->conn->dd_data; 23648c2ecf20Sopenharmony_ci struct cxgbi_conn *cconn = tcp_conn->dd_data; 23658c2ecf20Sopenharmony_ci struct iscsi_tcp_task *tcp_task = task->dd_data; 23668c2ecf20Sopenharmony_ci struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); 23678c2ecf20Sopenharmony_ci struct cxgbi_task_tag_info *ttinfo = &tdata->ttinfo; 23688c2ecf20Sopenharmony_ci struct sk_buff *skb; 23698c2ecf20Sopenharmony_ci struct cxgbi_sock *csk = NULL; 23708c2ecf20Sopenharmony_ci u32 pdulen = 0; 23718c2ecf20Sopenharmony_ci u32 datalen; 23728c2ecf20Sopenharmony_ci int err; 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_ci if (!tcp_task || (tcp_task->dd_data != tdata)) { 23758c2ecf20Sopenharmony_ci pr_err("task 0x%p,0x%p, tcp_task 0x%p, tdata 0x%p/0x%p.\n", 23768c2ecf20Sopenharmony_ci task, task->sc, tcp_task, 23778c2ecf20Sopenharmony_ci tcp_task ? tcp_task->dd_data : NULL, tdata); 23788c2ecf20Sopenharmony_ci return -EINVAL; 23798c2ecf20Sopenharmony_ci } 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ci skb = tdata->skb; 23828c2ecf20Sopenharmony_ci if (!skb) { 23838c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, 23848c2ecf20Sopenharmony_ci "task 0x%p, skb NULL.\n", task); 23858c2ecf20Sopenharmony_ci return 0; 23868c2ecf20Sopenharmony_ci } 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_ci if (cconn && cconn->cep) 23898c2ecf20Sopenharmony_ci csk = cconn->cep->csk; 23908c2ecf20Sopenharmony_ci 23918c2ecf20Sopenharmony_ci if (!csk) { 23928c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, 23938c2ecf20Sopenharmony_ci "task 0x%p, csk gone.\n", task); 23948c2ecf20Sopenharmony_ci return -EPIPE; 23958c2ecf20Sopenharmony_ci } 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci tdata->skb = NULL; 23988c2ecf20Sopenharmony_ci datalen = skb->data_len; 23998c2ecf20Sopenharmony_ci 24008c2ecf20Sopenharmony_ci /* write ppod first if using ofldq to write ppod */ 24018c2ecf20Sopenharmony_ci if (ttinfo->flags & CXGBI_PPOD_INFO_FLAG_VALID) { 24028c2ecf20Sopenharmony_ci struct cxgbi_ppm *ppm = csk->cdev->cdev2ppm(csk->cdev); 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_ci ttinfo->flags &= ~CXGBI_PPOD_INFO_FLAG_VALID; 24058c2ecf20Sopenharmony_ci if (csk->cdev->csk_ddp_set_map(ppm, csk, ttinfo) < 0) 24068c2ecf20Sopenharmony_ci pr_err("task 0x%p, ppod writing using ofldq failed.\n", 24078c2ecf20Sopenharmony_ci task); 24088c2ecf20Sopenharmony_ci /* continue. Let fl get the data */ 24098c2ecf20Sopenharmony_ci } 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_ci if (!task->sc) 24128c2ecf20Sopenharmony_ci memcpy(skb->data, task->hdr, SKB_TX_ISCSI_PDU_HEADER_MAX); 24138c2ecf20Sopenharmony_ci 24148c2ecf20Sopenharmony_ci err = cxgbi_sock_send_skb(csk, skb); 24158c2ecf20Sopenharmony_ci if (err > 0) { 24168c2ecf20Sopenharmony_ci pdulen += err; 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_TX, "task 0x%p,0x%p, rv %d.\n", 24198c2ecf20Sopenharmony_ci task, task->sc, err); 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_ci if (task->conn->hdrdgst_en) 24228c2ecf20Sopenharmony_ci pdulen += ISCSI_DIGEST_SIZE; 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci if (datalen && task->conn->datadgst_en) 24258c2ecf20Sopenharmony_ci pdulen += ISCSI_DIGEST_SIZE; 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_ci task->conn->txdata_octets += pdulen; 24288c2ecf20Sopenharmony_ci 24298c2ecf20Sopenharmony_ci if (unlikely(cxgbi_is_iso_config(csk) && cxgbi_is_iso_disabled(csk))) { 24308c2ecf20Sopenharmony_ci if (time_after(jiffies, csk->prev_iso_ts + HZ)) { 24318c2ecf20Sopenharmony_ci csk->disable_iso = false; 24328c2ecf20Sopenharmony_ci csk->prev_iso_ts = 0; 24338c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_TX, 24348c2ecf20Sopenharmony_ci "enable iso: csk 0x%p\n", csk); 24358c2ecf20Sopenharmony_ci } 24368c2ecf20Sopenharmony_ci } 24378c2ecf20Sopenharmony_ci 24388c2ecf20Sopenharmony_ci return 0; 24398c2ecf20Sopenharmony_ci } 24408c2ecf20Sopenharmony_ci 24418c2ecf20Sopenharmony_ci if (err == -EAGAIN || err == -ENOBUFS) { 24428c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_TX, 24438c2ecf20Sopenharmony_ci "task 0x%p, skb 0x%p, len %u/%u, %d EAGAIN.\n", 24448c2ecf20Sopenharmony_ci task, skb, skb->len, skb->data_len, err); 24458c2ecf20Sopenharmony_ci /* reset skb to send when we are called again */ 24468c2ecf20Sopenharmony_ci tdata->skb = skb; 24478c2ecf20Sopenharmony_ci 24488c2ecf20Sopenharmony_ci if (cxgbi_is_iso_config(csk) && !cxgbi_is_iso_disabled(csk) && 24498c2ecf20Sopenharmony_ci (csk->no_tx_credits++ >= 2)) { 24508c2ecf20Sopenharmony_ci csk->disable_iso = true; 24518c2ecf20Sopenharmony_ci csk->prev_iso_ts = jiffies; 24528c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_TX, 24538c2ecf20Sopenharmony_ci "disable iso:csk 0x%p, ts:%lu\n", 24548c2ecf20Sopenharmony_ci csk, csk->prev_iso_ts); 24558c2ecf20Sopenharmony_ci } 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_ci return err; 24588c2ecf20Sopenharmony_ci } 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, 24618c2ecf20Sopenharmony_ci "itt 0x%x, skb 0x%p, len %u/%u, xmit err %d.\n", 24628c2ecf20Sopenharmony_ci task->itt, skb, skb->len, skb->data_len, err); 24638c2ecf20Sopenharmony_ci __kfree_skb(skb); 24648c2ecf20Sopenharmony_ci iscsi_conn_printk(KERN_ERR, task->conn, "xmit err %d.\n", err); 24658c2ecf20Sopenharmony_ci iscsi_conn_failure(task->conn, ISCSI_ERR_XMIT_FAILED); 24668c2ecf20Sopenharmony_ci return err; 24678c2ecf20Sopenharmony_ci} 24688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_conn_xmit_pdu); 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_civoid cxgbi_cleanup_task(struct iscsi_task *task) 24718c2ecf20Sopenharmony_ci{ 24728c2ecf20Sopenharmony_ci struct iscsi_tcp_task *tcp_task = task->dd_data; 24738c2ecf20Sopenharmony_ci struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); 24748c2ecf20Sopenharmony_ci 24758c2ecf20Sopenharmony_ci if (!tcp_task || (tcp_task->dd_data != tdata)) { 24768c2ecf20Sopenharmony_ci pr_info("task 0x%p,0x%p, tcp_task 0x%p, tdata 0x%p/0x%p.\n", 24778c2ecf20Sopenharmony_ci task, task->sc, tcp_task, 24788c2ecf20Sopenharmony_ci tcp_task ? tcp_task->dd_data : NULL, tdata); 24798c2ecf20Sopenharmony_ci return; 24808c2ecf20Sopenharmony_ci } 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 24838c2ecf20Sopenharmony_ci "task 0x%p, skb 0x%p, itt 0x%x.\n", 24848c2ecf20Sopenharmony_ci task, tdata->skb, task->hdr_itt); 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_ci tcp_task->dd_data = NULL; 24878c2ecf20Sopenharmony_ci 24888c2ecf20Sopenharmony_ci if (!task->sc) 24898c2ecf20Sopenharmony_ci kfree(task->hdr); 24908c2ecf20Sopenharmony_ci task->hdr = NULL; 24918c2ecf20Sopenharmony_ci 24928c2ecf20Sopenharmony_ci /* never reached the xmit task callout */ 24938c2ecf20Sopenharmony_ci if (tdata->skb) { 24948c2ecf20Sopenharmony_ci __kfree_skb(tdata->skb); 24958c2ecf20Sopenharmony_ci tdata->skb = NULL; 24968c2ecf20Sopenharmony_ci } 24978c2ecf20Sopenharmony_ci 24988c2ecf20Sopenharmony_ci task_release_itt(task, task->hdr_itt); 24998c2ecf20Sopenharmony_ci memset(tdata, 0, sizeof(*tdata)); 25008c2ecf20Sopenharmony_ci 25018c2ecf20Sopenharmony_ci iscsi_tcp_cleanup_task(task); 25028c2ecf20Sopenharmony_ci} 25038c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_cleanup_task); 25048c2ecf20Sopenharmony_ci 25058c2ecf20Sopenharmony_civoid cxgbi_get_conn_stats(struct iscsi_cls_conn *cls_conn, 25068c2ecf20Sopenharmony_ci struct iscsi_stats *stats) 25078c2ecf20Sopenharmony_ci{ 25088c2ecf20Sopenharmony_ci struct iscsi_conn *conn = cls_conn->dd_data; 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_ci stats->txdata_octets = conn->txdata_octets; 25118c2ecf20Sopenharmony_ci stats->rxdata_octets = conn->rxdata_octets; 25128c2ecf20Sopenharmony_ci stats->scsicmd_pdus = conn->scsicmd_pdus_cnt; 25138c2ecf20Sopenharmony_ci stats->dataout_pdus = conn->dataout_pdus_cnt; 25148c2ecf20Sopenharmony_ci stats->scsirsp_pdus = conn->scsirsp_pdus_cnt; 25158c2ecf20Sopenharmony_ci stats->datain_pdus = conn->datain_pdus_cnt; 25168c2ecf20Sopenharmony_ci stats->r2t_pdus = conn->r2t_pdus_cnt; 25178c2ecf20Sopenharmony_ci stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt; 25188c2ecf20Sopenharmony_ci stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt; 25198c2ecf20Sopenharmony_ci stats->digest_err = 0; 25208c2ecf20Sopenharmony_ci stats->timeout_err = 0; 25218c2ecf20Sopenharmony_ci stats->custom_length = 1; 25228c2ecf20Sopenharmony_ci strcpy(stats->custom[0].desc, "eh_abort_cnt"); 25238c2ecf20Sopenharmony_ci stats->custom[0].value = conn->eh_abort_cnt; 25248c2ecf20Sopenharmony_ci} 25258c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_get_conn_stats); 25268c2ecf20Sopenharmony_ci 25278c2ecf20Sopenharmony_cistatic int cxgbi_conn_max_xmit_dlength(struct iscsi_conn *conn) 25288c2ecf20Sopenharmony_ci{ 25298c2ecf20Sopenharmony_ci struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 25308c2ecf20Sopenharmony_ci struct cxgbi_conn *cconn = tcp_conn->dd_data; 25318c2ecf20Sopenharmony_ci struct cxgbi_device *cdev = cconn->chba->cdev; 25328c2ecf20Sopenharmony_ci unsigned int headroom = SKB_MAX_HEAD(cdev->skb_tx_rsvd); 25338c2ecf20Sopenharmony_ci unsigned int max_def = 512 * MAX_SKB_FRAGS; 25348c2ecf20Sopenharmony_ci unsigned int max = max(max_def, headroom); 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ci max = min(cconn->chba->cdev->tx_max_size, max); 25378c2ecf20Sopenharmony_ci if (conn->max_xmit_dlength) 25388c2ecf20Sopenharmony_ci conn->max_xmit_dlength = min(conn->max_xmit_dlength, max); 25398c2ecf20Sopenharmony_ci else 25408c2ecf20Sopenharmony_ci conn->max_xmit_dlength = max; 25418c2ecf20Sopenharmony_ci cxgbi_align_pdu_size(conn->max_xmit_dlength); 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_ci return 0; 25448c2ecf20Sopenharmony_ci} 25458c2ecf20Sopenharmony_ci 25468c2ecf20Sopenharmony_cistatic int cxgbi_conn_max_recv_dlength(struct iscsi_conn *conn) 25478c2ecf20Sopenharmony_ci{ 25488c2ecf20Sopenharmony_ci struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 25498c2ecf20Sopenharmony_ci struct cxgbi_conn *cconn = tcp_conn->dd_data; 25508c2ecf20Sopenharmony_ci unsigned int max = cconn->chba->cdev->rx_max_size; 25518c2ecf20Sopenharmony_ci 25528c2ecf20Sopenharmony_ci cxgbi_align_pdu_size(max); 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_ci if (conn->max_recv_dlength) { 25558c2ecf20Sopenharmony_ci if (conn->max_recv_dlength > max) { 25568c2ecf20Sopenharmony_ci pr_err("MaxRecvDataSegmentLength %u > %u.\n", 25578c2ecf20Sopenharmony_ci conn->max_recv_dlength, max); 25588c2ecf20Sopenharmony_ci return -EINVAL; 25598c2ecf20Sopenharmony_ci } 25608c2ecf20Sopenharmony_ci conn->max_recv_dlength = min(conn->max_recv_dlength, max); 25618c2ecf20Sopenharmony_ci cxgbi_align_pdu_size(conn->max_recv_dlength); 25628c2ecf20Sopenharmony_ci } else 25638c2ecf20Sopenharmony_ci conn->max_recv_dlength = max; 25648c2ecf20Sopenharmony_ci 25658c2ecf20Sopenharmony_ci return 0; 25668c2ecf20Sopenharmony_ci} 25678c2ecf20Sopenharmony_ci 25688c2ecf20Sopenharmony_ciint cxgbi_set_conn_param(struct iscsi_cls_conn *cls_conn, 25698c2ecf20Sopenharmony_ci enum iscsi_param param, char *buf, int buflen) 25708c2ecf20Sopenharmony_ci{ 25718c2ecf20Sopenharmony_ci struct iscsi_conn *conn = cls_conn->dd_data; 25728c2ecf20Sopenharmony_ci struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 25738c2ecf20Sopenharmony_ci struct cxgbi_conn *cconn = tcp_conn->dd_data; 25748c2ecf20Sopenharmony_ci struct cxgbi_sock *csk = cconn->cep->csk; 25758c2ecf20Sopenharmony_ci int err; 25768c2ecf20Sopenharmony_ci 25778c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 25788c2ecf20Sopenharmony_ci "cls_conn 0x%p, param %d, buf(%d) %s.\n", 25798c2ecf20Sopenharmony_ci cls_conn, param, buflen, buf); 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci switch (param) { 25828c2ecf20Sopenharmony_ci case ISCSI_PARAM_HDRDGST_EN: 25838c2ecf20Sopenharmony_ci err = iscsi_set_param(cls_conn, param, buf, buflen); 25848c2ecf20Sopenharmony_ci if (!err && conn->hdrdgst_en) 25858c2ecf20Sopenharmony_ci err = csk->cdev->csk_ddp_setup_digest(csk, csk->tid, 25868c2ecf20Sopenharmony_ci conn->hdrdgst_en, 25878c2ecf20Sopenharmony_ci conn->datadgst_en); 25888c2ecf20Sopenharmony_ci break; 25898c2ecf20Sopenharmony_ci case ISCSI_PARAM_DATADGST_EN: 25908c2ecf20Sopenharmony_ci err = iscsi_set_param(cls_conn, param, buf, buflen); 25918c2ecf20Sopenharmony_ci if (!err && conn->datadgst_en) 25928c2ecf20Sopenharmony_ci err = csk->cdev->csk_ddp_setup_digest(csk, csk->tid, 25938c2ecf20Sopenharmony_ci conn->hdrdgst_en, 25948c2ecf20Sopenharmony_ci conn->datadgst_en); 25958c2ecf20Sopenharmony_ci break; 25968c2ecf20Sopenharmony_ci case ISCSI_PARAM_MAX_R2T: 25978c2ecf20Sopenharmony_ci return iscsi_tcp_set_max_r2t(conn, buf); 25988c2ecf20Sopenharmony_ci case ISCSI_PARAM_MAX_RECV_DLENGTH: 25998c2ecf20Sopenharmony_ci err = iscsi_set_param(cls_conn, param, buf, buflen); 26008c2ecf20Sopenharmony_ci if (!err) 26018c2ecf20Sopenharmony_ci err = cxgbi_conn_max_recv_dlength(conn); 26028c2ecf20Sopenharmony_ci break; 26038c2ecf20Sopenharmony_ci case ISCSI_PARAM_MAX_XMIT_DLENGTH: 26048c2ecf20Sopenharmony_ci err = iscsi_set_param(cls_conn, param, buf, buflen); 26058c2ecf20Sopenharmony_ci if (!err) 26068c2ecf20Sopenharmony_ci err = cxgbi_conn_max_xmit_dlength(conn); 26078c2ecf20Sopenharmony_ci break; 26088c2ecf20Sopenharmony_ci default: 26098c2ecf20Sopenharmony_ci return iscsi_set_param(cls_conn, param, buf, buflen); 26108c2ecf20Sopenharmony_ci } 26118c2ecf20Sopenharmony_ci return err; 26128c2ecf20Sopenharmony_ci} 26138c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_set_conn_param); 26148c2ecf20Sopenharmony_ci 26158c2ecf20Sopenharmony_ciint cxgbi_get_ep_param(struct iscsi_endpoint *ep, enum iscsi_param param, 26168c2ecf20Sopenharmony_ci char *buf) 26178c2ecf20Sopenharmony_ci{ 26188c2ecf20Sopenharmony_ci struct cxgbi_endpoint *cep = ep->dd_data; 26198c2ecf20Sopenharmony_ci struct cxgbi_sock *csk; 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 26228c2ecf20Sopenharmony_ci "cls_conn 0x%p, param %d.\n", ep, param); 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_ci switch (param) { 26258c2ecf20Sopenharmony_ci case ISCSI_PARAM_CONN_PORT: 26268c2ecf20Sopenharmony_ci case ISCSI_PARAM_CONN_ADDRESS: 26278c2ecf20Sopenharmony_ci if (!cep) 26288c2ecf20Sopenharmony_ci return -ENOTCONN; 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_ci csk = cep->csk; 26318c2ecf20Sopenharmony_ci if (!csk) 26328c2ecf20Sopenharmony_ci return -ENOTCONN; 26338c2ecf20Sopenharmony_ci 26348c2ecf20Sopenharmony_ci return iscsi_conn_get_addr_param((struct sockaddr_storage *) 26358c2ecf20Sopenharmony_ci &csk->daddr, param, buf); 26368c2ecf20Sopenharmony_ci default: 26378c2ecf20Sopenharmony_ci break; 26388c2ecf20Sopenharmony_ci } 26398c2ecf20Sopenharmony_ci return -ENOSYS; 26408c2ecf20Sopenharmony_ci} 26418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_get_ep_param); 26428c2ecf20Sopenharmony_ci 26438c2ecf20Sopenharmony_cistruct iscsi_cls_conn * 26448c2ecf20Sopenharmony_cicxgbi_create_conn(struct iscsi_cls_session *cls_session, u32 cid) 26458c2ecf20Sopenharmony_ci{ 26468c2ecf20Sopenharmony_ci struct iscsi_cls_conn *cls_conn; 26478c2ecf20Sopenharmony_ci struct iscsi_conn *conn; 26488c2ecf20Sopenharmony_ci struct iscsi_tcp_conn *tcp_conn; 26498c2ecf20Sopenharmony_ci struct cxgbi_conn *cconn; 26508c2ecf20Sopenharmony_ci 26518c2ecf20Sopenharmony_ci cls_conn = iscsi_tcp_conn_setup(cls_session, sizeof(*cconn), cid); 26528c2ecf20Sopenharmony_ci if (!cls_conn) 26538c2ecf20Sopenharmony_ci return NULL; 26548c2ecf20Sopenharmony_ci 26558c2ecf20Sopenharmony_ci conn = cls_conn->dd_data; 26568c2ecf20Sopenharmony_ci tcp_conn = conn->dd_data; 26578c2ecf20Sopenharmony_ci cconn = tcp_conn->dd_data; 26588c2ecf20Sopenharmony_ci cconn->iconn = conn; 26598c2ecf20Sopenharmony_ci 26608c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 26618c2ecf20Sopenharmony_ci "cid %u(0x%x), cls 0x%p,0x%p, conn 0x%p,0x%p,0x%p.\n", 26628c2ecf20Sopenharmony_ci cid, cid, cls_session, cls_conn, conn, tcp_conn, cconn); 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_ci return cls_conn; 26658c2ecf20Sopenharmony_ci} 26668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_create_conn); 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_ciint cxgbi_bind_conn(struct iscsi_cls_session *cls_session, 26698c2ecf20Sopenharmony_ci struct iscsi_cls_conn *cls_conn, 26708c2ecf20Sopenharmony_ci u64 transport_eph, int is_leading) 26718c2ecf20Sopenharmony_ci{ 26728c2ecf20Sopenharmony_ci struct iscsi_conn *conn = cls_conn->dd_data; 26738c2ecf20Sopenharmony_ci struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 26748c2ecf20Sopenharmony_ci struct cxgbi_conn *cconn = tcp_conn->dd_data; 26758c2ecf20Sopenharmony_ci struct cxgbi_ppm *ppm; 26768c2ecf20Sopenharmony_ci struct iscsi_endpoint *ep; 26778c2ecf20Sopenharmony_ci struct cxgbi_endpoint *cep; 26788c2ecf20Sopenharmony_ci struct cxgbi_sock *csk; 26798c2ecf20Sopenharmony_ci int err; 26808c2ecf20Sopenharmony_ci 26818c2ecf20Sopenharmony_ci ep = iscsi_lookup_endpoint(transport_eph); 26828c2ecf20Sopenharmony_ci if (!ep) 26838c2ecf20Sopenharmony_ci return -EINVAL; 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_ci /* setup ddp pagesize */ 26868c2ecf20Sopenharmony_ci cep = ep->dd_data; 26878c2ecf20Sopenharmony_ci csk = cep->csk; 26888c2ecf20Sopenharmony_ci 26898c2ecf20Sopenharmony_ci ppm = csk->cdev->cdev2ppm(csk->cdev); 26908c2ecf20Sopenharmony_ci err = csk->cdev->csk_ddp_setup_pgidx(csk, csk->tid, 26918c2ecf20Sopenharmony_ci ppm->tformat.pgsz_idx_dflt); 26928c2ecf20Sopenharmony_ci if (err < 0) 26938c2ecf20Sopenharmony_ci goto put_ep; 26948c2ecf20Sopenharmony_ci 26958c2ecf20Sopenharmony_ci err = iscsi_conn_bind(cls_session, cls_conn, is_leading); 26968c2ecf20Sopenharmony_ci if (err) { 26978c2ecf20Sopenharmony_ci err = -EINVAL; 26988c2ecf20Sopenharmony_ci goto put_ep; 26998c2ecf20Sopenharmony_ci } 27008c2ecf20Sopenharmony_ci 27018c2ecf20Sopenharmony_ci /* calculate the tag idx bits needed for this conn based on cmds_max */ 27028c2ecf20Sopenharmony_ci cconn->task_idx_bits = (__ilog2_u32(conn->session->cmds_max - 1)) + 1; 27038c2ecf20Sopenharmony_ci 27048c2ecf20Sopenharmony_ci write_lock_bh(&csk->callback_lock); 27058c2ecf20Sopenharmony_ci csk->user_data = conn; 27068c2ecf20Sopenharmony_ci cconn->chba = cep->chba; 27078c2ecf20Sopenharmony_ci cconn->cep = cep; 27088c2ecf20Sopenharmony_ci cep->cconn = cconn; 27098c2ecf20Sopenharmony_ci write_unlock_bh(&csk->callback_lock); 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_ci cxgbi_conn_max_xmit_dlength(conn); 27128c2ecf20Sopenharmony_ci cxgbi_conn_max_recv_dlength(conn); 27138c2ecf20Sopenharmony_ci 27148c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 27158c2ecf20Sopenharmony_ci "cls 0x%p,0x%p, ep 0x%p, cconn 0x%p, csk 0x%p.\n", 27168c2ecf20Sopenharmony_ci cls_session, cls_conn, ep, cconn, csk); 27178c2ecf20Sopenharmony_ci /* init recv engine */ 27188c2ecf20Sopenharmony_ci iscsi_tcp_hdr_recv_prep(tcp_conn); 27198c2ecf20Sopenharmony_ci 27208c2ecf20Sopenharmony_ciput_ep: 27218c2ecf20Sopenharmony_ci iscsi_put_endpoint(ep); 27228c2ecf20Sopenharmony_ci return err; 27238c2ecf20Sopenharmony_ci} 27248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_bind_conn); 27258c2ecf20Sopenharmony_ci 27268c2ecf20Sopenharmony_cistruct iscsi_cls_session *cxgbi_create_session(struct iscsi_endpoint *ep, 27278c2ecf20Sopenharmony_ci u16 cmds_max, u16 qdepth, 27288c2ecf20Sopenharmony_ci u32 initial_cmdsn) 27298c2ecf20Sopenharmony_ci{ 27308c2ecf20Sopenharmony_ci struct cxgbi_endpoint *cep; 27318c2ecf20Sopenharmony_ci struct cxgbi_hba *chba; 27328c2ecf20Sopenharmony_ci struct Scsi_Host *shost; 27338c2ecf20Sopenharmony_ci struct iscsi_cls_session *cls_session; 27348c2ecf20Sopenharmony_ci struct iscsi_session *session; 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci if (!ep) { 27378c2ecf20Sopenharmony_ci pr_err("missing endpoint.\n"); 27388c2ecf20Sopenharmony_ci return NULL; 27398c2ecf20Sopenharmony_ci } 27408c2ecf20Sopenharmony_ci 27418c2ecf20Sopenharmony_ci cep = ep->dd_data; 27428c2ecf20Sopenharmony_ci chba = cep->chba; 27438c2ecf20Sopenharmony_ci shost = chba->shost; 27448c2ecf20Sopenharmony_ci 27458c2ecf20Sopenharmony_ci BUG_ON(chba != iscsi_host_priv(shost)); 27468c2ecf20Sopenharmony_ci 27478c2ecf20Sopenharmony_ci cls_session = iscsi_session_setup(chba->cdev->itp, shost, 27488c2ecf20Sopenharmony_ci cmds_max, 0, 27498c2ecf20Sopenharmony_ci sizeof(struct iscsi_tcp_task) + 27508c2ecf20Sopenharmony_ci sizeof(struct cxgbi_task_data), 27518c2ecf20Sopenharmony_ci initial_cmdsn, ISCSI_MAX_TARGET); 27528c2ecf20Sopenharmony_ci if (!cls_session) 27538c2ecf20Sopenharmony_ci return NULL; 27548c2ecf20Sopenharmony_ci 27558c2ecf20Sopenharmony_ci session = cls_session->dd_data; 27568c2ecf20Sopenharmony_ci if (iscsi_tcp_r2tpool_alloc(session)) 27578c2ecf20Sopenharmony_ci goto remove_session; 27588c2ecf20Sopenharmony_ci 27598c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 27608c2ecf20Sopenharmony_ci "ep 0x%p, cls sess 0x%p.\n", ep, cls_session); 27618c2ecf20Sopenharmony_ci return cls_session; 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_ciremove_session: 27648c2ecf20Sopenharmony_ci iscsi_session_teardown(cls_session); 27658c2ecf20Sopenharmony_ci return NULL; 27668c2ecf20Sopenharmony_ci} 27678c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_create_session); 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_civoid cxgbi_destroy_session(struct iscsi_cls_session *cls_session) 27708c2ecf20Sopenharmony_ci{ 27718c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 27728c2ecf20Sopenharmony_ci "cls sess 0x%p.\n", cls_session); 27738c2ecf20Sopenharmony_ci 27748c2ecf20Sopenharmony_ci iscsi_tcp_r2tpool_free(cls_session->dd_data); 27758c2ecf20Sopenharmony_ci iscsi_session_teardown(cls_session); 27768c2ecf20Sopenharmony_ci} 27778c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_destroy_session); 27788c2ecf20Sopenharmony_ci 27798c2ecf20Sopenharmony_ciint cxgbi_set_host_param(struct Scsi_Host *shost, enum iscsi_host_param param, 27808c2ecf20Sopenharmony_ci char *buf, int buflen) 27818c2ecf20Sopenharmony_ci{ 27828c2ecf20Sopenharmony_ci struct cxgbi_hba *chba = iscsi_host_priv(shost); 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_ci if (!chba->ndev) { 27858c2ecf20Sopenharmony_ci shost_printk(KERN_ERR, shost, "Could not get host param. " 27868c2ecf20Sopenharmony_ci "netdev for host not set.\n"); 27878c2ecf20Sopenharmony_ci return -ENODEV; 27888c2ecf20Sopenharmony_ci } 27898c2ecf20Sopenharmony_ci 27908c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 27918c2ecf20Sopenharmony_ci "shost 0x%p, hba 0x%p,%s, param %d, buf(%d) %s.\n", 27928c2ecf20Sopenharmony_ci shost, chba, chba->ndev->name, param, buflen, buf); 27938c2ecf20Sopenharmony_ci 27948c2ecf20Sopenharmony_ci switch (param) { 27958c2ecf20Sopenharmony_ci case ISCSI_HOST_PARAM_IPADDRESS: 27968c2ecf20Sopenharmony_ci { 27978c2ecf20Sopenharmony_ci __be32 addr = in_aton(buf); 27988c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 27998c2ecf20Sopenharmony_ci "hba %s, req. ipv4 %pI4.\n", chba->ndev->name, &addr); 28008c2ecf20Sopenharmony_ci cxgbi_set_iscsi_ipv4(chba, addr); 28018c2ecf20Sopenharmony_ci return 0; 28028c2ecf20Sopenharmony_ci } 28038c2ecf20Sopenharmony_ci case ISCSI_HOST_PARAM_HWADDRESS: 28048c2ecf20Sopenharmony_ci case ISCSI_HOST_PARAM_NETDEV_NAME: 28058c2ecf20Sopenharmony_ci return 0; 28068c2ecf20Sopenharmony_ci default: 28078c2ecf20Sopenharmony_ci return iscsi_host_set_param(shost, param, buf, buflen); 28088c2ecf20Sopenharmony_ci } 28098c2ecf20Sopenharmony_ci} 28108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_set_host_param); 28118c2ecf20Sopenharmony_ci 28128c2ecf20Sopenharmony_ciint cxgbi_get_host_param(struct Scsi_Host *shost, enum iscsi_host_param param, 28138c2ecf20Sopenharmony_ci char *buf) 28148c2ecf20Sopenharmony_ci{ 28158c2ecf20Sopenharmony_ci struct cxgbi_hba *chba = iscsi_host_priv(shost); 28168c2ecf20Sopenharmony_ci int len = 0; 28178c2ecf20Sopenharmony_ci 28188c2ecf20Sopenharmony_ci if (!chba->ndev) { 28198c2ecf20Sopenharmony_ci shost_printk(KERN_ERR, shost, "Could not get host param. " 28208c2ecf20Sopenharmony_ci "netdev for host not set.\n"); 28218c2ecf20Sopenharmony_ci return -ENODEV; 28228c2ecf20Sopenharmony_ci } 28238c2ecf20Sopenharmony_ci 28248c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 28258c2ecf20Sopenharmony_ci "shost 0x%p, hba 0x%p,%s, param %d.\n", 28268c2ecf20Sopenharmony_ci shost, chba, chba->ndev->name, param); 28278c2ecf20Sopenharmony_ci 28288c2ecf20Sopenharmony_ci switch (param) { 28298c2ecf20Sopenharmony_ci case ISCSI_HOST_PARAM_HWADDRESS: 28308c2ecf20Sopenharmony_ci len = sysfs_format_mac(buf, chba->ndev->dev_addr, 6); 28318c2ecf20Sopenharmony_ci break; 28328c2ecf20Sopenharmony_ci case ISCSI_HOST_PARAM_NETDEV_NAME: 28338c2ecf20Sopenharmony_ci len = sprintf(buf, "%s\n", chba->ndev->name); 28348c2ecf20Sopenharmony_ci break; 28358c2ecf20Sopenharmony_ci case ISCSI_HOST_PARAM_IPADDRESS: 28368c2ecf20Sopenharmony_ci { 28378c2ecf20Sopenharmony_ci struct cxgbi_sock *csk = find_sock_on_port(chba->cdev, 28388c2ecf20Sopenharmony_ci chba->port_id); 28398c2ecf20Sopenharmony_ci if (csk) { 28408c2ecf20Sopenharmony_ci len = sprintf(buf, "%pIS", 28418c2ecf20Sopenharmony_ci (struct sockaddr *)&csk->saddr); 28428c2ecf20Sopenharmony_ci } 28438c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 28448c2ecf20Sopenharmony_ci "hba %s, addr %s.\n", chba->ndev->name, buf); 28458c2ecf20Sopenharmony_ci break; 28468c2ecf20Sopenharmony_ci } 28478c2ecf20Sopenharmony_ci default: 28488c2ecf20Sopenharmony_ci return iscsi_host_get_param(shost, param, buf); 28498c2ecf20Sopenharmony_ci } 28508c2ecf20Sopenharmony_ci 28518c2ecf20Sopenharmony_ci return len; 28528c2ecf20Sopenharmony_ci} 28538c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_get_host_param); 28548c2ecf20Sopenharmony_ci 28558c2ecf20Sopenharmony_cistruct iscsi_endpoint *cxgbi_ep_connect(struct Scsi_Host *shost, 28568c2ecf20Sopenharmony_ci struct sockaddr *dst_addr, 28578c2ecf20Sopenharmony_ci int non_blocking) 28588c2ecf20Sopenharmony_ci{ 28598c2ecf20Sopenharmony_ci struct iscsi_endpoint *ep; 28608c2ecf20Sopenharmony_ci struct cxgbi_endpoint *cep; 28618c2ecf20Sopenharmony_ci struct cxgbi_hba *hba = NULL; 28628c2ecf20Sopenharmony_ci struct cxgbi_sock *csk; 28638c2ecf20Sopenharmony_ci int ifindex = 0; 28648c2ecf20Sopenharmony_ci int err = -EINVAL; 28658c2ecf20Sopenharmony_ci 28668c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_SOCK, 28678c2ecf20Sopenharmony_ci "shost 0x%p, non_blocking %d, dst_addr 0x%p.\n", 28688c2ecf20Sopenharmony_ci shost, non_blocking, dst_addr); 28698c2ecf20Sopenharmony_ci 28708c2ecf20Sopenharmony_ci if (shost) { 28718c2ecf20Sopenharmony_ci hba = iscsi_host_priv(shost); 28728c2ecf20Sopenharmony_ci if (!hba) { 28738c2ecf20Sopenharmony_ci pr_info("shost 0x%p, priv NULL.\n", shost); 28748c2ecf20Sopenharmony_ci goto err_out; 28758c2ecf20Sopenharmony_ci } 28768c2ecf20Sopenharmony_ci } 28778c2ecf20Sopenharmony_ci 28788c2ecf20Sopenharmony_cicheck_route: 28798c2ecf20Sopenharmony_ci if (dst_addr->sa_family == AF_INET) { 28808c2ecf20Sopenharmony_ci csk = cxgbi_check_route(dst_addr, ifindex); 28818c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 28828c2ecf20Sopenharmony_ci } else if (dst_addr->sa_family == AF_INET6) { 28838c2ecf20Sopenharmony_ci csk = cxgbi_check_route6(dst_addr, ifindex); 28848c2ecf20Sopenharmony_ci#endif 28858c2ecf20Sopenharmony_ci } else { 28868c2ecf20Sopenharmony_ci pr_info("address family 0x%x NOT supported.\n", 28878c2ecf20Sopenharmony_ci dst_addr->sa_family); 28888c2ecf20Sopenharmony_ci err = -EAFNOSUPPORT; 28898c2ecf20Sopenharmony_ci return (struct iscsi_endpoint *)ERR_PTR(err); 28908c2ecf20Sopenharmony_ci } 28918c2ecf20Sopenharmony_ci 28928c2ecf20Sopenharmony_ci if (IS_ERR(csk)) 28938c2ecf20Sopenharmony_ci return (struct iscsi_endpoint *)csk; 28948c2ecf20Sopenharmony_ci cxgbi_sock_get(csk); 28958c2ecf20Sopenharmony_ci 28968c2ecf20Sopenharmony_ci if (!hba) 28978c2ecf20Sopenharmony_ci hba = csk->cdev->hbas[csk->port_id]; 28988c2ecf20Sopenharmony_ci else if (hba != csk->cdev->hbas[csk->port_id]) { 28998c2ecf20Sopenharmony_ci if (ifindex != hba->ndev->ifindex) { 29008c2ecf20Sopenharmony_ci cxgbi_sock_put(csk); 29018c2ecf20Sopenharmony_ci cxgbi_sock_closed(csk); 29028c2ecf20Sopenharmony_ci ifindex = hba->ndev->ifindex; 29038c2ecf20Sopenharmony_ci goto check_route; 29048c2ecf20Sopenharmony_ci } 29058c2ecf20Sopenharmony_ci 29068c2ecf20Sopenharmony_ci pr_info("Could not connect through requested host %u" 29078c2ecf20Sopenharmony_ci "hba 0x%p != 0x%p (%u).\n", 29088c2ecf20Sopenharmony_ci shost->host_no, hba, 29098c2ecf20Sopenharmony_ci csk->cdev->hbas[csk->port_id], csk->port_id); 29108c2ecf20Sopenharmony_ci err = -ENOSPC; 29118c2ecf20Sopenharmony_ci goto release_conn; 29128c2ecf20Sopenharmony_ci } 29138c2ecf20Sopenharmony_ci 29148c2ecf20Sopenharmony_ci err = sock_get_port(csk); 29158c2ecf20Sopenharmony_ci if (err) 29168c2ecf20Sopenharmony_ci goto release_conn; 29178c2ecf20Sopenharmony_ci 29188c2ecf20Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_CONNECTING); 29198c2ecf20Sopenharmony_ci err = csk->cdev->csk_init_act_open(csk); 29208c2ecf20Sopenharmony_ci if (err) 29218c2ecf20Sopenharmony_ci goto release_conn; 29228c2ecf20Sopenharmony_ci 29238c2ecf20Sopenharmony_ci if (cxgbi_sock_is_closing(csk)) { 29248c2ecf20Sopenharmony_ci err = -ENOSPC; 29258c2ecf20Sopenharmony_ci pr_info("csk 0x%p is closing.\n", csk); 29268c2ecf20Sopenharmony_ci goto release_conn; 29278c2ecf20Sopenharmony_ci } 29288c2ecf20Sopenharmony_ci 29298c2ecf20Sopenharmony_ci ep = iscsi_create_endpoint(sizeof(*cep)); 29308c2ecf20Sopenharmony_ci if (!ep) { 29318c2ecf20Sopenharmony_ci err = -ENOMEM; 29328c2ecf20Sopenharmony_ci pr_info("iscsi alloc ep, OOM.\n"); 29338c2ecf20Sopenharmony_ci goto release_conn; 29348c2ecf20Sopenharmony_ci } 29358c2ecf20Sopenharmony_ci 29368c2ecf20Sopenharmony_ci cep = ep->dd_data; 29378c2ecf20Sopenharmony_ci cep->csk = csk; 29388c2ecf20Sopenharmony_ci cep->chba = hba; 29398c2ecf20Sopenharmony_ci 29408c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_SOCK, 29418c2ecf20Sopenharmony_ci "ep 0x%p, cep 0x%p, csk 0x%p, hba 0x%p,%s.\n", 29428c2ecf20Sopenharmony_ci ep, cep, csk, hba, hba->ndev->name); 29438c2ecf20Sopenharmony_ci return ep; 29448c2ecf20Sopenharmony_ci 29458c2ecf20Sopenharmony_cirelease_conn: 29468c2ecf20Sopenharmony_ci cxgbi_sock_put(csk); 29478c2ecf20Sopenharmony_ci cxgbi_sock_closed(csk); 29488c2ecf20Sopenharmony_cierr_out: 29498c2ecf20Sopenharmony_ci return ERR_PTR(err); 29508c2ecf20Sopenharmony_ci} 29518c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_ep_connect); 29528c2ecf20Sopenharmony_ci 29538c2ecf20Sopenharmony_ciint cxgbi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) 29548c2ecf20Sopenharmony_ci{ 29558c2ecf20Sopenharmony_ci struct cxgbi_endpoint *cep = ep->dd_data; 29568c2ecf20Sopenharmony_ci struct cxgbi_sock *csk = cep->csk; 29578c2ecf20Sopenharmony_ci 29588c2ecf20Sopenharmony_ci if (!cxgbi_sock_is_established(csk)) 29598c2ecf20Sopenharmony_ci return 0; 29608c2ecf20Sopenharmony_ci return 1; 29618c2ecf20Sopenharmony_ci} 29628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_ep_poll); 29638c2ecf20Sopenharmony_ci 29648c2ecf20Sopenharmony_civoid cxgbi_ep_disconnect(struct iscsi_endpoint *ep) 29658c2ecf20Sopenharmony_ci{ 29668c2ecf20Sopenharmony_ci struct cxgbi_endpoint *cep = ep->dd_data; 29678c2ecf20Sopenharmony_ci struct cxgbi_conn *cconn = cep->cconn; 29688c2ecf20Sopenharmony_ci struct cxgbi_sock *csk = cep->csk; 29698c2ecf20Sopenharmony_ci 29708c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_SOCK, 29718c2ecf20Sopenharmony_ci "ep 0x%p, cep 0x%p, cconn 0x%p, csk 0x%p,%u,0x%lx.\n", 29728c2ecf20Sopenharmony_ci ep, cep, cconn, csk, csk->state, csk->flags); 29738c2ecf20Sopenharmony_ci 29748c2ecf20Sopenharmony_ci if (cconn && cconn->iconn) { 29758c2ecf20Sopenharmony_ci iscsi_suspend_tx(cconn->iconn); 29768c2ecf20Sopenharmony_ci write_lock_bh(&csk->callback_lock); 29778c2ecf20Sopenharmony_ci cep->csk->user_data = NULL; 29788c2ecf20Sopenharmony_ci cconn->cep = NULL; 29798c2ecf20Sopenharmony_ci write_unlock_bh(&csk->callback_lock); 29808c2ecf20Sopenharmony_ci } 29818c2ecf20Sopenharmony_ci iscsi_destroy_endpoint(ep); 29828c2ecf20Sopenharmony_ci 29838c2ecf20Sopenharmony_ci if (likely(csk->state >= CTP_ESTABLISHED)) 29848c2ecf20Sopenharmony_ci need_active_close(csk); 29858c2ecf20Sopenharmony_ci else 29868c2ecf20Sopenharmony_ci cxgbi_sock_closed(csk); 29878c2ecf20Sopenharmony_ci 29888c2ecf20Sopenharmony_ci cxgbi_sock_put(csk); 29898c2ecf20Sopenharmony_ci} 29908c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_ep_disconnect); 29918c2ecf20Sopenharmony_ci 29928c2ecf20Sopenharmony_ciint cxgbi_iscsi_init(struct iscsi_transport *itp, 29938c2ecf20Sopenharmony_ci struct scsi_transport_template **stt) 29948c2ecf20Sopenharmony_ci{ 29958c2ecf20Sopenharmony_ci *stt = iscsi_register_transport(itp); 29968c2ecf20Sopenharmony_ci if (*stt == NULL) { 29978c2ecf20Sopenharmony_ci pr_err("unable to register %s transport 0x%p.\n", 29988c2ecf20Sopenharmony_ci itp->name, itp); 29998c2ecf20Sopenharmony_ci return -ENODEV; 30008c2ecf20Sopenharmony_ci } 30018c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 30028c2ecf20Sopenharmony_ci "%s, registered iscsi transport 0x%p.\n", 30038c2ecf20Sopenharmony_ci itp->name, stt); 30048c2ecf20Sopenharmony_ci return 0; 30058c2ecf20Sopenharmony_ci} 30068c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_iscsi_init); 30078c2ecf20Sopenharmony_ci 30088c2ecf20Sopenharmony_civoid cxgbi_iscsi_cleanup(struct iscsi_transport *itp, 30098c2ecf20Sopenharmony_ci struct scsi_transport_template **stt) 30108c2ecf20Sopenharmony_ci{ 30118c2ecf20Sopenharmony_ci if (*stt) { 30128c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 30138c2ecf20Sopenharmony_ci "de-register transport 0x%p, %s, stt 0x%p.\n", 30148c2ecf20Sopenharmony_ci itp, itp->name, *stt); 30158c2ecf20Sopenharmony_ci *stt = NULL; 30168c2ecf20Sopenharmony_ci iscsi_unregister_transport(itp); 30178c2ecf20Sopenharmony_ci } 30188c2ecf20Sopenharmony_ci} 30198c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_iscsi_cleanup); 30208c2ecf20Sopenharmony_ci 30218c2ecf20Sopenharmony_ciumode_t cxgbi_attr_is_visible(int param_type, int param) 30228c2ecf20Sopenharmony_ci{ 30238c2ecf20Sopenharmony_ci switch (param_type) { 30248c2ecf20Sopenharmony_ci case ISCSI_HOST_PARAM: 30258c2ecf20Sopenharmony_ci switch (param) { 30268c2ecf20Sopenharmony_ci case ISCSI_HOST_PARAM_NETDEV_NAME: 30278c2ecf20Sopenharmony_ci case ISCSI_HOST_PARAM_HWADDRESS: 30288c2ecf20Sopenharmony_ci case ISCSI_HOST_PARAM_IPADDRESS: 30298c2ecf20Sopenharmony_ci case ISCSI_HOST_PARAM_INITIATOR_NAME: 30308c2ecf20Sopenharmony_ci return S_IRUGO; 30318c2ecf20Sopenharmony_ci default: 30328c2ecf20Sopenharmony_ci return 0; 30338c2ecf20Sopenharmony_ci } 30348c2ecf20Sopenharmony_ci case ISCSI_PARAM: 30358c2ecf20Sopenharmony_ci switch (param) { 30368c2ecf20Sopenharmony_ci case ISCSI_PARAM_MAX_RECV_DLENGTH: 30378c2ecf20Sopenharmony_ci case ISCSI_PARAM_MAX_XMIT_DLENGTH: 30388c2ecf20Sopenharmony_ci case ISCSI_PARAM_HDRDGST_EN: 30398c2ecf20Sopenharmony_ci case ISCSI_PARAM_DATADGST_EN: 30408c2ecf20Sopenharmony_ci case ISCSI_PARAM_CONN_ADDRESS: 30418c2ecf20Sopenharmony_ci case ISCSI_PARAM_CONN_PORT: 30428c2ecf20Sopenharmony_ci case ISCSI_PARAM_EXP_STATSN: 30438c2ecf20Sopenharmony_ci case ISCSI_PARAM_PERSISTENT_ADDRESS: 30448c2ecf20Sopenharmony_ci case ISCSI_PARAM_PERSISTENT_PORT: 30458c2ecf20Sopenharmony_ci case ISCSI_PARAM_PING_TMO: 30468c2ecf20Sopenharmony_ci case ISCSI_PARAM_RECV_TMO: 30478c2ecf20Sopenharmony_ci case ISCSI_PARAM_INITIAL_R2T_EN: 30488c2ecf20Sopenharmony_ci case ISCSI_PARAM_MAX_R2T: 30498c2ecf20Sopenharmony_ci case ISCSI_PARAM_IMM_DATA_EN: 30508c2ecf20Sopenharmony_ci case ISCSI_PARAM_FIRST_BURST: 30518c2ecf20Sopenharmony_ci case ISCSI_PARAM_MAX_BURST: 30528c2ecf20Sopenharmony_ci case ISCSI_PARAM_PDU_INORDER_EN: 30538c2ecf20Sopenharmony_ci case ISCSI_PARAM_DATASEQ_INORDER_EN: 30548c2ecf20Sopenharmony_ci case ISCSI_PARAM_ERL: 30558c2ecf20Sopenharmony_ci case ISCSI_PARAM_TARGET_NAME: 30568c2ecf20Sopenharmony_ci case ISCSI_PARAM_TPGT: 30578c2ecf20Sopenharmony_ci case ISCSI_PARAM_USERNAME: 30588c2ecf20Sopenharmony_ci case ISCSI_PARAM_PASSWORD: 30598c2ecf20Sopenharmony_ci case ISCSI_PARAM_USERNAME_IN: 30608c2ecf20Sopenharmony_ci case ISCSI_PARAM_PASSWORD_IN: 30618c2ecf20Sopenharmony_ci case ISCSI_PARAM_FAST_ABORT: 30628c2ecf20Sopenharmony_ci case ISCSI_PARAM_ABORT_TMO: 30638c2ecf20Sopenharmony_ci case ISCSI_PARAM_LU_RESET_TMO: 30648c2ecf20Sopenharmony_ci case ISCSI_PARAM_TGT_RESET_TMO: 30658c2ecf20Sopenharmony_ci case ISCSI_PARAM_IFACE_NAME: 30668c2ecf20Sopenharmony_ci case ISCSI_PARAM_INITIATOR_NAME: 30678c2ecf20Sopenharmony_ci return S_IRUGO; 30688c2ecf20Sopenharmony_ci default: 30698c2ecf20Sopenharmony_ci return 0; 30708c2ecf20Sopenharmony_ci } 30718c2ecf20Sopenharmony_ci } 30728c2ecf20Sopenharmony_ci 30738c2ecf20Sopenharmony_ci return 0; 30748c2ecf20Sopenharmony_ci} 30758c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_attr_is_visible); 30768c2ecf20Sopenharmony_ci 30778c2ecf20Sopenharmony_cistatic int __init libcxgbi_init_module(void) 30788c2ecf20Sopenharmony_ci{ 30798c2ecf20Sopenharmony_ci pr_info("%s", version); 30808c2ecf20Sopenharmony_ci 30818c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof_field(struct sk_buff, cb) < 30828c2ecf20Sopenharmony_ci sizeof(struct cxgbi_skb_cb)); 30838c2ecf20Sopenharmony_ci rsvd_page = alloc_page(GFP_KERNEL | __GFP_ZERO); 30848c2ecf20Sopenharmony_ci if (!rsvd_page) 30858c2ecf20Sopenharmony_ci return -ENOMEM; 30868c2ecf20Sopenharmony_ci 30878c2ecf20Sopenharmony_ci return 0; 30888c2ecf20Sopenharmony_ci} 30898c2ecf20Sopenharmony_ci 30908c2ecf20Sopenharmony_cistatic void __exit libcxgbi_exit_module(void) 30918c2ecf20Sopenharmony_ci{ 30928c2ecf20Sopenharmony_ci cxgbi_device_unregister_all(0xFF); 30938c2ecf20Sopenharmony_ci put_page(rsvd_page); 30948c2ecf20Sopenharmony_ci return; 30958c2ecf20Sopenharmony_ci} 30968c2ecf20Sopenharmony_ci 30978c2ecf20Sopenharmony_cimodule_init(libcxgbi_init_module); 30988c2ecf20Sopenharmony_cimodule_exit(libcxgbi_exit_module); 3099