162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * libcxgbi.c: Chelsio common library for T3/T4 iSCSI driver. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (c) 2010-2015 Chelsio Communications, Inc. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 762306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by 862306a36Sopenharmony_ci * the Free Software Foundation. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Written by: Karen Xie (kxie@chelsio.com) 1162306a36Sopenharmony_ci * Written by: Rakesh Ranjan (rranjan@chelsio.com) 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <linux/skbuff.h> 1762306a36Sopenharmony_ci#include <linux/crypto.h> 1862306a36Sopenharmony_ci#include <linux/scatterlist.h> 1962306a36Sopenharmony_ci#include <linux/pci.h> 2062306a36Sopenharmony_ci#include <scsi/scsi.h> 2162306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h> 2262306a36Sopenharmony_ci#include <scsi/scsi_host.h> 2362306a36Sopenharmony_ci#include <linux/if_vlan.h> 2462306a36Sopenharmony_ci#include <linux/inet.h> 2562306a36Sopenharmony_ci#include <net/dst.h> 2662306a36Sopenharmony_ci#include <net/route.h> 2762306a36Sopenharmony_ci#include <net/ipv6.h> 2862306a36Sopenharmony_ci#include <net/ip6_route.h> 2962306a36Sopenharmony_ci#include <net/addrconf.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include <linux/inetdevice.h> /* ip_dev_find */ 3262306a36Sopenharmony_ci#include <linux/module.h> 3362306a36Sopenharmony_ci#include <net/tcp.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic unsigned int dbg_level; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include "libcxgbi.h" 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define DRV_MODULE_NAME "libcxgbi" 4062306a36Sopenharmony_ci#define DRV_MODULE_DESC "Chelsio iSCSI driver library" 4162306a36Sopenharmony_ci#define DRV_MODULE_VERSION "0.9.1-ko" 4262306a36Sopenharmony_ci#define DRV_MODULE_RELDATE "Apr. 2015" 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic char version[] = 4562306a36Sopenharmony_ci DRV_MODULE_DESC " " DRV_MODULE_NAME 4662306a36Sopenharmony_ci " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ciMODULE_AUTHOR("Chelsio Communications, Inc."); 4962306a36Sopenharmony_ciMODULE_DESCRIPTION(DRV_MODULE_DESC); 5062306a36Sopenharmony_ciMODULE_VERSION(DRV_MODULE_VERSION); 5162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cimodule_param(dbg_level, uint, 0644); 5462306a36Sopenharmony_ciMODULE_PARM_DESC(dbg_level, "libiscsi debug level (default=0)"); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* 5862306a36Sopenharmony_ci * cxgbi device management 5962306a36Sopenharmony_ci * maintains a list of the cxgbi devices 6062306a36Sopenharmony_ci */ 6162306a36Sopenharmony_cistatic LIST_HEAD(cdev_list); 6262306a36Sopenharmony_cistatic DEFINE_MUTEX(cdev_mutex); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic LIST_HEAD(cdev_rcu_list); 6562306a36Sopenharmony_cistatic DEFINE_SPINLOCK(cdev_rcu_lock); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic inline void cxgbi_decode_sw_tag(u32 sw_tag, int *idx, int *age) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci if (age) 7062306a36Sopenharmony_ci *age = sw_tag & 0x7FFF; 7162306a36Sopenharmony_ci if (idx) 7262306a36Sopenharmony_ci *idx = (sw_tag >> 16) & 0x7FFF; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ciint cxgbi_device_portmap_create(struct cxgbi_device *cdev, unsigned int base, 7662306a36Sopenharmony_ci unsigned int max_conn) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci struct cxgbi_ports_map *pmap = &cdev->pmap; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci pmap->port_csk = kvzalloc(array_size(max_conn, 8162306a36Sopenharmony_ci sizeof(struct cxgbi_sock *)), 8262306a36Sopenharmony_ci GFP_KERNEL | __GFP_NOWARN); 8362306a36Sopenharmony_ci if (!pmap->port_csk) { 8462306a36Sopenharmony_ci pr_warn("cdev 0x%p, portmap OOM %u.\n", cdev, max_conn); 8562306a36Sopenharmony_ci return -ENOMEM; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci pmap->max_connect = max_conn; 8962306a36Sopenharmony_ci pmap->sport_base = base; 9062306a36Sopenharmony_ci spin_lock_init(&pmap->lock); 9162306a36Sopenharmony_ci return 0; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_device_portmap_create); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_civoid cxgbi_device_portmap_cleanup(struct cxgbi_device *cdev) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci struct cxgbi_ports_map *pmap = &cdev->pmap; 9862306a36Sopenharmony_ci struct cxgbi_sock *csk; 9962306a36Sopenharmony_ci int i; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci for (i = 0; i < pmap->max_connect; i++) { 10262306a36Sopenharmony_ci if (pmap->port_csk[i]) { 10362306a36Sopenharmony_ci csk = pmap->port_csk[i]; 10462306a36Sopenharmony_ci pmap->port_csk[i] = NULL; 10562306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, 10662306a36Sopenharmony_ci "csk 0x%p, cdev 0x%p, offload down.\n", 10762306a36Sopenharmony_ci csk, cdev); 10862306a36Sopenharmony_ci spin_lock_bh(&csk->lock); 10962306a36Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_OFFLOAD_DOWN); 11062306a36Sopenharmony_ci cxgbi_sock_closed(csk); 11162306a36Sopenharmony_ci spin_unlock_bh(&csk->lock); 11262306a36Sopenharmony_ci cxgbi_sock_put(csk); 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_device_portmap_cleanup); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic inline void cxgbi_device_destroy(struct cxgbi_device *cdev) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_DEV, 12162306a36Sopenharmony_ci "cdev 0x%p, p# %u.\n", cdev, cdev->nports); 12262306a36Sopenharmony_ci cxgbi_hbas_remove(cdev); 12362306a36Sopenharmony_ci cxgbi_device_portmap_cleanup(cdev); 12462306a36Sopenharmony_ci if (cdev->cdev2ppm) 12562306a36Sopenharmony_ci cxgbi_ppm_release(cdev->cdev2ppm(cdev)); 12662306a36Sopenharmony_ci if (cdev->pmap.max_connect) 12762306a36Sopenharmony_ci kvfree(cdev->pmap.port_csk); 12862306a36Sopenharmony_ci kfree(cdev); 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistruct cxgbi_device *cxgbi_device_register(unsigned int extra, 13262306a36Sopenharmony_ci unsigned int nports) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci struct cxgbi_device *cdev; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci cdev = kzalloc(sizeof(*cdev) + extra + nports * 13762306a36Sopenharmony_ci (sizeof(struct cxgbi_hba *) + 13862306a36Sopenharmony_ci sizeof(struct net_device *)), 13962306a36Sopenharmony_ci GFP_KERNEL); 14062306a36Sopenharmony_ci if (!cdev) { 14162306a36Sopenharmony_ci pr_warn("nport %d, OOM.\n", nports); 14262306a36Sopenharmony_ci return NULL; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci cdev->ports = (struct net_device **)(cdev + 1); 14562306a36Sopenharmony_ci cdev->hbas = (struct cxgbi_hba **)(((char*)cdev->ports) + nports * 14662306a36Sopenharmony_ci sizeof(struct net_device *)); 14762306a36Sopenharmony_ci if (extra) 14862306a36Sopenharmony_ci cdev->dd_data = ((char *)cdev->hbas) + 14962306a36Sopenharmony_ci nports * sizeof(struct cxgbi_hba *); 15062306a36Sopenharmony_ci spin_lock_init(&cdev->pmap.lock); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci mutex_lock(&cdev_mutex); 15362306a36Sopenharmony_ci list_add_tail(&cdev->list_head, &cdev_list); 15462306a36Sopenharmony_ci mutex_unlock(&cdev_mutex); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci spin_lock(&cdev_rcu_lock); 15762306a36Sopenharmony_ci list_add_tail_rcu(&cdev->rcu_node, &cdev_rcu_list); 15862306a36Sopenharmony_ci spin_unlock(&cdev_rcu_lock); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_DEV, 16162306a36Sopenharmony_ci "cdev 0x%p, p# %u.\n", cdev, nports); 16262306a36Sopenharmony_ci return cdev; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_device_register); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_civoid cxgbi_device_unregister(struct cxgbi_device *cdev) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_DEV, 16962306a36Sopenharmony_ci "cdev 0x%p, p# %u,%s.\n", 17062306a36Sopenharmony_ci cdev, cdev->nports, cdev->nports ? cdev->ports[0]->name : ""); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci mutex_lock(&cdev_mutex); 17362306a36Sopenharmony_ci list_del(&cdev->list_head); 17462306a36Sopenharmony_ci mutex_unlock(&cdev_mutex); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci spin_lock(&cdev_rcu_lock); 17762306a36Sopenharmony_ci list_del_rcu(&cdev->rcu_node); 17862306a36Sopenharmony_ci spin_unlock(&cdev_rcu_lock); 17962306a36Sopenharmony_ci synchronize_rcu(); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci cxgbi_device_destroy(cdev); 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_device_unregister); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_civoid cxgbi_device_unregister_all(unsigned int flag) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct cxgbi_device *cdev, *tmp; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci mutex_lock(&cdev_mutex); 19062306a36Sopenharmony_ci list_for_each_entry_safe(cdev, tmp, &cdev_list, list_head) { 19162306a36Sopenharmony_ci if ((cdev->flags & flag) == flag) { 19262306a36Sopenharmony_ci mutex_unlock(&cdev_mutex); 19362306a36Sopenharmony_ci cxgbi_device_unregister(cdev); 19462306a36Sopenharmony_ci mutex_lock(&cdev_mutex); 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci mutex_unlock(&cdev_mutex); 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_device_unregister_all); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistruct cxgbi_device *cxgbi_device_find_by_lldev(void *lldev) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci struct cxgbi_device *cdev, *tmp; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci mutex_lock(&cdev_mutex); 20662306a36Sopenharmony_ci list_for_each_entry_safe(cdev, tmp, &cdev_list, list_head) { 20762306a36Sopenharmony_ci if (cdev->lldev == lldev) { 20862306a36Sopenharmony_ci mutex_unlock(&cdev_mutex); 20962306a36Sopenharmony_ci return cdev; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci mutex_unlock(&cdev_mutex); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_DEV, 21562306a36Sopenharmony_ci "lldev 0x%p, NO match found.\n", lldev); 21662306a36Sopenharmony_ci return NULL; 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_device_find_by_lldev); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistruct cxgbi_device *cxgbi_device_find_by_netdev(struct net_device *ndev, 22162306a36Sopenharmony_ci int *port) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci struct net_device *vdev = NULL; 22462306a36Sopenharmony_ci struct cxgbi_device *cdev, *tmp; 22562306a36Sopenharmony_ci int i; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if (is_vlan_dev(ndev)) { 22862306a36Sopenharmony_ci vdev = ndev; 22962306a36Sopenharmony_ci ndev = vlan_dev_real_dev(ndev); 23062306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_DEV, 23162306a36Sopenharmony_ci "vlan dev %s -> %s.\n", vdev->name, ndev->name); 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci mutex_lock(&cdev_mutex); 23562306a36Sopenharmony_ci list_for_each_entry_safe(cdev, tmp, &cdev_list, list_head) { 23662306a36Sopenharmony_ci for (i = 0; i < cdev->nports; i++) { 23762306a36Sopenharmony_ci if (ndev == cdev->ports[i]) { 23862306a36Sopenharmony_ci cdev->hbas[i]->vdev = vdev; 23962306a36Sopenharmony_ci mutex_unlock(&cdev_mutex); 24062306a36Sopenharmony_ci if (port) 24162306a36Sopenharmony_ci *port = i; 24262306a36Sopenharmony_ci return cdev; 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci mutex_unlock(&cdev_mutex); 24762306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_DEV, 24862306a36Sopenharmony_ci "ndev 0x%p, %s, NO match found.\n", ndev, ndev->name); 24962306a36Sopenharmony_ci return NULL; 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_device_find_by_netdev); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistruct cxgbi_device *cxgbi_device_find_by_netdev_rcu(struct net_device *ndev, 25462306a36Sopenharmony_ci int *port) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci struct net_device *vdev = NULL; 25762306a36Sopenharmony_ci struct cxgbi_device *cdev; 25862306a36Sopenharmony_ci int i; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci if (is_vlan_dev(ndev)) { 26162306a36Sopenharmony_ci vdev = ndev; 26262306a36Sopenharmony_ci ndev = vlan_dev_real_dev(ndev); 26362306a36Sopenharmony_ci pr_info("vlan dev %s -> %s.\n", vdev->name, ndev->name); 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci rcu_read_lock(); 26762306a36Sopenharmony_ci list_for_each_entry_rcu(cdev, &cdev_rcu_list, rcu_node) { 26862306a36Sopenharmony_ci for (i = 0; i < cdev->nports; i++) { 26962306a36Sopenharmony_ci if (ndev == cdev->ports[i]) { 27062306a36Sopenharmony_ci cdev->hbas[i]->vdev = vdev; 27162306a36Sopenharmony_ci rcu_read_unlock(); 27262306a36Sopenharmony_ci if (port) 27362306a36Sopenharmony_ci *port = i; 27462306a36Sopenharmony_ci return cdev; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci rcu_read_unlock(); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_DEV, 28162306a36Sopenharmony_ci "ndev 0x%p, %s, NO match found.\n", ndev, ndev->name); 28262306a36Sopenharmony_ci return NULL; 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_device_find_by_netdev_rcu); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic struct cxgbi_device *cxgbi_device_find_by_mac(struct net_device *ndev, 28762306a36Sopenharmony_ci int *port) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci struct net_device *vdev = NULL; 29062306a36Sopenharmony_ci struct cxgbi_device *cdev, *tmp; 29162306a36Sopenharmony_ci int i; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (is_vlan_dev(ndev)) { 29462306a36Sopenharmony_ci vdev = ndev; 29562306a36Sopenharmony_ci ndev = vlan_dev_real_dev(ndev); 29662306a36Sopenharmony_ci pr_info("vlan dev %s -> %s.\n", vdev->name, ndev->name); 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci mutex_lock(&cdev_mutex); 30062306a36Sopenharmony_ci list_for_each_entry_safe(cdev, tmp, &cdev_list, list_head) { 30162306a36Sopenharmony_ci for (i = 0; i < cdev->nports; i++) { 30262306a36Sopenharmony_ci if (!memcmp(ndev->dev_addr, cdev->ports[i]->dev_addr, 30362306a36Sopenharmony_ci MAX_ADDR_LEN)) { 30462306a36Sopenharmony_ci cdev->hbas[i]->vdev = vdev; 30562306a36Sopenharmony_ci mutex_unlock(&cdev_mutex); 30662306a36Sopenharmony_ci if (port) 30762306a36Sopenharmony_ci *port = i; 30862306a36Sopenharmony_ci return cdev; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci mutex_unlock(&cdev_mutex); 31362306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_DEV, 31462306a36Sopenharmony_ci "ndev 0x%p, %s, NO match mac found.\n", 31562306a36Sopenharmony_ci ndev, ndev->name); 31662306a36Sopenharmony_ci return NULL; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_civoid cxgbi_hbas_remove(struct cxgbi_device *cdev) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci int i; 32262306a36Sopenharmony_ci struct cxgbi_hba *chba; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_DEV, 32562306a36Sopenharmony_ci "cdev 0x%p, p#%u.\n", cdev, cdev->nports); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci for (i = 0; i < cdev->nports; i++) { 32862306a36Sopenharmony_ci chba = cdev->hbas[i]; 32962306a36Sopenharmony_ci if (chba) { 33062306a36Sopenharmony_ci cdev->hbas[i] = NULL; 33162306a36Sopenharmony_ci iscsi_host_remove(chba->shost, false); 33262306a36Sopenharmony_ci pci_dev_put(cdev->pdev); 33362306a36Sopenharmony_ci iscsi_host_free(chba->shost); 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_hbas_remove); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ciint cxgbi_hbas_add(struct cxgbi_device *cdev, u64 max_lun, 34062306a36Sopenharmony_ci unsigned int max_conns, const struct scsi_host_template *sht, 34162306a36Sopenharmony_ci struct scsi_transport_template *stt) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci struct cxgbi_hba *chba; 34462306a36Sopenharmony_ci struct Scsi_Host *shost; 34562306a36Sopenharmony_ci int i, err; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_DEV, "cdev 0x%p, p#%u.\n", cdev, cdev->nports); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci for (i = 0; i < cdev->nports; i++) { 35062306a36Sopenharmony_ci shost = iscsi_host_alloc(sht, sizeof(*chba), 1); 35162306a36Sopenharmony_ci if (!shost) { 35262306a36Sopenharmony_ci pr_info("0x%p, p%d, %s, host alloc failed.\n", 35362306a36Sopenharmony_ci cdev, i, cdev->ports[i]->name); 35462306a36Sopenharmony_ci err = -ENOMEM; 35562306a36Sopenharmony_ci goto err_out; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci shost->transportt = stt; 35962306a36Sopenharmony_ci shost->max_lun = max_lun; 36062306a36Sopenharmony_ci shost->max_id = max_conns - 1; 36162306a36Sopenharmony_ci shost->max_channel = 0; 36262306a36Sopenharmony_ci shost->max_cmd_len = SCSI_MAX_VARLEN_CDB_SIZE; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci chba = iscsi_host_priv(shost); 36562306a36Sopenharmony_ci chba->cdev = cdev; 36662306a36Sopenharmony_ci chba->ndev = cdev->ports[i]; 36762306a36Sopenharmony_ci chba->shost = shost; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci shost->can_queue = sht->can_queue - ISCSI_MGMT_CMDS_MAX; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_DEV, 37262306a36Sopenharmony_ci "cdev 0x%p, p#%d %s: chba 0x%p.\n", 37362306a36Sopenharmony_ci cdev, i, cdev->ports[i]->name, chba); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci pci_dev_get(cdev->pdev); 37662306a36Sopenharmony_ci err = iscsi_host_add(shost, &cdev->pdev->dev); 37762306a36Sopenharmony_ci if (err) { 37862306a36Sopenharmony_ci pr_info("cdev 0x%p, p#%d %s, host add failed.\n", 37962306a36Sopenharmony_ci cdev, i, cdev->ports[i]->name); 38062306a36Sopenharmony_ci pci_dev_put(cdev->pdev); 38162306a36Sopenharmony_ci scsi_host_put(shost); 38262306a36Sopenharmony_ci goto err_out; 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci cdev->hbas[i] = chba; 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci return 0; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cierr_out: 39162306a36Sopenharmony_ci cxgbi_hbas_remove(cdev); 39262306a36Sopenharmony_ci return err; 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_hbas_add); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci/* 39762306a36Sopenharmony_ci * iSCSI offload 39862306a36Sopenharmony_ci * 39962306a36Sopenharmony_ci * - source port management 40062306a36Sopenharmony_ci * To find a free source port in the port allocation map we use a very simple 40162306a36Sopenharmony_ci * rotor scheme to look for the next free port. 40262306a36Sopenharmony_ci * 40362306a36Sopenharmony_ci * If a source port has been specified make sure that it doesn't collide with 40462306a36Sopenharmony_ci * our normal source port allocation map. If it's outside the range of our 40562306a36Sopenharmony_ci * allocation/deallocation scheme just let them use it. 40662306a36Sopenharmony_ci * 40762306a36Sopenharmony_ci * If the source port is outside our allocation range, the caller is 40862306a36Sopenharmony_ci * responsible for keeping track of their port usage. 40962306a36Sopenharmony_ci */ 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic struct cxgbi_sock *find_sock_on_port(struct cxgbi_device *cdev, 41262306a36Sopenharmony_ci unsigned char port_id) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci struct cxgbi_ports_map *pmap = &cdev->pmap; 41562306a36Sopenharmony_ci unsigned int i; 41662306a36Sopenharmony_ci unsigned int used; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (!pmap->max_connect || !pmap->used) 41962306a36Sopenharmony_ci return NULL; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci spin_lock_bh(&pmap->lock); 42262306a36Sopenharmony_ci used = pmap->used; 42362306a36Sopenharmony_ci for (i = 0; used && i < pmap->max_connect; i++) { 42462306a36Sopenharmony_ci struct cxgbi_sock *csk = pmap->port_csk[i]; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci if (csk) { 42762306a36Sopenharmony_ci if (csk->port_id == port_id) { 42862306a36Sopenharmony_ci spin_unlock_bh(&pmap->lock); 42962306a36Sopenharmony_ci return csk; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci used--; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci spin_unlock_bh(&pmap->lock); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci return NULL; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic int sock_get_port(struct cxgbi_sock *csk) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci struct cxgbi_device *cdev = csk->cdev; 44262306a36Sopenharmony_ci struct cxgbi_ports_map *pmap = &cdev->pmap; 44362306a36Sopenharmony_ci unsigned int start; 44462306a36Sopenharmony_ci int idx; 44562306a36Sopenharmony_ci __be16 *port; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (!pmap->max_connect) { 44862306a36Sopenharmony_ci pr_err("cdev 0x%p, p#%u %s, NO port map.\n", 44962306a36Sopenharmony_ci cdev, csk->port_id, cdev->ports[csk->port_id]->name); 45062306a36Sopenharmony_ci return -EADDRNOTAVAIL; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if (csk->csk_family == AF_INET) 45462306a36Sopenharmony_ci port = &csk->saddr.sin_port; 45562306a36Sopenharmony_ci else /* ipv6 */ 45662306a36Sopenharmony_ci port = &csk->saddr6.sin6_port; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (*port) { 45962306a36Sopenharmony_ci pr_err("source port NON-ZERO %u.\n", 46062306a36Sopenharmony_ci ntohs(*port)); 46162306a36Sopenharmony_ci return -EADDRINUSE; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci spin_lock_bh(&pmap->lock); 46562306a36Sopenharmony_ci if (pmap->used >= pmap->max_connect) { 46662306a36Sopenharmony_ci spin_unlock_bh(&pmap->lock); 46762306a36Sopenharmony_ci pr_info("cdev 0x%p, p#%u %s, ALL ports used.\n", 46862306a36Sopenharmony_ci cdev, csk->port_id, cdev->ports[csk->port_id]->name); 46962306a36Sopenharmony_ci return -EADDRNOTAVAIL; 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci start = idx = pmap->next; 47362306a36Sopenharmony_ci do { 47462306a36Sopenharmony_ci if (++idx >= pmap->max_connect) 47562306a36Sopenharmony_ci idx = 0; 47662306a36Sopenharmony_ci if (!pmap->port_csk[idx]) { 47762306a36Sopenharmony_ci pmap->used++; 47862306a36Sopenharmony_ci *port = htons(pmap->sport_base + idx); 47962306a36Sopenharmony_ci pmap->next = idx; 48062306a36Sopenharmony_ci pmap->port_csk[idx] = csk; 48162306a36Sopenharmony_ci spin_unlock_bh(&pmap->lock); 48262306a36Sopenharmony_ci cxgbi_sock_get(csk); 48362306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, 48462306a36Sopenharmony_ci "cdev 0x%p, p#%u %s, p %u, %u.\n", 48562306a36Sopenharmony_ci cdev, csk->port_id, 48662306a36Sopenharmony_ci cdev->ports[csk->port_id]->name, 48762306a36Sopenharmony_ci pmap->sport_base + idx, pmap->next); 48862306a36Sopenharmony_ci return 0; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci } while (idx != start); 49162306a36Sopenharmony_ci spin_unlock_bh(&pmap->lock); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci /* should not happen */ 49462306a36Sopenharmony_ci pr_warn("cdev 0x%p, p#%u %s, next %u?\n", 49562306a36Sopenharmony_ci cdev, csk->port_id, cdev->ports[csk->port_id]->name, 49662306a36Sopenharmony_ci pmap->next); 49762306a36Sopenharmony_ci return -EADDRNOTAVAIL; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic void sock_put_port(struct cxgbi_sock *csk) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci struct cxgbi_device *cdev = csk->cdev; 50362306a36Sopenharmony_ci struct cxgbi_ports_map *pmap = &cdev->pmap; 50462306a36Sopenharmony_ci __be16 *port; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci if (csk->csk_family == AF_INET) 50762306a36Sopenharmony_ci port = &csk->saddr.sin_port; 50862306a36Sopenharmony_ci else /* ipv6 */ 50962306a36Sopenharmony_ci port = &csk->saddr6.sin6_port; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (*port) { 51262306a36Sopenharmony_ci int idx = ntohs(*port) - pmap->sport_base; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci *port = 0; 51562306a36Sopenharmony_ci if (idx < 0 || idx >= pmap->max_connect) { 51662306a36Sopenharmony_ci pr_err("cdev 0x%p, p#%u %s, port %u OOR.\n", 51762306a36Sopenharmony_ci cdev, csk->port_id, 51862306a36Sopenharmony_ci cdev->ports[csk->port_id]->name, 51962306a36Sopenharmony_ci ntohs(*port)); 52062306a36Sopenharmony_ci return; 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci spin_lock_bh(&pmap->lock); 52462306a36Sopenharmony_ci pmap->port_csk[idx] = NULL; 52562306a36Sopenharmony_ci pmap->used--; 52662306a36Sopenharmony_ci spin_unlock_bh(&pmap->lock); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, 52962306a36Sopenharmony_ci "cdev 0x%p, p#%u %s, release %u.\n", 53062306a36Sopenharmony_ci cdev, csk->port_id, cdev->ports[csk->port_id]->name, 53162306a36Sopenharmony_ci pmap->sport_base + idx); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci cxgbi_sock_put(csk); 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci/* 53862306a36Sopenharmony_ci * iscsi tcp connection 53962306a36Sopenharmony_ci */ 54062306a36Sopenharmony_civoid cxgbi_sock_free_cpl_skbs(struct cxgbi_sock *csk) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci if (csk->cpl_close) { 54362306a36Sopenharmony_ci kfree_skb(csk->cpl_close); 54462306a36Sopenharmony_ci csk->cpl_close = NULL; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci if (csk->cpl_abort_req) { 54762306a36Sopenharmony_ci kfree_skb(csk->cpl_abort_req); 54862306a36Sopenharmony_ci csk->cpl_abort_req = NULL; 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci if (csk->cpl_abort_rpl) { 55162306a36Sopenharmony_ci kfree_skb(csk->cpl_abort_rpl); 55262306a36Sopenharmony_ci csk->cpl_abort_rpl = NULL; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_free_cpl_skbs); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_cistatic struct cxgbi_sock *cxgbi_sock_create(struct cxgbi_device *cdev) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci struct cxgbi_sock *csk = kzalloc(sizeof(*csk), GFP_NOIO); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (!csk) { 56262306a36Sopenharmony_ci pr_info("alloc csk %zu failed.\n", sizeof(*csk)); 56362306a36Sopenharmony_ci return NULL; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (cdev->csk_alloc_cpls(csk) < 0) { 56762306a36Sopenharmony_ci pr_info("csk 0x%p, alloc cpls failed.\n", csk); 56862306a36Sopenharmony_ci kfree(csk); 56962306a36Sopenharmony_ci return NULL; 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci spin_lock_init(&csk->lock); 57362306a36Sopenharmony_ci kref_init(&csk->refcnt); 57462306a36Sopenharmony_ci skb_queue_head_init(&csk->receive_queue); 57562306a36Sopenharmony_ci skb_queue_head_init(&csk->write_queue); 57662306a36Sopenharmony_ci timer_setup(&csk->retry_timer, NULL, 0); 57762306a36Sopenharmony_ci init_completion(&csk->cmpl); 57862306a36Sopenharmony_ci rwlock_init(&csk->callback_lock); 57962306a36Sopenharmony_ci csk->cdev = cdev; 58062306a36Sopenharmony_ci csk->flags = 0; 58162306a36Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_CLOSED); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, "cdev 0x%p, new csk 0x%p.\n", cdev, csk); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci return csk; 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_cistatic struct rtable *find_route_ipv4(struct flowi4 *fl4, 58962306a36Sopenharmony_ci __be32 saddr, __be32 daddr, 59062306a36Sopenharmony_ci __be16 sport, __be16 dport, u8 tos, 59162306a36Sopenharmony_ci int ifindex) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci struct rtable *rt; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci rt = ip_route_output_ports(&init_net, fl4, NULL, daddr, saddr, 59662306a36Sopenharmony_ci dport, sport, IPPROTO_TCP, tos, ifindex); 59762306a36Sopenharmony_ci if (IS_ERR(rt)) 59862306a36Sopenharmony_ci return NULL; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci return rt; 60162306a36Sopenharmony_ci} 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_cistatic struct cxgbi_sock * 60462306a36Sopenharmony_cicxgbi_check_route(struct sockaddr *dst_addr, int ifindex) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci struct sockaddr_in *daddr = (struct sockaddr_in *)dst_addr; 60762306a36Sopenharmony_ci struct dst_entry *dst; 60862306a36Sopenharmony_ci struct net_device *ndev; 60962306a36Sopenharmony_ci struct cxgbi_device *cdev; 61062306a36Sopenharmony_ci struct rtable *rt = NULL; 61162306a36Sopenharmony_ci struct neighbour *n; 61262306a36Sopenharmony_ci struct flowi4 fl4; 61362306a36Sopenharmony_ci struct cxgbi_sock *csk = NULL; 61462306a36Sopenharmony_ci unsigned int mtu = 0; 61562306a36Sopenharmony_ci int port = 0xFFFF; 61662306a36Sopenharmony_ci int err = 0; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci rt = find_route_ipv4(&fl4, 0, daddr->sin_addr.s_addr, 0, 61962306a36Sopenharmony_ci daddr->sin_port, 0, ifindex); 62062306a36Sopenharmony_ci if (!rt) { 62162306a36Sopenharmony_ci pr_info("no route to ipv4 0x%x, port %u.\n", 62262306a36Sopenharmony_ci be32_to_cpu(daddr->sin_addr.s_addr), 62362306a36Sopenharmony_ci be16_to_cpu(daddr->sin_port)); 62462306a36Sopenharmony_ci err = -ENETUNREACH; 62562306a36Sopenharmony_ci goto err_out; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci dst = &rt->dst; 62862306a36Sopenharmony_ci n = dst_neigh_lookup(dst, &daddr->sin_addr.s_addr); 62962306a36Sopenharmony_ci if (!n) { 63062306a36Sopenharmony_ci err = -ENODEV; 63162306a36Sopenharmony_ci goto rel_rt; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci ndev = n->dev; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { 63662306a36Sopenharmony_ci pr_info("multi-cast route %pI4, port %u, dev %s.\n", 63762306a36Sopenharmony_ci &daddr->sin_addr.s_addr, ntohs(daddr->sin_port), 63862306a36Sopenharmony_ci ndev->name); 63962306a36Sopenharmony_ci err = -ENETUNREACH; 64062306a36Sopenharmony_ci goto rel_neigh; 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (ndev->flags & IFF_LOOPBACK) { 64462306a36Sopenharmony_ci ndev = ip_dev_find(&init_net, daddr->sin_addr.s_addr); 64562306a36Sopenharmony_ci if (!ndev) { 64662306a36Sopenharmony_ci err = -ENETUNREACH; 64762306a36Sopenharmony_ci goto rel_neigh; 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci mtu = ndev->mtu; 65062306a36Sopenharmony_ci pr_info("rt dev %s, loopback -> %s, mtu %u.\n", 65162306a36Sopenharmony_ci n->dev->name, ndev->name, mtu); 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci if (!(ndev->flags & IFF_UP) || !netif_carrier_ok(ndev)) { 65562306a36Sopenharmony_ci pr_info("%s interface not up.\n", ndev->name); 65662306a36Sopenharmony_ci err = -ENETDOWN; 65762306a36Sopenharmony_ci goto rel_neigh; 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci cdev = cxgbi_device_find_by_netdev(ndev, &port); 66162306a36Sopenharmony_ci if (!cdev) 66262306a36Sopenharmony_ci cdev = cxgbi_device_find_by_mac(ndev, &port); 66362306a36Sopenharmony_ci if (!cdev) { 66462306a36Sopenharmony_ci pr_info("dst %pI4, %s, NOT cxgbi device.\n", 66562306a36Sopenharmony_ci &daddr->sin_addr.s_addr, ndev->name); 66662306a36Sopenharmony_ci err = -ENETUNREACH; 66762306a36Sopenharmony_ci goto rel_neigh; 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, 67062306a36Sopenharmony_ci "route to %pI4 :%u, ndev p#%d,%s, cdev 0x%p.\n", 67162306a36Sopenharmony_ci &daddr->sin_addr.s_addr, ntohs(daddr->sin_port), 67262306a36Sopenharmony_ci port, ndev->name, cdev); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci csk = cxgbi_sock_create(cdev); 67562306a36Sopenharmony_ci if (!csk) { 67662306a36Sopenharmony_ci err = -ENOMEM; 67762306a36Sopenharmony_ci goto rel_neigh; 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci csk->cdev = cdev; 68062306a36Sopenharmony_ci csk->port_id = port; 68162306a36Sopenharmony_ci csk->mtu = mtu; 68262306a36Sopenharmony_ci csk->dst = dst; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci csk->csk_family = AF_INET; 68562306a36Sopenharmony_ci csk->daddr.sin_addr.s_addr = daddr->sin_addr.s_addr; 68662306a36Sopenharmony_ci csk->daddr.sin_port = daddr->sin_port; 68762306a36Sopenharmony_ci csk->daddr.sin_family = daddr->sin_family; 68862306a36Sopenharmony_ci csk->saddr.sin_family = daddr->sin_family; 68962306a36Sopenharmony_ci csk->saddr.sin_addr.s_addr = fl4.saddr; 69062306a36Sopenharmony_ci neigh_release(n); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci return csk; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cirel_neigh: 69562306a36Sopenharmony_ci neigh_release(n); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_cirel_rt: 69862306a36Sopenharmony_ci ip_rt_put(rt); 69962306a36Sopenharmony_cierr_out: 70062306a36Sopenharmony_ci return ERR_PTR(err); 70162306a36Sopenharmony_ci} 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 70462306a36Sopenharmony_cistatic struct rt6_info *find_route_ipv6(const struct in6_addr *saddr, 70562306a36Sopenharmony_ci const struct in6_addr *daddr, 70662306a36Sopenharmony_ci int ifindex) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci struct flowi6 fl; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci memset(&fl, 0, sizeof(fl)); 71162306a36Sopenharmony_ci fl.flowi6_oif = ifindex; 71262306a36Sopenharmony_ci if (saddr) 71362306a36Sopenharmony_ci memcpy(&fl.saddr, saddr, sizeof(struct in6_addr)); 71462306a36Sopenharmony_ci if (daddr) 71562306a36Sopenharmony_ci memcpy(&fl.daddr, daddr, sizeof(struct in6_addr)); 71662306a36Sopenharmony_ci return (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl); 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_cistatic struct cxgbi_sock * 72062306a36Sopenharmony_cicxgbi_check_route6(struct sockaddr *dst_addr, int ifindex) 72162306a36Sopenharmony_ci{ 72262306a36Sopenharmony_ci struct sockaddr_in6 *daddr6 = (struct sockaddr_in6 *)dst_addr; 72362306a36Sopenharmony_ci struct dst_entry *dst; 72462306a36Sopenharmony_ci struct net_device *ndev; 72562306a36Sopenharmony_ci struct cxgbi_device *cdev; 72662306a36Sopenharmony_ci struct rt6_info *rt = NULL; 72762306a36Sopenharmony_ci struct neighbour *n; 72862306a36Sopenharmony_ci struct in6_addr pref_saddr; 72962306a36Sopenharmony_ci struct cxgbi_sock *csk = NULL; 73062306a36Sopenharmony_ci unsigned int mtu = 0; 73162306a36Sopenharmony_ci int port = 0xFFFF; 73262306a36Sopenharmony_ci int err = 0; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci rt = find_route_ipv6(NULL, &daddr6->sin6_addr, ifindex); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci if (!rt) { 73762306a36Sopenharmony_ci pr_info("no route to ipv6 %pI6 port %u\n", 73862306a36Sopenharmony_ci daddr6->sin6_addr.s6_addr, 73962306a36Sopenharmony_ci be16_to_cpu(daddr6->sin6_port)); 74062306a36Sopenharmony_ci err = -ENETUNREACH; 74162306a36Sopenharmony_ci goto err_out; 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci dst = &rt->dst; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci n = dst_neigh_lookup(dst, &daddr6->sin6_addr); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci if (!n) { 74962306a36Sopenharmony_ci pr_info("%pI6, port %u, dst no neighbour.\n", 75062306a36Sopenharmony_ci daddr6->sin6_addr.s6_addr, 75162306a36Sopenharmony_ci be16_to_cpu(daddr6->sin6_port)); 75262306a36Sopenharmony_ci err = -ENETUNREACH; 75362306a36Sopenharmony_ci goto rel_rt; 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci ndev = n->dev; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci if (!(ndev->flags & IFF_UP) || !netif_carrier_ok(ndev)) { 75862306a36Sopenharmony_ci pr_info("%s interface not up.\n", ndev->name); 75962306a36Sopenharmony_ci err = -ENETDOWN; 76062306a36Sopenharmony_ci goto rel_rt; 76162306a36Sopenharmony_ci } 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci if (ipv6_addr_is_multicast(&daddr6->sin6_addr)) { 76462306a36Sopenharmony_ci pr_info("multi-cast route %pI6 port %u, dev %s.\n", 76562306a36Sopenharmony_ci daddr6->sin6_addr.s6_addr, 76662306a36Sopenharmony_ci ntohs(daddr6->sin6_port), ndev->name); 76762306a36Sopenharmony_ci err = -ENETUNREACH; 76862306a36Sopenharmony_ci goto rel_rt; 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci cdev = cxgbi_device_find_by_netdev(ndev, &port); 77262306a36Sopenharmony_ci if (!cdev) 77362306a36Sopenharmony_ci cdev = cxgbi_device_find_by_mac(ndev, &port); 77462306a36Sopenharmony_ci if (!cdev) { 77562306a36Sopenharmony_ci pr_info("dst %pI6 %s, NOT cxgbi device.\n", 77662306a36Sopenharmony_ci daddr6->sin6_addr.s6_addr, ndev->name); 77762306a36Sopenharmony_ci err = -ENETUNREACH; 77862306a36Sopenharmony_ci goto rel_rt; 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, 78162306a36Sopenharmony_ci "route to %pI6 :%u, ndev p#%d,%s, cdev 0x%p.\n", 78262306a36Sopenharmony_ci daddr6->sin6_addr.s6_addr, ntohs(daddr6->sin6_port), port, 78362306a36Sopenharmony_ci ndev->name, cdev); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci csk = cxgbi_sock_create(cdev); 78662306a36Sopenharmony_ci if (!csk) { 78762306a36Sopenharmony_ci err = -ENOMEM; 78862306a36Sopenharmony_ci goto rel_rt; 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci csk->cdev = cdev; 79162306a36Sopenharmony_ci csk->port_id = port; 79262306a36Sopenharmony_ci csk->mtu = mtu; 79362306a36Sopenharmony_ci csk->dst = dst; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci rt6_get_prefsrc(rt, &pref_saddr); 79662306a36Sopenharmony_ci if (ipv6_addr_any(&pref_saddr)) { 79762306a36Sopenharmony_ci struct inet6_dev *idev = ip6_dst_idev((struct dst_entry *)rt); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci err = ipv6_dev_get_saddr(&init_net, idev ? idev->dev : NULL, 80062306a36Sopenharmony_ci &daddr6->sin6_addr, 0, &pref_saddr); 80162306a36Sopenharmony_ci if (err) { 80262306a36Sopenharmony_ci pr_info("failed to get source address to reach %pI6\n", 80362306a36Sopenharmony_ci &daddr6->sin6_addr); 80462306a36Sopenharmony_ci goto rel_rt; 80562306a36Sopenharmony_ci } 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci csk->csk_family = AF_INET6; 80962306a36Sopenharmony_ci csk->daddr6.sin6_addr = daddr6->sin6_addr; 81062306a36Sopenharmony_ci csk->daddr6.sin6_port = daddr6->sin6_port; 81162306a36Sopenharmony_ci csk->daddr6.sin6_family = daddr6->sin6_family; 81262306a36Sopenharmony_ci csk->saddr6.sin6_family = daddr6->sin6_family; 81362306a36Sopenharmony_ci csk->saddr6.sin6_addr = pref_saddr; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci neigh_release(n); 81662306a36Sopenharmony_ci return csk; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_cirel_rt: 81962306a36Sopenharmony_ci if (n) 82062306a36Sopenharmony_ci neigh_release(n); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci ip6_rt_put(rt); 82362306a36Sopenharmony_ci if (csk) 82462306a36Sopenharmony_ci cxgbi_sock_closed(csk); 82562306a36Sopenharmony_cierr_out: 82662306a36Sopenharmony_ci return ERR_PTR(err); 82762306a36Sopenharmony_ci} 82862306a36Sopenharmony_ci#endif /* IS_ENABLED(CONFIG_IPV6) */ 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_civoid cxgbi_sock_established(struct cxgbi_sock *csk, unsigned int snd_isn, 83162306a36Sopenharmony_ci unsigned int opt) 83262306a36Sopenharmony_ci{ 83362306a36Sopenharmony_ci csk->write_seq = csk->snd_nxt = csk->snd_una = snd_isn; 83462306a36Sopenharmony_ci dst_confirm(csk->dst); 83562306a36Sopenharmony_ci smp_mb(); 83662306a36Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_ESTABLISHED); 83762306a36Sopenharmony_ci} 83862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_established); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_cistatic void cxgbi_inform_iscsi_conn_closing(struct cxgbi_sock *csk) 84162306a36Sopenharmony_ci{ 84262306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, 84362306a36Sopenharmony_ci "csk 0x%p, state %u, flags 0x%lx, conn 0x%p.\n", 84462306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->user_data); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci if (csk->state != CTP_ESTABLISHED) { 84762306a36Sopenharmony_ci read_lock_bh(&csk->callback_lock); 84862306a36Sopenharmony_ci if (csk->user_data) 84962306a36Sopenharmony_ci iscsi_conn_failure(csk->user_data, 85062306a36Sopenharmony_ci ISCSI_ERR_TCP_CONN_CLOSE); 85162306a36Sopenharmony_ci read_unlock_bh(&csk->callback_lock); 85262306a36Sopenharmony_ci } 85362306a36Sopenharmony_ci} 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_civoid cxgbi_sock_closed(struct cxgbi_sock *csk) 85662306a36Sopenharmony_ci{ 85762306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", 85862306a36Sopenharmony_ci csk, (csk)->state, (csk)->flags, (csk)->tid); 85962306a36Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_ACTIVE_CLOSE_NEEDED); 86062306a36Sopenharmony_ci if (csk->state == CTP_ACTIVE_OPEN || csk->state == CTP_CLOSED) 86162306a36Sopenharmony_ci return; 86262306a36Sopenharmony_ci if (csk->saddr.sin_port) 86362306a36Sopenharmony_ci sock_put_port(csk); 86462306a36Sopenharmony_ci if (csk->dst) 86562306a36Sopenharmony_ci dst_release(csk->dst); 86662306a36Sopenharmony_ci csk->cdev->csk_release_offload_resources(csk); 86762306a36Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_CLOSED); 86862306a36Sopenharmony_ci cxgbi_inform_iscsi_conn_closing(csk); 86962306a36Sopenharmony_ci cxgbi_sock_put(csk); 87062306a36Sopenharmony_ci} 87162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_closed); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_cistatic void need_active_close(struct cxgbi_sock *csk) 87462306a36Sopenharmony_ci{ 87562306a36Sopenharmony_ci int data_lost; 87662306a36Sopenharmony_ci int close_req = 0; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", 87962306a36Sopenharmony_ci csk, (csk)->state, (csk)->flags, (csk)->tid); 88062306a36Sopenharmony_ci spin_lock_bh(&csk->lock); 88162306a36Sopenharmony_ci if (csk->dst) 88262306a36Sopenharmony_ci dst_confirm(csk->dst); 88362306a36Sopenharmony_ci data_lost = skb_queue_len(&csk->receive_queue); 88462306a36Sopenharmony_ci __skb_queue_purge(&csk->receive_queue); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci if (csk->state == CTP_ACTIVE_OPEN) 88762306a36Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_ACTIVE_CLOSE_NEEDED); 88862306a36Sopenharmony_ci else if (csk->state == CTP_ESTABLISHED) { 88962306a36Sopenharmony_ci close_req = 1; 89062306a36Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_ACTIVE_CLOSE); 89162306a36Sopenharmony_ci } else if (csk->state == CTP_PASSIVE_CLOSE) { 89262306a36Sopenharmony_ci close_req = 1; 89362306a36Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_CLOSE_WAIT_2); 89462306a36Sopenharmony_ci } 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci if (close_req) { 89762306a36Sopenharmony_ci if (!cxgbi_sock_flag(csk, CTPF_LOGOUT_RSP_RCVD) || 89862306a36Sopenharmony_ci data_lost) 89962306a36Sopenharmony_ci csk->cdev->csk_send_abort_req(csk); 90062306a36Sopenharmony_ci else 90162306a36Sopenharmony_ci csk->cdev->csk_send_close_req(csk); 90262306a36Sopenharmony_ci } 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci spin_unlock_bh(&csk->lock); 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_civoid cxgbi_sock_fail_act_open(struct cxgbi_sock *csk, int errno) 90862306a36Sopenharmony_ci{ 90962306a36Sopenharmony_ci pr_info("csk 0x%p,%u,%lx, %pI4:%u-%pI4:%u, err %d.\n", 91062306a36Sopenharmony_ci csk, csk->state, csk->flags, 91162306a36Sopenharmony_ci &csk->saddr.sin_addr.s_addr, csk->saddr.sin_port, 91262306a36Sopenharmony_ci &csk->daddr.sin_addr.s_addr, csk->daddr.sin_port, 91362306a36Sopenharmony_ci errno); 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_CONNECTING); 91662306a36Sopenharmony_ci csk->err = errno; 91762306a36Sopenharmony_ci cxgbi_sock_closed(csk); 91862306a36Sopenharmony_ci} 91962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_fail_act_open); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_civoid cxgbi_sock_act_open_req_arp_failure(void *handle, struct sk_buff *skb) 92262306a36Sopenharmony_ci{ 92362306a36Sopenharmony_ci struct cxgbi_sock *csk = (struct cxgbi_sock *)skb->sk; 92462306a36Sopenharmony_ci struct module *owner = csk->cdev->owner; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", 92762306a36Sopenharmony_ci csk, (csk)->state, (csk)->flags, (csk)->tid); 92862306a36Sopenharmony_ci cxgbi_sock_get(csk); 92962306a36Sopenharmony_ci spin_lock_bh(&csk->lock); 93062306a36Sopenharmony_ci if (csk->state == CTP_ACTIVE_OPEN) 93162306a36Sopenharmony_ci cxgbi_sock_fail_act_open(csk, -EHOSTUNREACH); 93262306a36Sopenharmony_ci spin_unlock_bh(&csk->lock); 93362306a36Sopenharmony_ci cxgbi_sock_put(csk); 93462306a36Sopenharmony_ci __kfree_skb(skb); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci module_put(owner); 93762306a36Sopenharmony_ci} 93862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_act_open_req_arp_failure); 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_civoid cxgbi_sock_rcv_abort_rpl(struct cxgbi_sock *csk) 94162306a36Sopenharmony_ci{ 94262306a36Sopenharmony_ci cxgbi_sock_get(csk); 94362306a36Sopenharmony_ci spin_lock_bh(&csk->lock); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_ABORT_RPL_RCVD); 94662306a36Sopenharmony_ci if (cxgbi_sock_flag(csk, CTPF_ABORT_RPL_PENDING)) { 94762306a36Sopenharmony_ci cxgbi_sock_clear_flag(csk, CTPF_ABORT_RPL_PENDING); 94862306a36Sopenharmony_ci if (cxgbi_sock_flag(csk, CTPF_ABORT_REQ_RCVD)) 94962306a36Sopenharmony_ci pr_err("csk 0x%p,%u,0x%lx,%u,ABT_RPL_RSS.\n", 95062306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 95162306a36Sopenharmony_ci cxgbi_sock_closed(csk); 95262306a36Sopenharmony_ci } 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci spin_unlock_bh(&csk->lock); 95562306a36Sopenharmony_ci cxgbi_sock_put(csk); 95662306a36Sopenharmony_ci} 95762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_rcv_abort_rpl); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_civoid cxgbi_sock_rcv_peer_close(struct cxgbi_sock *csk) 96062306a36Sopenharmony_ci{ 96162306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", 96262306a36Sopenharmony_ci csk, (csk)->state, (csk)->flags, (csk)->tid); 96362306a36Sopenharmony_ci cxgbi_sock_get(csk); 96462306a36Sopenharmony_ci spin_lock_bh(&csk->lock); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci if (cxgbi_sock_flag(csk, CTPF_ABORT_RPL_PENDING)) 96762306a36Sopenharmony_ci goto done; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci switch (csk->state) { 97062306a36Sopenharmony_ci case CTP_ESTABLISHED: 97162306a36Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_PASSIVE_CLOSE); 97262306a36Sopenharmony_ci break; 97362306a36Sopenharmony_ci case CTP_ACTIVE_CLOSE: 97462306a36Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_CLOSE_WAIT_2); 97562306a36Sopenharmony_ci break; 97662306a36Sopenharmony_ci case CTP_CLOSE_WAIT_1: 97762306a36Sopenharmony_ci cxgbi_sock_closed(csk); 97862306a36Sopenharmony_ci break; 97962306a36Sopenharmony_ci case CTP_ABORTING: 98062306a36Sopenharmony_ci break; 98162306a36Sopenharmony_ci default: 98262306a36Sopenharmony_ci pr_err("csk 0x%p,%u,0x%lx,%u, bad state.\n", 98362306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 98462306a36Sopenharmony_ci } 98562306a36Sopenharmony_ci cxgbi_inform_iscsi_conn_closing(csk); 98662306a36Sopenharmony_cidone: 98762306a36Sopenharmony_ci spin_unlock_bh(&csk->lock); 98862306a36Sopenharmony_ci cxgbi_sock_put(csk); 98962306a36Sopenharmony_ci} 99062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_rcv_peer_close); 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_civoid cxgbi_sock_rcv_close_conn_rpl(struct cxgbi_sock *csk, u32 snd_nxt) 99362306a36Sopenharmony_ci{ 99462306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", 99562306a36Sopenharmony_ci csk, (csk)->state, (csk)->flags, (csk)->tid); 99662306a36Sopenharmony_ci cxgbi_sock_get(csk); 99762306a36Sopenharmony_ci spin_lock_bh(&csk->lock); 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci csk->snd_una = snd_nxt - 1; 100062306a36Sopenharmony_ci if (cxgbi_sock_flag(csk, CTPF_ABORT_RPL_PENDING)) 100162306a36Sopenharmony_ci goto done; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci switch (csk->state) { 100462306a36Sopenharmony_ci case CTP_ACTIVE_CLOSE: 100562306a36Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_CLOSE_WAIT_1); 100662306a36Sopenharmony_ci break; 100762306a36Sopenharmony_ci case CTP_CLOSE_WAIT_1: 100862306a36Sopenharmony_ci case CTP_CLOSE_WAIT_2: 100962306a36Sopenharmony_ci cxgbi_sock_closed(csk); 101062306a36Sopenharmony_ci break; 101162306a36Sopenharmony_ci case CTP_ABORTING: 101262306a36Sopenharmony_ci break; 101362306a36Sopenharmony_ci default: 101462306a36Sopenharmony_ci pr_err("csk 0x%p,%u,0x%lx,%u, bad state.\n", 101562306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 101662306a36Sopenharmony_ci } 101762306a36Sopenharmony_cidone: 101862306a36Sopenharmony_ci spin_unlock_bh(&csk->lock); 101962306a36Sopenharmony_ci cxgbi_sock_put(csk); 102062306a36Sopenharmony_ci} 102162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_rcv_close_conn_rpl); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_civoid cxgbi_sock_rcv_wr_ack(struct cxgbi_sock *csk, unsigned int credits, 102462306a36Sopenharmony_ci unsigned int snd_una, int seq_chk) 102562306a36Sopenharmony_ci{ 102662306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 102762306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, cr %u,%u+%u, snd_una %u,%d.\n", 102862306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, credits, 102962306a36Sopenharmony_ci csk->wr_cred, csk->wr_una_cred, snd_una, seq_chk); 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci spin_lock_bh(&csk->lock); 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci csk->wr_cred += credits; 103462306a36Sopenharmony_ci if (csk->wr_una_cred > csk->wr_max_cred - csk->wr_cred) 103562306a36Sopenharmony_ci csk->wr_una_cred = csk->wr_max_cred - csk->wr_cred; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci while (credits) { 103862306a36Sopenharmony_ci struct sk_buff *p = cxgbi_sock_peek_wr(csk); 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci if (unlikely(!p)) { 104162306a36Sopenharmony_ci pr_err("csk 0x%p,%u,0x%lx,%u, cr %u,%u+%u, empty.\n", 104262306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, credits, 104362306a36Sopenharmony_ci csk->wr_cred, csk->wr_una_cred); 104462306a36Sopenharmony_ci break; 104562306a36Sopenharmony_ci } 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci if (unlikely(credits < p->csum)) { 104862306a36Sopenharmony_ci pr_warn("csk 0x%p,%u,0x%lx,%u, cr %u,%u+%u, < %u.\n", 104962306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, 105062306a36Sopenharmony_ci credits, csk->wr_cred, csk->wr_una_cred, 105162306a36Sopenharmony_ci p->csum); 105262306a36Sopenharmony_ci p->csum -= credits; 105362306a36Sopenharmony_ci break; 105462306a36Sopenharmony_ci } else { 105562306a36Sopenharmony_ci cxgbi_sock_dequeue_wr(csk); 105662306a36Sopenharmony_ci credits -= p->csum; 105762306a36Sopenharmony_ci kfree_skb(p); 105862306a36Sopenharmony_ci } 105962306a36Sopenharmony_ci } 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci cxgbi_sock_check_wr_invariants(csk); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci if (seq_chk) { 106462306a36Sopenharmony_ci if (unlikely(before(snd_una, csk->snd_una))) { 106562306a36Sopenharmony_ci pr_warn("csk 0x%p,%u,0x%lx,%u, snd_una %u/%u.", 106662306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, snd_una, 106762306a36Sopenharmony_ci csk->snd_una); 106862306a36Sopenharmony_ci goto done; 106962306a36Sopenharmony_ci } 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci if (csk->snd_una != snd_una) { 107262306a36Sopenharmony_ci csk->snd_una = snd_una; 107362306a36Sopenharmony_ci dst_confirm(csk->dst); 107462306a36Sopenharmony_ci } 107562306a36Sopenharmony_ci } 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci if (skb_queue_len(&csk->write_queue)) { 107862306a36Sopenharmony_ci if (csk->cdev->csk_push_tx_frames(csk, 0)) 107962306a36Sopenharmony_ci cxgbi_conn_tx_open(csk); 108062306a36Sopenharmony_ci } else 108162306a36Sopenharmony_ci cxgbi_conn_tx_open(csk); 108262306a36Sopenharmony_cidone: 108362306a36Sopenharmony_ci spin_unlock_bh(&csk->lock); 108462306a36Sopenharmony_ci} 108562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_rcv_wr_ack); 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_cistatic unsigned int cxgbi_sock_find_best_mtu(struct cxgbi_sock *csk, 108862306a36Sopenharmony_ci unsigned short mtu) 108962306a36Sopenharmony_ci{ 109062306a36Sopenharmony_ci int i = 0; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci while (i < csk->cdev->nmtus - 1 && csk->cdev->mtus[i + 1] <= mtu) 109362306a36Sopenharmony_ci ++i; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci return i; 109662306a36Sopenharmony_ci} 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ciunsigned int cxgbi_sock_select_mss(struct cxgbi_sock *csk, unsigned int pmtu) 109962306a36Sopenharmony_ci{ 110062306a36Sopenharmony_ci unsigned int idx; 110162306a36Sopenharmony_ci struct dst_entry *dst = csk->dst; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci csk->advmss = dst_metric_advmss(dst); 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci if (csk->advmss > pmtu - 40) 110662306a36Sopenharmony_ci csk->advmss = pmtu - 40; 110762306a36Sopenharmony_ci if (csk->advmss < csk->cdev->mtus[0] - 40) 110862306a36Sopenharmony_ci csk->advmss = csk->cdev->mtus[0] - 40; 110962306a36Sopenharmony_ci idx = cxgbi_sock_find_best_mtu(csk, csk->advmss + 40); 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci return idx; 111262306a36Sopenharmony_ci} 111362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_select_mss); 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_civoid cxgbi_sock_skb_entail(struct cxgbi_sock *csk, struct sk_buff *skb) 111662306a36Sopenharmony_ci{ 111762306a36Sopenharmony_ci cxgbi_skcb_tcp_seq(skb) = csk->write_seq; 111862306a36Sopenharmony_ci __skb_queue_tail(&csk->write_queue, skb); 111962306a36Sopenharmony_ci} 112062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_skb_entail); 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_civoid cxgbi_sock_purge_wr_queue(struct cxgbi_sock *csk) 112362306a36Sopenharmony_ci{ 112462306a36Sopenharmony_ci struct sk_buff *skb; 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci while ((skb = cxgbi_sock_dequeue_wr(csk)) != NULL) 112762306a36Sopenharmony_ci kfree_skb(skb); 112862306a36Sopenharmony_ci} 112962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_purge_wr_queue); 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_civoid cxgbi_sock_check_wr_invariants(const struct cxgbi_sock *csk) 113262306a36Sopenharmony_ci{ 113362306a36Sopenharmony_ci int pending = cxgbi_sock_count_pending_wrs(csk); 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci if (unlikely(csk->wr_cred + pending != csk->wr_max_cred)) 113662306a36Sopenharmony_ci pr_err("csk 0x%p, tid %u, credit %u + %u != %u.\n", 113762306a36Sopenharmony_ci csk, csk->tid, csk->wr_cred, pending, csk->wr_max_cred); 113862306a36Sopenharmony_ci} 113962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_sock_check_wr_invariants); 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_cistatic inline void 114262306a36Sopenharmony_ciscmd_get_params(struct scsi_cmnd *sc, struct scatterlist **sgl, 114362306a36Sopenharmony_ci unsigned int *sgcnt, unsigned int *dlen, 114462306a36Sopenharmony_ci unsigned int prot) 114562306a36Sopenharmony_ci{ 114662306a36Sopenharmony_ci struct scsi_data_buffer *sdb = prot ? scsi_prot(sc) : &sc->sdb; 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci *sgl = sdb->table.sgl; 114962306a36Sopenharmony_ci *sgcnt = sdb->table.nents; 115062306a36Sopenharmony_ci *dlen = sdb->length; 115162306a36Sopenharmony_ci /* Caution: for protection sdb, sdb->length is invalid */ 115262306a36Sopenharmony_ci} 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_civoid cxgbi_ddp_set_one_ppod(struct cxgbi_pagepod *ppod, 115562306a36Sopenharmony_ci struct cxgbi_task_tag_info *ttinfo, 115662306a36Sopenharmony_ci struct scatterlist **sg_pp, unsigned int *sg_off) 115762306a36Sopenharmony_ci{ 115862306a36Sopenharmony_ci struct scatterlist *sg = sg_pp ? *sg_pp : NULL; 115962306a36Sopenharmony_ci unsigned int offset = sg_off ? *sg_off : 0; 116062306a36Sopenharmony_ci dma_addr_t addr = 0UL; 116162306a36Sopenharmony_ci unsigned int len = 0; 116262306a36Sopenharmony_ci int i; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci memcpy(ppod, &ttinfo->hdr, sizeof(struct cxgbi_pagepod_hdr)); 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci if (sg) { 116762306a36Sopenharmony_ci addr = sg_dma_address(sg); 116862306a36Sopenharmony_ci len = sg_dma_len(sg); 116962306a36Sopenharmony_ci } 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci for (i = 0; i < PPOD_PAGES_MAX; i++) { 117262306a36Sopenharmony_ci if (sg) { 117362306a36Sopenharmony_ci ppod->addr[i] = cpu_to_be64(addr + offset); 117462306a36Sopenharmony_ci offset += PAGE_SIZE; 117562306a36Sopenharmony_ci if (offset == (len + sg->offset)) { 117662306a36Sopenharmony_ci offset = 0; 117762306a36Sopenharmony_ci sg = sg_next(sg); 117862306a36Sopenharmony_ci if (sg) { 117962306a36Sopenharmony_ci addr = sg_dma_address(sg); 118062306a36Sopenharmony_ci len = sg_dma_len(sg); 118162306a36Sopenharmony_ci } 118262306a36Sopenharmony_ci } 118362306a36Sopenharmony_ci } else { 118462306a36Sopenharmony_ci ppod->addr[i] = 0ULL; 118562306a36Sopenharmony_ci } 118662306a36Sopenharmony_ci } 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci /* 118962306a36Sopenharmony_ci * the fifth address needs to be repeated in the next ppod, so do 119062306a36Sopenharmony_ci * not move sg 119162306a36Sopenharmony_ci */ 119262306a36Sopenharmony_ci if (sg_pp) { 119362306a36Sopenharmony_ci *sg_pp = sg; 119462306a36Sopenharmony_ci *sg_off = offset; 119562306a36Sopenharmony_ci } 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci if (offset == len) { 119862306a36Sopenharmony_ci offset = 0; 119962306a36Sopenharmony_ci sg = sg_next(sg); 120062306a36Sopenharmony_ci if (sg) { 120162306a36Sopenharmony_ci addr = sg_dma_address(sg); 120262306a36Sopenharmony_ci len = sg_dma_len(sg); 120362306a36Sopenharmony_ci } 120462306a36Sopenharmony_ci } 120562306a36Sopenharmony_ci ppod->addr[i] = sg ? cpu_to_be64(addr + offset) : 0ULL; 120662306a36Sopenharmony_ci} 120762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_ddp_set_one_ppod); 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci/* 121062306a36Sopenharmony_ci * APIs interacting with open-iscsi libraries 121162306a36Sopenharmony_ci */ 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ciint cxgbi_ddp_ppm_setup(void **ppm_pp, struct cxgbi_device *cdev, 121462306a36Sopenharmony_ci struct cxgbi_tag_format *tformat, 121562306a36Sopenharmony_ci unsigned int iscsi_size, unsigned int llimit, 121662306a36Sopenharmony_ci unsigned int start, unsigned int rsvd_factor, 121762306a36Sopenharmony_ci unsigned int edram_start, unsigned int edram_size) 121862306a36Sopenharmony_ci{ 121962306a36Sopenharmony_ci int err = cxgbi_ppm_init(ppm_pp, cdev->ports[0], cdev->pdev, 122062306a36Sopenharmony_ci cdev->lldev, tformat, iscsi_size, llimit, start, 122162306a36Sopenharmony_ci rsvd_factor, edram_start, edram_size); 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci if (err >= 0) { 122462306a36Sopenharmony_ci struct cxgbi_ppm *ppm = (struct cxgbi_ppm *)(*ppm_pp); 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci if (ppm->ppmax < 1024 || 122762306a36Sopenharmony_ci ppm->tformat.pgsz_idx_dflt >= DDP_PGIDX_MAX) 122862306a36Sopenharmony_ci cdev->flags |= CXGBI_FLAG_DDP_OFF; 122962306a36Sopenharmony_ci err = 0; 123062306a36Sopenharmony_ci } else { 123162306a36Sopenharmony_ci cdev->flags |= CXGBI_FLAG_DDP_OFF; 123262306a36Sopenharmony_ci } 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci return err; 123562306a36Sopenharmony_ci} 123662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_ddp_ppm_setup); 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_cistatic int cxgbi_ddp_sgl_check(struct scatterlist *sgl, int nents) 123962306a36Sopenharmony_ci{ 124062306a36Sopenharmony_ci int i; 124162306a36Sopenharmony_ci int last_sgidx = nents - 1; 124262306a36Sopenharmony_ci struct scatterlist *sg = sgl; 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci for (i = 0; i < nents; i++, sg = sg_next(sg)) { 124562306a36Sopenharmony_ci unsigned int len = sg->length + sg->offset; 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci if ((sg->offset & 0x3) || (i && sg->offset) || 124862306a36Sopenharmony_ci ((i != last_sgidx) && len != PAGE_SIZE)) { 124962306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_DDP, 125062306a36Sopenharmony_ci "sg %u/%u, %u,%u, not aligned.\n", 125162306a36Sopenharmony_ci i, nents, sg->offset, sg->length); 125262306a36Sopenharmony_ci goto err_out; 125362306a36Sopenharmony_ci } 125462306a36Sopenharmony_ci } 125562306a36Sopenharmony_ci return 0; 125662306a36Sopenharmony_cierr_out: 125762306a36Sopenharmony_ci return -EINVAL; 125862306a36Sopenharmony_ci} 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_cistatic int cxgbi_ddp_reserve(struct cxgbi_conn *cconn, 126162306a36Sopenharmony_ci struct cxgbi_task_data *tdata, u32 sw_tag, 126262306a36Sopenharmony_ci unsigned int xferlen) 126362306a36Sopenharmony_ci{ 126462306a36Sopenharmony_ci struct cxgbi_sock *csk = cconn->cep->csk; 126562306a36Sopenharmony_ci struct cxgbi_device *cdev = csk->cdev; 126662306a36Sopenharmony_ci struct cxgbi_ppm *ppm = cdev->cdev2ppm(cdev); 126762306a36Sopenharmony_ci struct cxgbi_task_tag_info *ttinfo = &tdata->ttinfo; 126862306a36Sopenharmony_ci struct scatterlist *sgl = ttinfo->sgl; 126962306a36Sopenharmony_ci unsigned int sgcnt = ttinfo->nents; 127062306a36Sopenharmony_ci unsigned int sg_offset = sgl->offset; 127162306a36Sopenharmony_ci int err; 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci if (cdev->flags & CXGBI_FLAG_DDP_OFF) { 127462306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_DDP, 127562306a36Sopenharmony_ci "cdev 0x%p DDP off.\n", cdev); 127662306a36Sopenharmony_ci return -EINVAL; 127762306a36Sopenharmony_ci } 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci if (!ppm || xferlen < DDP_THRESHOLD || !sgcnt || 128062306a36Sopenharmony_ci ppm->tformat.pgsz_idx_dflt >= DDP_PGIDX_MAX) { 128162306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_DDP, 128262306a36Sopenharmony_ci "ppm 0x%p, pgidx %u, xfer %u, sgcnt %u, NO ddp.\n", 128362306a36Sopenharmony_ci ppm, ppm ? ppm->tformat.pgsz_idx_dflt : DDP_PGIDX_MAX, 128462306a36Sopenharmony_ci xferlen, ttinfo->nents); 128562306a36Sopenharmony_ci return -EINVAL; 128662306a36Sopenharmony_ci } 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci /* make sure the buffer is suitable for ddp */ 128962306a36Sopenharmony_ci if (cxgbi_ddp_sgl_check(sgl, sgcnt) < 0) 129062306a36Sopenharmony_ci return -EINVAL; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci ttinfo->nr_pages = (xferlen + sgl->offset + (1 << PAGE_SHIFT) - 1) >> 129362306a36Sopenharmony_ci PAGE_SHIFT; 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci /* 129662306a36Sopenharmony_ci * the ddp tag will be used for the itt in the outgoing pdu, 129762306a36Sopenharmony_ci * the itt genrated by libiscsi is saved in the ppm and can be 129862306a36Sopenharmony_ci * retrieved via the ddp tag 129962306a36Sopenharmony_ci */ 130062306a36Sopenharmony_ci err = cxgbi_ppm_ppods_reserve(ppm, ttinfo->nr_pages, 0, &ttinfo->idx, 130162306a36Sopenharmony_ci &ttinfo->tag, (unsigned long)sw_tag); 130262306a36Sopenharmony_ci if (err < 0) { 130362306a36Sopenharmony_ci cconn->ddp_full++; 130462306a36Sopenharmony_ci return err; 130562306a36Sopenharmony_ci } 130662306a36Sopenharmony_ci ttinfo->npods = err; 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci /* setup dma from scsi command sgl */ 130962306a36Sopenharmony_ci sgl->offset = 0; 131062306a36Sopenharmony_ci err = dma_map_sg(&ppm->pdev->dev, sgl, sgcnt, DMA_FROM_DEVICE); 131162306a36Sopenharmony_ci sgl->offset = sg_offset; 131262306a36Sopenharmony_ci if (err == 0) { 131362306a36Sopenharmony_ci pr_info("%s: 0x%x, xfer %u, sgl %u dma mapping err.\n", 131462306a36Sopenharmony_ci __func__, sw_tag, xferlen, sgcnt); 131562306a36Sopenharmony_ci goto rel_ppods; 131662306a36Sopenharmony_ci } 131762306a36Sopenharmony_ci if (err != ttinfo->nr_pages) { 131862306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_DDP, 131962306a36Sopenharmony_ci "%s: sw tag 0x%x, xfer %u, sgl %u, dma count %d.\n", 132062306a36Sopenharmony_ci __func__, sw_tag, xferlen, sgcnt, err); 132162306a36Sopenharmony_ci } 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci ttinfo->flags |= CXGBI_PPOD_INFO_FLAG_MAPPED; 132462306a36Sopenharmony_ci ttinfo->cid = csk->port_id; 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci cxgbi_ppm_make_ppod_hdr(ppm, ttinfo->tag, csk->tid, sgl->offset, 132762306a36Sopenharmony_ci xferlen, &ttinfo->hdr); 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci if (cdev->flags & CXGBI_FLAG_USE_PPOD_OFLDQ) { 133062306a36Sopenharmony_ci /* write ppod from xmit_pdu (of iscsi_scsi_command pdu) */ 133162306a36Sopenharmony_ci ttinfo->flags |= CXGBI_PPOD_INFO_FLAG_VALID; 133262306a36Sopenharmony_ci } else { 133362306a36Sopenharmony_ci /* write ppod from control queue now */ 133462306a36Sopenharmony_ci err = cdev->csk_ddp_set_map(ppm, csk, ttinfo); 133562306a36Sopenharmony_ci if (err < 0) 133662306a36Sopenharmony_ci goto rel_ppods; 133762306a36Sopenharmony_ci } 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci return 0; 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_cirel_ppods: 134262306a36Sopenharmony_ci cxgbi_ppm_ppod_release(ppm, ttinfo->idx); 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci if (ttinfo->flags & CXGBI_PPOD_INFO_FLAG_MAPPED) { 134562306a36Sopenharmony_ci ttinfo->flags &= ~CXGBI_PPOD_INFO_FLAG_MAPPED; 134662306a36Sopenharmony_ci dma_unmap_sg(&ppm->pdev->dev, sgl, sgcnt, DMA_FROM_DEVICE); 134762306a36Sopenharmony_ci } 134862306a36Sopenharmony_ci return -EINVAL; 134962306a36Sopenharmony_ci} 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_cistatic void task_release_itt(struct iscsi_task *task, itt_t hdr_itt) 135262306a36Sopenharmony_ci{ 135362306a36Sopenharmony_ci struct scsi_cmnd *sc = task->sc; 135462306a36Sopenharmony_ci struct iscsi_tcp_conn *tcp_conn = task->conn->dd_data; 135562306a36Sopenharmony_ci struct cxgbi_conn *cconn = tcp_conn->dd_data; 135662306a36Sopenharmony_ci struct cxgbi_device *cdev = cconn->chba->cdev; 135762306a36Sopenharmony_ci struct cxgbi_ppm *ppm = cdev->cdev2ppm(cdev); 135862306a36Sopenharmony_ci u32 tag = ntohl((__force u32)hdr_itt); 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_DDP, 136162306a36Sopenharmony_ci "cdev 0x%p, task 0x%p, release tag 0x%x.\n", 136262306a36Sopenharmony_ci cdev, task, tag); 136362306a36Sopenharmony_ci if (sc && sc->sc_data_direction == DMA_FROM_DEVICE && 136462306a36Sopenharmony_ci cxgbi_ppm_is_ddp_tag(ppm, tag)) { 136562306a36Sopenharmony_ci struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); 136662306a36Sopenharmony_ci struct cxgbi_task_tag_info *ttinfo = &tdata->ttinfo; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci if (!(cdev->flags & CXGBI_FLAG_USE_PPOD_OFLDQ)) 136962306a36Sopenharmony_ci cdev->csk_ddp_clear_map(cdev, ppm, ttinfo); 137062306a36Sopenharmony_ci cxgbi_ppm_ppod_release(ppm, ttinfo->idx); 137162306a36Sopenharmony_ci dma_unmap_sg(&ppm->pdev->dev, ttinfo->sgl, ttinfo->nents, 137262306a36Sopenharmony_ci DMA_FROM_DEVICE); 137362306a36Sopenharmony_ci } 137462306a36Sopenharmony_ci} 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_cistatic inline u32 cxgbi_build_sw_tag(u32 idx, u32 age) 137762306a36Sopenharmony_ci{ 137862306a36Sopenharmony_ci /* assume idx and age both are < 0x7FFF (32767) */ 137962306a36Sopenharmony_ci return (idx << 16) | age; 138062306a36Sopenharmony_ci} 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_cistatic int task_reserve_itt(struct iscsi_task *task, itt_t *hdr_itt) 138362306a36Sopenharmony_ci{ 138462306a36Sopenharmony_ci struct scsi_cmnd *sc = task->sc; 138562306a36Sopenharmony_ci struct iscsi_conn *conn = task->conn; 138662306a36Sopenharmony_ci struct iscsi_session *sess = conn->session; 138762306a36Sopenharmony_ci struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 138862306a36Sopenharmony_ci struct cxgbi_conn *cconn = tcp_conn->dd_data; 138962306a36Sopenharmony_ci struct cxgbi_device *cdev = cconn->chba->cdev; 139062306a36Sopenharmony_ci struct cxgbi_ppm *ppm = cdev->cdev2ppm(cdev); 139162306a36Sopenharmony_ci u32 sw_tag = cxgbi_build_sw_tag(task->itt, sess->age); 139262306a36Sopenharmony_ci u32 tag = 0; 139362306a36Sopenharmony_ci int err = -EINVAL; 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci if (sc && sc->sc_data_direction == DMA_FROM_DEVICE) { 139662306a36Sopenharmony_ci struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); 139762306a36Sopenharmony_ci struct cxgbi_task_tag_info *ttinfo = &tdata->ttinfo; 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci scmd_get_params(sc, &ttinfo->sgl, &ttinfo->nents, 140062306a36Sopenharmony_ci &tdata->dlen, 0); 140162306a36Sopenharmony_ci err = cxgbi_ddp_reserve(cconn, tdata, sw_tag, tdata->dlen); 140262306a36Sopenharmony_ci if (!err) 140362306a36Sopenharmony_ci tag = ttinfo->tag; 140462306a36Sopenharmony_ci else 140562306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_DDP, 140662306a36Sopenharmony_ci "csk 0x%p, R task 0x%p, %u,%u, no ddp.\n", 140762306a36Sopenharmony_ci cconn->cep->csk, task, tdata->dlen, 140862306a36Sopenharmony_ci ttinfo->nents); 140962306a36Sopenharmony_ci } 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci if (err < 0) { 141262306a36Sopenharmony_ci err = cxgbi_ppm_make_non_ddp_tag(ppm, sw_tag, &tag); 141362306a36Sopenharmony_ci if (err < 0) 141462306a36Sopenharmony_ci return err; 141562306a36Sopenharmony_ci } 141662306a36Sopenharmony_ci /* the itt need to sent in big-endian order */ 141762306a36Sopenharmony_ci *hdr_itt = (__force itt_t)htonl(tag); 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_DDP, 142062306a36Sopenharmony_ci "cdev 0x%p, task 0x%p, 0x%x(0x%x,0x%x)->0x%x/0x%x.\n", 142162306a36Sopenharmony_ci cdev, task, sw_tag, task->itt, sess->age, tag, *hdr_itt); 142262306a36Sopenharmony_ci return 0; 142362306a36Sopenharmony_ci} 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_civoid cxgbi_parse_pdu_itt(struct iscsi_conn *conn, itt_t itt, int *idx, int *age) 142662306a36Sopenharmony_ci{ 142762306a36Sopenharmony_ci struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 142862306a36Sopenharmony_ci struct cxgbi_conn *cconn = tcp_conn->dd_data; 142962306a36Sopenharmony_ci struct cxgbi_device *cdev = cconn->chba->cdev; 143062306a36Sopenharmony_ci struct cxgbi_ppm *ppm = cdev->cdev2ppm(cdev); 143162306a36Sopenharmony_ci u32 tag = ntohl((__force u32)itt); 143262306a36Sopenharmony_ci u32 sw_bits; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci if (ppm) { 143562306a36Sopenharmony_ci if (cxgbi_ppm_is_ddp_tag(ppm, tag)) 143662306a36Sopenharmony_ci sw_bits = cxgbi_ppm_get_tag_caller_data(ppm, tag); 143762306a36Sopenharmony_ci else 143862306a36Sopenharmony_ci sw_bits = cxgbi_ppm_decode_non_ddp_tag(ppm, tag); 143962306a36Sopenharmony_ci } else { 144062306a36Sopenharmony_ci sw_bits = tag; 144162306a36Sopenharmony_ci } 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci cxgbi_decode_sw_tag(sw_bits, idx, age); 144462306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_DDP, 144562306a36Sopenharmony_ci "cdev 0x%p, tag 0x%x/0x%x, -> 0x%x(0x%x,0x%x).\n", 144662306a36Sopenharmony_ci cdev, tag, itt, sw_bits, idx ? *idx : 0xFFFFF, 144762306a36Sopenharmony_ci age ? *age : 0xFF); 144862306a36Sopenharmony_ci} 144962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_parse_pdu_itt); 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_civoid cxgbi_conn_tx_open(struct cxgbi_sock *csk) 145262306a36Sopenharmony_ci{ 145362306a36Sopenharmony_ci struct iscsi_conn *conn = csk->user_data; 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci if (conn) { 145662306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_SOCK, 145762306a36Sopenharmony_ci "csk 0x%p, cid %d.\n", csk, conn->id); 145862306a36Sopenharmony_ci iscsi_conn_queue_xmit(conn); 145962306a36Sopenharmony_ci } 146062306a36Sopenharmony_ci} 146162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_conn_tx_open); 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci/* 146462306a36Sopenharmony_ci * pdu receive, interact with libiscsi_tcp 146562306a36Sopenharmony_ci */ 146662306a36Sopenharmony_cistatic inline int read_pdu_skb(struct iscsi_conn *conn, 146762306a36Sopenharmony_ci struct sk_buff *skb, 146862306a36Sopenharmony_ci unsigned int offset, 146962306a36Sopenharmony_ci int offloaded) 147062306a36Sopenharmony_ci{ 147162306a36Sopenharmony_ci int status = 0; 147262306a36Sopenharmony_ci int bytes_read; 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci bytes_read = iscsi_tcp_recv_skb(conn, skb, offset, offloaded, &status); 147562306a36Sopenharmony_ci switch (status) { 147662306a36Sopenharmony_ci case ISCSI_TCP_CONN_ERR: 147762306a36Sopenharmony_ci pr_info("skb 0x%p, off %u, %d, TCP_ERR.\n", 147862306a36Sopenharmony_ci skb, offset, offloaded); 147962306a36Sopenharmony_ci return -EIO; 148062306a36Sopenharmony_ci case ISCSI_TCP_SUSPENDED: 148162306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 148262306a36Sopenharmony_ci "skb 0x%p, off %u, %d, TCP_SUSPEND, rc %d.\n", 148362306a36Sopenharmony_ci skb, offset, offloaded, bytes_read); 148462306a36Sopenharmony_ci /* no transfer - just have caller flush queue */ 148562306a36Sopenharmony_ci return bytes_read; 148662306a36Sopenharmony_ci case ISCSI_TCP_SKB_DONE: 148762306a36Sopenharmony_ci pr_info("skb 0x%p, off %u, %d, TCP_SKB_DONE.\n", 148862306a36Sopenharmony_ci skb, offset, offloaded); 148962306a36Sopenharmony_ci /* 149062306a36Sopenharmony_ci * pdus should always fit in the skb and we should get 149162306a36Sopenharmony_ci * segment done notifcation. 149262306a36Sopenharmony_ci */ 149362306a36Sopenharmony_ci iscsi_conn_printk(KERN_ERR, conn, "Invalid pdu or skb."); 149462306a36Sopenharmony_ci return -EFAULT; 149562306a36Sopenharmony_ci case ISCSI_TCP_SEGMENT_DONE: 149662306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 149762306a36Sopenharmony_ci "skb 0x%p, off %u, %d, TCP_SEG_DONE, rc %d.\n", 149862306a36Sopenharmony_ci skb, offset, offloaded, bytes_read); 149962306a36Sopenharmony_ci return bytes_read; 150062306a36Sopenharmony_ci default: 150162306a36Sopenharmony_ci pr_info("skb 0x%p, off %u, %d, invalid status %d.\n", 150262306a36Sopenharmony_ci skb, offset, offloaded, status); 150362306a36Sopenharmony_ci return -EINVAL; 150462306a36Sopenharmony_ci } 150562306a36Sopenharmony_ci} 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_cistatic int 150862306a36Sopenharmony_ciskb_read_pdu_bhs(struct cxgbi_sock *csk, struct iscsi_conn *conn, 150962306a36Sopenharmony_ci struct sk_buff *skb) 151062306a36Sopenharmony_ci{ 151162306a36Sopenharmony_ci struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 151262306a36Sopenharmony_ci int err; 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 151562306a36Sopenharmony_ci "conn 0x%p, skb 0x%p, len %u, flag 0x%lx.\n", 151662306a36Sopenharmony_ci conn, skb, skb->len, cxgbi_skcb_flags(skb)); 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci if (!iscsi_tcp_recv_segment_is_hdr(tcp_conn)) { 151962306a36Sopenharmony_ci pr_info("conn 0x%p, skb 0x%p, not hdr.\n", conn, skb); 152062306a36Sopenharmony_ci iscsi_conn_failure(conn, ISCSI_ERR_PROTO); 152162306a36Sopenharmony_ci return -EIO; 152262306a36Sopenharmony_ci } 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci if (conn->hdrdgst_en && 152562306a36Sopenharmony_ci cxgbi_skcb_test_flag(skb, SKCBF_RX_HCRC_ERR)) { 152662306a36Sopenharmony_ci pr_info("conn 0x%p, skb 0x%p, hcrc.\n", conn, skb); 152762306a36Sopenharmony_ci iscsi_conn_failure(conn, ISCSI_ERR_HDR_DGST); 152862306a36Sopenharmony_ci return -EIO; 152962306a36Sopenharmony_ci } 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci if (cxgbi_skcb_test_flag(skb, SKCBF_RX_ISCSI_COMPL) && 153262306a36Sopenharmony_ci cxgbi_skcb_test_flag(skb, SKCBF_RX_DATA_DDPD)) { 153362306a36Sopenharmony_ci /* If completion flag is set and data is directly 153462306a36Sopenharmony_ci * placed in to the host memory then update 153562306a36Sopenharmony_ci * task->exp_datasn to the datasn in completion 153662306a36Sopenharmony_ci * iSCSI hdr as T6 adapter generates completion only 153762306a36Sopenharmony_ci * for the last pdu of a sequence. 153862306a36Sopenharmony_ci */ 153962306a36Sopenharmony_ci itt_t itt = ((struct iscsi_data *)skb->data)->itt; 154062306a36Sopenharmony_ci struct iscsi_task *task = iscsi_itt_to_ctask(conn, itt); 154162306a36Sopenharmony_ci u32 data_sn = be32_to_cpu(((struct iscsi_data *) 154262306a36Sopenharmony_ci skb->data)->datasn); 154362306a36Sopenharmony_ci if (task && task->sc) { 154462306a36Sopenharmony_ci struct iscsi_tcp_task *tcp_task = task->dd_data; 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci tcp_task->exp_datasn = data_sn; 154762306a36Sopenharmony_ci } 154862306a36Sopenharmony_ci } 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci err = read_pdu_skb(conn, skb, 0, 0); 155162306a36Sopenharmony_ci if (likely(err >= 0)) { 155262306a36Sopenharmony_ci struct iscsi_hdr *hdr = (struct iscsi_hdr *)skb->data; 155362306a36Sopenharmony_ci u8 opcode = hdr->opcode & ISCSI_OPCODE_MASK; 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci if (unlikely(opcode == ISCSI_OP_LOGOUT_RSP)) 155662306a36Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_LOGOUT_RSP_RCVD); 155762306a36Sopenharmony_ci } 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci return err; 156062306a36Sopenharmony_ci} 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_cistatic int skb_read_pdu_data(struct iscsi_conn *conn, struct sk_buff *lskb, 156362306a36Sopenharmony_ci struct sk_buff *skb, unsigned int offset) 156462306a36Sopenharmony_ci{ 156562306a36Sopenharmony_ci struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 156662306a36Sopenharmony_ci bool offloaded = 0; 156762306a36Sopenharmony_ci int opcode = tcp_conn->in.hdr->opcode & ISCSI_OPCODE_MASK; 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 157062306a36Sopenharmony_ci "conn 0x%p, skb 0x%p, len %u, flag 0x%lx.\n", 157162306a36Sopenharmony_ci conn, skb, skb->len, cxgbi_skcb_flags(skb)); 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci if (conn->datadgst_en && 157462306a36Sopenharmony_ci cxgbi_skcb_test_flag(lskb, SKCBF_RX_DCRC_ERR)) { 157562306a36Sopenharmony_ci pr_info("conn 0x%p, skb 0x%p, dcrc 0x%lx.\n", 157662306a36Sopenharmony_ci conn, lskb, cxgbi_skcb_flags(lskb)); 157762306a36Sopenharmony_ci iscsi_conn_failure(conn, ISCSI_ERR_DATA_DGST); 157862306a36Sopenharmony_ci return -EIO; 157962306a36Sopenharmony_ci } 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci if (iscsi_tcp_recv_segment_is_hdr(tcp_conn)) 158262306a36Sopenharmony_ci return 0; 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci /* coalesced, add header digest length */ 158562306a36Sopenharmony_ci if (lskb == skb && conn->hdrdgst_en) 158662306a36Sopenharmony_ci offset += ISCSI_DIGEST_SIZE; 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci if (cxgbi_skcb_test_flag(lskb, SKCBF_RX_DATA_DDPD)) 158962306a36Sopenharmony_ci offloaded = 1; 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci if (opcode == ISCSI_OP_SCSI_DATA_IN) 159262306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 159362306a36Sopenharmony_ci "skb 0x%p, op 0x%x, itt 0x%x, %u %s ddp'ed.\n", 159462306a36Sopenharmony_ci skb, opcode, ntohl(tcp_conn->in.hdr->itt), 159562306a36Sopenharmony_ci tcp_conn->in.datalen, offloaded ? "is" : "not"); 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci return read_pdu_skb(conn, skb, offset, offloaded); 159862306a36Sopenharmony_ci} 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_cistatic void csk_return_rx_credits(struct cxgbi_sock *csk, int copied) 160162306a36Sopenharmony_ci{ 160262306a36Sopenharmony_ci struct cxgbi_device *cdev = csk->cdev; 160362306a36Sopenharmony_ci int must_send; 160462306a36Sopenharmony_ci u32 credits; 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 160762306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, seq %u, wup %u, thre %u, %u.\n", 160862306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, csk->copied_seq, 160962306a36Sopenharmony_ci csk->rcv_wup, cdev->rx_credit_thres, 161062306a36Sopenharmony_ci csk->rcv_win); 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci if (!cdev->rx_credit_thres) 161362306a36Sopenharmony_ci return; 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci if (csk->state != CTP_ESTABLISHED) 161662306a36Sopenharmony_ci return; 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci credits = csk->copied_seq - csk->rcv_wup; 161962306a36Sopenharmony_ci if (unlikely(!credits)) 162062306a36Sopenharmony_ci return; 162162306a36Sopenharmony_ci must_send = credits + 16384 >= csk->rcv_win; 162262306a36Sopenharmony_ci if (must_send || credits >= cdev->rx_credit_thres) 162362306a36Sopenharmony_ci csk->rcv_wup += cdev->csk_send_rx_credits(csk, credits); 162462306a36Sopenharmony_ci} 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_civoid cxgbi_conn_pdu_ready(struct cxgbi_sock *csk) 162762306a36Sopenharmony_ci{ 162862306a36Sopenharmony_ci struct cxgbi_device *cdev = csk->cdev; 162962306a36Sopenharmony_ci struct iscsi_conn *conn = csk->user_data; 163062306a36Sopenharmony_ci struct sk_buff *skb; 163162306a36Sopenharmony_ci unsigned int read = 0; 163262306a36Sopenharmony_ci int err = 0; 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 163562306a36Sopenharmony_ci "csk 0x%p, conn 0x%p.\n", csk, conn); 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci if (unlikely(!conn || test_bit(ISCSI_CONN_FLAG_SUSPEND_RX, &conn->flags))) { 163862306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 163962306a36Sopenharmony_ci "csk 0x%p, conn 0x%p, id %d, conn flags 0x%lx!\n", 164062306a36Sopenharmony_ci csk, conn, conn ? conn->id : 0xFF, 164162306a36Sopenharmony_ci conn ? conn->flags : 0xFF); 164262306a36Sopenharmony_ci return; 164362306a36Sopenharmony_ci } 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci while (!err) { 164662306a36Sopenharmony_ci skb = skb_peek(&csk->receive_queue); 164762306a36Sopenharmony_ci if (!skb || 164862306a36Sopenharmony_ci !(cxgbi_skcb_test_flag(skb, SKCBF_RX_STATUS))) { 164962306a36Sopenharmony_ci if (skb) 165062306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 165162306a36Sopenharmony_ci "skb 0x%p, NOT ready 0x%lx.\n", 165262306a36Sopenharmony_ci skb, cxgbi_skcb_flags(skb)); 165362306a36Sopenharmony_ci break; 165462306a36Sopenharmony_ci } 165562306a36Sopenharmony_ci __skb_unlink(skb, &csk->receive_queue); 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci read += cxgbi_skcb_rx_pdulen(skb); 165862306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 165962306a36Sopenharmony_ci "csk 0x%p, skb 0x%p,%u,f 0x%lx, pdu len %u.\n", 166062306a36Sopenharmony_ci csk, skb, skb->len, cxgbi_skcb_flags(skb), 166162306a36Sopenharmony_ci cxgbi_skcb_rx_pdulen(skb)); 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci if (cxgbi_skcb_test_flag(skb, SKCBF_RX_COALESCED)) { 166462306a36Sopenharmony_ci err = skb_read_pdu_bhs(csk, conn, skb); 166562306a36Sopenharmony_ci if (err < 0) { 166662306a36Sopenharmony_ci pr_err("coalesced bhs, csk 0x%p, skb 0x%p,%u, " 166762306a36Sopenharmony_ci "f 0x%lx, plen %u.\n", 166862306a36Sopenharmony_ci csk, skb, skb->len, 166962306a36Sopenharmony_ci cxgbi_skcb_flags(skb), 167062306a36Sopenharmony_ci cxgbi_skcb_rx_pdulen(skb)); 167162306a36Sopenharmony_ci goto skb_done; 167262306a36Sopenharmony_ci } 167362306a36Sopenharmony_ci err = skb_read_pdu_data(conn, skb, skb, 167462306a36Sopenharmony_ci err + cdev->skb_rx_extra); 167562306a36Sopenharmony_ci if (err < 0) 167662306a36Sopenharmony_ci pr_err("coalesced data, csk 0x%p, skb 0x%p,%u, " 167762306a36Sopenharmony_ci "f 0x%lx, plen %u.\n", 167862306a36Sopenharmony_ci csk, skb, skb->len, 167962306a36Sopenharmony_ci cxgbi_skcb_flags(skb), 168062306a36Sopenharmony_ci cxgbi_skcb_rx_pdulen(skb)); 168162306a36Sopenharmony_ci } else { 168262306a36Sopenharmony_ci err = skb_read_pdu_bhs(csk, conn, skb); 168362306a36Sopenharmony_ci if (err < 0) { 168462306a36Sopenharmony_ci pr_err("bhs, csk 0x%p, skb 0x%p,%u, " 168562306a36Sopenharmony_ci "f 0x%lx, plen %u.\n", 168662306a36Sopenharmony_ci csk, skb, skb->len, 168762306a36Sopenharmony_ci cxgbi_skcb_flags(skb), 168862306a36Sopenharmony_ci cxgbi_skcb_rx_pdulen(skb)); 168962306a36Sopenharmony_ci goto skb_done; 169062306a36Sopenharmony_ci } 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci if (cxgbi_skcb_test_flag(skb, SKCBF_RX_DATA)) { 169362306a36Sopenharmony_ci struct sk_buff *dskb; 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci dskb = skb_peek(&csk->receive_queue); 169662306a36Sopenharmony_ci if (!dskb) { 169762306a36Sopenharmony_ci pr_err("csk 0x%p, skb 0x%p,%u, f 0x%lx," 169862306a36Sopenharmony_ci " plen %u, NO data.\n", 169962306a36Sopenharmony_ci csk, skb, skb->len, 170062306a36Sopenharmony_ci cxgbi_skcb_flags(skb), 170162306a36Sopenharmony_ci cxgbi_skcb_rx_pdulen(skb)); 170262306a36Sopenharmony_ci err = -EIO; 170362306a36Sopenharmony_ci goto skb_done; 170462306a36Sopenharmony_ci } 170562306a36Sopenharmony_ci __skb_unlink(dskb, &csk->receive_queue); 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci err = skb_read_pdu_data(conn, skb, dskb, 0); 170862306a36Sopenharmony_ci if (err < 0) 170962306a36Sopenharmony_ci pr_err("data, csk 0x%p, skb 0x%p,%u, " 171062306a36Sopenharmony_ci "f 0x%lx, plen %u, dskb 0x%p," 171162306a36Sopenharmony_ci "%u.\n", 171262306a36Sopenharmony_ci csk, skb, skb->len, 171362306a36Sopenharmony_ci cxgbi_skcb_flags(skb), 171462306a36Sopenharmony_ci cxgbi_skcb_rx_pdulen(skb), 171562306a36Sopenharmony_ci dskb, dskb->len); 171662306a36Sopenharmony_ci __kfree_skb(dskb); 171762306a36Sopenharmony_ci } else 171862306a36Sopenharmony_ci err = skb_read_pdu_data(conn, skb, skb, 0); 171962306a36Sopenharmony_ci } 172062306a36Sopenharmony_ciskb_done: 172162306a36Sopenharmony_ci __kfree_skb(skb); 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci if (err < 0) 172462306a36Sopenharmony_ci break; 172562306a36Sopenharmony_ci } 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, "csk 0x%p, read %u.\n", csk, read); 172862306a36Sopenharmony_ci if (read) { 172962306a36Sopenharmony_ci csk->copied_seq += read; 173062306a36Sopenharmony_ci csk_return_rx_credits(csk, read); 173162306a36Sopenharmony_ci conn->rxdata_octets += read; 173262306a36Sopenharmony_ci } 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_ci if (err < 0) { 173562306a36Sopenharmony_ci pr_info("csk 0x%p, 0x%p, rx failed %d, read %u.\n", 173662306a36Sopenharmony_ci csk, conn, err, read); 173762306a36Sopenharmony_ci iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); 173862306a36Sopenharmony_ci } 173962306a36Sopenharmony_ci} 174062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_conn_pdu_ready); 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_cistatic int sgl_seek_offset(struct scatterlist *sgl, unsigned int sgcnt, 174362306a36Sopenharmony_ci unsigned int offset, unsigned int *off, 174462306a36Sopenharmony_ci struct scatterlist **sgp) 174562306a36Sopenharmony_ci{ 174662306a36Sopenharmony_ci int i; 174762306a36Sopenharmony_ci struct scatterlist *sg; 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci for_each_sg(sgl, sg, sgcnt, i) { 175062306a36Sopenharmony_ci if (offset < sg->length) { 175162306a36Sopenharmony_ci *off = offset; 175262306a36Sopenharmony_ci *sgp = sg; 175362306a36Sopenharmony_ci return 0; 175462306a36Sopenharmony_ci } 175562306a36Sopenharmony_ci offset -= sg->length; 175662306a36Sopenharmony_ci } 175762306a36Sopenharmony_ci return -EFAULT; 175862306a36Sopenharmony_ci} 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_cistatic int 176162306a36Sopenharmony_cisgl_read_to_frags(struct scatterlist *sg, unsigned int sgoffset, 176262306a36Sopenharmony_ci unsigned int dlen, struct page_frag *frags, 176362306a36Sopenharmony_ci int frag_max, u32 *dlimit) 176462306a36Sopenharmony_ci{ 176562306a36Sopenharmony_ci unsigned int datalen = dlen; 176662306a36Sopenharmony_ci unsigned int sglen = sg->length - sgoffset; 176762306a36Sopenharmony_ci struct page *page = sg_page(sg); 176862306a36Sopenharmony_ci int i; 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci i = 0; 177162306a36Sopenharmony_ci do { 177262306a36Sopenharmony_ci unsigned int copy; 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci if (!sglen) { 177562306a36Sopenharmony_ci sg = sg_next(sg); 177662306a36Sopenharmony_ci if (!sg) { 177762306a36Sopenharmony_ci pr_warn("sg %d NULL, len %u/%u.\n", 177862306a36Sopenharmony_ci i, datalen, dlen); 177962306a36Sopenharmony_ci return -EINVAL; 178062306a36Sopenharmony_ci } 178162306a36Sopenharmony_ci sgoffset = 0; 178262306a36Sopenharmony_ci sglen = sg->length; 178362306a36Sopenharmony_ci page = sg_page(sg); 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci } 178662306a36Sopenharmony_ci copy = min(datalen, sglen); 178762306a36Sopenharmony_ci if (i && page == frags[i - 1].page && 178862306a36Sopenharmony_ci sgoffset + sg->offset == 178962306a36Sopenharmony_ci frags[i - 1].offset + frags[i - 1].size) { 179062306a36Sopenharmony_ci frags[i - 1].size += copy; 179162306a36Sopenharmony_ci } else { 179262306a36Sopenharmony_ci if (i >= frag_max) { 179362306a36Sopenharmony_ci pr_warn("too many pages %u, dlen %u.\n", 179462306a36Sopenharmony_ci frag_max, dlen); 179562306a36Sopenharmony_ci *dlimit = dlen - datalen; 179662306a36Sopenharmony_ci return -EINVAL; 179762306a36Sopenharmony_ci } 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci frags[i].page = page; 180062306a36Sopenharmony_ci frags[i].offset = sg->offset + sgoffset; 180162306a36Sopenharmony_ci frags[i].size = copy; 180262306a36Sopenharmony_ci i++; 180362306a36Sopenharmony_ci } 180462306a36Sopenharmony_ci datalen -= copy; 180562306a36Sopenharmony_ci sgoffset += copy; 180662306a36Sopenharmony_ci sglen -= copy; 180762306a36Sopenharmony_ci } while (datalen); 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci return i; 181062306a36Sopenharmony_ci} 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_cistatic void cxgbi_task_data_sgl_check(struct iscsi_task *task) 181362306a36Sopenharmony_ci{ 181462306a36Sopenharmony_ci struct scsi_cmnd *sc = task->sc; 181562306a36Sopenharmony_ci struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); 181662306a36Sopenharmony_ci struct scatterlist *sg, *sgl = NULL; 181762306a36Sopenharmony_ci u32 sgcnt = 0; 181862306a36Sopenharmony_ci int i; 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci tdata->flags = CXGBI_TASK_SGL_CHECKED; 182162306a36Sopenharmony_ci if (!sc) 182262306a36Sopenharmony_ci return; 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci scmd_get_params(sc, &sgl, &sgcnt, &tdata->dlen, 0); 182562306a36Sopenharmony_ci if (!sgl || !sgcnt) { 182662306a36Sopenharmony_ci tdata->flags |= CXGBI_TASK_SGL_COPY; 182762306a36Sopenharmony_ci return; 182862306a36Sopenharmony_ci } 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci for_each_sg(sgl, sg, sgcnt, i) { 183162306a36Sopenharmony_ci if (page_count(sg_page(sg)) < 1) { 183262306a36Sopenharmony_ci tdata->flags |= CXGBI_TASK_SGL_COPY; 183362306a36Sopenharmony_ci return; 183462306a36Sopenharmony_ci } 183562306a36Sopenharmony_ci } 183662306a36Sopenharmony_ci} 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_cistatic int 183962306a36Sopenharmony_cicxgbi_task_data_sgl_read(struct iscsi_task *task, u32 offset, u32 count, 184062306a36Sopenharmony_ci u32 *dlimit) 184162306a36Sopenharmony_ci{ 184262306a36Sopenharmony_ci struct scsi_cmnd *sc = task->sc; 184362306a36Sopenharmony_ci struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); 184462306a36Sopenharmony_ci struct scatterlist *sgl = NULL; 184562306a36Sopenharmony_ci struct scatterlist *sg; 184662306a36Sopenharmony_ci u32 dlen = 0; 184762306a36Sopenharmony_ci u32 sgcnt; 184862306a36Sopenharmony_ci int err; 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_ci if (!sc) 185162306a36Sopenharmony_ci return 0; 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ci scmd_get_params(sc, &sgl, &sgcnt, &dlen, 0); 185462306a36Sopenharmony_ci if (!sgl || !sgcnt) 185562306a36Sopenharmony_ci return 0; 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci err = sgl_seek_offset(sgl, sgcnt, offset, &tdata->sgoffset, &sg); 185862306a36Sopenharmony_ci if (err < 0) { 185962306a36Sopenharmony_ci pr_warn("tpdu max, sgl %u, bad offset %u/%u.\n", 186062306a36Sopenharmony_ci sgcnt, offset, tdata->dlen); 186162306a36Sopenharmony_ci return err; 186262306a36Sopenharmony_ci } 186362306a36Sopenharmony_ci err = sgl_read_to_frags(sg, tdata->sgoffset, count, 186462306a36Sopenharmony_ci tdata->frags, MAX_SKB_FRAGS, dlimit); 186562306a36Sopenharmony_ci if (err < 0) { 186662306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 186762306a36Sopenharmony_ci "sgl max limit, sgl %u, offset %u, %u/%u, dlimit %u.\n", 186862306a36Sopenharmony_ci sgcnt, offset, count, tdata->dlen, *dlimit); 186962306a36Sopenharmony_ci return err; 187062306a36Sopenharmony_ci } 187162306a36Sopenharmony_ci tdata->offset = offset; 187262306a36Sopenharmony_ci tdata->count = count; 187362306a36Sopenharmony_ci tdata->nr_frags = err; 187462306a36Sopenharmony_ci tdata->total_count = count; 187562306a36Sopenharmony_ci tdata->total_offset = offset; 187662306a36Sopenharmony_ci 187762306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, 187862306a36Sopenharmony_ci "%s: offset %u, count %u,\n" 187962306a36Sopenharmony_ci "err %u, total_count %u, total_offset %u\n", 188062306a36Sopenharmony_ci __func__, offset, count, err, tdata->total_count, tdata->total_offset); 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_ci return 0; 188362306a36Sopenharmony_ci} 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ciint cxgbi_conn_alloc_pdu(struct iscsi_task *task, u8 op) 188662306a36Sopenharmony_ci{ 188762306a36Sopenharmony_ci struct iscsi_conn *conn = task->conn; 188862306a36Sopenharmony_ci struct iscsi_session *session = task->conn->session; 188962306a36Sopenharmony_ci struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 189062306a36Sopenharmony_ci struct cxgbi_conn *cconn = tcp_conn->dd_data; 189162306a36Sopenharmony_ci struct cxgbi_device *cdev = cconn->chba->cdev; 189262306a36Sopenharmony_ci struct cxgbi_sock *csk = cconn->cep ? cconn->cep->csk : NULL; 189362306a36Sopenharmony_ci struct iscsi_tcp_task *tcp_task = task->dd_data; 189462306a36Sopenharmony_ci struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); 189562306a36Sopenharmony_ci struct scsi_cmnd *sc = task->sc; 189662306a36Sopenharmony_ci u32 headroom = SKB_TX_ISCSI_PDU_HEADER_MAX; 189762306a36Sopenharmony_ci u32 max_txdata_len = conn->max_xmit_dlength; 189862306a36Sopenharmony_ci u32 iso_tx_rsvd = 0, local_iso_info = 0; 189962306a36Sopenharmony_ci u32 last_tdata_offset, last_tdata_count; 190062306a36Sopenharmony_ci int err = 0; 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci if (!tcp_task) { 190362306a36Sopenharmony_ci pr_err("task 0x%p, tcp_task 0x%p, tdata 0x%p.\n", 190462306a36Sopenharmony_ci task, tcp_task, tdata); 190562306a36Sopenharmony_ci return -ENOMEM; 190662306a36Sopenharmony_ci } 190762306a36Sopenharmony_ci if (!csk) { 190862306a36Sopenharmony_ci pr_err("task 0x%p, csk gone.\n", task); 190962306a36Sopenharmony_ci return -EPIPE; 191062306a36Sopenharmony_ci } 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ci op &= ISCSI_OPCODE_MASK; 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ci tcp_task->dd_data = tdata; 191562306a36Sopenharmony_ci task->hdr = NULL; 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci last_tdata_count = tdata->count; 191862306a36Sopenharmony_ci last_tdata_offset = tdata->offset; 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci if ((op == ISCSI_OP_SCSI_DATA_OUT) || 192162306a36Sopenharmony_ci ((op == ISCSI_OP_SCSI_CMD) && 192262306a36Sopenharmony_ci (sc->sc_data_direction == DMA_TO_DEVICE))) { 192362306a36Sopenharmony_ci u32 remaining_data_tosend, dlimit = 0; 192462306a36Sopenharmony_ci u32 max_pdu_size, max_num_pdu, num_pdu; 192562306a36Sopenharmony_ci u32 count; 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_ci /* Preserve conn->max_xmit_dlength because it can get updated to 192862306a36Sopenharmony_ci * ISO data size. 192962306a36Sopenharmony_ci */ 193062306a36Sopenharmony_ci if (task->state == ISCSI_TASK_PENDING) 193162306a36Sopenharmony_ci tdata->max_xmit_dlength = conn->max_xmit_dlength; 193262306a36Sopenharmony_ci 193362306a36Sopenharmony_ci if (!tdata->offset) 193462306a36Sopenharmony_ci cxgbi_task_data_sgl_check(task); 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci remaining_data_tosend = 193762306a36Sopenharmony_ci tdata->dlen - tdata->offset - tdata->count; 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_cirecalculate_sgl: 194062306a36Sopenharmony_ci max_txdata_len = tdata->max_xmit_dlength; 194162306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, 194262306a36Sopenharmony_ci "tdata->dlen %u, remaining to send %u " 194362306a36Sopenharmony_ci "conn->max_xmit_dlength %u, " 194462306a36Sopenharmony_ci "tdata->max_xmit_dlength %u\n", 194562306a36Sopenharmony_ci tdata->dlen, remaining_data_tosend, 194662306a36Sopenharmony_ci conn->max_xmit_dlength, tdata->max_xmit_dlength); 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci if (cdev->skb_iso_txhdr && !csk->disable_iso && 194962306a36Sopenharmony_ci (remaining_data_tosend > tdata->max_xmit_dlength) && 195062306a36Sopenharmony_ci !(remaining_data_tosend % 4)) { 195162306a36Sopenharmony_ci u32 max_iso_data; 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci if ((op == ISCSI_OP_SCSI_CMD) && 195462306a36Sopenharmony_ci session->initial_r2t_en) 195562306a36Sopenharmony_ci goto no_iso; 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci max_pdu_size = tdata->max_xmit_dlength + 195862306a36Sopenharmony_ci ISCSI_PDU_NONPAYLOAD_LEN; 195962306a36Sopenharmony_ci max_iso_data = rounddown(CXGBI_MAX_ISO_DATA_IN_SKB, 196062306a36Sopenharmony_ci csk->advmss); 196162306a36Sopenharmony_ci max_num_pdu = max_iso_data / max_pdu_size; 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci num_pdu = (remaining_data_tosend + 196462306a36Sopenharmony_ci tdata->max_xmit_dlength - 1) / 196562306a36Sopenharmony_ci tdata->max_xmit_dlength; 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci if (num_pdu > max_num_pdu) 196862306a36Sopenharmony_ci num_pdu = max_num_pdu; 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_ci conn->max_xmit_dlength = tdata->max_xmit_dlength * num_pdu; 197162306a36Sopenharmony_ci max_txdata_len = conn->max_xmit_dlength; 197262306a36Sopenharmony_ci iso_tx_rsvd = cdev->skb_iso_txhdr; 197362306a36Sopenharmony_ci local_iso_info = sizeof(struct cxgbi_iso_info); 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, 197662306a36Sopenharmony_ci "max_pdu_size %u, max_num_pdu %u, " 197762306a36Sopenharmony_ci "max_txdata %u, num_pdu %u\n", 197862306a36Sopenharmony_ci max_pdu_size, max_num_pdu, 197962306a36Sopenharmony_ci max_txdata_len, num_pdu); 198062306a36Sopenharmony_ci } 198162306a36Sopenharmony_cino_iso: 198262306a36Sopenharmony_ci count = min_t(u32, max_txdata_len, remaining_data_tosend); 198362306a36Sopenharmony_ci err = cxgbi_task_data_sgl_read(task, 198462306a36Sopenharmony_ci tdata->offset + tdata->count, 198562306a36Sopenharmony_ci count, &dlimit); 198662306a36Sopenharmony_ci if (unlikely(err < 0)) { 198762306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 198862306a36Sopenharmony_ci "task 0x%p, tcp_task 0x%p, tdata 0x%p, " 198962306a36Sopenharmony_ci "sgl err %d, count %u, dlimit %u\n", 199062306a36Sopenharmony_ci task, tcp_task, tdata, err, count, dlimit); 199162306a36Sopenharmony_ci if (dlimit) { 199262306a36Sopenharmony_ci remaining_data_tosend = 199362306a36Sopenharmony_ci rounddown(dlimit, 199462306a36Sopenharmony_ci tdata->max_xmit_dlength); 199562306a36Sopenharmony_ci if (!remaining_data_tosend) 199662306a36Sopenharmony_ci remaining_data_tosend = dlimit; 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci dlimit = 0; 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci conn->max_xmit_dlength = remaining_data_tosend; 200162306a36Sopenharmony_ci goto recalculate_sgl; 200262306a36Sopenharmony_ci } 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci pr_err("task 0x%p, tcp_task 0x%p, tdata 0x%p, " 200562306a36Sopenharmony_ci "sgl err %d\n", 200662306a36Sopenharmony_ci task, tcp_task, tdata, err); 200762306a36Sopenharmony_ci goto ret_err; 200862306a36Sopenharmony_ci } 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_ci if ((tdata->flags & CXGBI_TASK_SGL_COPY) || 201162306a36Sopenharmony_ci (tdata->nr_frags > MAX_SKB_FRAGS)) 201262306a36Sopenharmony_ci headroom += conn->max_xmit_dlength; 201362306a36Sopenharmony_ci } 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_ci tdata->skb = alloc_skb(local_iso_info + cdev->skb_tx_rsvd + 201662306a36Sopenharmony_ci iso_tx_rsvd + headroom, GFP_ATOMIC); 201762306a36Sopenharmony_ci if (!tdata->skb) { 201862306a36Sopenharmony_ci tdata->count = last_tdata_count; 201962306a36Sopenharmony_ci tdata->offset = last_tdata_offset; 202062306a36Sopenharmony_ci err = -ENOMEM; 202162306a36Sopenharmony_ci goto ret_err; 202262306a36Sopenharmony_ci } 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci skb_reserve(tdata->skb, local_iso_info + cdev->skb_tx_rsvd + 202562306a36Sopenharmony_ci iso_tx_rsvd); 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci if (task->sc) { 202862306a36Sopenharmony_ci task->hdr = (struct iscsi_hdr *)tdata->skb->data; 202962306a36Sopenharmony_ci } else { 203062306a36Sopenharmony_ci task->hdr = kzalloc(SKB_TX_ISCSI_PDU_HEADER_MAX, GFP_ATOMIC); 203162306a36Sopenharmony_ci if (!task->hdr) { 203262306a36Sopenharmony_ci __kfree_skb(tdata->skb); 203362306a36Sopenharmony_ci tdata->skb = NULL; 203462306a36Sopenharmony_ci return -ENOMEM; 203562306a36Sopenharmony_ci } 203662306a36Sopenharmony_ci } 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci task->hdr_max = SKB_TX_ISCSI_PDU_HEADER_MAX; 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_ci if (iso_tx_rsvd) 204162306a36Sopenharmony_ci cxgbi_skcb_set_flag(tdata->skb, SKCBF_TX_ISO); 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ci /* data_out uses scsi_cmd's itt */ 204462306a36Sopenharmony_ci if (op != ISCSI_OP_SCSI_DATA_OUT) 204562306a36Sopenharmony_ci task_reserve_itt(task, &task->hdr->itt); 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, 204862306a36Sopenharmony_ci "task 0x%p, op 0x%x, skb 0x%p,%u+%u/%u, itt 0x%x.\n", 204962306a36Sopenharmony_ci task, op, tdata->skb, cdev->skb_tx_rsvd, headroom, 205062306a36Sopenharmony_ci conn->max_xmit_dlength, be32_to_cpu(task->hdr->itt)); 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci return 0; 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_ciret_err: 205562306a36Sopenharmony_ci conn->max_xmit_dlength = tdata->max_xmit_dlength; 205662306a36Sopenharmony_ci return err; 205762306a36Sopenharmony_ci} 205862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_conn_alloc_pdu); 205962306a36Sopenharmony_ci 206062306a36Sopenharmony_cistatic int 206162306a36Sopenharmony_cicxgbi_prep_iso_info(struct iscsi_task *task, struct sk_buff *skb, 206262306a36Sopenharmony_ci u32 count) 206362306a36Sopenharmony_ci{ 206462306a36Sopenharmony_ci struct cxgbi_iso_info *iso_info = (struct cxgbi_iso_info *)skb->head; 206562306a36Sopenharmony_ci struct iscsi_r2t_info *r2t; 206662306a36Sopenharmony_ci struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); 206762306a36Sopenharmony_ci struct iscsi_conn *conn = task->conn; 206862306a36Sopenharmony_ci struct iscsi_session *session = conn->session; 206962306a36Sopenharmony_ci struct iscsi_tcp_task *tcp_task = task->dd_data; 207062306a36Sopenharmony_ci u32 burst_size = 0, r2t_dlength = 0, dlength; 207162306a36Sopenharmony_ci u32 max_pdu_len = tdata->max_xmit_dlength; 207262306a36Sopenharmony_ci u32 segment_offset = 0; 207362306a36Sopenharmony_ci u32 num_pdu; 207462306a36Sopenharmony_ci 207562306a36Sopenharmony_ci if (unlikely(!cxgbi_skcb_test_flag(skb, SKCBF_TX_ISO))) 207662306a36Sopenharmony_ci return 0; 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci memset(iso_info, 0, sizeof(struct cxgbi_iso_info)); 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_ci if (task->hdr->opcode == ISCSI_OP_SCSI_CMD && session->imm_data_en) { 208162306a36Sopenharmony_ci iso_info->flags |= CXGBI_ISO_INFO_IMM_ENABLE; 208262306a36Sopenharmony_ci burst_size = count; 208362306a36Sopenharmony_ci } 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci dlength = ntoh24(task->hdr->dlength); 208662306a36Sopenharmony_ci dlength = min(dlength, max_pdu_len); 208762306a36Sopenharmony_ci hton24(task->hdr->dlength, dlength); 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci num_pdu = (count + max_pdu_len - 1) / max_pdu_len; 209062306a36Sopenharmony_ci 209162306a36Sopenharmony_ci if (iscsi_task_has_unsol_data(task)) 209262306a36Sopenharmony_ci r2t = &task->unsol_r2t; 209362306a36Sopenharmony_ci else 209462306a36Sopenharmony_ci r2t = tcp_task->r2t; 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_ci if (r2t) { 209762306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, 209862306a36Sopenharmony_ci "count %u, tdata->count %u, num_pdu %u," 209962306a36Sopenharmony_ci "task->hdr_len %u, r2t->data_length %u, r2t->sent %u\n", 210062306a36Sopenharmony_ci count, tdata->count, num_pdu, task->hdr_len, 210162306a36Sopenharmony_ci r2t->data_length, r2t->sent); 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_ci r2t_dlength = r2t->data_length - r2t->sent; 210462306a36Sopenharmony_ci segment_offset = r2t->sent; 210562306a36Sopenharmony_ci r2t->datasn += num_pdu - 1; 210662306a36Sopenharmony_ci } 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_ci if (!r2t || !r2t->sent) 210962306a36Sopenharmony_ci iso_info->flags |= CXGBI_ISO_INFO_FSLICE; 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci if (task->hdr->flags & ISCSI_FLAG_CMD_FINAL) 211262306a36Sopenharmony_ci iso_info->flags |= CXGBI_ISO_INFO_LSLICE; 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci task->hdr->flags &= ~ISCSI_FLAG_CMD_FINAL; 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci iso_info->op = task->hdr->opcode; 211762306a36Sopenharmony_ci iso_info->ahs = task->hdr->hlength; 211862306a36Sopenharmony_ci iso_info->num_pdu = num_pdu; 211962306a36Sopenharmony_ci iso_info->mpdu = max_pdu_len; 212062306a36Sopenharmony_ci iso_info->burst_size = (burst_size + r2t_dlength) >> 2; 212162306a36Sopenharmony_ci iso_info->len = count + task->hdr_len; 212262306a36Sopenharmony_ci iso_info->segment_offset = segment_offset; 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ci cxgbi_skcb_tx_iscsi_hdrlen(skb) = task->hdr_len; 212562306a36Sopenharmony_ci return 0; 212662306a36Sopenharmony_ci} 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_cistatic inline void tx_skb_setmode(struct sk_buff *skb, int hcrc, int dcrc) 212962306a36Sopenharmony_ci{ 213062306a36Sopenharmony_ci if (hcrc || dcrc) { 213162306a36Sopenharmony_ci u8 submode = 0; 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_ci if (hcrc) 213462306a36Sopenharmony_ci submode |= 1; 213562306a36Sopenharmony_ci if (dcrc) 213662306a36Sopenharmony_ci submode |= 2; 213762306a36Sopenharmony_ci cxgbi_skcb_tx_ulp_mode(skb) = (ULP2_MODE_ISCSI << 4) | submode; 213862306a36Sopenharmony_ci } else 213962306a36Sopenharmony_ci cxgbi_skcb_tx_ulp_mode(skb) = 0; 214062306a36Sopenharmony_ci} 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_cistatic struct page *rsvd_page; 214362306a36Sopenharmony_ci 214462306a36Sopenharmony_ciint cxgbi_conn_init_pdu(struct iscsi_task *task, unsigned int offset, 214562306a36Sopenharmony_ci unsigned int count) 214662306a36Sopenharmony_ci{ 214762306a36Sopenharmony_ci struct iscsi_conn *conn = task->conn; 214862306a36Sopenharmony_ci struct iscsi_tcp_task *tcp_task = task->dd_data; 214962306a36Sopenharmony_ci struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); 215062306a36Sopenharmony_ci struct sk_buff *skb; 215162306a36Sopenharmony_ci struct scsi_cmnd *sc = task->sc; 215262306a36Sopenharmony_ci u32 expected_count, expected_offset; 215362306a36Sopenharmony_ci u32 datalen = count, dlimit = 0; 215462306a36Sopenharmony_ci u32 i, padlen = iscsi_padding(count); 215562306a36Sopenharmony_ci struct page *pg; 215662306a36Sopenharmony_ci int err; 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci if (!tcp_task || (tcp_task->dd_data != tdata)) { 215962306a36Sopenharmony_ci pr_err("task 0x%p,0x%p, tcp_task 0x%p, tdata 0x%p/0x%p.\n", 216062306a36Sopenharmony_ci task, task->sc, tcp_task, 216162306a36Sopenharmony_ci tcp_task ? tcp_task->dd_data : NULL, tdata); 216262306a36Sopenharmony_ci return -EINVAL; 216362306a36Sopenharmony_ci } 216462306a36Sopenharmony_ci skb = tdata->skb; 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, 216762306a36Sopenharmony_ci "task 0x%p,0x%p, skb 0x%p, 0x%x,0x%x,0x%x, %u+%u.\n", 216862306a36Sopenharmony_ci task, task->sc, skb, (*skb->data) & ISCSI_OPCODE_MASK, 216962306a36Sopenharmony_ci be32_to_cpu(task->cmdsn), be32_to_cpu(task->hdr->itt), offset, count); 217062306a36Sopenharmony_ci 217162306a36Sopenharmony_ci skb_put(skb, task->hdr_len); 217262306a36Sopenharmony_ci tx_skb_setmode(skb, conn->hdrdgst_en, datalen ? conn->datadgst_en : 0); 217362306a36Sopenharmony_ci if (!count) { 217462306a36Sopenharmony_ci tdata->count = count; 217562306a36Sopenharmony_ci tdata->offset = offset; 217662306a36Sopenharmony_ci tdata->nr_frags = 0; 217762306a36Sopenharmony_ci tdata->total_offset = 0; 217862306a36Sopenharmony_ci tdata->total_count = 0; 217962306a36Sopenharmony_ci if (tdata->max_xmit_dlength) 218062306a36Sopenharmony_ci conn->max_xmit_dlength = tdata->max_xmit_dlength; 218162306a36Sopenharmony_ci cxgbi_skcb_clear_flag(skb, SKCBF_TX_ISO); 218262306a36Sopenharmony_ci return 0; 218362306a36Sopenharmony_ci } 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, 218662306a36Sopenharmony_ci "data->total_count %u, tdata->total_offset %u\n", 218762306a36Sopenharmony_ci tdata->total_count, tdata->total_offset); 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_ci expected_count = tdata->total_count; 219062306a36Sopenharmony_ci expected_offset = tdata->total_offset; 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_ci if ((count != expected_count) || 219362306a36Sopenharmony_ci (offset != expected_offset)) { 219462306a36Sopenharmony_ci err = cxgbi_task_data_sgl_read(task, offset, count, &dlimit); 219562306a36Sopenharmony_ci if (err < 0) { 219662306a36Sopenharmony_ci pr_err("task 0x%p,0x%p, tcp_task 0x%p, tdata 0x%p/0x%p " 219762306a36Sopenharmony_ci "dlimit %u, sgl err %d.\n", task, task->sc, 219862306a36Sopenharmony_ci tcp_task, tcp_task ? tcp_task->dd_data : NULL, 219962306a36Sopenharmony_ci tdata, dlimit, err); 220062306a36Sopenharmony_ci return err; 220162306a36Sopenharmony_ci } 220262306a36Sopenharmony_ci } 220362306a36Sopenharmony_ci 220462306a36Sopenharmony_ci /* Restore original value of conn->max_xmit_dlength because 220562306a36Sopenharmony_ci * it can get updated to ISO data size. 220662306a36Sopenharmony_ci */ 220762306a36Sopenharmony_ci conn->max_xmit_dlength = tdata->max_xmit_dlength; 220862306a36Sopenharmony_ci 220962306a36Sopenharmony_ci if (sc) { 221062306a36Sopenharmony_ci struct page_frag *frag = tdata->frags; 221162306a36Sopenharmony_ci 221262306a36Sopenharmony_ci if ((tdata->flags & CXGBI_TASK_SGL_COPY) || 221362306a36Sopenharmony_ci (tdata->nr_frags > MAX_SKB_FRAGS) || 221462306a36Sopenharmony_ci (padlen && (tdata->nr_frags == 221562306a36Sopenharmony_ci MAX_SKB_FRAGS))) { 221662306a36Sopenharmony_ci char *dst = skb->data + task->hdr_len; 221762306a36Sopenharmony_ci 221862306a36Sopenharmony_ci /* data fits in the skb's headroom */ 221962306a36Sopenharmony_ci for (i = 0; i < tdata->nr_frags; i++, frag++) { 222062306a36Sopenharmony_ci char *src = kmap_atomic(frag->page); 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci memcpy(dst, src + frag->offset, frag->size); 222362306a36Sopenharmony_ci dst += frag->size; 222462306a36Sopenharmony_ci kunmap_atomic(src); 222562306a36Sopenharmony_ci } 222662306a36Sopenharmony_ci 222762306a36Sopenharmony_ci if (padlen) { 222862306a36Sopenharmony_ci memset(dst, 0, padlen); 222962306a36Sopenharmony_ci padlen = 0; 223062306a36Sopenharmony_ci } 223162306a36Sopenharmony_ci skb_put(skb, count + padlen); 223262306a36Sopenharmony_ci } else { 223362306a36Sopenharmony_ci for (i = 0; i < tdata->nr_frags; i++, frag++) { 223462306a36Sopenharmony_ci get_page(frag->page); 223562306a36Sopenharmony_ci skb_fill_page_desc(skb, i, frag->page, 223662306a36Sopenharmony_ci frag->offset, frag->size); 223762306a36Sopenharmony_ci } 223862306a36Sopenharmony_ci 223962306a36Sopenharmony_ci skb->len += count; 224062306a36Sopenharmony_ci skb->data_len += count; 224162306a36Sopenharmony_ci skb->truesize += count; 224262306a36Sopenharmony_ci } 224362306a36Sopenharmony_ci } else { 224462306a36Sopenharmony_ci pg = virt_to_head_page(task->data); 224562306a36Sopenharmony_ci get_page(pg); 224662306a36Sopenharmony_ci skb_fill_page_desc(skb, 0, pg, 224762306a36Sopenharmony_ci task->data - (char *)page_address(pg), 224862306a36Sopenharmony_ci count); 224962306a36Sopenharmony_ci skb->len += count; 225062306a36Sopenharmony_ci skb->data_len += count; 225162306a36Sopenharmony_ci skb->truesize += count; 225262306a36Sopenharmony_ci } 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci if (padlen) { 225562306a36Sopenharmony_ci get_page(rsvd_page); 225662306a36Sopenharmony_ci skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, 225762306a36Sopenharmony_ci rsvd_page, 0, padlen); 225862306a36Sopenharmony_ci 225962306a36Sopenharmony_ci skb->data_len += padlen; 226062306a36Sopenharmony_ci skb->truesize += padlen; 226162306a36Sopenharmony_ci skb->len += padlen; 226262306a36Sopenharmony_ci } 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_ci if (likely(count > tdata->max_xmit_dlength)) 226562306a36Sopenharmony_ci cxgbi_prep_iso_info(task, skb, count); 226662306a36Sopenharmony_ci else 226762306a36Sopenharmony_ci cxgbi_skcb_clear_flag(skb, SKCBF_TX_ISO); 226862306a36Sopenharmony_ci 226962306a36Sopenharmony_ci return 0; 227062306a36Sopenharmony_ci} 227162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_conn_init_pdu); 227262306a36Sopenharmony_ci 227362306a36Sopenharmony_cistatic int cxgbi_sock_tx_queue_up(struct cxgbi_sock *csk, struct sk_buff *skb) 227462306a36Sopenharmony_ci{ 227562306a36Sopenharmony_ci struct cxgbi_device *cdev = csk->cdev; 227662306a36Sopenharmony_ci struct cxgbi_iso_info *iso_cpl; 227762306a36Sopenharmony_ci u32 frags = skb_shinfo(skb)->nr_frags; 227862306a36Sopenharmony_ci u32 extra_len, num_pdu, hdr_len; 227962306a36Sopenharmony_ci u32 iso_tx_rsvd = 0; 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_ci if (csk->state != CTP_ESTABLISHED) { 228262306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_TX, 228362306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, EAGAIN.\n", 228462306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 228562306a36Sopenharmony_ci return -EPIPE; 228662306a36Sopenharmony_ci } 228762306a36Sopenharmony_ci 228862306a36Sopenharmony_ci if (csk->err) { 228962306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_TX, 229062306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, EPIPE %d.\n", 229162306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, csk->err); 229262306a36Sopenharmony_ci return -EPIPE; 229362306a36Sopenharmony_ci } 229462306a36Sopenharmony_ci 229562306a36Sopenharmony_ci if ((cdev->flags & CXGBI_FLAG_DEV_T3) && 229662306a36Sopenharmony_ci before((csk->snd_win + csk->snd_una), csk->write_seq)) { 229762306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_TX, 229862306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, FULL %u-%u >= %u.\n", 229962306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, csk->write_seq, 230062306a36Sopenharmony_ci csk->snd_una, csk->snd_win); 230162306a36Sopenharmony_ci return -ENOBUFS; 230262306a36Sopenharmony_ci } 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_ci if (cxgbi_skcb_test_flag(skb, SKCBF_TX_ISO)) 230562306a36Sopenharmony_ci iso_tx_rsvd = cdev->skb_iso_txhdr; 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ci if (unlikely(skb_headroom(skb) < (cdev->skb_tx_rsvd + iso_tx_rsvd))) { 230862306a36Sopenharmony_ci pr_err("csk 0x%p, skb head %u < %u.\n", 230962306a36Sopenharmony_ci csk, skb_headroom(skb), cdev->skb_tx_rsvd); 231062306a36Sopenharmony_ci return -EINVAL; 231162306a36Sopenharmony_ci } 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_ci if (skb->len != skb->data_len) 231462306a36Sopenharmony_ci frags++; 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci if (frags >= SKB_WR_LIST_SIZE) { 231762306a36Sopenharmony_ci pr_err("csk 0x%p, frags %u, %u,%u >%u.\n", 231862306a36Sopenharmony_ci csk, skb_shinfo(skb)->nr_frags, skb->len, 231962306a36Sopenharmony_ci skb->data_len, (unsigned int)SKB_WR_LIST_SIZE); 232062306a36Sopenharmony_ci return -EINVAL; 232162306a36Sopenharmony_ci } 232262306a36Sopenharmony_ci 232362306a36Sopenharmony_ci cxgbi_skcb_set_flag(skb, SKCBF_TX_NEED_HDR); 232462306a36Sopenharmony_ci skb_reset_transport_header(skb); 232562306a36Sopenharmony_ci cxgbi_sock_skb_entail(csk, skb); 232662306a36Sopenharmony_ci 232762306a36Sopenharmony_ci extra_len = cxgbi_ulp_extra_len(cxgbi_skcb_tx_ulp_mode(skb)); 232862306a36Sopenharmony_ci 232962306a36Sopenharmony_ci if (likely(cxgbi_skcb_test_flag(skb, SKCBF_TX_ISO))) { 233062306a36Sopenharmony_ci iso_cpl = (struct cxgbi_iso_info *)skb->head; 233162306a36Sopenharmony_ci num_pdu = iso_cpl->num_pdu; 233262306a36Sopenharmony_ci hdr_len = cxgbi_skcb_tx_iscsi_hdrlen(skb); 233362306a36Sopenharmony_ci extra_len = (cxgbi_ulp_extra_len(cxgbi_skcb_tx_ulp_mode(skb)) * 233462306a36Sopenharmony_ci num_pdu) + (hdr_len * (num_pdu - 1)); 233562306a36Sopenharmony_ci } 233662306a36Sopenharmony_ci 233762306a36Sopenharmony_ci csk->write_seq += (skb->len + extra_len); 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_ci return 0; 234062306a36Sopenharmony_ci} 234162306a36Sopenharmony_ci 234262306a36Sopenharmony_cistatic int cxgbi_sock_send_skb(struct cxgbi_sock *csk, struct sk_buff *skb) 234362306a36Sopenharmony_ci{ 234462306a36Sopenharmony_ci struct cxgbi_device *cdev = csk->cdev; 234562306a36Sopenharmony_ci int len = skb->len; 234662306a36Sopenharmony_ci int err; 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_ci spin_lock_bh(&csk->lock); 234962306a36Sopenharmony_ci err = cxgbi_sock_tx_queue_up(csk, skb); 235062306a36Sopenharmony_ci if (err < 0) { 235162306a36Sopenharmony_ci spin_unlock_bh(&csk->lock); 235262306a36Sopenharmony_ci return err; 235362306a36Sopenharmony_ci } 235462306a36Sopenharmony_ci 235562306a36Sopenharmony_ci if (likely(skb_queue_len(&csk->write_queue))) 235662306a36Sopenharmony_ci cdev->csk_push_tx_frames(csk, 0); 235762306a36Sopenharmony_ci spin_unlock_bh(&csk->lock); 235862306a36Sopenharmony_ci return len; 235962306a36Sopenharmony_ci} 236062306a36Sopenharmony_ci 236162306a36Sopenharmony_ciint cxgbi_conn_xmit_pdu(struct iscsi_task *task) 236262306a36Sopenharmony_ci{ 236362306a36Sopenharmony_ci struct iscsi_tcp_conn *tcp_conn = task->conn->dd_data; 236462306a36Sopenharmony_ci struct cxgbi_conn *cconn = tcp_conn->dd_data; 236562306a36Sopenharmony_ci struct iscsi_tcp_task *tcp_task = task->dd_data; 236662306a36Sopenharmony_ci struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); 236762306a36Sopenharmony_ci struct cxgbi_task_tag_info *ttinfo = &tdata->ttinfo; 236862306a36Sopenharmony_ci struct sk_buff *skb; 236962306a36Sopenharmony_ci struct cxgbi_sock *csk = NULL; 237062306a36Sopenharmony_ci u32 pdulen = 0; 237162306a36Sopenharmony_ci u32 datalen; 237262306a36Sopenharmony_ci int err; 237362306a36Sopenharmony_ci 237462306a36Sopenharmony_ci if (!tcp_task || (tcp_task->dd_data != tdata)) { 237562306a36Sopenharmony_ci pr_err("task 0x%p,0x%p, tcp_task 0x%p, tdata 0x%p/0x%p.\n", 237662306a36Sopenharmony_ci task, task->sc, tcp_task, 237762306a36Sopenharmony_ci tcp_task ? tcp_task->dd_data : NULL, tdata); 237862306a36Sopenharmony_ci return -EINVAL; 237962306a36Sopenharmony_ci } 238062306a36Sopenharmony_ci 238162306a36Sopenharmony_ci skb = tdata->skb; 238262306a36Sopenharmony_ci if (!skb) { 238362306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, 238462306a36Sopenharmony_ci "task 0x%p, skb NULL.\n", task); 238562306a36Sopenharmony_ci return 0; 238662306a36Sopenharmony_ci } 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_ci if (cconn && cconn->cep) 238962306a36Sopenharmony_ci csk = cconn->cep->csk; 239062306a36Sopenharmony_ci 239162306a36Sopenharmony_ci if (!csk) { 239262306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, 239362306a36Sopenharmony_ci "task 0x%p, csk gone.\n", task); 239462306a36Sopenharmony_ci return -EPIPE; 239562306a36Sopenharmony_ci } 239662306a36Sopenharmony_ci 239762306a36Sopenharmony_ci tdata->skb = NULL; 239862306a36Sopenharmony_ci datalen = skb->data_len; 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci /* write ppod first if using ofldq to write ppod */ 240162306a36Sopenharmony_ci if (ttinfo->flags & CXGBI_PPOD_INFO_FLAG_VALID) { 240262306a36Sopenharmony_ci struct cxgbi_ppm *ppm = csk->cdev->cdev2ppm(csk->cdev); 240362306a36Sopenharmony_ci 240462306a36Sopenharmony_ci ttinfo->flags &= ~CXGBI_PPOD_INFO_FLAG_VALID; 240562306a36Sopenharmony_ci if (csk->cdev->csk_ddp_set_map(ppm, csk, ttinfo) < 0) 240662306a36Sopenharmony_ci pr_err("task 0x%p, ppod writing using ofldq failed.\n", 240762306a36Sopenharmony_ci task); 240862306a36Sopenharmony_ci /* continue. Let fl get the data */ 240962306a36Sopenharmony_ci } 241062306a36Sopenharmony_ci 241162306a36Sopenharmony_ci if (!task->sc) 241262306a36Sopenharmony_ci memcpy(skb->data, task->hdr, SKB_TX_ISCSI_PDU_HEADER_MAX); 241362306a36Sopenharmony_ci 241462306a36Sopenharmony_ci err = cxgbi_sock_send_skb(csk, skb); 241562306a36Sopenharmony_ci if (err > 0) { 241662306a36Sopenharmony_ci pdulen += err; 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_TX, "task 0x%p,0x%p, rv %d.\n", 241962306a36Sopenharmony_ci task, task->sc, err); 242062306a36Sopenharmony_ci 242162306a36Sopenharmony_ci if (task->conn->hdrdgst_en) 242262306a36Sopenharmony_ci pdulen += ISCSI_DIGEST_SIZE; 242362306a36Sopenharmony_ci 242462306a36Sopenharmony_ci if (datalen && task->conn->datadgst_en) 242562306a36Sopenharmony_ci pdulen += ISCSI_DIGEST_SIZE; 242662306a36Sopenharmony_ci 242762306a36Sopenharmony_ci task->conn->txdata_octets += pdulen; 242862306a36Sopenharmony_ci 242962306a36Sopenharmony_ci if (unlikely(cxgbi_is_iso_config(csk) && cxgbi_is_iso_disabled(csk))) { 243062306a36Sopenharmony_ci if (time_after(jiffies, csk->prev_iso_ts + HZ)) { 243162306a36Sopenharmony_ci csk->disable_iso = false; 243262306a36Sopenharmony_ci csk->prev_iso_ts = 0; 243362306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_TX, 243462306a36Sopenharmony_ci "enable iso: csk 0x%p\n", csk); 243562306a36Sopenharmony_ci } 243662306a36Sopenharmony_ci } 243762306a36Sopenharmony_ci 243862306a36Sopenharmony_ci return 0; 243962306a36Sopenharmony_ci } 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_ci if (err == -EAGAIN || err == -ENOBUFS) { 244262306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_TX, 244362306a36Sopenharmony_ci "task 0x%p, skb 0x%p, len %u/%u, %d EAGAIN.\n", 244462306a36Sopenharmony_ci task, skb, skb->len, skb->data_len, err); 244562306a36Sopenharmony_ci /* reset skb to send when we are called again */ 244662306a36Sopenharmony_ci tdata->skb = skb; 244762306a36Sopenharmony_ci 244862306a36Sopenharmony_ci if (cxgbi_is_iso_config(csk) && !cxgbi_is_iso_disabled(csk) && 244962306a36Sopenharmony_ci (csk->no_tx_credits++ >= 2)) { 245062306a36Sopenharmony_ci csk->disable_iso = true; 245162306a36Sopenharmony_ci csk->prev_iso_ts = jiffies; 245262306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_TX, 245362306a36Sopenharmony_ci "disable iso:csk 0x%p, ts:%lu\n", 245462306a36Sopenharmony_ci csk, csk->prev_iso_ts); 245562306a36Sopenharmony_ci } 245662306a36Sopenharmony_ci 245762306a36Sopenharmony_ci return err; 245862306a36Sopenharmony_ci } 245962306a36Sopenharmony_ci 246062306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, 246162306a36Sopenharmony_ci "itt 0x%x, skb 0x%p, len %u/%u, xmit err %d.\n", 246262306a36Sopenharmony_ci task->itt, skb, skb->len, skb->data_len, err); 246362306a36Sopenharmony_ci __kfree_skb(skb); 246462306a36Sopenharmony_ci iscsi_conn_printk(KERN_ERR, task->conn, "xmit err %d.\n", err); 246562306a36Sopenharmony_ci iscsi_conn_failure(task->conn, ISCSI_ERR_XMIT_FAILED); 246662306a36Sopenharmony_ci return err; 246762306a36Sopenharmony_ci} 246862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_conn_xmit_pdu); 246962306a36Sopenharmony_ci 247062306a36Sopenharmony_civoid cxgbi_cleanup_task(struct iscsi_task *task) 247162306a36Sopenharmony_ci{ 247262306a36Sopenharmony_ci struct iscsi_tcp_task *tcp_task = task->dd_data; 247362306a36Sopenharmony_ci struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); 247462306a36Sopenharmony_ci 247562306a36Sopenharmony_ci if (!tcp_task || (tcp_task->dd_data != tdata)) { 247662306a36Sopenharmony_ci pr_info("task 0x%p,0x%p, tcp_task 0x%p, tdata 0x%p/0x%p.\n", 247762306a36Sopenharmony_ci task, task->sc, tcp_task, 247862306a36Sopenharmony_ci tcp_task ? tcp_task->dd_data : NULL, tdata); 247962306a36Sopenharmony_ci return; 248062306a36Sopenharmony_ci } 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 248362306a36Sopenharmony_ci "task 0x%p, skb 0x%p, itt 0x%x.\n", 248462306a36Sopenharmony_ci task, tdata->skb, task->hdr_itt); 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci tcp_task->dd_data = NULL; 248762306a36Sopenharmony_ci 248862306a36Sopenharmony_ci if (!task->sc) 248962306a36Sopenharmony_ci kfree(task->hdr); 249062306a36Sopenharmony_ci task->hdr = NULL; 249162306a36Sopenharmony_ci 249262306a36Sopenharmony_ci /* never reached the xmit task callout */ 249362306a36Sopenharmony_ci if (tdata->skb) { 249462306a36Sopenharmony_ci __kfree_skb(tdata->skb); 249562306a36Sopenharmony_ci tdata->skb = NULL; 249662306a36Sopenharmony_ci } 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_ci task_release_itt(task, task->hdr_itt); 249962306a36Sopenharmony_ci memset(tdata, 0, sizeof(*tdata)); 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_ci iscsi_tcp_cleanup_task(task); 250262306a36Sopenharmony_ci} 250362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_cleanup_task); 250462306a36Sopenharmony_ci 250562306a36Sopenharmony_civoid cxgbi_get_conn_stats(struct iscsi_cls_conn *cls_conn, 250662306a36Sopenharmony_ci struct iscsi_stats *stats) 250762306a36Sopenharmony_ci{ 250862306a36Sopenharmony_ci struct iscsi_conn *conn = cls_conn->dd_data; 250962306a36Sopenharmony_ci 251062306a36Sopenharmony_ci stats->txdata_octets = conn->txdata_octets; 251162306a36Sopenharmony_ci stats->rxdata_octets = conn->rxdata_octets; 251262306a36Sopenharmony_ci stats->scsicmd_pdus = conn->scsicmd_pdus_cnt; 251362306a36Sopenharmony_ci stats->dataout_pdus = conn->dataout_pdus_cnt; 251462306a36Sopenharmony_ci stats->scsirsp_pdus = conn->scsirsp_pdus_cnt; 251562306a36Sopenharmony_ci stats->datain_pdus = conn->datain_pdus_cnt; 251662306a36Sopenharmony_ci stats->r2t_pdus = conn->r2t_pdus_cnt; 251762306a36Sopenharmony_ci stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt; 251862306a36Sopenharmony_ci stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt; 251962306a36Sopenharmony_ci stats->digest_err = 0; 252062306a36Sopenharmony_ci stats->timeout_err = 0; 252162306a36Sopenharmony_ci stats->custom_length = 1; 252262306a36Sopenharmony_ci strcpy(stats->custom[0].desc, "eh_abort_cnt"); 252362306a36Sopenharmony_ci stats->custom[0].value = conn->eh_abort_cnt; 252462306a36Sopenharmony_ci} 252562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_get_conn_stats); 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_cistatic int cxgbi_conn_max_xmit_dlength(struct iscsi_conn *conn) 252862306a36Sopenharmony_ci{ 252962306a36Sopenharmony_ci struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 253062306a36Sopenharmony_ci struct cxgbi_conn *cconn = tcp_conn->dd_data; 253162306a36Sopenharmony_ci struct cxgbi_device *cdev = cconn->chba->cdev; 253262306a36Sopenharmony_ci unsigned int headroom = SKB_MAX_HEAD(cdev->skb_tx_rsvd); 253362306a36Sopenharmony_ci unsigned int max_def = 512 * MAX_SKB_FRAGS; 253462306a36Sopenharmony_ci unsigned int max = max(max_def, headroom); 253562306a36Sopenharmony_ci 253662306a36Sopenharmony_ci max = min(cconn->chba->cdev->tx_max_size, max); 253762306a36Sopenharmony_ci if (conn->max_xmit_dlength) 253862306a36Sopenharmony_ci conn->max_xmit_dlength = min(conn->max_xmit_dlength, max); 253962306a36Sopenharmony_ci else 254062306a36Sopenharmony_ci conn->max_xmit_dlength = max; 254162306a36Sopenharmony_ci cxgbi_align_pdu_size(conn->max_xmit_dlength); 254262306a36Sopenharmony_ci 254362306a36Sopenharmony_ci return 0; 254462306a36Sopenharmony_ci} 254562306a36Sopenharmony_ci 254662306a36Sopenharmony_cistatic int cxgbi_conn_max_recv_dlength(struct iscsi_conn *conn) 254762306a36Sopenharmony_ci{ 254862306a36Sopenharmony_ci struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 254962306a36Sopenharmony_ci struct cxgbi_conn *cconn = tcp_conn->dd_data; 255062306a36Sopenharmony_ci unsigned int max = cconn->chba->cdev->rx_max_size; 255162306a36Sopenharmony_ci 255262306a36Sopenharmony_ci cxgbi_align_pdu_size(max); 255362306a36Sopenharmony_ci 255462306a36Sopenharmony_ci if (conn->max_recv_dlength) { 255562306a36Sopenharmony_ci if (conn->max_recv_dlength > max) { 255662306a36Sopenharmony_ci pr_err("MaxRecvDataSegmentLength %u > %u.\n", 255762306a36Sopenharmony_ci conn->max_recv_dlength, max); 255862306a36Sopenharmony_ci return -EINVAL; 255962306a36Sopenharmony_ci } 256062306a36Sopenharmony_ci conn->max_recv_dlength = min(conn->max_recv_dlength, max); 256162306a36Sopenharmony_ci cxgbi_align_pdu_size(conn->max_recv_dlength); 256262306a36Sopenharmony_ci } else 256362306a36Sopenharmony_ci conn->max_recv_dlength = max; 256462306a36Sopenharmony_ci 256562306a36Sopenharmony_ci return 0; 256662306a36Sopenharmony_ci} 256762306a36Sopenharmony_ci 256862306a36Sopenharmony_ciint cxgbi_set_conn_param(struct iscsi_cls_conn *cls_conn, 256962306a36Sopenharmony_ci enum iscsi_param param, char *buf, int buflen) 257062306a36Sopenharmony_ci{ 257162306a36Sopenharmony_ci struct iscsi_conn *conn = cls_conn->dd_data; 257262306a36Sopenharmony_ci struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 257362306a36Sopenharmony_ci struct cxgbi_conn *cconn = tcp_conn->dd_data; 257462306a36Sopenharmony_ci struct cxgbi_sock *csk = cconn->cep->csk; 257562306a36Sopenharmony_ci int err; 257662306a36Sopenharmony_ci 257762306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 257862306a36Sopenharmony_ci "cls_conn 0x%p, param %d, buf(%d) %s.\n", 257962306a36Sopenharmony_ci cls_conn, param, buflen, buf); 258062306a36Sopenharmony_ci 258162306a36Sopenharmony_ci switch (param) { 258262306a36Sopenharmony_ci case ISCSI_PARAM_HDRDGST_EN: 258362306a36Sopenharmony_ci err = iscsi_set_param(cls_conn, param, buf, buflen); 258462306a36Sopenharmony_ci if (!err && conn->hdrdgst_en) 258562306a36Sopenharmony_ci err = csk->cdev->csk_ddp_setup_digest(csk, csk->tid, 258662306a36Sopenharmony_ci conn->hdrdgst_en, 258762306a36Sopenharmony_ci conn->datadgst_en); 258862306a36Sopenharmony_ci break; 258962306a36Sopenharmony_ci case ISCSI_PARAM_DATADGST_EN: 259062306a36Sopenharmony_ci err = iscsi_set_param(cls_conn, param, buf, buflen); 259162306a36Sopenharmony_ci if (!err && conn->datadgst_en) 259262306a36Sopenharmony_ci err = csk->cdev->csk_ddp_setup_digest(csk, csk->tid, 259362306a36Sopenharmony_ci conn->hdrdgst_en, 259462306a36Sopenharmony_ci conn->datadgst_en); 259562306a36Sopenharmony_ci break; 259662306a36Sopenharmony_ci case ISCSI_PARAM_MAX_R2T: 259762306a36Sopenharmony_ci return iscsi_tcp_set_max_r2t(conn, buf); 259862306a36Sopenharmony_ci case ISCSI_PARAM_MAX_RECV_DLENGTH: 259962306a36Sopenharmony_ci err = iscsi_set_param(cls_conn, param, buf, buflen); 260062306a36Sopenharmony_ci if (!err) 260162306a36Sopenharmony_ci err = cxgbi_conn_max_recv_dlength(conn); 260262306a36Sopenharmony_ci break; 260362306a36Sopenharmony_ci case ISCSI_PARAM_MAX_XMIT_DLENGTH: 260462306a36Sopenharmony_ci err = iscsi_set_param(cls_conn, param, buf, buflen); 260562306a36Sopenharmony_ci if (!err) 260662306a36Sopenharmony_ci err = cxgbi_conn_max_xmit_dlength(conn); 260762306a36Sopenharmony_ci break; 260862306a36Sopenharmony_ci default: 260962306a36Sopenharmony_ci return iscsi_set_param(cls_conn, param, buf, buflen); 261062306a36Sopenharmony_ci } 261162306a36Sopenharmony_ci return err; 261262306a36Sopenharmony_ci} 261362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_set_conn_param); 261462306a36Sopenharmony_ci 261562306a36Sopenharmony_ciint cxgbi_get_ep_param(struct iscsi_endpoint *ep, enum iscsi_param param, 261662306a36Sopenharmony_ci char *buf) 261762306a36Sopenharmony_ci{ 261862306a36Sopenharmony_ci struct cxgbi_endpoint *cep = ep->dd_data; 261962306a36Sopenharmony_ci struct cxgbi_sock *csk; 262062306a36Sopenharmony_ci 262162306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 262262306a36Sopenharmony_ci "cls_conn 0x%p, param %d.\n", ep, param); 262362306a36Sopenharmony_ci 262462306a36Sopenharmony_ci switch (param) { 262562306a36Sopenharmony_ci case ISCSI_PARAM_CONN_PORT: 262662306a36Sopenharmony_ci case ISCSI_PARAM_CONN_ADDRESS: 262762306a36Sopenharmony_ci if (!cep) 262862306a36Sopenharmony_ci return -ENOTCONN; 262962306a36Sopenharmony_ci 263062306a36Sopenharmony_ci csk = cep->csk; 263162306a36Sopenharmony_ci if (!csk) 263262306a36Sopenharmony_ci return -ENOTCONN; 263362306a36Sopenharmony_ci 263462306a36Sopenharmony_ci return iscsi_conn_get_addr_param((struct sockaddr_storage *) 263562306a36Sopenharmony_ci &csk->daddr, param, buf); 263662306a36Sopenharmony_ci default: 263762306a36Sopenharmony_ci break; 263862306a36Sopenharmony_ci } 263962306a36Sopenharmony_ci return -ENOSYS; 264062306a36Sopenharmony_ci} 264162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_get_ep_param); 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_cistruct iscsi_cls_conn * 264462306a36Sopenharmony_cicxgbi_create_conn(struct iscsi_cls_session *cls_session, u32 cid) 264562306a36Sopenharmony_ci{ 264662306a36Sopenharmony_ci struct iscsi_cls_conn *cls_conn; 264762306a36Sopenharmony_ci struct iscsi_conn *conn; 264862306a36Sopenharmony_ci struct iscsi_tcp_conn *tcp_conn; 264962306a36Sopenharmony_ci struct cxgbi_conn *cconn; 265062306a36Sopenharmony_ci 265162306a36Sopenharmony_ci cls_conn = iscsi_tcp_conn_setup(cls_session, sizeof(*cconn), cid); 265262306a36Sopenharmony_ci if (!cls_conn) 265362306a36Sopenharmony_ci return NULL; 265462306a36Sopenharmony_ci 265562306a36Sopenharmony_ci conn = cls_conn->dd_data; 265662306a36Sopenharmony_ci tcp_conn = conn->dd_data; 265762306a36Sopenharmony_ci cconn = tcp_conn->dd_data; 265862306a36Sopenharmony_ci cconn->iconn = conn; 265962306a36Sopenharmony_ci 266062306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 266162306a36Sopenharmony_ci "cid %u(0x%x), cls 0x%p,0x%p, conn 0x%p,0x%p,0x%p.\n", 266262306a36Sopenharmony_ci cid, cid, cls_session, cls_conn, conn, tcp_conn, cconn); 266362306a36Sopenharmony_ci 266462306a36Sopenharmony_ci return cls_conn; 266562306a36Sopenharmony_ci} 266662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_create_conn); 266762306a36Sopenharmony_ci 266862306a36Sopenharmony_ciint cxgbi_bind_conn(struct iscsi_cls_session *cls_session, 266962306a36Sopenharmony_ci struct iscsi_cls_conn *cls_conn, 267062306a36Sopenharmony_ci u64 transport_eph, int is_leading) 267162306a36Sopenharmony_ci{ 267262306a36Sopenharmony_ci struct iscsi_conn *conn = cls_conn->dd_data; 267362306a36Sopenharmony_ci struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 267462306a36Sopenharmony_ci struct cxgbi_conn *cconn = tcp_conn->dd_data; 267562306a36Sopenharmony_ci struct cxgbi_ppm *ppm; 267662306a36Sopenharmony_ci struct iscsi_endpoint *ep; 267762306a36Sopenharmony_ci struct cxgbi_endpoint *cep; 267862306a36Sopenharmony_ci struct cxgbi_sock *csk; 267962306a36Sopenharmony_ci int err; 268062306a36Sopenharmony_ci 268162306a36Sopenharmony_ci ep = iscsi_lookup_endpoint(transport_eph); 268262306a36Sopenharmony_ci if (!ep) 268362306a36Sopenharmony_ci return -EINVAL; 268462306a36Sopenharmony_ci 268562306a36Sopenharmony_ci /* setup ddp pagesize */ 268662306a36Sopenharmony_ci cep = ep->dd_data; 268762306a36Sopenharmony_ci csk = cep->csk; 268862306a36Sopenharmony_ci 268962306a36Sopenharmony_ci ppm = csk->cdev->cdev2ppm(csk->cdev); 269062306a36Sopenharmony_ci err = csk->cdev->csk_ddp_setup_pgidx(csk, csk->tid, 269162306a36Sopenharmony_ci ppm->tformat.pgsz_idx_dflt); 269262306a36Sopenharmony_ci if (err < 0) 269362306a36Sopenharmony_ci goto put_ep; 269462306a36Sopenharmony_ci 269562306a36Sopenharmony_ci err = iscsi_conn_bind(cls_session, cls_conn, is_leading); 269662306a36Sopenharmony_ci if (err) { 269762306a36Sopenharmony_ci err = -EINVAL; 269862306a36Sopenharmony_ci goto put_ep; 269962306a36Sopenharmony_ci } 270062306a36Sopenharmony_ci 270162306a36Sopenharmony_ci /* calculate the tag idx bits needed for this conn based on cmds_max */ 270262306a36Sopenharmony_ci cconn->task_idx_bits = (__ilog2_u32(conn->session->cmds_max - 1)) + 1; 270362306a36Sopenharmony_ci 270462306a36Sopenharmony_ci write_lock_bh(&csk->callback_lock); 270562306a36Sopenharmony_ci csk->user_data = conn; 270662306a36Sopenharmony_ci cconn->chba = cep->chba; 270762306a36Sopenharmony_ci cconn->cep = cep; 270862306a36Sopenharmony_ci cep->cconn = cconn; 270962306a36Sopenharmony_ci write_unlock_bh(&csk->callback_lock); 271062306a36Sopenharmony_ci 271162306a36Sopenharmony_ci cxgbi_conn_max_xmit_dlength(conn); 271262306a36Sopenharmony_ci cxgbi_conn_max_recv_dlength(conn); 271362306a36Sopenharmony_ci 271462306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 271562306a36Sopenharmony_ci "cls 0x%p,0x%p, ep 0x%p, cconn 0x%p, csk 0x%p.\n", 271662306a36Sopenharmony_ci cls_session, cls_conn, ep, cconn, csk); 271762306a36Sopenharmony_ci /* init recv engine */ 271862306a36Sopenharmony_ci iscsi_tcp_hdr_recv_prep(tcp_conn); 271962306a36Sopenharmony_ci 272062306a36Sopenharmony_ciput_ep: 272162306a36Sopenharmony_ci iscsi_put_endpoint(ep); 272262306a36Sopenharmony_ci return err; 272362306a36Sopenharmony_ci} 272462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_bind_conn); 272562306a36Sopenharmony_ci 272662306a36Sopenharmony_cistruct iscsi_cls_session *cxgbi_create_session(struct iscsi_endpoint *ep, 272762306a36Sopenharmony_ci u16 cmds_max, u16 qdepth, 272862306a36Sopenharmony_ci u32 initial_cmdsn) 272962306a36Sopenharmony_ci{ 273062306a36Sopenharmony_ci struct cxgbi_endpoint *cep; 273162306a36Sopenharmony_ci struct cxgbi_hba *chba; 273262306a36Sopenharmony_ci struct Scsi_Host *shost; 273362306a36Sopenharmony_ci struct iscsi_cls_session *cls_session; 273462306a36Sopenharmony_ci struct iscsi_session *session; 273562306a36Sopenharmony_ci 273662306a36Sopenharmony_ci if (!ep) { 273762306a36Sopenharmony_ci pr_err("missing endpoint.\n"); 273862306a36Sopenharmony_ci return NULL; 273962306a36Sopenharmony_ci } 274062306a36Sopenharmony_ci 274162306a36Sopenharmony_ci cep = ep->dd_data; 274262306a36Sopenharmony_ci chba = cep->chba; 274362306a36Sopenharmony_ci shost = chba->shost; 274462306a36Sopenharmony_ci 274562306a36Sopenharmony_ci BUG_ON(chba != iscsi_host_priv(shost)); 274662306a36Sopenharmony_ci 274762306a36Sopenharmony_ci cls_session = iscsi_session_setup(chba->cdev->itp, shost, 274862306a36Sopenharmony_ci cmds_max, 0, 274962306a36Sopenharmony_ci sizeof(struct iscsi_tcp_task) + 275062306a36Sopenharmony_ci sizeof(struct cxgbi_task_data), 275162306a36Sopenharmony_ci initial_cmdsn, ISCSI_MAX_TARGET); 275262306a36Sopenharmony_ci if (!cls_session) 275362306a36Sopenharmony_ci return NULL; 275462306a36Sopenharmony_ci 275562306a36Sopenharmony_ci session = cls_session->dd_data; 275662306a36Sopenharmony_ci if (iscsi_tcp_r2tpool_alloc(session)) 275762306a36Sopenharmony_ci goto remove_session; 275862306a36Sopenharmony_ci 275962306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 276062306a36Sopenharmony_ci "ep 0x%p, cls sess 0x%p.\n", ep, cls_session); 276162306a36Sopenharmony_ci return cls_session; 276262306a36Sopenharmony_ci 276362306a36Sopenharmony_ciremove_session: 276462306a36Sopenharmony_ci iscsi_session_teardown(cls_session); 276562306a36Sopenharmony_ci return NULL; 276662306a36Sopenharmony_ci} 276762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_create_session); 276862306a36Sopenharmony_ci 276962306a36Sopenharmony_civoid cxgbi_destroy_session(struct iscsi_cls_session *cls_session) 277062306a36Sopenharmony_ci{ 277162306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 277262306a36Sopenharmony_ci "cls sess 0x%p.\n", cls_session); 277362306a36Sopenharmony_ci 277462306a36Sopenharmony_ci iscsi_tcp_r2tpool_free(cls_session->dd_data); 277562306a36Sopenharmony_ci iscsi_session_teardown(cls_session); 277662306a36Sopenharmony_ci} 277762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_destroy_session); 277862306a36Sopenharmony_ci 277962306a36Sopenharmony_ciint cxgbi_set_host_param(struct Scsi_Host *shost, enum iscsi_host_param param, 278062306a36Sopenharmony_ci char *buf, int buflen) 278162306a36Sopenharmony_ci{ 278262306a36Sopenharmony_ci struct cxgbi_hba *chba = iscsi_host_priv(shost); 278362306a36Sopenharmony_ci 278462306a36Sopenharmony_ci if (!chba->ndev) { 278562306a36Sopenharmony_ci shost_printk(KERN_ERR, shost, "Could not get host param. " 278662306a36Sopenharmony_ci "netdev for host not set.\n"); 278762306a36Sopenharmony_ci return -ENODEV; 278862306a36Sopenharmony_ci } 278962306a36Sopenharmony_ci 279062306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 279162306a36Sopenharmony_ci "shost 0x%p, hba 0x%p,%s, param %d, buf(%d) %s.\n", 279262306a36Sopenharmony_ci shost, chba, chba->ndev->name, param, buflen, buf); 279362306a36Sopenharmony_ci 279462306a36Sopenharmony_ci switch (param) { 279562306a36Sopenharmony_ci case ISCSI_HOST_PARAM_IPADDRESS: 279662306a36Sopenharmony_ci { 279762306a36Sopenharmony_ci __be32 addr = in_aton(buf); 279862306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 279962306a36Sopenharmony_ci "hba %s, req. ipv4 %pI4.\n", chba->ndev->name, &addr); 280062306a36Sopenharmony_ci cxgbi_set_iscsi_ipv4(chba, addr); 280162306a36Sopenharmony_ci return 0; 280262306a36Sopenharmony_ci } 280362306a36Sopenharmony_ci case ISCSI_HOST_PARAM_HWADDRESS: 280462306a36Sopenharmony_ci case ISCSI_HOST_PARAM_NETDEV_NAME: 280562306a36Sopenharmony_ci return 0; 280662306a36Sopenharmony_ci default: 280762306a36Sopenharmony_ci return iscsi_host_set_param(shost, param, buf, buflen); 280862306a36Sopenharmony_ci } 280962306a36Sopenharmony_ci} 281062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_set_host_param); 281162306a36Sopenharmony_ci 281262306a36Sopenharmony_ciint cxgbi_get_host_param(struct Scsi_Host *shost, enum iscsi_host_param param, 281362306a36Sopenharmony_ci char *buf) 281462306a36Sopenharmony_ci{ 281562306a36Sopenharmony_ci struct cxgbi_hba *chba = iscsi_host_priv(shost); 281662306a36Sopenharmony_ci int len = 0; 281762306a36Sopenharmony_ci 281862306a36Sopenharmony_ci if (!chba->ndev) { 281962306a36Sopenharmony_ci shost_printk(KERN_ERR, shost, "Could not get host param. " 282062306a36Sopenharmony_ci "netdev for host not set.\n"); 282162306a36Sopenharmony_ci return -ENODEV; 282262306a36Sopenharmony_ci } 282362306a36Sopenharmony_ci 282462306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 282562306a36Sopenharmony_ci "shost 0x%p, hba 0x%p,%s, param %d.\n", 282662306a36Sopenharmony_ci shost, chba, chba->ndev->name, param); 282762306a36Sopenharmony_ci 282862306a36Sopenharmony_ci switch (param) { 282962306a36Sopenharmony_ci case ISCSI_HOST_PARAM_HWADDRESS: 283062306a36Sopenharmony_ci len = sysfs_format_mac(buf, chba->ndev->dev_addr, 6); 283162306a36Sopenharmony_ci break; 283262306a36Sopenharmony_ci case ISCSI_HOST_PARAM_NETDEV_NAME: 283362306a36Sopenharmony_ci len = sprintf(buf, "%s\n", chba->ndev->name); 283462306a36Sopenharmony_ci break; 283562306a36Sopenharmony_ci case ISCSI_HOST_PARAM_IPADDRESS: 283662306a36Sopenharmony_ci { 283762306a36Sopenharmony_ci struct cxgbi_sock *csk = find_sock_on_port(chba->cdev, 283862306a36Sopenharmony_ci chba->port_id); 283962306a36Sopenharmony_ci if (csk) { 284062306a36Sopenharmony_ci len = sprintf(buf, "%pIS", 284162306a36Sopenharmony_ci (struct sockaddr *)&csk->saddr); 284262306a36Sopenharmony_ci } 284362306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 284462306a36Sopenharmony_ci "hba %s, addr %s.\n", chba->ndev->name, buf); 284562306a36Sopenharmony_ci break; 284662306a36Sopenharmony_ci } 284762306a36Sopenharmony_ci default: 284862306a36Sopenharmony_ci return iscsi_host_get_param(shost, param, buf); 284962306a36Sopenharmony_ci } 285062306a36Sopenharmony_ci 285162306a36Sopenharmony_ci return len; 285262306a36Sopenharmony_ci} 285362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_get_host_param); 285462306a36Sopenharmony_ci 285562306a36Sopenharmony_cistruct iscsi_endpoint *cxgbi_ep_connect(struct Scsi_Host *shost, 285662306a36Sopenharmony_ci struct sockaddr *dst_addr, 285762306a36Sopenharmony_ci int non_blocking) 285862306a36Sopenharmony_ci{ 285962306a36Sopenharmony_ci struct iscsi_endpoint *ep; 286062306a36Sopenharmony_ci struct cxgbi_endpoint *cep; 286162306a36Sopenharmony_ci struct cxgbi_hba *hba = NULL; 286262306a36Sopenharmony_ci struct cxgbi_sock *csk; 286362306a36Sopenharmony_ci int ifindex = 0; 286462306a36Sopenharmony_ci int err = -EINVAL; 286562306a36Sopenharmony_ci 286662306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_SOCK, 286762306a36Sopenharmony_ci "shost 0x%p, non_blocking %d, dst_addr 0x%p.\n", 286862306a36Sopenharmony_ci shost, non_blocking, dst_addr); 286962306a36Sopenharmony_ci 287062306a36Sopenharmony_ci if (shost) { 287162306a36Sopenharmony_ci hba = iscsi_host_priv(shost); 287262306a36Sopenharmony_ci if (!hba) { 287362306a36Sopenharmony_ci pr_info("shost 0x%p, priv NULL.\n", shost); 287462306a36Sopenharmony_ci goto err_out; 287562306a36Sopenharmony_ci } 287662306a36Sopenharmony_ci } 287762306a36Sopenharmony_ci 287862306a36Sopenharmony_cicheck_route: 287962306a36Sopenharmony_ci if (dst_addr->sa_family == AF_INET) { 288062306a36Sopenharmony_ci csk = cxgbi_check_route(dst_addr, ifindex); 288162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 288262306a36Sopenharmony_ci } else if (dst_addr->sa_family == AF_INET6) { 288362306a36Sopenharmony_ci csk = cxgbi_check_route6(dst_addr, ifindex); 288462306a36Sopenharmony_ci#endif 288562306a36Sopenharmony_ci } else { 288662306a36Sopenharmony_ci pr_info("address family 0x%x NOT supported.\n", 288762306a36Sopenharmony_ci dst_addr->sa_family); 288862306a36Sopenharmony_ci err = -EAFNOSUPPORT; 288962306a36Sopenharmony_ci return (struct iscsi_endpoint *)ERR_PTR(err); 289062306a36Sopenharmony_ci } 289162306a36Sopenharmony_ci 289262306a36Sopenharmony_ci if (IS_ERR(csk)) 289362306a36Sopenharmony_ci return (struct iscsi_endpoint *)csk; 289462306a36Sopenharmony_ci cxgbi_sock_get(csk); 289562306a36Sopenharmony_ci 289662306a36Sopenharmony_ci if (!hba) 289762306a36Sopenharmony_ci hba = csk->cdev->hbas[csk->port_id]; 289862306a36Sopenharmony_ci else if (hba != csk->cdev->hbas[csk->port_id]) { 289962306a36Sopenharmony_ci if (ifindex != hba->ndev->ifindex) { 290062306a36Sopenharmony_ci cxgbi_sock_put(csk); 290162306a36Sopenharmony_ci cxgbi_sock_closed(csk); 290262306a36Sopenharmony_ci ifindex = hba->ndev->ifindex; 290362306a36Sopenharmony_ci goto check_route; 290462306a36Sopenharmony_ci } 290562306a36Sopenharmony_ci 290662306a36Sopenharmony_ci pr_info("Could not connect through requested host %u" 290762306a36Sopenharmony_ci "hba 0x%p != 0x%p (%u).\n", 290862306a36Sopenharmony_ci shost->host_no, hba, 290962306a36Sopenharmony_ci csk->cdev->hbas[csk->port_id], csk->port_id); 291062306a36Sopenharmony_ci err = -ENOSPC; 291162306a36Sopenharmony_ci goto release_conn; 291262306a36Sopenharmony_ci } 291362306a36Sopenharmony_ci 291462306a36Sopenharmony_ci err = sock_get_port(csk); 291562306a36Sopenharmony_ci if (err) 291662306a36Sopenharmony_ci goto release_conn; 291762306a36Sopenharmony_ci 291862306a36Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_CONNECTING); 291962306a36Sopenharmony_ci err = csk->cdev->csk_init_act_open(csk); 292062306a36Sopenharmony_ci if (err) 292162306a36Sopenharmony_ci goto release_conn; 292262306a36Sopenharmony_ci 292362306a36Sopenharmony_ci if (cxgbi_sock_is_closing(csk)) { 292462306a36Sopenharmony_ci err = -ENOSPC; 292562306a36Sopenharmony_ci pr_info("csk 0x%p is closing.\n", csk); 292662306a36Sopenharmony_ci goto release_conn; 292762306a36Sopenharmony_ci } 292862306a36Sopenharmony_ci 292962306a36Sopenharmony_ci ep = iscsi_create_endpoint(sizeof(*cep)); 293062306a36Sopenharmony_ci if (!ep) { 293162306a36Sopenharmony_ci err = -ENOMEM; 293262306a36Sopenharmony_ci pr_info("iscsi alloc ep, OOM.\n"); 293362306a36Sopenharmony_ci goto release_conn; 293462306a36Sopenharmony_ci } 293562306a36Sopenharmony_ci 293662306a36Sopenharmony_ci cep = ep->dd_data; 293762306a36Sopenharmony_ci cep->csk = csk; 293862306a36Sopenharmony_ci cep->chba = hba; 293962306a36Sopenharmony_ci 294062306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_SOCK, 294162306a36Sopenharmony_ci "ep 0x%p, cep 0x%p, csk 0x%p, hba 0x%p,%s.\n", 294262306a36Sopenharmony_ci ep, cep, csk, hba, hba->ndev->name); 294362306a36Sopenharmony_ci return ep; 294462306a36Sopenharmony_ci 294562306a36Sopenharmony_cirelease_conn: 294662306a36Sopenharmony_ci cxgbi_sock_put(csk); 294762306a36Sopenharmony_ci cxgbi_sock_closed(csk); 294862306a36Sopenharmony_cierr_out: 294962306a36Sopenharmony_ci return ERR_PTR(err); 295062306a36Sopenharmony_ci} 295162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_ep_connect); 295262306a36Sopenharmony_ci 295362306a36Sopenharmony_ciint cxgbi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) 295462306a36Sopenharmony_ci{ 295562306a36Sopenharmony_ci struct cxgbi_endpoint *cep = ep->dd_data; 295662306a36Sopenharmony_ci struct cxgbi_sock *csk = cep->csk; 295762306a36Sopenharmony_ci 295862306a36Sopenharmony_ci if (!cxgbi_sock_is_established(csk)) 295962306a36Sopenharmony_ci return 0; 296062306a36Sopenharmony_ci return 1; 296162306a36Sopenharmony_ci} 296262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_ep_poll); 296362306a36Sopenharmony_ci 296462306a36Sopenharmony_civoid cxgbi_ep_disconnect(struct iscsi_endpoint *ep) 296562306a36Sopenharmony_ci{ 296662306a36Sopenharmony_ci struct cxgbi_endpoint *cep = ep->dd_data; 296762306a36Sopenharmony_ci struct cxgbi_conn *cconn = cep->cconn; 296862306a36Sopenharmony_ci struct cxgbi_sock *csk = cep->csk; 296962306a36Sopenharmony_ci 297062306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_SOCK, 297162306a36Sopenharmony_ci "ep 0x%p, cep 0x%p, cconn 0x%p, csk 0x%p,%u,0x%lx.\n", 297262306a36Sopenharmony_ci ep, cep, cconn, csk, csk->state, csk->flags); 297362306a36Sopenharmony_ci 297462306a36Sopenharmony_ci if (cconn && cconn->iconn) { 297562306a36Sopenharmony_ci write_lock_bh(&csk->callback_lock); 297662306a36Sopenharmony_ci cep->csk->user_data = NULL; 297762306a36Sopenharmony_ci cconn->cep = NULL; 297862306a36Sopenharmony_ci write_unlock_bh(&csk->callback_lock); 297962306a36Sopenharmony_ci } 298062306a36Sopenharmony_ci iscsi_destroy_endpoint(ep); 298162306a36Sopenharmony_ci 298262306a36Sopenharmony_ci if (likely(csk->state >= CTP_ESTABLISHED)) 298362306a36Sopenharmony_ci need_active_close(csk); 298462306a36Sopenharmony_ci else 298562306a36Sopenharmony_ci cxgbi_sock_closed(csk); 298662306a36Sopenharmony_ci 298762306a36Sopenharmony_ci cxgbi_sock_put(csk); 298862306a36Sopenharmony_ci} 298962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_ep_disconnect); 299062306a36Sopenharmony_ci 299162306a36Sopenharmony_ciint cxgbi_iscsi_init(struct iscsi_transport *itp, 299262306a36Sopenharmony_ci struct scsi_transport_template **stt) 299362306a36Sopenharmony_ci{ 299462306a36Sopenharmony_ci *stt = iscsi_register_transport(itp); 299562306a36Sopenharmony_ci if (*stt == NULL) { 299662306a36Sopenharmony_ci pr_err("unable to register %s transport 0x%p.\n", 299762306a36Sopenharmony_ci itp->name, itp); 299862306a36Sopenharmony_ci return -ENODEV; 299962306a36Sopenharmony_ci } 300062306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 300162306a36Sopenharmony_ci "%s, registered iscsi transport 0x%p.\n", 300262306a36Sopenharmony_ci itp->name, stt); 300362306a36Sopenharmony_ci return 0; 300462306a36Sopenharmony_ci} 300562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_iscsi_init); 300662306a36Sopenharmony_ci 300762306a36Sopenharmony_civoid cxgbi_iscsi_cleanup(struct iscsi_transport *itp, 300862306a36Sopenharmony_ci struct scsi_transport_template **stt) 300962306a36Sopenharmony_ci{ 301062306a36Sopenharmony_ci if (*stt) { 301162306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 301262306a36Sopenharmony_ci "de-register transport 0x%p, %s, stt 0x%p.\n", 301362306a36Sopenharmony_ci itp, itp->name, *stt); 301462306a36Sopenharmony_ci *stt = NULL; 301562306a36Sopenharmony_ci iscsi_unregister_transport(itp); 301662306a36Sopenharmony_ci } 301762306a36Sopenharmony_ci} 301862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_iscsi_cleanup); 301962306a36Sopenharmony_ci 302062306a36Sopenharmony_ciumode_t cxgbi_attr_is_visible(int param_type, int param) 302162306a36Sopenharmony_ci{ 302262306a36Sopenharmony_ci switch (param_type) { 302362306a36Sopenharmony_ci case ISCSI_HOST_PARAM: 302462306a36Sopenharmony_ci switch (param) { 302562306a36Sopenharmony_ci case ISCSI_HOST_PARAM_NETDEV_NAME: 302662306a36Sopenharmony_ci case ISCSI_HOST_PARAM_HWADDRESS: 302762306a36Sopenharmony_ci case ISCSI_HOST_PARAM_IPADDRESS: 302862306a36Sopenharmony_ci case ISCSI_HOST_PARAM_INITIATOR_NAME: 302962306a36Sopenharmony_ci return S_IRUGO; 303062306a36Sopenharmony_ci default: 303162306a36Sopenharmony_ci return 0; 303262306a36Sopenharmony_ci } 303362306a36Sopenharmony_ci case ISCSI_PARAM: 303462306a36Sopenharmony_ci switch (param) { 303562306a36Sopenharmony_ci case ISCSI_PARAM_MAX_RECV_DLENGTH: 303662306a36Sopenharmony_ci case ISCSI_PARAM_MAX_XMIT_DLENGTH: 303762306a36Sopenharmony_ci case ISCSI_PARAM_HDRDGST_EN: 303862306a36Sopenharmony_ci case ISCSI_PARAM_DATADGST_EN: 303962306a36Sopenharmony_ci case ISCSI_PARAM_CONN_ADDRESS: 304062306a36Sopenharmony_ci case ISCSI_PARAM_CONN_PORT: 304162306a36Sopenharmony_ci case ISCSI_PARAM_EXP_STATSN: 304262306a36Sopenharmony_ci case ISCSI_PARAM_PERSISTENT_ADDRESS: 304362306a36Sopenharmony_ci case ISCSI_PARAM_PERSISTENT_PORT: 304462306a36Sopenharmony_ci case ISCSI_PARAM_PING_TMO: 304562306a36Sopenharmony_ci case ISCSI_PARAM_RECV_TMO: 304662306a36Sopenharmony_ci case ISCSI_PARAM_INITIAL_R2T_EN: 304762306a36Sopenharmony_ci case ISCSI_PARAM_MAX_R2T: 304862306a36Sopenharmony_ci case ISCSI_PARAM_IMM_DATA_EN: 304962306a36Sopenharmony_ci case ISCSI_PARAM_FIRST_BURST: 305062306a36Sopenharmony_ci case ISCSI_PARAM_MAX_BURST: 305162306a36Sopenharmony_ci case ISCSI_PARAM_PDU_INORDER_EN: 305262306a36Sopenharmony_ci case ISCSI_PARAM_DATASEQ_INORDER_EN: 305362306a36Sopenharmony_ci case ISCSI_PARAM_ERL: 305462306a36Sopenharmony_ci case ISCSI_PARAM_TARGET_NAME: 305562306a36Sopenharmony_ci case ISCSI_PARAM_TPGT: 305662306a36Sopenharmony_ci case ISCSI_PARAM_USERNAME: 305762306a36Sopenharmony_ci case ISCSI_PARAM_PASSWORD: 305862306a36Sopenharmony_ci case ISCSI_PARAM_USERNAME_IN: 305962306a36Sopenharmony_ci case ISCSI_PARAM_PASSWORD_IN: 306062306a36Sopenharmony_ci case ISCSI_PARAM_FAST_ABORT: 306162306a36Sopenharmony_ci case ISCSI_PARAM_ABORT_TMO: 306262306a36Sopenharmony_ci case ISCSI_PARAM_LU_RESET_TMO: 306362306a36Sopenharmony_ci case ISCSI_PARAM_TGT_RESET_TMO: 306462306a36Sopenharmony_ci case ISCSI_PARAM_IFACE_NAME: 306562306a36Sopenharmony_ci case ISCSI_PARAM_INITIATOR_NAME: 306662306a36Sopenharmony_ci return S_IRUGO; 306762306a36Sopenharmony_ci default: 306862306a36Sopenharmony_ci return 0; 306962306a36Sopenharmony_ci } 307062306a36Sopenharmony_ci } 307162306a36Sopenharmony_ci 307262306a36Sopenharmony_ci return 0; 307362306a36Sopenharmony_ci} 307462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cxgbi_attr_is_visible); 307562306a36Sopenharmony_ci 307662306a36Sopenharmony_cistatic int __init libcxgbi_init_module(void) 307762306a36Sopenharmony_ci{ 307862306a36Sopenharmony_ci pr_info("%s", version); 307962306a36Sopenharmony_ci 308062306a36Sopenharmony_ci BUILD_BUG_ON(sizeof_field(struct sk_buff, cb) < 308162306a36Sopenharmony_ci sizeof(struct cxgbi_skb_cb)); 308262306a36Sopenharmony_ci rsvd_page = alloc_page(GFP_KERNEL | __GFP_ZERO); 308362306a36Sopenharmony_ci if (!rsvd_page) 308462306a36Sopenharmony_ci return -ENOMEM; 308562306a36Sopenharmony_ci 308662306a36Sopenharmony_ci return 0; 308762306a36Sopenharmony_ci} 308862306a36Sopenharmony_ci 308962306a36Sopenharmony_cistatic void __exit libcxgbi_exit_module(void) 309062306a36Sopenharmony_ci{ 309162306a36Sopenharmony_ci cxgbi_device_unregister_all(0xFF); 309262306a36Sopenharmony_ci put_page(rsvd_page); 309362306a36Sopenharmony_ci return; 309462306a36Sopenharmony_ci} 309562306a36Sopenharmony_ci 309662306a36Sopenharmony_cimodule_init(libcxgbi_init_module); 309762306a36Sopenharmony_cimodule_exit(libcxgbi_exit_module); 3098