162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * cxgb4i.c: Chelsio 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 * 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/kernel.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/moduleparam.h> 1962306a36Sopenharmony_ci#include <scsi/scsi_host.h> 2062306a36Sopenharmony_ci#include <net/tcp.h> 2162306a36Sopenharmony_ci#include <net/dst.h> 2262306a36Sopenharmony_ci#include <linux/netdevice.h> 2362306a36Sopenharmony_ci#include <net/addrconf.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include "t4_regs.h" 2662306a36Sopenharmony_ci#include "t4_msg.h" 2762306a36Sopenharmony_ci#include "cxgb4.h" 2862306a36Sopenharmony_ci#include "cxgb4_uld.h" 2962306a36Sopenharmony_ci#include "t4fw_api.h" 3062306a36Sopenharmony_ci#include "l2t.h" 3162306a36Sopenharmony_ci#include "cxgb4i.h" 3262306a36Sopenharmony_ci#include "clip_tbl.h" 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic unsigned int dbg_level; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include "../libcxgbi.h" 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 3962306a36Sopenharmony_ci#include <net/dcbevent.h> 4062306a36Sopenharmony_ci#include "cxgb4_dcb.h" 4162306a36Sopenharmony_ci#endif 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define DRV_MODULE_NAME "cxgb4i" 4462306a36Sopenharmony_ci#define DRV_MODULE_DESC "Chelsio T4-T6 iSCSI Driver" 4562306a36Sopenharmony_ci#define DRV_MODULE_VERSION "0.9.5-ko" 4662306a36Sopenharmony_ci#define DRV_MODULE_RELDATE "Apr. 2015" 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic char version[] = 4962306a36Sopenharmony_ci DRV_MODULE_DESC " " DRV_MODULE_NAME 5062306a36Sopenharmony_ci " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ciMODULE_AUTHOR("Chelsio Communications, Inc."); 5362306a36Sopenharmony_ciMODULE_DESCRIPTION(DRV_MODULE_DESC); 5462306a36Sopenharmony_ciMODULE_VERSION(DRV_MODULE_VERSION); 5562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cimodule_param(dbg_level, uint, 0644); 5862306a36Sopenharmony_ciMODULE_PARM_DESC(dbg_level, "Debug flag (default=0)"); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define CXGB4I_DEFAULT_10G_RCV_WIN (256 * 1024) 6162306a36Sopenharmony_cistatic int cxgb4i_rcv_win = -1; 6262306a36Sopenharmony_cimodule_param(cxgb4i_rcv_win, int, 0644); 6362306a36Sopenharmony_ciMODULE_PARM_DESC(cxgb4i_rcv_win, "TCP receive window in bytes"); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#define CXGB4I_DEFAULT_10G_SND_WIN (128 * 1024) 6662306a36Sopenharmony_cistatic int cxgb4i_snd_win = -1; 6762306a36Sopenharmony_cimodule_param(cxgb4i_snd_win, int, 0644); 6862306a36Sopenharmony_ciMODULE_PARM_DESC(cxgb4i_snd_win, "TCP send window in bytes"); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic int cxgb4i_rx_credit_thres = 10 * 1024; 7162306a36Sopenharmony_cimodule_param(cxgb4i_rx_credit_thres, int, 0644); 7262306a36Sopenharmony_ciMODULE_PARM_DESC(cxgb4i_rx_credit_thres, 7362306a36Sopenharmony_ci "RX credits return threshold in bytes (default=10KB)"); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic unsigned int cxgb4i_max_connect = (8 * 1024); 7662306a36Sopenharmony_cimodule_param(cxgb4i_max_connect, uint, 0644); 7762306a36Sopenharmony_ciMODULE_PARM_DESC(cxgb4i_max_connect, "Maximum number of connections"); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic unsigned short cxgb4i_sport_base = 20000; 8062306a36Sopenharmony_cimodule_param(cxgb4i_sport_base, ushort, 0644); 8162306a36Sopenharmony_ciMODULE_PARM_DESC(cxgb4i_sport_base, "Starting port number (default 20000)"); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_citypedef void (*cxgb4i_cplhandler_func)(struct cxgbi_device *, struct sk_buff *); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic void *t4_uld_add(const struct cxgb4_lld_info *); 8662306a36Sopenharmony_cistatic int t4_uld_rx_handler(void *, const __be64 *, const struct pkt_gl *); 8762306a36Sopenharmony_cistatic int t4_uld_state_change(void *, enum cxgb4_state state); 8862306a36Sopenharmony_cistatic inline int send_tx_flowc_wr(struct cxgbi_sock *); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic const struct cxgb4_uld_info cxgb4i_uld_info = { 9162306a36Sopenharmony_ci .name = DRV_MODULE_NAME, 9262306a36Sopenharmony_ci .nrxq = MAX_ULD_QSETS, 9362306a36Sopenharmony_ci .ntxq = MAX_ULD_QSETS, 9462306a36Sopenharmony_ci .rxq_size = 1024, 9562306a36Sopenharmony_ci .lro = false, 9662306a36Sopenharmony_ci .add = t4_uld_add, 9762306a36Sopenharmony_ci .rx_handler = t4_uld_rx_handler, 9862306a36Sopenharmony_ci .state_change = t4_uld_state_change, 9962306a36Sopenharmony_ci}; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic struct scsi_host_template cxgb4i_host_template = { 10262306a36Sopenharmony_ci .module = THIS_MODULE, 10362306a36Sopenharmony_ci .name = DRV_MODULE_NAME, 10462306a36Sopenharmony_ci .proc_name = DRV_MODULE_NAME, 10562306a36Sopenharmony_ci .can_queue = CXGB4I_SCSI_HOST_QDEPTH, 10662306a36Sopenharmony_ci .queuecommand = iscsi_queuecommand, 10762306a36Sopenharmony_ci .change_queue_depth = scsi_change_queue_depth, 10862306a36Sopenharmony_ci .sg_tablesize = SG_ALL, 10962306a36Sopenharmony_ci .max_sectors = 0xFFFF, 11062306a36Sopenharmony_ci .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN, 11162306a36Sopenharmony_ci .eh_timed_out = iscsi_eh_cmd_timed_out, 11262306a36Sopenharmony_ci .eh_abort_handler = iscsi_eh_abort, 11362306a36Sopenharmony_ci .eh_device_reset_handler = iscsi_eh_device_reset, 11462306a36Sopenharmony_ci .eh_target_reset_handler = iscsi_eh_recover_target, 11562306a36Sopenharmony_ci .target_alloc = iscsi_target_alloc, 11662306a36Sopenharmony_ci .dma_boundary = PAGE_SIZE - 1, 11762306a36Sopenharmony_ci .this_id = -1, 11862306a36Sopenharmony_ci .track_queue_depth = 1, 11962306a36Sopenharmony_ci .cmd_size = sizeof(struct iscsi_cmd), 12062306a36Sopenharmony_ci}; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic struct iscsi_transport cxgb4i_iscsi_transport = { 12362306a36Sopenharmony_ci .owner = THIS_MODULE, 12462306a36Sopenharmony_ci .name = DRV_MODULE_NAME, 12562306a36Sopenharmony_ci .caps = CAP_RECOVERY_L0 | CAP_MULTI_R2T | CAP_HDRDGST | 12662306a36Sopenharmony_ci CAP_DATADGST | CAP_DIGEST_OFFLOAD | 12762306a36Sopenharmony_ci CAP_PADDING_OFFLOAD | CAP_TEXT_NEGO, 12862306a36Sopenharmony_ci .attr_is_visible = cxgbi_attr_is_visible, 12962306a36Sopenharmony_ci .get_host_param = cxgbi_get_host_param, 13062306a36Sopenharmony_ci .set_host_param = cxgbi_set_host_param, 13162306a36Sopenharmony_ci /* session management */ 13262306a36Sopenharmony_ci .create_session = cxgbi_create_session, 13362306a36Sopenharmony_ci .destroy_session = cxgbi_destroy_session, 13462306a36Sopenharmony_ci .get_session_param = iscsi_session_get_param, 13562306a36Sopenharmony_ci /* connection management */ 13662306a36Sopenharmony_ci .create_conn = cxgbi_create_conn, 13762306a36Sopenharmony_ci .bind_conn = cxgbi_bind_conn, 13862306a36Sopenharmony_ci .unbind_conn = iscsi_conn_unbind, 13962306a36Sopenharmony_ci .destroy_conn = iscsi_tcp_conn_teardown, 14062306a36Sopenharmony_ci .start_conn = iscsi_conn_start, 14162306a36Sopenharmony_ci .stop_conn = iscsi_conn_stop, 14262306a36Sopenharmony_ci .get_conn_param = iscsi_conn_get_param, 14362306a36Sopenharmony_ci .set_param = cxgbi_set_conn_param, 14462306a36Sopenharmony_ci .get_stats = cxgbi_get_conn_stats, 14562306a36Sopenharmony_ci /* pdu xmit req from user space */ 14662306a36Sopenharmony_ci .send_pdu = iscsi_conn_send_pdu, 14762306a36Sopenharmony_ci /* task */ 14862306a36Sopenharmony_ci .init_task = iscsi_tcp_task_init, 14962306a36Sopenharmony_ci .xmit_task = iscsi_tcp_task_xmit, 15062306a36Sopenharmony_ci .cleanup_task = cxgbi_cleanup_task, 15162306a36Sopenharmony_ci /* pdu */ 15262306a36Sopenharmony_ci .alloc_pdu = cxgbi_conn_alloc_pdu, 15362306a36Sopenharmony_ci .init_pdu = cxgbi_conn_init_pdu, 15462306a36Sopenharmony_ci .xmit_pdu = cxgbi_conn_xmit_pdu, 15562306a36Sopenharmony_ci .parse_pdu_itt = cxgbi_parse_pdu_itt, 15662306a36Sopenharmony_ci /* TCP connect/disconnect */ 15762306a36Sopenharmony_ci .get_ep_param = cxgbi_get_ep_param, 15862306a36Sopenharmony_ci .ep_connect = cxgbi_ep_connect, 15962306a36Sopenharmony_ci .ep_poll = cxgbi_ep_poll, 16062306a36Sopenharmony_ci .ep_disconnect = cxgbi_ep_disconnect, 16162306a36Sopenharmony_ci /* Error recovery timeout call */ 16262306a36Sopenharmony_ci .session_recovery_timedout = iscsi_session_recovery_timedout, 16362306a36Sopenharmony_ci}; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 16662306a36Sopenharmony_cistatic int 16762306a36Sopenharmony_cicxgb4_dcb_change_notify(struct notifier_block *, unsigned long, void *); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic struct notifier_block cxgb4_dcb_change = { 17062306a36Sopenharmony_ci .notifier_call = cxgb4_dcb_change_notify, 17162306a36Sopenharmony_ci}; 17262306a36Sopenharmony_ci#endif 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic struct scsi_transport_template *cxgb4i_stt; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci/* 17762306a36Sopenharmony_ci * CPL (Chelsio Protocol Language) defines a message passing interface between 17862306a36Sopenharmony_ci * the host driver and Chelsio asic. 17962306a36Sopenharmony_ci * The section below implments CPLs that related to iscsi tcp connection 18062306a36Sopenharmony_ci * open/close/abort and data send/receive. 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci#define RCV_BUFSIZ_MASK 0x3FFU 18462306a36Sopenharmony_ci#define MAX_IMM_TX_PKT_LEN 256 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic int push_tx_frames(struct cxgbi_sock *, int); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci/* 18962306a36Sopenharmony_ci * is_ofld_imm - check whether a packet can be sent as immediate data 19062306a36Sopenharmony_ci * @skb: the packet 19162306a36Sopenharmony_ci * 19262306a36Sopenharmony_ci * Returns true if a packet can be sent as an offload WR with immediate 19362306a36Sopenharmony_ci * data. We currently use the same limit as for Ethernet packets. 19462306a36Sopenharmony_ci */ 19562306a36Sopenharmony_cistatic inline bool is_ofld_imm(const struct sk_buff *skb) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci int len = skb->len; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (likely(cxgbi_skcb_test_flag(skb, SKCBF_TX_NEED_HDR))) 20062306a36Sopenharmony_ci len += sizeof(struct fw_ofld_tx_data_wr); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci if (likely(cxgbi_skcb_test_flag((struct sk_buff *)skb, SKCBF_TX_ISO))) 20362306a36Sopenharmony_ci len += sizeof(struct cpl_tx_data_iso); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci return (len <= MAX_IMM_OFLD_TX_DATA_WR_LEN); 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic void send_act_open_req(struct cxgbi_sock *csk, struct sk_buff *skb, 20962306a36Sopenharmony_ci struct l2t_entry *e) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(csk->cdev); 21262306a36Sopenharmony_ci int wscale = cxgbi_sock_compute_wscale(csk->mss_idx); 21362306a36Sopenharmony_ci unsigned long long opt0; 21462306a36Sopenharmony_ci unsigned int opt2; 21562306a36Sopenharmony_ci unsigned int qid_atid = ((unsigned int)csk->atid) | 21662306a36Sopenharmony_ci (((unsigned int)csk->rss_qid) << 14); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci opt0 = KEEP_ALIVE_F | 21962306a36Sopenharmony_ci WND_SCALE_V(wscale) | 22062306a36Sopenharmony_ci MSS_IDX_V(csk->mss_idx) | 22162306a36Sopenharmony_ci L2T_IDX_V(((struct l2t_entry *)csk->l2t)->idx) | 22262306a36Sopenharmony_ci TX_CHAN_V(csk->tx_chan) | 22362306a36Sopenharmony_ci SMAC_SEL_V(csk->smac_idx) | 22462306a36Sopenharmony_ci ULP_MODE_V(ULP_MODE_ISCSI) | 22562306a36Sopenharmony_ci RCV_BUFSIZ_V(csk->rcv_win >> 10); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci opt2 = RX_CHANNEL_V(0) | 22862306a36Sopenharmony_ci RSS_QUEUE_VALID_F | 22962306a36Sopenharmony_ci RSS_QUEUE_V(csk->rss_qid); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci if (is_t4(lldi->adapter_type)) { 23262306a36Sopenharmony_ci struct cpl_act_open_req *req = 23362306a36Sopenharmony_ci (struct cpl_act_open_req *)skb->head; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci INIT_TP_WR(req, 0); 23662306a36Sopenharmony_ci OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, 23762306a36Sopenharmony_ci qid_atid)); 23862306a36Sopenharmony_ci req->local_port = csk->saddr.sin_port; 23962306a36Sopenharmony_ci req->peer_port = csk->daddr.sin_port; 24062306a36Sopenharmony_ci req->local_ip = csk->saddr.sin_addr.s_addr; 24162306a36Sopenharmony_ci req->peer_ip = csk->daddr.sin_addr.s_addr; 24262306a36Sopenharmony_ci req->opt0 = cpu_to_be64(opt0); 24362306a36Sopenharmony_ci req->params = cpu_to_be32(cxgb4_select_ntuple( 24462306a36Sopenharmony_ci csk->cdev->ports[csk->port_id], 24562306a36Sopenharmony_ci csk->l2t)); 24662306a36Sopenharmony_ci opt2 |= RX_FC_VALID_F; 24762306a36Sopenharmony_ci req->opt2 = cpu_to_be32(opt2); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 25062306a36Sopenharmony_ci "csk t4 0x%p, %pI4:%u-%pI4:%u, atid %d, qid %u.\n", 25162306a36Sopenharmony_ci csk, &req->local_ip, ntohs(req->local_port), 25262306a36Sopenharmony_ci &req->peer_ip, ntohs(req->peer_port), 25362306a36Sopenharmony_ci csk->atid, csk->rss_qid); 25462306a36Sopenharmony_ci } else if (is_t5(lldi->adapter_type)) { 25562306a36Sopenharmony_ci struct cpl_t5_act_open_req *req = 25662306a36Sopenharmony_ci (struct cpl_t5_act_open_req *)skb->head; 25762306a36Sopenharmony_ci u32 isn = (get_random_u32() & ~7UL) - 1; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci INIT_TP_WR(req, 0); 26062306a36Sopenharmony_ci OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, 26162306a36Sopenharmony_ci qid_atid)); 26262306a36Sopenharmony_ci req->local_port = csk->saddr.sin_port; 26362306a36Sopenharmony_ci req->peer_port = csk->daddr.sin_port; 26462306a36Sopenharmony_ci req->local_ip = csk->saddr.sin_addr.s_addr; 26562306a36Sopenharmony_ci req->peer_ip = csk->daddr.sin_addr.s_addr; 26662306a36Sopenharmony_ci req->opt0 = cpu_to_be64(opt0); 26762306a36Sopenharmony_ci req->params = cpu_to_be64(FILTER_TUPLE_V( 26862306a36Sopenharmony_ci cxgb4_select_ntuple( 26962306a36Sopenharmony_ci csk->cdev->ports[csk->port_id], 27062306a36Sopenharmony_ci csk->l2t))); 27162306a36Sopenharmony_ci req->rsvd = cpu_to_be32(isn); 27262306a36Sopenharmony_ci opt2 |= T5_ISS_VALID; 27362306a36Sopenharmony_ci opt2 |= T5_OPT_2_VALID_F; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci req->opt2 = cpu_to_be32(opt2); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 27862306a36Sopenharmony_ci "csk t5 0x%p, %pI4:%u-%pI4:%u, atid %d, qid %u.\n", 27962306a36Sopenharmony_ci csk, &req->local_ip, ntohs(req->local_port), 28062306a36Sopenharmony_ci &req->peer_ip, ntohs(req->peer_port), 28162306a36Sopenharmony_ci csk->atid, csk->rss_qid); 28262306a36Sopenharmony_ci } else { 28362306a36Sopenharmony_ci struct cpl_t6_act_open_req *req = 28462306a36Sopenharmony_ci (struct cpl_t6_act_open_req *)skb->head; 28562306a36Sopenharmony_ci u32 isn = (get_random_u32() & ~7UL) - 1; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci INIT_TP_WR(req, 0); 28862306a36Sopenharmony_ci OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, 28962306a36Sopenharmony_ci qid_atid)); 29062306a36Sopenharmony_ci req->local_port = csk->saddr.sin_port; 29162306a36Sopenharmony_ci req->peer_port = csk->daddr.sin_port; 29262306a36Sopenharmony_ci req->local_ip = csk->saddr.sin_addr.s_addr; 29362306a36Sopenharmony_ci req->peer_ip = csk->daddr.sin_addr.s_addr; 29462306a36Sopenharmony_ci req->opt0 = cpu_to_be64(opt0); 29562306a36Sopenharmony_ci req->params = cpu_to_be64(FILTER_TUPLE_V( 29662306a36Sopenharmony_ci cxgb4_select_ntuple( 29762306a36Sopenharmony_ci csk->cdev->ports[csk->port_id], 29862306a36Sopenharmony_ci csk->l2t))); 29962306a36Sopenharmony_ci req->rsvd = cpu_to_be32(isn); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci opt2 |= T5_ISS_VALID; 30262306a36Sopenharmony_ci opt2 |= RX_FC_DISABLE_F; 30362306a36Sopenharmony_ci opt2 |= T5_OPT_2_VALID_F; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci req->opt2 = cpu_to_be32(opt2); 30662306a36Sopenharmony_ci req->rsvd2 = cpu_to_be32(0); 30762306a36Sopenharmony_ci req->opt3 = cpu_to_be32(0); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 31062306a36Sopenharmony_ci "csk t6 0x%p, %pI4:%u-%pI4:%u, atid %d, qid %u.\n", 31162306a36Sopenharmony_ci csk, &req->local_ip, ntohs(req->local_port), 31262306a36Sopenharmony_ci &req->peer_ip, ntohs(req->peer_port), 31362306a36Sopenharmony_ci csk->atid, csk->rss_qid); 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_SETUP, csk->port_id); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci pr_info_ipaddr("t%d csk 0x%p,%u,0x%lx,%u, rss_qid %u.\n", 31962306a36Sopenharmony_ci (&csk->saddr), (&csk->daddr), 32062306a36Sopenharmony_ci CHELSIO_CHIP_VERSION(lldi->adapter_type), csk, 32162306a36Sopenharmony_ci csk->state, csk->flags, csk->atid, csk->rss_qid); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci cxgb4_l2t_send(csk->cdev->ports[csk->port_id], skb, csk->l2t); 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 32762306a36Sopenharmony_cistatic void send_act_open_req6(struct cxgbi_sock *csk, struct sk_buff *skb, 32862306a36Sopenharmony_ci struct l2t_entry *e) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(csk->cdev); 33162306a36Sopenharmony_ci int wscale = cxgbi_sock_compute_wscale(csk->mss_idx); 33262306a36Sopenharmony_ci unsigned long long opt0; 33362306a36Sopenharmony_ci unsigned int opt2; 33462306a36Sopenharmony_ci unsigned int qid_atid = ((unsigned int)csk->atid) | 33562306a36Sopenharmony_ci (((unsigned int)csk->rss_qid) << 14); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci opt0 = KEEP_ALIVE_F | 33862306a36Sopenharmony_ci WND_SCALE_V(wscale) | 33962306a36Sopenharmony_ci MSS_IDX_V(csk->mss_idx) | 34062306a36Sopenharmony_ci L2T_IDX_V(((struct l2t_entry *)csk->l2t)->idx) | 34162306a36Sopenharmony_ci TX_CHAN_V(csk->tx_chan) | 34262306a36Sopenharmony_ci SMAC_SEL_V(csk->smac_idx) | 34362306a36Sopenharmony_ci ULP_MODE_V(ULP_MODE_ISCSI) | 34462306a36Sopenharmony_ci RCV_BUFSIZ_V(csk->rcv_win >> 10); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci opt2 = RX_CHANNEL_V(0) | 34762306a36Sopenharmony_ci RSS_QUEUE_VALID_F | 34862306a36Sopenharmony_ci RSS_QUEUE_V(csk->rss_qid); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci if (is_t4(lldi->adapter_type)) { 35162306a36Sopenharmony_ci struct cpl_act_open_req6 *req = 35262306a36Sopenharmony_ci (struct cpl_act_open_req6 *)skb->head; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci INIT_TP_WR(req, 0); 35562306a36Sopenharmony_ci OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ6, 35662306a36Sopenharmony_ci qid_atid)); 35762306a36Sopenharmony_ci req->local_port = csk->saddr6.sin6_port; 35862306a36Sopenharmony_ci req->peer_port = csk->daddr6.sin6_port; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci req->local_ip_hi = *(__be64 *)(csk->saddr6.sin6_addr.s6_addr); 36162306a36Sopenharmony_ci req->local_ip_lo = *(__be64 *)(csk->saddr6.sin6_addr.s6_addr + 36262306a36Sopenharmony_ci 8); 36362306a36Sopenharmony_ci req->peer_ip_hi = *(__be64 *)(csk->daddr6.sin6_addr.s6_addr); 36462306a36Sopenharmony_ci req->peer_ip_lo = *(__be64 *)(csk->daddr6.sin6_addr.s6_addr + 36562306a36Sopenharmony_ci 8); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci req->opt0 = cpu_to_be64(opt0); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci opt2 |= RX_FC_VALID_F; 37062306a36Sopenharmony_ci req->opt2 = cpu_to_be32(opt2); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci req->params = cpu_to_be32(cxgb4_select_ntuple( 37362306a36Sopenharmony_ci csk->cdev->ports[csk->port_id], 37462306a36Sopenharmony_ci csk->l2t)); 37562306a36Sopenharmony_ci } else if (is_t5(lldi->adapter_type)) { 37662306a36Sopenharmony_ci struct cpl_t5_act_open_req6 *req = 37762306a36Sopenharmony_ci (struct cpl_t5_act_open_req6 *)skb->head; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci INIT_TP_WR(req, 0); 38062306a36Sopenharmony_ci OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ6, 38162306a36Sopenharmony_ci qid_atid)); 38262306a36Sopenharmony_ci req->local_port = csk->saddr6.sin6_port; 38362306a36Sopenharmony_ci req->peer_port = csk->daddr6.sin6_port; 38462306a36Sopenharmony_ci req->local_ip_hi = *(__be64 *)(csk->saddr6.sin6_addr.s6_addr); 38562306a36Sopenharmony_ci req->local_ip_lo = *(__be64 *)(csk->saddr6.sin6_addr.s6_addr + 38662306a36Sopenharmony_ci 8); 38762306a36Sopenharmony_ci req->peer_ip_hi = *(__be64 *)(csk->daddr6.sin6_addr.s6_addr); 38862306a36Sopenharmony_ci req->peer_ip_lo = *(__be64 *)(csk->daddr6.sin6_addr.s6_addr + 38962306a36Sopenharmony_ci 8); 39062306a36Sopenharmony_ci req->opt0 = cpu_to_be64(opt0); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci opt2 |= T5_OPT_2_VALID_F; 39362306a36Sopenharmony_ci req->opt2 = cpu_to_be32(opt2); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci req->params = cpu_to_be64(FILTER_TUPLE_V(cxgb4_select_ntuple( 39662306a36Sopenharmony_ci csk->cdev->ports[csk->port_id], 39762306a36Sopenharmony_ci csk->l2t))); 39862306a36Sopenharmony_ci } else { 39962306a36Sopenharmony_ci struct cpl_t6_act_open_req6 *req = 40062306a36Sopenharmony_ci (struct cpl_t6_act_open_req6 *)skb->head; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci INIT_TP_WR(req, 0); 40362306a36Sopenharmony_ci OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ6, 40462306a36Sopenharmony_ci qid_atid)); 40562306a36Sopenharmony_ci req->local_port = csk->saddr6.sin6_port; 40662306a36Sopenharmony_ci req->peer_port = csk->daddr6.sin6_port; 40762306a36Sopenharmony_ci req->local_ip_hi = *(__be64 *)(csk->saddr6.sin6_addr.s6_addr); 40862306a36Sopenharmony_ci req->local_ip_lo = *(__be64 *)(csk->saddr6.sin6_addr.s6_addr + 40962306a36Sopenharmony_ci 8); 41062306a36Sopenharmony_ci req->peer_ip_hi = *(__be64 *)(csk->daddr6.sin6_addr.s6_addr); 41162306a36Sopenharmony_ci req->peer_ip_lo = *(__be64 *)(csk->daddr6.sin6_addr.s6_addr + 41262306a36Sopenharmony_ci 8); 41362306a36Sopenharmony_ci req->opt0 = cpu_to_be64(opt0); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci opt2 |= RX_FC_DISABLE_F; 41662306a36Sopenharmony_ci opt2 |= T5_OPT_2_VALID_F; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci req->opt2 = cpu_to_be32(opt2); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci req->params = cpu_to_be64(FILTER_TUPLE_V(cxgb4_select_ntuple( 42162306a36Sopenharmony_ci csk->cdev->ports[csk->port_id], 42262306a36Sopenharmony_ci csk->l2t))); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci req->rsvd2 = cpu_to_be32(0); 42562306a36Sopenharmony_ci req->opt3 = cpu_to_be32(0); 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_SETUP, csk->port_id); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci pr_info("t%d csk 0x%p,%u,0x%lx,%u, [%pI6]:%u-[%pI6]:%u, rss_qid %u.\n", 43162306a36Sopenharmony_ci CHELSIO_CHIP_VERSION(lldi->adapter_type), csk, csk->state, 43262306a36Sopenharmony_ci csk->flags, csk->atid, 43362306a36Sopenharmony_ci &csk->saddr6.sin6_addr, ntohs(csk->saddr.sin_port), 43462306a36Sopenharmony_ci &csk->daddr6.sin6_addr, ntohs(csk->daddr.sin_port), 43562306a36Sopenharmony_ci csk->rss_qid); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci cxgb4_l2t_send(csk->cdev->ports[csk->port_id], skb, csk->l2t); 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci#endif 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_cistatic void send_close_req(struct cxgbi_sock *csk) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci struct sk_buff *skb = csk->cpl_close; 44462306a36Sopenharmony_ci struct cpl_close_con_req *req = (struct cpl_close_con_req *)skb->head; 44562306a36Sopenharmony_ci unsigned int tid = csk->tid; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 44862306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx, tid %u.\n", 44962306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 45062306a36Sopenharmony_ci csk->cpl_close = NULL; 45162306a36Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_DATA, csk->port_id); 45262306a36Sopenharmony_ci INIT_TP_WR(req, tid); 45362306a36Sopenharmony_ci OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_CLOSE_CON_REQ, tid)); 45462306a36Sopenharmony_ci req->rsvd = 0; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci cxgbi_sock_skb_entail(csk, skb); 45762306a36Sopenharmony_ci if (csk->state >= CTP_ESTABLISHED) 45862306a36Sopenharmony_ci push_tx_frames(csk, 1); 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic void abort_arp_failure(void *handle, struct sk_buff *skb) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci struct cxgbi_sock *csk = (struct cxgbi_sock *)handle; 46462306a36Sopenharmony_ci struct cpl_abort_req *req; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 46762306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx, tid %u, abort.\n", 46862306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 46962306a36Sopenharmony_ci req = (struct cpl_abort_req *)skb->data; 47062306a36Sopenharmony_ci req->cmd = CPL_ABORT_NO_RST; 47162306a36Sopenharmony_ci cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cistatic void send_abort_req(struct cxgbi_sock *csk) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci struct cpl_abort_req *req; 47762306a36Sopenharmony_ci struct sk_buff *skb = csk->cpl_abort_req; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if (unlikely(csk->state == CTP_ABORTING) || !skb || !csk->cdev) 48062306a36Sopenharmony_ci return; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci if (!cxgbi_sock_flag(csk, CTPF_TX_DATA_SENT)) { 48362306a36Sopenharmony_ci send_tx_flowc_wr(csk); 48462306a36Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_TX_DATA_SENT); 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_ABORTING); 48862306a36Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_ABORT_RPL_PENDING); 48962306a36Sopenharmony_ci cxgbi_sock_purge_write_queue(csk); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci csk->cpl_abort_req = NULL; 49262306a36Sopenharmony_ci req = (struct cpl_abort_req *)skb->head; 49362306a36Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_DATA, csk->port_id); 49462306a36Sopenharmony_ci req->cmd = CPL_ABORT_SEND_RST; 49562306a36Sopenharmony_ci t4_set_arp_err_handler(skb, csk, abort_arp_failure); 49662306a36Sopenharmony_ci INIT_TP_WR(req, csk->tid); 49762306a36Sopenharmony_ci OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ABORT_REQ, csk->tid)); 49862306a36Sopenharmony_ci req->rsvd0 = htonl(csk->snd_nxt); 49962306a36Sopenharmony_ci req->rsvd1 = !cxgbi_sock_flag(csk, CTPF_TX_DATA_SENT); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 50262306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, snd_nxt %u, 0x%x.\n", 50362306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, csk->snd_nxt, 50462306a36Sopenharmony_ci req->rsvd1); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci cxgb4_l2t_send(csk->cdev->ports[csk->port_id], skb, csk->l2t); 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic void send_abort_rpl(struct cxgbi_sock *csk, int rst_status) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci struct sk_buff *skb = csk->cpl_abort_rpl; 51262306a36Sopenharmony_ci struct cpl_abort_rpl *rpl = (struct cpl_abort_rpl *)skb->head; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 51562306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, status %d.\n", 51662306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, rst_status); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci csk->cpl_abort_rpl = NULL; 51962306a36Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_DATA, csk->port_id); 52062306a36Sopenharmony_ci INIT_TP_WR(rpl, csk->tid); 52162306a36Sopenharmony_ci OPCODE_TID(rpl) = cpu_to_be32(MK_OPCODE_TID(CPL_ABORT_RPL, csk->tid)); 52262306a36Sopenharmony_ci rpl->cmd = rst_status; 52362306a36Sopenharmony_ci cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci/* 52762306a36Sopenharmony_ci * CPL connection rx data ack: host -> 52862306a36Sopenharmony_ci * Send RX credits through an RX_DATA_ACK CPL message. Returns the number of 52962306a36Sopenharmony_ci * credits sent. 53062306a36Sopenharmony_ci */ 53162306a36Sopenharmony_cistatic u32 send_rx_credits(struct cxgbi_sock *csk, u32 credits) 53262306a36Sopenharmony_ci{ 53362306a36Sopenharmony_ci struct sk_buff *skb; 53462306a36Sopenharmony_ci struct cpl_rx_data_ack *req; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, 53762306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, credit %u.\n", 53862306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, credits); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci skb = alloc_wr(sizeof(*req), 0, GFP_ATOMIC); 54162306a36Sopenharmony_ci if (!skb) { 54262306a36Sopenharmony_ci pr_info("csk 0x%p, credit %u, OOM.\n", csk, credits); 54362306a36Sopenharmony_ci return 0; 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci req = (struct cpl_rx_data_ack *)skb->head; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_ACK, csk->port_id); 54862306a36Sopenharmony_ci INIT_TP_WR(req, csk->tid); 54962306a36Sopenharmony_ci OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_RX_DATA_ACK, 55062306a36Sopenharmony_ci csk->tid)); 55162306a36Sopenharmony_ci req->credit_dack = cpu_to_be32(RX_CREDITS_V(credits) 55262306a36Sopenharmony_ci | RX_FORCE_ACK_F); 55362306a36Sopenharmony_ci cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); 55462306a36Sopenharmony_ci return credits; 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci/* 55862306a36Sopenharmony_ci * sgl_len - calculates the size of an SGL of the given capacity 55962306a36Sopenharmony_ci * @n: the number of SGL entries 56062306a36Sopenharmony_ci * Calculates the number of flits needed for a scatter/gather list that 56162306a36Sopenharmony_ci * can hold the given number of entries. 56262306a36Sopenharmony_ci */ 56362306a36Sopenharmony_cistatic inline unsigned int sgl_len(unsigned int n) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci n--; 56662306a36Sopenharmony_ci return (3 * n) / 2 + (n & 1) + 2; 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci/* 57062306a36Sopenharmony_ci * calc_tx_flits_ofld - calculate # of flits for an offload packet 57162306a36Sopenharmony_ci * @skb: the packet 57262306a36Sopenharmony_ci * 57362306a36Sopenharmony_ci * Returns the number of flits needed for the given offload packet. 57462306a36Sopenharmony_ci * These packets are already fully constructed and no additional headers 57562306a36Sopenharmony_ci * will be added. 57662306a36Sopenharmony_ci */ 57762306a36Sopenharmony_cistatic inline unsigned int calc_tx_flits_ofld(const struct sk_buff *skb) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci unsigned int flits, cnt; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci if (is_ofld_imm(skb)) 58262306a36Sopenharmony_ci return DIV_ROUND_UP(skb->len, 8); 58362306a36Sopenharmony_ci flits = skb_transport_offset(skb) / 8; 58462306a36Sopenharmony_ci cnt = skb_shinfo(skb)->nr_frags; 58562306a36Sopenharmony_ci if (skb_tail_pointer(skb) != skb_transport_header(skb)) 58662306a36Sopenharmony_ci cnt++; 58762306a36Sopenharmony_ci return flits + sgl_len(cnt); 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci#define FLOWC_WR_NPARAMS_MIN 9 59162306a36Sopenharmony_cistatic inline int tx_flowc_wr_credits(int *nparamsp, int *flowclenp) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci int nparams, flowclen16, flowclen; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci nparams = FLOWC_WR_NPARAMS_MIN; 59662306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 59762306a36Sopenharmony_ci nparams++; 59862306a36Sopenharmony_ci#endif 59962306a36Sopenharmony_ci flowclen = offsetof(struct fw_flowc_wr, mnemval[nparams]); 60062306a36Sopenharmony_ci flowclen16 = DIV_ROUND_UP(flowclen, 16); 60162306a36Sopenharmony_ci flowclen = flowclen16 * 16; 60262306a36Sopenharmony_ci /* 60362306a36Sopenharmony_ci * Return the number of 16-byte credits used by the FlowC request. 60462306a36Sopenharmony_ci * Pass back the nparams and actual FlowC length if requested. 60562306a36Sopenharmony_ci */ 60662306a36Sopenharmony_ci if (nparamsp) 60762306a36Sopenharmony_ci *nparamsp = nparams; 60862306a36Sopenharmony_ci if (flowclenp) 60962306a36Sopenharmony_ci *flowclenp = flowclen; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci return flowclen16; 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_cistatic inline int send_tx_flowc_wr(struct cxgbi_sock *csk) 61562306a36Sopenharmony_ci{ 61662306a36Sopenharmony_ci struct sk_buff *skb; 61762306a36Sopenharmony_ci struct fw_flowc_wr *flowc; 61862306a36Sopenharmony_ci int nparams, flowclen16, flowclen; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 62162306a36Sopenharmony_ci u16 vlan = ((struct l2t_entry *)csk->l2t)->vlan; 62262306a36Sopenharmony_ci#endif 62362306a36Sopenharmony_ci flowclen16 = tx_flowc_wr_credits(&nparams, &flowclen); 62462306a36Sopenharmony_ci skb = alloc_wr(flowclen, 0, GFP_ATOMIC); 62562306a36Sopenharmony_ci flowc = (struct fw_flowc_wr *)skb->head; 62662306a36Sopenharmony_ci flowc->op_to_nparams = 62762306a36Sopenharmony_ci htonl(FW_WR_OP_V(FW_FLOWC_WR) | FW_FLOWC_WR_NPARAMS_V(nparams)); 62862306a36Sopenharmony_ci flowc->flowid_len16 = 62962306a36Sopenharmony_ci htonl(FW_WR_LEN16_V(flowclen16) | FW_WR_FLOWID_V(csk->tid)); 63062306a36Sopenharmony_ci flowc->mnemval[0].mnemonic = FW_FLOWC_MNEM_PFNVFN; 63162306a36Sopenharmony_ci flowc->mnemval[0].val = htonl(csk->cdev->pfvf); 63262306a36Sopenharmony_ci flowc->mnemval[1].mnemonic = FW_FLOWC_MNEM_CH; 63362306a36Sopenharmony_ci flowc->mnemval[1].val = htonl(csk->tx_chan); 63462306a36Sopenharmony_ci flowc->mnemval[2].mnemonic = FW_FLOWC_MNEM_PORT; 63562306a36Sopenharmony_ci flowc->mnemval[2].val = htonl(csk->tx_chan); 63662306a36Sopenharmony_ci flowc->mnemval[3].mnemonic = FW_FLOWC_MNEM_IQID; 63762306a36Sopenharmony_ci flowc->mnemval[3].val = htonl(csk->rss_qid); 63862306a36Sopenharmony_ci flowc->mnemval[4].mnemonic = FW_FLOWC_MNEM_SNDNXT; 63962306a36Sopenharmony_ci flowc->mnemval[4].val = htonl(csk->snd_nxt); 64062306a36Sopenharmony_ci flowc->mnemval[5].mnemonic = FW_FLOWC_MNEM_RCVNXT; 64162306a36Sopenharmony_ci flowc->mnemval[5].val = htonl(csk->rcv_nxt); 64262306a36Sopenharmony_ci flowc->mnemval[6].mnemonic = FW_FLOWC_MNEM_SNDBUF; 64362306a36Sopenharmony_ci flowc->mnemval[6].val = htonl(csk->snd_win); 64462306a36Sopenharmony_ci flowc->mnemval[7].mnemonic = FW_FLOWC_MNEM_MSS; 64562306a36Sopenharmony_ci flowc->mnemval[7].val = htonl(csk->advmss); 64662306a36Sopenharmony_ci flowc->mnemval[8].mnemonic = 0; 64762306a36Sopenharmony_ci flowc->mnemval[8].val = 0; 64862306a36Sopenharmony_ci flowc->mnemval[8].mnemonic = FW_FLOWC_MNEM_TXDATAPLEN_MAX; 64962306a36Sopenharmony_ci if (csk->cdev->skb_iso_txhdr) 65062306a36Sopenharmony_ci flowc->mnemval[8].val = cpu_to_be32(CXGBI_MAX_ISO_DATA_IN_SKB); 65162306a36Sopenharmony_ci else 65262306a36Sopenharmony_ci flowc->mnemval[8].val = cpu_to_be32(16128); 65362306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 65462306a36Sopenharmony_ci flowc->mnemval[9].mnemonic = FW_FLOWC_MNEM_DCBPRIO; 65562306a36Sopenharmony_ci if (vlan == CPL_L2T_VLAN_NONE) { 65662306a36Sopenharmony_ci pr_warn_ratelimited("csk %u without VLAN Tag on DCB Link\n", 65762306a36Sopenharmony_ci csk->tid); 65862306a36Sopenharmony_ci flowc->mnemval[9].val = cpu_to_be32(0); 65962306a36Sopenharmony_ci } else { 66062306a36Sopenharmony_ci flowc->mnemval[9].val = cpu_to_be32((vlan & VLAN_PRIO_MASK) >> 66162306a36Sopenharmony_ci VLAN_PRIO_SHIFT); 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci#endif 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_DATA, csk->port_id); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 66862306a36Sopenharmony_ci "csk 0x%p, tid 0x%x, %u,%u,%u,%u,%u,%u,%u.\n", 66962306a36Sopenharmony_ci csk, csk->tid, 0, csk->tx_chan, csk->rss_qid, 67062306a36Sopenharmony_ci csk->snd_nxt, csk->rcv_nxt, csk->snd_win, 67162306a36Sopenharmony_ci csk->advmss); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci return flowclen16; 67662306a36Sopenharmony_ci} 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_cistatic void 67962306a36Sopenharmony_cicxgb4i_make_tx_iso_cpl(struct sk_buff *skb, struct cpl_tx_data_iso *cpl) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci struct cxgbi_iso_info *info = (struct cxgbi_iso_info *)skb->head; 68262306a36Sopenharmony_ci u32 imm_en = !!(info->flags & CXGBI_ISO_INFO_IMM_ENABLE); 68362306a36Sopenharmony_ci u32 fslice = !!(info->flags & CXGBI_ISO_INFO_FSLICE); 68462306a36Sopenharmony_ci u32 lslice = !!(info->flags & CXGBI_ISO_INFO_LSLICE); 68562306a36Sopenharmony_ci u32 pdu_type = (info->op == ISCSI_OP_SCSI_CMD) ? 0 : 1; 68662306a36Sopenharmony_ci u32 submode = cxgbi_skcb_tx_ulp_mode(skb) & 0x3; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci cpl->op_to_scsi = cpu_to_be32(CPL_TX_DATA_ISO_OP_V(CPL_TX_DATA_ISO) | 68962306a36Sopenharmony_ci CPL_TX_DATA_ISO_FIRST_V(fslice) | 69062306a36Sopenharmony_ci CPL_TX_DATA_ISO_LAST_V(lslice) | 69162306a36Sopenharmony_ci CPL_TX_DATA_ISO_CPLHDRLEN_V(0) | 69262306a36Sopenharmony_ci CPL_TX_DATA_ISO_HDRCRC_V(submode & 1) | 69362306a36Sopenharmony_ci CPL_TX_DATA_ISO_PLDCRC_V(((submode >> 1) & 1)) | 69462306a36Sopenharmony_ci CPL_TX_DATA_ISO_IMMEDIATE_V(imm_en) | 69562306a36Sopenharmony_ci CPL_TX_DATA_ISO_SCSI_V(pdu_type)); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci cpl->ahs_len = info->ahs; 69862306a36Sopenharmony_ci cpl->mpdu = cpu_to_be16(DIV_ROUND_UP(info->mpdu, 4)); 69962306a36Sopenharmony_ci cpl->burst_size = cpu_to_be32(info->burst_size); 70062306a36Sopenharmony_ci cpl->len = cpu_to_be32(info->len); 70162306a36Sopenharmony_ci cpl->reserved2_seglen_offset = 70262306a36Sopenharmony_ci cpu_to_be32(CPL_TX_DATA_ISO_SEGLEN_OFFSET_V(info->segment_offset)); 70362306a36Sopenharmony_ci cpl->datasn_offset = cpu_to_be32(info->datasn_offset); 70462306a36Sopenharmony_ci cpl->buffer_offset = cpu_to_be32(info->buffer_offset); 70562306a36Sopenharmony_ci cpl->reserved3 = cpu_to_be32(0); 70662306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, 70762306a36Sopenharmony_ci "iso: flags 0x%x, op %u, ahs %u, num_pdu %u, mpdu %u, " 70862306a36Sopenharmony_ci "burst_size %u, iso_len %u\n", 70962306a36Sopenharmony_ci info->flags, info->op, info->ahs, info->num_pdu, 71062306a36Sopenharmony_ci info->mpdu, info->burst_size << 2, info->len); 71162306a36Sopenharmony_ci} 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_cistatic void 71462306a36Sopenharmony_cicxgb4i_make_tx_data_wr(struct cxgbi_sock *csk, struct sk_buff *skb, int dlen, 71562306a36Sopenharmony_ci int len, u32 credits, int compl) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci struct cxgbi_device *cdev = csk->cdev; 71862306a36Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 71962306a36Sopenharmony_ci struct fw_ofld_tx_data_wr *req; 72062306a36Sopenharmony_ci struct cpl_tx_data_iso *cpl; 72162306a36Sopenharmony_ci u32 submode = cxgbi_skcb_tx_ulp_mode(skb) & 0x3; 72262306a36Sopenharmony_ci u32 wr_ulp_mode = 0; 72362306a36Sopenharmony_ci u32 hdr_size = sizeof(*req); 72462306a36Sopenharmony_ci u32 opcode = FW_OFLD_TX_DATA_WR; 72562306a36Sopenharmony_ci u32 immlen = 0; 72662306a36Sopenharmony_ci u32 force = is_t5(lldi->adapter_type) ? TX_FORCE_V(!submode) : 72762306a36Sopenharmony_ci T6_TX_FORCE_F; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci if (cxgbi_skcb_test_flag(skb, SKCBF_TX_ISO)) { 73062306a36Sopenharmony_ci hdr_size += sizeof(struct cpl_tx_data_iso); 73162306a36Sopenharmony_ci opcode = FW_ISCSI_TX_DATA_WR; 73262306a36Sopenharmony_ci immlen += sizeof(struct cpl_tx_data_iso); 73362306a36Sopenharmony_ci submode |= 8; 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci if (is_ofld_imm(skb)) 73762306a36Sopenharmony_ci immlen += dlen; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci req = (struct fw_ofld_tx_data_wr *)__skb_push(skb, hdr_size); 74062306a36Sopenharmony_ci req->op_to_immdlen = cpu_to_be32(FW_WR_OP_V(opcode) | 74162306a36Sopenharmony_ci FW_WR_COMPL_V(compl) | 74262306a36Sopenharmony_ci FW_WR_IMMDLEN_V(immlen)); 74362306a36Sopenharmony_ci req->flowid_len16 = cpu_to_be32(FW_WR_FLOWID_V(csk->tid) | 74462306a36Sopenharmony_ci FW_WR_LEN16_V(credits)); 74562306a36Sopenharmony_ci req->plen = cpu_to_be32(len); 74662306a36Sopenharmony_ci cpl = (struct cpl_tx_data_iso *)(req + 1); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci if (likely(cxgbi_skcb_test_flag(skb, SKCBF_TX_ISO))) 74962306a36Sopenharmony_ci cxgb4i_make_tx_iso_cpl(skb, cpl); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci if (submode) 75262306a36Sopenharmony_ci wr_ulp_mode = FW_OFLD_TX_DATA_WR_ULPMODE_V(ULP2_MODE_ISCSI) | 75362306a36Sopenharmony_ci FW_OFLD_TX_DATA_WR_ULPSUBMODE_V(submode); 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci req->tunnel_to_proxy = cpu_to_be32(wr_ulp_mode | force | 75662306a36Sopenharmony_ci FW_OFLD_TX_DATA_WR_SHOVE_V(1U)); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci if (!cxgbi_sock_flag(csk, CTPF_TX_DATA_SENT)) 75962306a36Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_TX_DATA_SENT); 76062306a36Sopenharmony_ci} 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_cistatic void arp_failure_skb_discard(void *handle, struct sk_buff *skb) 76362306a36Sopenharmony_ci{ 76462306a36Sopenharmony_ci kfree_skb(skb); 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_cistatic int push_tx_frames(struct cxgbi_sock *csk, int req_completion) 76862306a36Sopenharmony_ci{ 76962306a36Sopenharmony_ci int total_size = 0; 77062306a36Sopenharmony_ci struct sk_buff *skb; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci if (unlikely(csk->state < CTP_ESTABLISHED || 77362306a36Sopenharmony_ci csk->state == CTP_CLOSE_WAIT_1 || csk->state >= CTP_ABORTING)) { 77462306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK | 77562306a36Sopenharmony_ci 1 << CXGBI_DBG_PDU_TX, 77662306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, in closing state.\n", 77762306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 77862306a36Sopenharmony_ci return 0; 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci while (csk->wr_cred && ((skb = skb_peek(&csk->write_queue)) != NULL)) { 78262306a36Sopenharmony_ci struct cxgbi_iso_info *iso_cpl; 78362306a36Sopenharmony_ci u32 dlen = skb->len; 78462306a36Sopenharmony_ci u32 len = skb->len; 78562306a36Sopenharmony_ci u32 iso_cpl_len = 0; 78662306a36Sopenharmony_ci u32 flowclen16 = 0; 78762306a36Sopenharmony_ci u32 credits_needed; 78862306a36Sopenharmony_ci u32 num_pdu = 1, hdr_len; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci if (cxgbi_skcb_test_flag(skb, SKCBF_TX_ISO)) 79162306a36Sopenharmony_ci iso_cpl_len = sizeof(struct cpl_tx_data_iso); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci if (is_ofld_imm(skb)) 79462306a36Sopenharmony_ci credits_needed = DIV_ROUND_UP(dlen + iso_cpl_len, 16); 79562306a36Sopenharmony_ci else 79662306a36Sopenharmony_ci credits_needed = 79762306a36Sopenharmony_ci DIV_ROUND_UP((8 * calc_tx_flits_ofld(skb)) + 79862306a36Sopenharmony_ci iso_cpl_len, 16); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci if (likely(cxgbi_skcb_test_flag(skb, SKCBF_TX_NEED_HDR))) 80162306a36Sopenharmony_ci credits_needed += 80262306a36Sopenharmony_ci DIV_ROUND_UP(sizeof(struct fw_ofld_tx_data_wr), 16); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci /* 80562306a36Sopenharmony_ci * Assumes the initial credits is large enough to support 80662306a36Sopenharmony_ci * fw_flowc_wr plus largest possible first payload 80762306a36Sopenharmony_ci */ 80862306a36Sopenharmony_ci if (!cxgbi_sock_flag(csk, CTPF_TX_DATA_SENT)) { 80962306a36Sopenharmony_ci flowclen16 = send_tx_flowc_wr(csk); 81062306a36Sopenharmony_ci csk->wr_cred -= flowclen16; 81162306a36Sopenharmony_ci csk->wr_una_cred += flowclen16; 81262306a36Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_TX_DATA_SENT); 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci if (csk->wr_cred < credits_needed) { 81662306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_TX, 81762306a36Sopenharmony_ci "csk 0x%p, skb %u/%u, wr %d < %u.\n", 81862306a36Sopenharmony_ci csk, skb->len, skb->data_len, 81962306a36Sopenharmony_ci credits_needed, csk->wr_cred); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci csk->no_tx_credits++; 82262306a36Sopenharmony_ci break; 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci csk->no_tx_credits = 0; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci __skb_unlink(skb, &csk->write_queue); 82862306a36Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_DATA, csk->port_id); 82962306a36Sopenharmony_ci skb->csum = (__force __wsum)(credits_needed + flowclen16); 83062306a36Sopenharmony_ci csk->wr_cred -= credits_needed; 83162306a36Sopenharmony_ci csk->wr_una_cred += credits_needed; 83262306a36Sopenharmony_ci cxgbi_sock_enqueue_wr(csk, skb); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_TX, 83562306a36Sopenharmony_ci "csk 0x%p, skb %u/%u, wr %d, left %u, unack %u.\n", 83662306a36Sopenharmony_ci csk, skb->len, skb->data_len, credits_needed, 83762306a36Sopenharmony_ci csk->wr_cred, csk->wr_una_cred); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci if (!req_completion && 84062306a36Sopenharmony_ci ((csk->wr_una_cred >= (csk->wr_max_cred / 2)) || 84162306a36Sopenharmony_ci after(csk->write_seq, (csk->snd_una + csk->snd_win / 2)))) 84262306a36Sopenharmony_ci req_completion = 1; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci if (likely(cxgbi_skcb_test_flag(skb, SKCBF_TX_NEED_HDR))) { 84562306a36Sopenharmony_ci u32 ulp_mode = cxgbi_skcb_tx_ulp_mode(skb); 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci if (cxgbi_skcb_test_flag(skb, SKCBF_TX_ISO)) { 84862306a36Sopenharmony_ci iso_cpl = (struct cxgbi_iso_info *)skb->head; 84962306a36Sopenharmony_ci num_pdu = iso_cpl->num_pdu; 85062306a36Sopenharmony_ci hdr_len = cxgbi_skcb_tx_iscsi_hdrlen(skb); 85162306a36Sopenharmony_ci len += (cxgbi_ulp_extra_len(ulp_mode) * num_pdu) + 85262306a36Sopenharmony_ci (hdr_len * (num_pdu - 1)); 85362306a36Sopenharmony_ci } else { 85462306a36Sopenharmony_ci len += cxgbi_ulp_extra_len(ulp_mode); 85562306a36Sopenharmony_ci } 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci cxgb4i_make_tx_data_wr(csk, skb, dlen, len, 85862306a36Sopenharmony_ci credits_needed, req_completion); 85962306a36Sopenharmony_ci csk->snd_nxt += len; 86062306a36Sopenharmony_ci cxgbi_skcb_clear_flag(skb, SKCBF_TX_NEED_HDR); 86162306a36Sopenharmony_ci } else if (cxgbi_skcb_test_flag(skb, SKCBF_TX_FLAG_COMPL) && 86262306a36Sopenharmony_ci (csk->wr_una_cred >= (csk->wr_max_cred / 2))) { 86362306a36Sopenharmony_ci struct cpl_close_con_req *req = 86462306a36Sopenharmony_ci (struct cpl_close_con_req *)skb->data; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci req->wr.wr_hi |= cpu_to_be32(FW_WR_COMPL_F); 86762306a36Sopenharmony_ci } 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci total_size += skb->truesize; 87062306a36Sopenharmony_ci t4_set_arp_err_handler(skb, csk, arp_failure_skb_discard); 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_TX, 87362306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, skb 0x%p, %u.\n", 87462306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, skb, len); 87562306a36Sopenharmony_ci cxgb4_l2t_send(csk->cdev->ports[csk->port_id], skb, csk->l2t); 87662306a36Sopenharmony_ci } 87762306a36Sopenharmony_ci return total_size; 87862306a36Sopenharmony_ci} 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_cistatic inline void free_atid(struct cxgbi_sock *csk) 88162306a36Sopenharmony_ci{ 88262306a36Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(csk->cdev); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci if (cxgbi_sock_flag(csk, CTPF_HAS_ATID)) { 88562306a36Sopenharmony_ci cxgb4_free_atid(lldi->tids, csk->atid); 88662306a36Sopenharmony_ci cxgbi_sock_clear_flag(csk, CTPF_HAS_ATID); 88762306a36Sopenharmony_ci cxgbi_sock_put(csk); 88862306a36Sopenharmony_ci } 88962306a36Sopenharmony_ci} 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_cistatic void do_act_establish(struct cxgbi_device *cdev, struct sk_buff *skb) 89262306a36Sopenharmony_ci{ 89362306a36Sopenharmony_ci struct cxgbi_sock *csk; 89462306a36Sopenharmony_ci struct cpl_act_establish *req = (struct cpl_act_establish *)skb->data; 89562306a36Sopenharmony_ci unsigned short tcp_opt = ntohs(req->tcp_opt); 89662306a36Sopenharmony_ci unsigned int tid = GET_TID(req); 89762306a36Sopenharmony_ci unsigned int atid = TID_TID_G(ntohl(req->tos_atid)); 89862306a36Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 89962306a36Sopenharmony_ci struct tid_info *t = lldi->tids; 90062306a36Sopenharmony_ci u32 rcv_isn = be32_to_cpu(req->rcv_isn); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci csk = lookup_atid(t, atid); 90362306a36Sopenharmony_ci if (unlikely(!csk)) { 90462306a36Sopenharmony_ci pr_err("NO conn. for atid %u, cdev 0x%p.\n", atid, cdev); 90562306a36Sopenharmony_ci goto rel_skb; 90662306a36Sopenharmony_ci } 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci if (csk->atid != atid) { 90962306a36Sopenharmony_ci pr_err("bad conn atid %u, csk 0x%p,%u,0x%lx,tid %u, atid %u.\n", 91062306a36Sopenharmony_ci atid, csk, csk->state, csk->flags, csk->tid, csk->atid); 91162306a36Sopenharmony_ci goto rel_skb; 91262306a36Sopenharmony_ci } 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci pr_info_ipaddr("atid 0x%x, tid 0x%x, csk 0x%p,%u,0x%lx, isn %u.\n", 91562306a36Sopenharmony_ci (&csk->saddr), (&csk->daddr), 91662306a36Sopenharmony_ci atid, tid, csk, csk->state, csk->flags, rcv_isn); 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci module_put(cdev->owner); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci cxgbi_sock_get(csk); 92162306a36Sopenharmony_ci csk->tid = tid; 92262306a36Sopenharmony_ci cxgb4_insert_tid(lldi->tids, csk, tid, csk->csk_family); 92362306a36Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_HAS_TID); 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci free_atid(csk); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci spin_lock_bh(&csk->lock); 92862306a36Sopenharmony_ci if (unlikely(csk->state != CTP_ACTIVE_OPEN)) 92962306a36Sopenharmony_ci pr_info("csk 0x%p,%u,0x%lx,%u, got EST.\n", 93062306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci if (csk->retry_timer.function) { 93362306a36Sopenharmony_ci del_timer(&csk->retry_timer); 93462306a36Sopenharmony_ci csk->retry_timer.function = NULL; 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci csk->copied_seq = csk->rcv_wup = csk->rcv_nxt = rcv_isn; 93862306a36Sopenharmony_ci /* 93962306a36Sopenharmony_ci * Causes the first RX_DATA_ACK to supply any Rx credits we couldn't 94062306a36Sopenharmony_ci * pass through opt0. 94162306a36Sopenharmony_ci */ 94262306a36Sopenharmony_ci if (csk->rcv_win > (RCV_BUFSIZ_MASK << 10)) 94362306a36Sopenharmony_ci csk->rcv_wup -= csk->rcv_win - (RCV_BUFSIZ_MASK << 10); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci csk->advmss = lldi->mtus[TCPOPT_MSS_G(tcp_opt)] - 40; 94662306a36Sopenharmony_ci if (TCPOPT_TSTAMP_G(tcp_opt)) 94762306a36Sopenharmony_ci csk->advmss -= 12; 94862306a36Sopenharmony_ci if (csk->advmss < 128) 94962306a36Sopenharmony_ci csk->advmss = 128; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 95262306a36Sopenharmony_ci "csk 0x%p, mss_idx %u, advmss %u.\n", 95362306a36Sopenharmony_ci csk, TCPOPT_MSS_G(tcp_opt), csk->advmss); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci cxgbi_sock_established(csk, ntohl(req->snd_isn), ntohs(req->tcp_opt)); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci if (unlikely(cxgbi_sock_flag(csk, CTPF_ACTIVE_CLOSE_NEEDED))) 95862306a36Sopenharmony_ci send_abort_req(csk); 95962306a36Sopenharmony_ci else { 96062306a36Sopenharmony_ci if (skb_queue_len(&csk->write_queue)) 96162306a36Sopenharmony_ci push_tx_frames(csk, 0); 96262306a36Sopenharmony_ci cxgbi_conn_tx_open(csk); 96362306a36Sopenharmony_ci } 96462306a36Sopenharmony_ci spin_unlock_bh(&csk->lock); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_cirel_skb: 96762306a36Sopenharmony_ci __kfree_skb(skb); 96862306a36Sopenharmony_ci} 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_cistatic int act_open_rpl_status_to_errno(int status) 97162306a36Sopenharmony_ci{ 97262306a36Sopenharmony_ci switch (status) { 97362306a36Sopenharmony_ci case CPL_ERR_CONN_RESET: 97462306a36Sopenharmony_ci return -ECONNREFUSED; 97562306a36Sopenharmony_ci case CPL_ERR_ARP_MISS: 97662306a36Sopenharmony_ci return -EHOSTUNREACH; 97762306a36Sopenharmony_ci case CPL_ERR_CONN_TIMEDOUT: 97862306a36Sopenharmony_ci return -ETIMEDOUT; 97962306a36Sopenharmony_ci case CPL_ERR_TCAM_FULL: 98062306a36Sopenharmony_ci return -ENOMEM; 98162306a36Sopenharmony_ci case CPL_ERR_CONN_EXIST: 98262306a36Sopenharmony_ci return -EADDRINUSE; 98362306a36Sopenharmony_ci default: 98462306a36Sopenharmony_ci return -EIO; 98562306a36Sopenharmony_ci } 98662306a36Sopenharmony_ci} 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_cistatic void csk_act_open_retry_timer(struct timer_list *t) 98962306a36Sopenharmony_ci{ 99062306a36Sopenharmony_ci struct sk_buff *skb = NULL; 99162306a36Sopenharmony_ci struct cxgbi_sock *csk = from_timer(csk, t, retry_timer); 99262306a36Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(csk->cdev); 99362306a36Sopenharmony_ci void (*send_act_open_func)(struct cxgbi_sock *, struct sk_buff *, 99462306a36Sopenharmony_ci struct l2t_entry *); 99562306a36Sopenharmony_ci int t4 = is_t4(lldi->adapter_type), size, size6; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 99862306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u.\n", 99962306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci cxgbi_sock_get(csk); 100262306a36Sopenharmony_ci spin_lock_bh(&csk->lock); 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci if (t4) { 100562306a36Sopenharmony_ci size = sizeof(struct cpl_act_open_req); 100662306a36Sopenharmony_ci size6 = sizeof(struct cpl_act_open_req6); 100762306a36Sopenharmony_ci } else { 100862306a36Sopenharmony_ci size = sizeof(struct cpl_t5_act_open_req); 100962306a36Sopenharmony_ci size6 = sizeof(struct cpl_t5_act_open_req6); 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci if (csk->csk_family == AF_INET) { 101362306a36Sopenharmony_ci send_act_open_func = send_act_open_req; 101462306a36Sopenharmony_ci skb = alloc_wr(size, 0, GFP_ATOMIC); 101562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 101662306a36Sopenharmony_ci } else { 101762306a36Sopenharmony_ci send_act_open_func = send_act_open_req6; 101862306a36Sopenharmony_ci skb = alloc_wr(size6, 0, GFP_ATOMIC); 101962306a36Sopenharmony_ci#endif 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci if (!skb) 102362306a36Sopenharmony_ci cxgbi_sock_fail_act_open(csk, -ENOMEM); 102462306a36Sopenharmony_ci else { 102562306a36Sopenharmony_ci skb->sk = (struct sock *)csk; 102662306a36Sopenharmony_ci t4_set_arp_err_handler(skb, csk, 102762306a36Sopenharmony_ci cxgbi_sock_act_open_req_arp_failure); 102862306a36Sopenharmony_ci send_act_open_func(csk, skb, csk->l2t); 102962306a36Sopenharmony_ci } 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci spin_unlock_bh(&csk->lock); 103262306a36Sopenharmony_ci cxgbi_sock_put(csk); 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci} 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_cistatic inline bool is_neg_adv(unsigned int status) 103762306a36Sopenharmony_ci{ 103862306a36Sopenharmony_ci return status == CPL_ERR_RTX_NEG_ADVICE || 103962306a36Sopenharmony_ci status == CPL_ERR_KEEPALV_NEG_ADVICE || 104062306a36Sopenharmony_ci status == CPL_ERR_PERSIST_NEG_ADVICE; 104162306a36Sopenharmony_ci} 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_cistatic void do_act_open_rpl(struct cxgbi_device *cdev, struct sk_buff *skb) 104462306a36Sopenharmony_ci{ 104562306a36Sopenharmony_ci struct cxgbi_sock *csk; 104662306a36Sopenharmony_ci struct cpl_act_open_rpl *rpl = (struct cpl_act_open_rpl *)skb->data; 104762306a36Sopenharmony_ci unsigned int tid = GET_TID(rpl); 104862306a36Sopenharmony_ci unsigned int atid = 104962306a36Sopenharmony_ci TID_TID_G(AOPEN_ATID_G(be32_to_cpu(rpl->atid_status))); 105062306a36Sopenharmony_ci unsigned int status = AOPEN_STATUS_G(be32_to_cpu(rpl->atid_status)); 105162306a36Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 105262306a36Sopenharmony_ci struct tid_info *t = lldi->tids; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci csk = lookup_atid(t, atid); 105562306a36Sopenharmony_ci if (unlikely(!csk)) { 105662306a36Sopenharmony_ci pr_err("NO matching conn. atid %u, tid %u.\n", atid, tid); 105762306a36Sopenharmony_ci goto rel_skb; 105862306a36Sopenharmony_ci } 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci pr_info_ipaddr("tid %u/%u, status %u.\n" 106162306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx. ", (&csk->saddr), (&csk->daddr), 106262306a36Sopenharmony_ci atid, tid, status, csk, csk->state, csk->flags); 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci if (is_neg_adv(status)) 106562306a36Sopenharmony_ci goto rel_skb; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci module_put(cdev->owner); 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci if (status && status != CPL_ERR_TCAM_FULL && 107062306a36Sopenharmony_ci status != CPL_ERR_CONN_EXIST && 107162306a36Sopenharmony_ci status != CPL_ERR_ARP_MISS) 107262306a36Sopenharmony_ci cxgb4_remove_tid(lldi->tids, csk->port_id, GET_TID(rpl), 107362306a36Sopenharmony_ci csk->csk_family); 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci cxgbi_sock_get(csk); 107662306a36Sopenharmony_ci spin_lock_bh(&csk->lock); 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci if (status == CPL_ERR_CONN_EXIST && 107962306a36Sopenharmony_ci csk->retry_timer.function != csk_act_open_retry_timer) { 108062306a36Sopenharmony_ci csk->retry_timer.function = csk_act_open_retry_timer; 108162306a36Sopenharmony_ci mod_timer(&csk->retry_timer, jiffies + HZ / 2); 108262306a36Sopenharmony_ci } else 108362306a36Sopenharmony_ci cxgbi_sock_fail_act_open(csk, 108462306a36Sopenharmony_ci act_open_rpl_status_to_errno(status)); 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci spin_unlock_bh(&csk->lock); 108762306a36Sopenharmony_ci cxgbi_sock_put(csk); 108862306a36Sopenharmony_cirel_skb: 108962306a36Sopenharmony_ci __kfree_skb(skb); 109062306a36Sopenharmony_ci} 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_cistatic void do_peer_close(struct cxgbi_device *cdev, struct sk_buff *skb) 109362306a36Sopenharmony_ci{ 109462306a36Sopenharmony_ci struct cxgbi_sock *csk; 109562306a36Sopenharmony_ci struct cpl_peer_close *req = (struct cpl_peer_close *)skb->data; 109662306a36Sopenharmony_ci unsigned int tid = GET_TID(req); 109762306a36Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 109862306a36Sopenharmony_ci struct tid_info *t = lldi->tids; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci csk = lookup_tid(t, tid); 110162306a36Sopenharmony_ci if (unlikely(!csk)) { 110262306a36Sopenharmony_ci pr_err("can't find connection for tid %u.\n", tid); 110362306a36Sopenharmony_ci goto rel_skb; 110462306a36Sopenharmony_ci } 110562306a36Sopenharmony_ci pr_info_ipaddr("csk 0x%p,%u,0x%lx,%u.\n", 110662306a36Sopenharmony_ci (&csk->saddr), (&csk->daddr), 110762306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 110862306a36Sopenharmony_ci cxgbi_sock_rcv_peer_close(csk); 110962306a36Sopenharmony_cirel_skb: 111062306a36Sopenharmony_ci __kfree_skb(skb); 111162306a36Sopenharmony_ci} 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_cistatic void do_close_con_rpl(struct cxgbi_device *cdev, struct sk_buff *skb) 111462306a36Sopenharmony_ci{ 111562306a36Sopenharmony_ci struct cxgbi_sock *csk; 111662306a36Sopenharmony_ci struct cpl_close_con_rpl *rpl = (struct cpl_close_con_rpl *)skb->data; 111762306a36Sopenharmony_ci unsigned int tid = GET_TID(rpl); 111862306a36Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 111962306a36Sopenharmony_ci struct tid_info *t = lldi->tids; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci csk = lookup_tid(t, tid); 112262306a36Sopenharmony_ci if (unlikely(!csk)) { 112362306a36Sopenharmony_ci pr_err("can't find connection for tid %u.\n", tid); 112462306a36Sopenharmony_ci goto rel_skb; 112562306a36Sopenharmony_ci } 112662306a36Sopenharmony_ci pr_info_ipaddr("csk 0x%p,%u,0x%lx,%u.\n", 112762306a36Sopenharmony_ci (&csk->saddr), (&csk->daddr), 112862306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 112962306a36Sopenharmony_ci cxgbi_sock_rcv_close_conn_rpl(csk, ntohl(rpl->snd_nxt)); 113062306a36Sopenharmony_cirel_skb: 113162306a36Sopenharmony_ci __kfree_skb(skb); 113262306a36Sopenharmony_ci} 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_cistatic int abort_status_to_errno(struct cxgbi_sock *csk, int abort_reason, 113562306a36Sopenharmony_ci int *need_rst) 113662306a36Sopenharmony_ci{ 113762306a36Sopenharmony_ci switch (abort_reason) { 113862306a36Sopenharmony_ci case CPL_ERR_BAD_SYN: 113962306a36Sopenharmony_ci case CPL_ERR_CONN_RESET: 114062306a36Sopenharmony_ci return csk->state > CTP_ESTABLISHED ? 114162306a36Sopenharmony_ci -EPIPE : -ECONNRESET; 114262306a36Sopenharmony_ci case CPL_ERR_XMIT_TIMEDOUT: 114362306a36Sopenharmony_ci case CPL_ERR_PERSIST_TIMEDOUT: 114462306a36Sopenharmony_ci case CPL_ERR_FINWAIT2_TIMEDOUT: 114562306a36Sopenharmony_ci case CPL_ERR_KEEPALIVE_TIMEDOUT: 114662306a36Sopenharmony_ci return -ETIMEDOUT; 114762306a36Sopenharmony_ci default: 114862306a36Sopenharmony_ci return -EIO; 114962306a36Sopenharmony_ci } 115062306a36Sopenharmony_ci} 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_cistatic void do_abort_req_rss(struct cxgbi_device *cdev, struct sk_buff *skb) 115362306a36Sopenharmony_ci{ 115462306a36Sopenharmony_ci struct cxgbi_sock *csk; 115562306a36Sopenharmony_ci struct cpl_abort_req_rss *req = (struct cpl_abort_req_rss *)skb->data; 115662306a36Sopenharmony_ci unsigned int tid = GET_TID(req); 115762306a36Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 115862306a36Sopenharmony_ci struct tid_info *t = lldi->tids; 115962306a36Sopenharmony_ci int rst_status = CPL_ABORT_NO_RST; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci csk = lookup_tid(t, tid); 116262306a36Sopenharmony_ci if (unlikely(!csk)) { 116362306a36Sopenharmony_ci pr_err("can't find connection for tid %u.\n", tid); 116462306a36Sopenharmony_ci goto rel_skb; 116562306a36Sopenharmony_ci } 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci pr_info_ipaddr("csk 0x%p,%u,0x%lx,%u, status %u.\n", 116862306a36Sopenharmony_ci (&csk->saddr), (&csk->daddr), 116962306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, req->status); 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci if (is_neg_adv(req->status)) 117262306a36Sopenharmony_ci goto rel_skb; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci cxgbi_sock_get(csk); 117562306a36Sopenharmony_ci spin_lock_bh(&csk->lock); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci cxgbi_sock_clear_flag(csk, CTPF_ABORT_REQ_RCVD); 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci if (!cxgbi_sock_flag(csk, CTPF_TX_DATA_SENT)) { 118062306a36Sopenharmony_ci send_tx_flowc_wr(csk); 118162306a36Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_TX_DATA_SENT); 118262306a36Sopenharmony_ci } 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_ABORT_REQ_RCVD); 118562306a36Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_ABORTING); 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci send_abort_rpl(csk, rst_status); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci if (!cxgbi_sock_flag(csk, CTPF_ABORT_RPL_PENDING)) { 119062306a36Sopenharmony_ci csk->err = abort_status_to_errno(csk, req->status, &rst_status); 119162306a36Sopenharmony_ci cxgbi_sock_closed(csk); 119262306a36Sopenharmony_ci } 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci spin_unlock_bh(&csk->lock); 119562306a36Sopenharmony_ci cxgbi_sock_put(csk); 119662306a36Sopenharmony_cirel_skb: 119762306a36Sopenharmony_ci __kfree_skb(skb); 119862306a36Sopenharmony_ci} 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_cistatic void do_abort_rpl_rss(struct cxgbi_device *cdev, struct sk_buff *skb) 120162306a36Sopenharmony_ci{ 120262306a36Sopenharmony_ci struct cxgbi_sock *csk; 120362306a36Sopenharmony_ci struct cpl_abort_rpl_rss *rpl = (struct cpl_abort_rpl_rss *)skb->data; 120462306a36Sopenharmony_ci unsigned int tid = GET_TID(rpl); 120562306a36Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 120662306a36Sopenharmony_ci struct tid_info *t = lldi->tids; 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci csk = lookup_tid(t, tid); 120962306a36Sopenharmony_ci if (!csk) 121062306a36Sopenharmony_ci goto rel_skb; 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci pr_info_ipaddr("csk 0x%p,%u,0x%lx,%u, status %u.\n", 121362306a36Sopenharmony_ci (&csk->saddr), (&csk->daddr), csk, 121462306a36Sopenharmony_ci csk->state, csk->flags, csk->tid, rpl->status); 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci if (rpl->status == CPL_ERR_ABORT_FAILED) 121762306a36Sopenharmony_ci goto rel_skb; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci cxgbi_sock_rcv_abort_rpl(csk); 122062306a36Sopenharmony_cirel_skb: 122162306a36Sopenharmony_ci __kfree_skb(skb); 122262306a36Sopenharmony_ci} 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_cistatic void do_rx_data(struct cxgbi_device *cdev, struct sk_buff *skb) 122562306a36Sopenharmony_ci{ 122662306a36Sopenharmony_ci struct cxgbi_sock *csk; 122762306a36Sopenharmony_ci struct cpl_rx_data *cpl = (struct cpl_rx_data *)skb->data; 122862306a36Sopenharmony_ci unsigned int tid = GET_TID(cpl); 122962306a36Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 123062306a36Sopenharmony_ci struct tid_info *t = lldi->tids; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci csk = lookup_tid(t, tid); 123362306a36Sopenharmony_ci if (!csk) { 123462306a36Sopenharmony_ci pr_err("can't find connection for tid %u.\n", tid); 123562306a36Sopenharmony_ci } else { 123662306a36Sopenharmony_ci /* not expecting this, reset the connection. */ 123762306a36Sopenharmony_ci pr_err("csk 0x%p, tid %u, rcv cpl_rx_data.\n", csk, tid); 123862306a36Sopenharmony_ci spin_lock_bh(&csk->lock); 123962306a36Sopenharmony_ci send_abort_req(csk); 124062306a36Sopenharmony_ci spin_unlock_bh(&csk->lock); 124162306a36Sopenharmony_ci } 124262306a36Sopenharmony_ci __kfree_skb(skb); 124362306a36Sopenharmony_ci} 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_cistatic void do_rx_iscsi_hdr(struct cxgbi_device *cdev, struct sk_buff *skb) 124662306a36Sopenharmony_ci{ 124762306a36Sopenharmony_ci struct cxgbi_sock *csk; 124862306a36Sopenharmony_ci struct cpl_iscsi_hdr *cpl = (struct cpl_iscsi_hdr *)skb->data; 124962306a36Sopenharmony_ci unsigned short pdu_len_ddp = be16_to_cpu(cpl->pdu_len_ddp); 125062306a36Sopenharmony_ci unsigned int tid = GET_TID(cpl); 125162306a36Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 125262306a36Sopenharmony_ci struct tid_info *t = lldi->tids; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci csk = lookup_tid(t, tid); 125562306a36Sopenharmony_ci if (unlikely(!csk)) { 125662306a36Sopenharmony_ci pr_err("can't find conn. for tid %u.\n", tid); 125762306a36Sopenharmony_ci goto rel_skb; 125862306a36Sopenharmony_ci } 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, 126162306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx, tid %u, skb 0x%p,%u, 0x%x.\n", 126262306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, skb, skb->len, 126362306a36Sopenharmony_ci pdu_len_ddp); 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci spin_lock_bh(&csk->lock); 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci if (unlikely(csk->state >= CTP_PASSIVE_CLOSE)) { 126862306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 126962306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, bad state.\n", 127062306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 127162306a36Sopenharmony_ci if (csk->state != CTP_ABORTING) 127262306a36Sopenharmony_ci goto abort_conn; 127362306a36Sopenharmony_ci else 127462306a36Sopenharmony_ci goto discard; 127562306a36Sopenharmony_ci } 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci cxgbi_skcb_tcp_seq(skb) = ntohl(cpl->seq); 127862306a36Sopenharmony_ci cxgbi_skcb_flags(skb) = 0; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci skb_reset_transport_header(skb); 128162306a36Sopenharmony_ci __skb_pull(skb, sizeof(*cpl)); 128262306a36Sopenharmony_ci __pskb_trim(skb, ntohs(cpl->len)); 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci if (!csk->skb_ulp_lhdr) { 128562306a36Sopenharmony_ci unsigned char *bhs; 128662306a36Sopenharmony_ci unsigned int hlen, dlen, plen; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, 128962306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx, tid %u, skb 0x%p header.\n", 129062306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, skb); 129162306a36Sopenharmony_ci csk->skb_ulp_lhdr = skb; 129262306a36Sopenharmony_ci cxgbi_skcb_set_flag(skb, SKCBF_RX_HDR); 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci if ((CHELSIO_CHIP_VERSION(lldi->adapter_type) <= CHELSIO_T5) && 129562306a36Sopenharmony_ci (cxgbi_skcb_tcp_seq(skb) != csk->rcv_nxt)) { 129662306a36Sopenharmony_ci pr_info("tid %u, CPL_ISCSI_HDR, bad seq, 0x%x/0x%x.\n", 129762306a36Sopenharmony_ci csk->tid, cxgbi_skcb_tcp_seq(skb), 129862306a36Sopenharmony_ci csk->rcv_nxt); 129962306a36Sopenharmony_ci goto abort_conn; 130062306a36Sopenharmony_ci } 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci bhs = skb->data; 130362306a36Sopenharmony_ci hlen = ntohs(cpl->len); 130462306a36Sopenharmony_ci dlen = ntohl(*(unsigned int *)(bhs + 4)) & 0xFFFFFF; 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci plen = ISCSI_PDU_LEN_G(pdu_len_ddp); 130762306a36Sopenharmony_ci if (is_t4(lldi->adapter_type)) 130862306a36Sopenharmony_ci plen -= 40; 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci if ((hlen + dlen) != plen) { 131162306a36Sopenharmony_ci pr_info("tid 0x%x, CPL_ISCSI_HDR, pdu len " 131262306a36Sopenharmony_ci "mismatch %u != %u + %u, seq 0x%x.\n", 131362306a36Sopenharmony_ci csk->tid, plen, hlen, dlen, 131462306a36Sopenharmony_ci cxgbi_skcb_tcp_seq(skb)); 131562306a36Sopenharmony_ci goto abort_conn; 131662306a36Sopenharmony_ci } 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci cxgbi_skcb_rx_pdulen(skb) = (hlen + dlen + 3) & (~0x3); 131962306a36Sopenharmony_ci if (dlen) 132062306a36Sopenharmony_ci cxgbi_skcb_rx_pdulen(skb) += csk->dcrc_len; 132162306a36Sopenharmony_ci csk->rcv_nxt += cxgbi_skcb_rx_pdulen(skb); 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, 132462306a36Sopenharmony_ci "csk 0x%p, skb 0x%p, 0x%x,%u+%u,0x%x,0x%x.\n", 132562306a36Sopenharmony_ci csk, skb, *bhs, hlen, dlen, 132662306a36Sopenharmony_ci ntohl(*((unsigned int *)(bhs + 16))), 132762306a36Sopenharmony_ci ntohl(*((unsigned int *)(bhs + 24)))); 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci } else { 133062306a36Sopenharmony_ci struct sk_buff *lskb = csk->skb_ulp_lhdr; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci cxgbi_skcb_set_flag(lskb, SKCBF_RX_DATA); 133362306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, 133462306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx, skb 0x%p data, 0x%p.\n", 133562306a36Sopenharmony_ci csk, csk->state, csk->flags, skb, lskb); 133662306a36Sopenharmony_ci } 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci __skb_queue_tail(&csk->receive_queue, skb); 133962306a36Sopenharmony_ci spin_unlock_bh(&csk->lock); 134062306a36Sopenharmony_ci return; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ciabort_conn: 134362306a36Sopenharmony_ci send_abort_req(csk); 134462306a36Sopenharmony_cidiscard: 134562306a36Sopenharmony_ci spin_unlock_bh(&csk->lock); 134662306a36Sopenharmony_cirel_skb: 134762306a36Sopenharmony_ci __kfree_skb(skb); 134862306a36Sopenharmony_ci} 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_cistatic void do_rx_iscsi_data(struct cxgbi_device *cdev, struct sk_buff *skb) 135162306a36Sopenharmony_ci{ 135262306a36Sopenharmony_ci struct cxgbi_sock *csk; 135362306a36Sopenharmony_ci struct cpl_iscsi_hdr *cpl = (struct cpl_iscsi_hdr *)skb->data; 135462306a36Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 135562306a36Sopenharmony_ci struct tid_info *t = lldi->tids; 135662306a36Sopenharmony_ci struct sk_buff *lskb; 135762306a36Sopenharmony_ci u32 tid = GET_TID(cpl); 135862306a36Sopenharmony_ci u16 pdu_len_ddp = be16_to_cpu(cpl->pdu_len_ddp); 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci csk = lookup_tid(t, tid); 136162306a36Sopenharmony_ci if (unlikely(!csk)) { 136262306a36Sopenharmony_ci pr_err("can't find conn. for tid %u.\n", tid); 136362306a36Sopenharmony_ci goto rel_skb; 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, 136762306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx, tid %u, skb 0x%p,%u, 0x%x.\n", 136862306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, skb, 136962306a36Sopenharmony_ci skb->len, pdu_len_ddp); 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci spin_lock_bh(&csk->lock); 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci if (unlikely(csk->state >= CTP_PASSIVE_CLOSE)) { 137462306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 137562306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, bad state.\n", 137662306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci if (csk->state != CTP_ABORTING) 137962306a36Sopenharmony_ci goto abort_conn; 138062306a36Sopenharmony_ci else 138162306a36Sopenharmony_ci goto discard; 138262306a36Sopenharmony_ci } 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci cxgbi_skcb_tcp_seq(skb) = be32_to_cpu(cpl->seq); 138562306a36Sopenharmony_ci cxgbi_skcb_flags(skb) = 0; 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci skb_reset_transport_header(skb); 138862306a36Sopenharmony_ci __skb_pull(skb, sizeof(*cpl)); 138962306a36Sopenharmony_ci __pskb_trim(skb, ntohs(cpl->len)); 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci if (!csk->skb_ulp_lhdr) 139262306a36Sopenharmony_ci csk->skb_ulp_lhdr = skb; 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci lskb = csk->skb_ulp_lhdr; 139562306a36Sopenharmony_ci cxgbi_skcb_set_flag(lskb, SKCBF_RX_DATA); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, 139862306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx, skb 0x%p data, 0x%p.\n", 139962306a36Sopenharmony_ci csk, csk->state, csk->flags, skb, lskb); 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci __skb_queue_tail(&csk->receive_queue, skb); 140262306a36Sopenharmony_ci spin_unlock_bh(&csk->lock); 140362306a36Sopenharmony_ci return; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ciabort_conn: 140662306a36Sopenharmony_ci send_abort_req(csk); 140762306a36Sopenharmony_cidiscard: 140862306a36Sopenharmony_ci spin_unlock_bh(&csk->lock); 140962306a36Sopenharmony_cirel_skb: 141062306a36Sopenharmony_ci __kfree_skb(skb); 141162306a36Sopenharmony_ci} 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_cistatic void 141462306a36Sopenharmony_cicxgb4i_process_ddpvld(struct cxgbi_sock *csk, 141562306a36Sopenharmony_ci struct sk_buff *skb, u32 ddpvld) 141662306a36Sopenharmony_ci{ 141762306a36Sopenharmony_ci if (ddpvld & (1 << CPL_RX_DDP_STATUS_HCRC_SHIFT)) { 141862306a36Sopenharmony_ci pr_info("csk 0x%p, lhdr 0x%p, status 0x%x, hcrc bad 0x%lx.\n", 141962306a36Sopenharmony_ci csk, skb, ddpvld, cxgbi_skcb_flags(skb)); 142062306a36Sopenharmony_ci cxgbi_skcb_set_flag(skb, SKCBF_RX_HCRC_ERR); 142162306a36Sopenharmony_ci } 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci if (ddpvld & (1 << CPL_RX_DDP_STATUS_DCRC_SHIFT)) { 142462306a36Sopenharmony_ci pr_info("csk 0x%p, lhdr 0x%p, status 0x%x, dcrc bad 0x%lx.\n", 142562306a36Sopenharmony_ci csk, skb, ddpvld, cxgbi_skcb_flags(skb)); 142662306a36Sopenharmony_ci cxgbi_skcb_set_flag(skb, SKCBF_RX_DCRC_ERR); 142762306a36Sopenharmony_ci } 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci if (ddpvld & (1 << CPL_RX_DDP_STATUS_PAD_SHIFT)) { 143062306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 143162306a36Sopenharmony_ci "csk 0x%p, lhdr 0x%p, status 0x%x, pad bad.\n", 143262306a36Sopenharmony_ci csk, skb, ddpvld); 143362306a36Sopenharmony_ci cxgbi_skcb_set_flag(skb, SKCBF_RX_PAD_ERR); 143462306a36Sopenharmony_ci } 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci if ((ddpvld & (1 << CPL_RX_DDP_STATUS_DDP_SHIFT)) && 143762306a36Sopenharmony_ci !cxgbi_skcb_test_flag(skb, SKCBF_RX_DATA)) { 143862306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 143962306a36Sopenharmony_ci "csk 0x%p, lhdr 0x%p, 0x%x, data ddp'ed.\n", 144062306a36Sopenharmony_ci csk, skb, ddpvld); 144162306a36Sopenharmony_ci cxgbi_skcb_set_flag(skb, SKCBF_RX_DATA_DDPD); 144262306a36Sopenharmony_ci } 144362306a36Sopenharmony_ci} 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_cistatic void do_rx_data_ddp(struct cxgbi_device *cdev, 144662306a36Sopenharmony_ci struct sk_buff *skb) 144762306a36Sopenharmony_ci{ 144862306a36Sopenharmony_ci struct cxgbi_sock *csk; 144962306a36Sopenharmony_ci struct sk_buff *lskb; 145062306a36Sopenharmony_ci struct cpl_rx_data_ddp *rpl = (struct cpl_rx_data_ddp *)skb->data; 145162306a36Sopenharmony_ci unsigned int tid = GET_TID(rpl); 145262306a36Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 145362306a36Sopenharmony_ci struct tid_info *t = lldi->tids; 145462306a36Sopenharmony_ci u32 ddpvld = be32_to_cpu(rpl->ddpvld); 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci csk = lookup_tid(t, tid); 145762306a36Sopenharmony_ci if (unlikely(!csk)) { 145862306a36Sopenharmony_ci pr_err("can't find connection for tid %u.\n", tid); 145962306a36Sopenharmony_ci goto rel_skb; 146062306a36Sopenharmony_ci } 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, 146362306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx, skb 0x%p,0x%x, lhdr 0x%p.\n", 146462306a36Sopenharmony_ci csk, csk->state, csk->flags, skb, ddpvld, csk->skb_ulp_lhdr); 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci spin_lock_bh(&csk->lock); 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci if (unlikely(csk->state >= CTP_PASSIVE_CLOSE)) { 146962306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 147062306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, bad state.\n", 147162306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 147262306a36Sopenharmony_ci if (csk->state != CTP_ABORTING) 147362306a36Sopenharmony_ci goto abort_conn; 147462306a36Sopenharmony_ci else 147562306a36Sopenharmony_ci goto discard; 147662306a36Sopenharmony_ci } 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci if (!csk->skb_ulp_lhdr) { 147962306a36Sopenharmony_ci pr_err("tid 0x%x, rcv RX_DATA_DDP w/o pdu bhs.\n", csk->tid); 148062306a36Sopenharmony_ci goto abort_conn; 148162306a36Sopenharmony_ci } 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci lskb = csk->skb_ulp_lhdr; 148462306a36Sopenharmony_ci csk->skb_ulp_lhdr = NULL; 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci cxgbi_skcb_rx_ddigest(lskb) = ntohl(rpl->ulp_crc); 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci if (ntohs(rpl->len) != cxgbi_skcb_rx_pdulen(lskb)) 148962306a36Sopenharmony_ci pr_info("tid 0x%x, RX_DATA_DDP pdulen %u != %u.\n", 149062306a36Sopenharmony_ci csk->tid, ntohs(rpl->len), cxgbi_skcb_rx_pdulen(lskb)); 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci cxgb4i_process_ddpvld(csk, lskb, ddpvld); 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 149562306a36Sopenharmony_ci "csk 0x%p, lskb 0x%p, f 0x%lx.\n", 149662306a36Sopenharmony_ci csk, lskb, cxgbi_skcb_flags(lskb)); 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci cxgbi_skcb_set_flag(lskb, SKCBF_RX_STATUS); 149962306a36Sopenharmony_ci cxgbi_conn_pdu_ready(csk); 150062306a36Sopenharmony_ci spin_unlock_bh(&csk->lock); 150162306a36Sopenharmony_ci goto rel_skb; 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ciabort_conn: 150462306a36Sopenharmony_ci send_abort_req(csk); 150562306a36Sopenharmony_cidiscard: 150662306a36Sopenharmony_ci spin_unlock_bh(&csk->lock); 150762306a36Sopenharmony_cirel_skb: 150862306a36Sopenharmony_ci __kfree_skb(skb); 150962306a36Sopenharmony_ci} 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_cistatic void 151262306a36Sopenharmony_cido_rx_iscsi_cmp(struct cxgbi_device *cdev, struct sk_buff *skb) 151362306a36Sopenharmony_ci{ 151462306a36Sopenharmony_ci struct cxgbi_sock *csk; 151562306a36Sopenharmony_ci struct cpl_rx_iscsi_cmp *rpl = (struct cpl_rx_iscsi_cmp *)skb->data; 151662306a36Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 151762306a36Sopenharmony_ci struct tid_info *t = lldi->tids; 151862306a36Sopenharmony_ci struct sk_buff *data_skb = NULL; 151962306a36Sopenharmony_ci u32 tid = GET_TID(rpl); 152062306a36Sopenharmony_ci u32 ddpvld = be32_to_cpu(rpl->ddpvld); 152162306a36Sopenharmony_ci u32 seq = be32_to_cpu(rpl->seq); 152262306a36Sopenharmony_ci u16 pdu_len_ddp = be16_to_cpu(rpl->pdu_len_ddp); 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci csk = lookup_tid(t, tid); 152562306a36Sopenharmony_ci if (unlikely(!csk)) { 152662306a36Sopenharmony_ci pr_err("can't find connection for tid %u.\n", tid); 152762306a36Sopenharmony_ci goto rel_skb; 152862306a36Sopenharmony_ci } 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, 153162306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx, skb 0x%p,0x%x, lhdr 0x%p, len %u, " 153262306a36Sopenharmony_ci "pdu_len_ddp %u, status %u.\n", 153362306a36Sopenharmony_ci csk, csk->state, csk->flags, skb, ddpvld, csk->skb_ulp_lhdr, 153462306a36Sopenharmony_ci ntohs(rpl->len), pdu_len_ddp, rpl->status); 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci spin_lock_bh(&csk->lock); 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci if (unlikely(csk->state >= CTP_PASSIVE_CLOSE)) { 153962306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 154062306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, bad state.\n", 154162306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci if (csk->state != CTP_ABORTING) 154462306a36Sopenharmony_ci goto abort_conn; 154562306a36Sopenharmony_ci else 154662306a36Sopenharmony_ci goto discard; 154762306a36Sopenharmony_ci } 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci cxgbi_skcb_tcp_seq(skb) = seq; 155062306a36Sopenharmony_ci cxgbi_skcb_flags(skb) = 0; 155162306a36Sopenharmony_ci cxgbi_skcb_rx_pdulen(skb) = 0; 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci skb_reset_transport_header(skb); 155462306a36Sopenharmony_ci __skb_pull(skb, sizeof(*rpl)); 155562306a36Sopenharmony_ci __pskb_trim(skb, be16_to_cpu(rpl->len)); 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci csk->rcv_nxt = seq + pdu_len_ddp; 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci if (csk->skb_ulp_lhdr) { 156062306a36Sopenharmony_ci data_skb = skb_peek(&csk->receive_queue); 156162306a36Sopenharmony_ci if (!data_skb || 156262306a36Sopenharmony_ci !cxgbi_skcb_test_flag(data_skb, SKCBF_RX_DATA)) { 156362306a36Sopenharmony_ci pr_err("Error! freelist data not found 0x%p, tid %u\n", 156462306a36Sopenharmony_ci data_skb, tid); 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci goto abort_conn; 156762306a36Sopenharmony_ci } 156862306a36Sopenharmony_ci __skb_unlink(data_skb, &csk->receive_queue); 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci cxgbi_skcb_set_flag(skb, SKCBF_RX_DATA); 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci __skb_queue_tail(&csk->receive_queue, skb); 157362306a36Sopenharmony_ci __skb_queue_tail(&csk->receive_queue, data_skb); 157462306a36Sopenharmony_ci } else { 157562306a36Sopenharmony_ci __skb_queue_tail(&csk->receive_queue, skb); 157662306a36Sopenharmony_ci } 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci csk->skb_ulp_lhdr = NULL; 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci cxgbi_skcb_set_flag(skb, SKCBF_RX_HDR); 158162306a36Sopenharmony_ci cxgbi_skcb_set_flag(skb, SKCBF_RX_STATUS); 158262306a36Sopenharmony_ci cxgbi_skcb_set_flag(skb, SKCBF_RX_ISCSI_COMPL); 158362306a36Sopenharmony_ci cxgbi_skcb_rx_ddigest(skb) = be32_to_cpu(rpl->ulp_crc); 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci cxgb4i_process_ddpvld(csk, skb, ddpvld); 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, "csk 0x%p, skb 0x%p, f 0x%lx.\n", 158862306a36Sopenharmony_ci csk, skb, cxgbi_skcb_flags(skb)); 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci cxgbi_conn_pdu_ready(csk); 159162306a36Sopenharmony_ci spin_unlock_bh(&csk->lock); 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci return; 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ciabort_conn: 159662306a36Sopenharmony_ci send_abort_req(csk); 159762306a36Sopenharmony_cidiscard: 159862306a36Sopenharmony_ci spin_unlock_bh(&csk->lock); 159962306a36Sopenharmony_cirel_skb: 160062306a36Sopenharmony_ci __kfree_skb(skb); 160162306a36Sopenharmony_ci} 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_cistatic void do_fw4_ack(struct cxgbi_device *cdev, struct sk_buff *skb) 160462306a36Sopenharmony_ci{ 160562306a36Sopenharmony_ci struct cxgbi_sock *csk; 160662306a36Sopenharmony_ci struct cpl_fw4_ack *rpl = (struct cpl_fw4_ack *)skb->data; 160762306a36Sopenharmony_ci unsigned int tid = GET_TID(rpl); 160862306a36Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 160962306a36Sopenharmony_ci struct tid_info *t = lldi->tids; 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci csk = lookup_tid(t, tid); 161262306a36Sopenharmony_ci if (unlikely(!csk)) 161362306a36Sopenharmony_ci pr_err("can't find connection for tid %u.\n", tid); 161462306a36Sopenharmony_ci else { 161562306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 161662306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u.\n", 161762306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 161862306a36Sopenharmony_ci cxgbi_sock_rcv_wr_ack(csk, rpl->credits, ntohl(rpl->snd_una), 161962306a36Sopenharmony_ci rpl->seq_vld); 162062306a36Sopenharmony_ci } 162162306a36Sopenharmony_ci __kfree_skb(skb); 162262306a36Sopenharmony_ci} 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_cistatic void do_set_tcb_rpl(struct cxgbi_device *cdev, struct sk_buff *skb) 162562306a36Sopenharmony_ci{ 162662306a36Sopenharmony_ci struct cpl_set_tcb_rpl *rpl = (struct cpl_set_tcb_rpl *)skb->data; 162762306a36Sopenharmony_ci unsigned int tid = GET_TID(rpl); 162862306a36Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 162962306a36Sopenharmony_ci struct tid_info *t = lldi->tids; 163062306a36Sopenharmony_ci struct cxgbi_sock *csk; 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci csk = lookup_tid(t, tid); 163362306a36Sopenharmony_ci if (!csk) { 163462306a36Sopenharmony_ci pr_err("can't find conn. for tid %u.\n", tid); 163562306a36Sopenharmony_ci return; 163662306a36Sopenharmony_ci } 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 163962306a36Sopenharmony_ci "csk 0x%p,%u,%lx,%u, status 0x%x.\n", 164062306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, rpl->status); 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci if (rpl->status != CPL_ERR_NONE) { 164362306a36Sopenharmony_ci pr_err("csk 0x%p,%u, SET_TCB_RPL status %u.\n", 164462306a36Sopenharmony_ci csk, tid, rpl->status); 164562306a36Sopenharmony_ci csk->err = -EINVAL; 164662306a36Sopenharmony_ci } 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci complete(&csk->cmpl); 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci __kfree_skb(skb); 165162306a36Sopenharmony_ci} 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_cistatic int alloc_cpls(struct cxgbi_sock *csk) 165462306a36Sopenharmony_ci{ 165562306a36Sopenharmony_ci csk->cpl_close = alloc_wr(sizeof(struct cpl_close_con_req), 165662306a36Sopenharmony_ci 0, GFP_KERNEL); 165762306a36Sopenharmony_ci if (!csk->cpl_close) 165862306a36Sopenharmony_ci return -ENOMEM; 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci csk->cpl_abort_req = alloc_wr(sizeof(struct cpl_abort_req), 166162306a36Sopenharmony_ci 0, GFP_KERNEL); 166262306a36Sopenharmony_ci if (!csk->cpl_abort_req) 166362306a36Sopenharmony_ci goto free_cpls; 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci csk->cpl_abort_rpl = alloc_wr(sizeof(struct cpl_abort_rpl), 166662306a36Sopenharmony_ci 0, GFP_KERNEL); 166762306a36Sopenharmony_ci if (!csk->cpl_abort_rpl) 166862306a36Sopenharmony_ci goto free_cpls; 166962306a36Sopenharmony_ci return 0; 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_cifree_cpls: 167262306a36Sopenharmony_ci cxgbi_sock_free_cpl_skbs(csk); 167362306a36Sopenharmony_ci return -ENOMEM; 167462306a36Sopenharmony_ci} 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_cistatic inline void l2t_put(struct cxgbi_sock *csk) 167762306a36Sopenharmony_ci{ 167862306a36Sopenharmony_ci if (csk->l2t) { 167962306a36Sopenharmony_ci cxgb4_l2t_release(csk->l2t); 168062306a36Sopenharmony_ci csk->l2t = NULL; 168162306a36Sopenharmony_ci cxgbi_sock_put(csk); 168262306a36Sopenharmony_ci } 168362306a36Sopenharmony_ci} 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_cistatic void release_offload_resources(struct cxgbi_sock *csk) 168662306a36Sopenharmony_ci{ 168762306a36Sopenharmony_ci struct cxgb4_lld_info *lldi; 168862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 168962306a36Sopenharmony_ci struct net_device *ndev = csk->cdev->ports[csk->port_id]; 169062306a36Sopenharmony_ci#endif 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 169362306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u.\n", 169462306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci cxgbi_sock_free_cpl_skbs(csk); 169762306a36Sopenharmony_ci cxgbi_sock_purge_write_queue(csk); 169862306a36Sopenharmony_ci if (csk->wr_cred != csk->wr_max_cred) { 169962306a36Sopenharmony_ci cxgbi_sock_purge_wr_queue(csk); 170062306a36Sopenharmony_ci cxgbi_sock_reset_wr_list(csk); 170162306a36Sopenharmony_ci } 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci l2t_put(csk); 170462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 170562306a36Sopenharmony_ci if (csk->csk_family == AF_INET6) 170662306a36Sopenharmony_ci cxgb4_clip_release(ndev, 170762306a36Sopenharmony_ci (const u32 *)&csk->saddr6.sin6_addr, 1); 170862306a36Sopenharmony_ci#endif 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ci if (cxgbi_sock_flag(csk, CTPF_HAS_ATID)) 171162306a36Sopenharmony_ci free_atid(csk); 171262306a36Sopenharmony_ci else if (cxgbi_sock_flag(csk, CTPF_HAS_TID)) { 171362306a36Sopenharmony_ci lldi = cxgbi_cdev_priv(csk->cdev); 171462306a36Sopenharmony_ci cxgb4_remove_tid(lldi->tids, 0, csk->tid, 171562306a36Sopenharmony_ci csk->csk_family); 171662306a36Sopenharmony_ci cxgbi_sock_clear_flag(csk, CTPF_HAS_TID); 171762306a36Sopenharmony_ci cxgbi_sock_put(csk); 171862306a36Sopenharmony_ci } 171962306a36Sopenharmony_ci csk->dst = NULL; 172062306a36Sopenharmony_ci} 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 172362306a36Sopenharmony_cistatic inline u8 get_iscsi_dcb_state(struct net_device *ndev) 172462306a36Sopenharmony_ci{ 172562306a36Sopenharmony_ci return ndev->dcbnl_ops->getstate(ndev); 172662306a36Sopenharmony_ci} 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_cistatic int select_priority(int pri_mask) 172962306a36Sopenharmony_ci{ 173062306a36Sopenharmony_ci if (!pri_mask) 173162306a36Sopenharmony_ci return 0; 173262306a36Sopenharmony_ci return (ffs(pri_mask) - 1); 173362306a36Sopenharmony_ci} 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_cistatic u8 get_iscsi_dcb_priority(struct net_device *ndev) 173662306a36Sopenharmony_ci{ 173762306a36Sopenharmony_ci int rv; 173862306a36Sopenharmony_ci u8 caps; 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci struct dcb_app iscsi_dcb_app = { 174162306a36Sopenharmony_ci .protocol = 3260 174262306a36Sopenharmony_ci }; 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci rv = (int)ndev->dcbnl_ops->getcap(ndev, DCB_CAP_ATTR_DCBX, &caps); 174562306a36Sopenharmony_ci if (rv) 174662306a36Sopenharmony_ci return 0; 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci if (caps & DCB_CAP_DCBX_VER_IEEE) { 174962306a36Sopenharmony_ci iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_STREAM; 175062306a36Sopenharmony_ci rv = dcb_ieee_getapp_mask(ndev, &iscsi_dcb_app); 175162306a36Sopenharmony_ci if (!rv) { 175262306a36Sopenharmony_ci iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_ANY; 175362306a36Sopenharmony_ci rv = dcb_ieee_getapp_mask(ndev, &iscsi_dcb_app); 175462306a36Sopenharmony_ci } 175562306a36Sopenharmony_ci } else if (caps & DCB_CAP_DCBX_VER_CEE) { 175662306a36Sopenharmony_ci iscsi_dcb_app.selector = DCB_APP_IDTYPE_PORTNUM; 175762306a36Sopenharmony_ci rv = dcb_getapp(ndev, &iscsi_dcb_app); 175862306a36Sopenharmony_ci } 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 176162306a36Sopenharmony_ci "iSCSI priority is set to %u\n", select_priority(rv)); 176262306a36Sopenharmony_ci return select_priority(rv); 176362306a36Sopenharmony_ci} 176462306a36Sopenharmony_ci#endif 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_cistatic int init_act_open(struct cxgbi_sock *csk) 176762306a36Sopenharmony_ci{ 176862306a36Sopenharmony_ci struct cxgbi_device *cdev = csk->cdev; 176962306a36Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 177062306a36Sopenharmony_ci struct net_device *ndev = cdev->ports[csk->port_id]; 177162306a36Sopenharmony_ci struct sk_buff *skb = NULL; 177262306a36Sopenharmony_ci struct neighbour *n = NULL; 177362306a36Sopenharmony_ci void *daddr; 177462306a36Sopenharmony_ci unsigned int step; 177562306a36Sopenharmony_ci unsigned int rxq_idx; 177662306a36Sopenharmony_ci unsigned int size, size6; 177762306a36Sopenharmony_ci unsigned int linkspeed; 177862306a36Sopenharmony_ci unsigned int rcv_winf, snd_winf; 177962306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 178062306a36Sopenharmony_ci u8 priority = 0; 178162306a36Sopenharmony_ci#endif 178262306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 178362306a36Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u.\n", 178462306a36Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci if (csk->csk_family == AF_INET) 178762306a36Sopenharmony_ci daddr = &csk->daddr.sin_addr.s_addr; 178862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 178962306a36Sopenharmony_ci else if (csk->csk_family == AF_INET6) 179062306a36Sopenharmony_ci daddr = &csk->daddr6.sin6_addr; 179162306a36Sopenharmony_ci#endif 179262306a36Sopenharmony_ci else { 179362306a36Sopenharmony_ci pr_err("address family 0x%x not supported\n", csk->csk_family); 179462306a36Sopenharmony_ci goto rel_resource; 179562306a36Sopenharmony_ci } 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci n = dst_neigh_lookup(csk->dst, daddr); 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci if (!n) { 180062306a36Sopenharmony_ci pr_err("%s, can't get neighbour of csk->dst.\n", ndev->name); 180162306a36Sopenharmony_ci goto rel_resource; 180262306a36Sopenharmony_ci } 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci if (!(n->nud_state & NUD_VALID)) 180562306a36Sopenharmony_ci neigh_event_send(n, NULL); 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci csk->atid = cxgb4_alloc_atid(lldi->tids, csk); 180862306a36Sopenharmony_ci if (csk->atid < 0) { 180962306a36Sopenharmony_ci pr_err("%s, NO atid available.\n", ndev->name); 181062306a36Sopenharmony_ci goto rel_resource_without_clip; 181162306a36Sopenharmony_ci } 181262306a36Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_HAS_ATID); 181362306a36Sopenharmony_ci cxgbi_sock_get(csk); 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 181662306a36Sopenharmony_ci if (get_iscsi_dcb_state(ndev)) 181762306a36Sopenharmony_ci priority = get_iscsi_dcb_priority(ndev); 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_ci csk->dcb_priority = priority; 182062306a36Sopenharmony_ci csk->l2t = cxgb4_l2t_get(lldi->l2t, n, ndev, priority); 182162306a36Sopenharmony_ci#else 182262306a36Sopenharmony_ci csk->l2t = cxgb4_l2t_get(lldi->l2t, n, ndev, 0); 182362306a36Sopenharmony_ci#endif 182462306a36Sopenharmony_ci if (!csk->l2t) { 182562306a36Sopenharmony_ci pr_err("%s, cannot alloc l2t.\n", ndev->name); 182662306a36Sopenharmony_ci goto rel_resource_without_clip; 182762306a36Sopenharmony_ci } 182862306a36Sopenharmony_ci cxgbi_sock_get(csk); 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 183162306a36Sopenharmony_ci if (csk->csk_family == AF_INET6) 183262306a36Sopenharmony_ci cxgb4_clip_get(ndev, (const u32 *)&csk->saddr6.sin6_addr, 1); 183362306a36Sopenharmony_ci#endif 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci if (is_t4(lldi->adapter_type)) { 183662306a36Sopenharmony_ci size = sizeof(struct cpl_act_open_req); 183762306a36Sopenharmony_ci size6 = sizeof(struct cpl_act_open_req6); 183862306a36Sopenharmony_ci } else if (is_t5(lldi->adapter_type)) { 183962306a36Sopenharmony_ci size = sizeof(struct cpl_t5_act_open_req); 184062306a36Sopenharmony_ci size6 = sizeof(struct cpl_t5_act_open_req6); 184162306a36Sopenharmony_ci } else { 184262306a36Sopenharmony_ci size = sizeof(struct cpl_t6_act_open_req); 184362306a36Sopenharmony_ci size6 = sizeof(struct cpl_t6_act_open_req6); 184462306a36Sopenharmony_ci } 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci if (csk->csk_family == AF_INET) 184762306a36Sopenharmony_ci skb = alloc_wr(size, 0, GFP_NOIO); 184862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 184962306a36Sopenharmony_ci else 185062306a36Sopenharmony_ci skb = alloc_wr(size6, 0, GFP_NOIO); 185162306a36Sopenharmony_ci#endif 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ci if (!skb) 185462306a36Sopenharmony_ci goto rel_resource; 185562306a36Sopenharmony_ci skb->sk = (struct sock *)csk; 185662306a36Sopenharmony_ci t4_set_arp_err_handler(skb, csk, cxgbi_sock_act_open_req_arp_failure); 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci if (!csk->mtu) 185962306a36Sopenharmony_ci csk->mtu = dst_mtu(csk->dst); 186062306a36Sopenharmony_ci cxgb4_best_mtu(lldi->mtus, csk->mtu, &csk->mss_idx); 186162306a36Sopenharmony_ci csk->tx_chan = cxgb4_port_chan(ndev); 186262306a36Sopenharmony_ci csk->smac_idx = ((struct port_info *)netdev_priv(ndev))->smt_idx; 186362306a36Sopenharmony_ci step = lldi->ntxq / lldi->nchan; 186462306a36Sopenharmony_ci csk->txq_idx = cxgb4_port_idx(ndev) * step; 186562306a36Sopenharmony_ci step = lldi->nrxq / lldi->nchan; 186662306a36Sopenharmony_ci rxq_idx = (cxgb4_port_idx(ndev) * step) + (cdev->rxq_idx_cntr % step); 186762306a36Sopenharmony_ci cdev->rxq_idx_cntr++; 186862306a36Sopenharmony_ci csk->rss_qid = lldi->rxq_ids[rxq_idx]; 186962306a36Sopenharmony_ci linkspeed = ((struct port_info *)netdev_priv(ndev))->link_cfg.speed; 187062306a36Sopenharmony_ci csk->snd_win = cxgb4i_snd_win; 187162306a36Sopenharmony_ci csk->rcv_win = cxgb4i_rcv_win; 187262306a36Sopenharmony_ci if (cxgb4i_rcv_win <= 0) { 187362306a36Sopenharmony_ci csk->rcv_win = CXGB4I_DEFAULT_10G_RCV_WIN; 187462306a36Sopenharmony_ci rcv_winf = linkspeed / SPEED_10000; 187562306a36Sopenharmony_ci if (rcv_winf) 187662306a36Sopenharmony_ci csk->rcv_win *= rcv_winf; 187762306a36Sopenharmony_ci } 187862306a36Sopenharmony_ci if (cxgb4i_snd_win <= 0) { 187962306a36Sopenharmony_ci csk->snd_win = CXGB4I_DEFAULT_10G_SND_WIN; 188062306a36Sopenharmony_ci snd_winf = linkspeed / SPEED_10000; 188162306a36Sopenharmony_ci if (snd_winf) 188262306a36Sopenharmony_ci csk->snd_win *= snd_winf; 188362306a36Sopenharmony_ci } 188462306a36Sopenharmony_ci csk->wr_cred = lldi->wr_cred - 188562306a36Sopenharmony_ci DIV_ROUND_UP(sizeof(struct cpl_abort_req), 16); 188662306a36Sopenharmony_ci csk->wr_max_cred = csk->wr_cred; 188762306a36Sopenharmony_ci csk->wr_una_cred = 0; 188862306a36Sopenharmony_ci cxgbi_sock_reset_wr_list(csk); 188962306a36Sopenharmony_ci csk->err = 0; 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_ci pr_info_ipaddr("csk 0x%p,%u,0x%lx,%u,%u,%u, mtu %u,%u, smac %u.\n", 189262306a36Sopenharmony_ci (&csk->saddr), (&csk->daddr), csk, csk->state, 189362306a36Sopenharmony_ci csk->flags, csk->tx_chan, csk->txq_idx, csk->rss_qid, 189462306a36Sopenharmony_ci csk->mtu, csk->mss_idx, csk->smac_idx); 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_ci /* must wait for either a act_open_rpl or act_open_establish */ 189762306a36Sopenharmony_ci if (!try_module_get(cdev->owner)) { 189862306a36Sopenharmony_ci pr_err("%s, try_module_get failed.\n", ndev->name); 189962306a36Sopenharmony_ci goto rel_resource; 190062306a36Sopenharmony_ci } 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_ACTIVE_OPEN); 190362306a36Sopenharmony_ci if (csk->csk_family == AF_INET) 190462306a36Sopenharmony_ci send_act_open_req(csk, skb, csk->l2t); 190562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 190662306a36Sopenharmony_ci else 190762306a36Sopenharmony_ci send_act_open_req6(csk, skb, csk->l2t); 190862306a36Sopenharmony_ci#endif 190962306a36Sopenharmony_ci neigh_release(n); 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci return 0; 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_cirel_resource: 191462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 191562306a36Sopenharmony_ci if (csk->csk_family == AF_INET6) 191662306a36Sopenharmony_ci cxgb4_clip_release(ndev, 191762306a36Sopenharmony_ci (const u32 *)&csk->saddr6.sin6_addr, 1); 191862306a36Sopenharmony_ci#endif 191962306a36Sopenharmony_cirel_resource_without_clip: 192062306a36Sopenharmony_ci if (n) 192162306a36Sopenharmony_ci neigh_release(n); 192262306a36Sopenharmony_ci if (skb) 192362306a36Sopenharmony_ci __kfree_skb(skb); 192462306a36Sopenharmony_ci return -EINVAL; 192562306a36Sopenharmony_ci} 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_cistatic cxgb4i_cplhandler_func cxgb4i_cplhandlers[NUM_CPL_CMDS] = { 192862306a36Sopenharmony_ci [CPL_ACT_ESTABLISH] = do_act_establish, 192962306a36Sopenharmony_ci [CPL_ACT_OPEN_RPL] = do_act_open_rpl, 193062306a36Sopenharmony_ci [CPL_PEER_CLOSE] = do_peer_close, 193162306a36Sopenharmony_ci [CPL_ABORT_REQ_RSS] = do_abort_req_rss, 193262306a36Sopenharmony_ci [CPL_ABORT_RPL_RSS] = do_abort_rpl_rss, 193362306a36Sopenharmony_ci [CPL_CLOSE_CON_RPL] = do_close_con_rpl, 193462306a36Sopenharmony_ci [CPL_FW4_ACK] = do_fw4_ack, 193562306a36Sopenharmony_ci [CPL_ISCSI_HDR] = do_rx_iscsi_hdr, 193662306a36Sopenharmony_ci [CPL_ISCSI_DATA] = do_rx_iscsi_data, 193762306a36Sopenharmony_ci [CPL_SET_TCB_RPL] = do_set_tcb_rpl, 193862306a36Sopenharmony_ci [CPL_RX_DATA_DDP] = do_rx_data_ddp, 193962306a36Sopenharmony_ci [CPL_RX_ISCSI_DDP] = do_rx_data_ddp, 194062306a36Sopenharmony_ci [CPL_RX_ISCSI_CMP] = do_rx_iscsi_cmp, 194162306a36Sopenharmony_ci [CPL_RX_DATA] = do_rx_data, 194262306a36Sopenharmony_ci}; 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_cistatic int cxgb4i_ofld_init(struct cxgbi_device *cdev) 194562306a36Sopenharmony_ci{ 194662306a36Sopenharmony_ci int rc; 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci if (cxgb4i_max_connect > CXGB4I_MAX_CONN) 194962306a36Sopenharmony_ci cxgb4i_max_connect = CXGB4I_MAX_CONN; 195062306a36Sopenharmony_ci 195162306a36Sopenharmony_ci rc = cxgbi_device_portmap_create(cdev, cxgb4i_sport_base, 195262306a36Sopenharmony_ci cxgb4i_max_connect); 195362306a36Sopenharmony_ci if (rc < 0) 195462306a36Sopenharmony_ci return rc; 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_ci cdev->csk_release_offload_resources = release_offload_resources; 195762306a36Sopenharmony_ci cdev->csk_push_tx_frames = push_tx_frames; 195862306a36Sopenharmony_ci cdev->csk_send_abort_req = send_abort_req; 195962306a36Sopenharmony_ci cdev->csk_send_close_req = send_close_req; 196062306a36Sopenharmony_ci cdev->csk_send_rx_credits = send_rx_credits; 196162306a36Sopenharmony_ci cdev->csk_alloc_cpls = alloc_cpls; 196262306a36Sopenharmony_ci cdev->csk_init_act_open = init_act_open; 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci pr_info("cdev 0x%p, offload up, added.\n", cdev); 196562306a36Sopenharmony_ci return 0; 196662306a36Sopenharmony_ci} 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_cistatic inline void 196962306a36Sopenharmony_ciulp_mem_io_set_hdr(struct cxgbi_device *cdev, 197062306a36Sopenharmony_ci struct ulp_mem_io *req, 197162306a36Sopenharmony_ci unsigned int wr_len, unsigned int dlen, 197262306a36Sopenharmony_ci unsigned int pm_addr, 197362306a36Sopenharmony_ci int tid) 197462306a36Sopenharmony_ci{ 197562306a36Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 197662306a36Sopenharmony_ci struct ulptx_idata *idata = (struct ulptx_idata *)(req + 1); 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci INIT_ULPTX_WR(req, wr_len, 0, tid); 197962306a36Sopenharmony_ci req->wr.wr_hi = htonl(FW_WR_OP_V(FW_ULPTX_WR) | 198062306a36Sopenharmony_ci FW_WR_ATOMIC_V(0)); 198162306a36Sopenharmony_ci req->cmd = htonl(ULPTX_CMD_V(ULP_TX_MEM_WRITE) | 198262306a36Sopenharmony_ci ULP_MEMIO_ORDER_V(is_t4(lldi->adapter_type)) | 198362306a36Sopenharmony_ci T5_ULP_MEMIO_IMM_V(!is_t4(lldi->adapter_type))); 198462306a36Sopenharmony_ci req->dlen = htonl(ULP_MEMIO_DATA_LEN_V(dlen >> 5)); 198562306a36Sopenharmony_ci req->lock_addr = htonl(ULP_MEMIO_ADDR_V(pm_addr >> 5)); 198662306a36Sopenharmony_ci req->len16 = htonl(DIV_ROUND_UP(wr_len - sizeof(req->wr), 16)); 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_ci idata->cmd_more = htonl(ULPTX_CMD_V(ULP_TX_SC_IMM)); 198962306a36Sopenharmony_ci idata->len = htonl(dlen); 199062306a36Sopenharmony_ci} 199162306a36Sopenharmony_ci 199262306a36Sopenharmony_cistatic struct sk_buff * 199362306a36Sopenharmony_ciddp_ppod_init_idata(struct cxgbi_device *cdev, 199462306a36Sopenharmony_ci struct cxgbi_ppm *ppm, 199562306a36Sopenharmony_ci unsigned int idx, unsigned int npods, 199662306a36Sopenharmony_ci unsigned int tid) 199762306a36Sopenharmony_ci{ 199862306a36Sopenharmony_ci unsigned int pm_addr = (idx << PPOD_SIZE_SHIFT) + ppm->llimit; 199962306a36Sopenharmony_ci unsigned int dlen = npods << PPOD_SIZE_SHIFT; 200062306a36Sopenharmony_ci unsigned int wr_len = roundup(sizeof(struct ulp_mem_io) + 200162306a36Sopenharmony_ci sizeof(struct ulptx_idata) + dlen, 16); 200262306a36Sopenharmony_ci struct sk_buff *skb = alloc_wr(wr_len, 0, GFP_ATOMIC); 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci if (!skb) { 200562306a36Sopenharmony_ci pr_err("%s: %s idx %u, npods %u, OOM.\n", 200662306a36Sopenharmony_ci __func__, ppm->ndev->name, idx, npods); 200762306a36Sopenharmony_ci return NULL; 200862306a36Sopenharmony_ci } 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_ci ulp_mem_io_set_hdr(cdev, (struct ulp_mem_io *)skb->head, wr_len, dlen, 201162306a36Sopenharmony_ci pm_addr, tid); 201262306a36Sopenharmony_ci 201362306a36Sopenharmony_ci return skb; 201462306a36Sopenharmony_ci} 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_cistatic int ddp_ppod_write_idata(struct cxgbi_ppm *ppm, struct cxgbi_sock *csk, 201762306a36Sopenharmony_ci struct cxgbi_task_tag_info *ttinfo, 201862306a36Sopenharmony_ci unsigned int idx, unsigned int npods, 201962306a36Sopenharmony_ci struct scatterlist **sg_pp, 202062306a36Sopenharmony_ci unsigned int *sg_off) 202162306a36Sopenharmony_ci{ 202262306a36Sopenharmony_ci struct cxgbi_device *cdev = csk->cdev; 202362306a36Sopenharmony_ci struct sk_buff *skb = ddp_ppod_init_idata(cdev, ppm, idx, npods, 202462306a36Sopenharmony_ci csk->tid); 202562306a36Sopenharmony_ci struct ulp_mem_io *req; 202662306a36Sopenharmony_ci struct ulptx_idata *idata; 202762306a36Sopenharmony_ci struct cxgbi_pagepod *ppod; 202862306a36Sopenharmony_ci int i; 202962306a36Sopenharmony_ci 203062306a36Sopenharmony_ci if (!skb) 203162306a36Sopenharmony_ci return -ENOMEM; 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_ci req = (struct ulp_mem_io *)skb->head; 203462306a36Sopenharmony_ci idata = (struct ulptx_idata *)(req + 1); 203562306a36Sopenharmony_ci ppod = (struct cxgbi_pagepod *)(idata + 1); 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci for (i = 0; i < npods; i++, ppod++) 203862306a36Sopenharmony_ci cxgbi_ddp_set_one_ppod(ppod, ttinfo, sg_pp, sg_off); 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_ci cxgbi_skcb_set_flag(skb, SKCBF_TX_MEM_WRITE); 204162306a36Sopenharmony_ci cxgbi_skcb_set_flag(skb, SKCBF_TX_FLAG_COMPL); 204262306a36Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_DATA, csk->port_id); 204362306a36Sopenharmony_ci 204462306a36Sopenharmony_ci spin_lock_bh(&csk->lock); 204562306a36Sopenharmony_ci cxgbi_sock_skb_entail(csk, skb); 204662306a36Sopenharmony_ci spin_unlock_bh(&csk->lock); 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci return 0; 204962306a36Sopenharmony_ci} 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_cistatic int ddp_set_map(struct cxgbi_ppm *ppm, struct cxgbi_sock *csk, 205262306a36Sopenharmony_ci struct cxgbi_task_tag_info *ttinfo) 205362306a36Sopenharmony_ci{ 205462306a36Sopenharmony_ci unsigned int pidx = ttinfo->idx; 205562306a36Sopenharmony_ci unsigned int npods = ttinfo->npods; 205662306a36Sopenharmony_ci unsigned int i, cnt; 205762306a36Sopenharmony_ci int err = 0; 205862306a36Sopenharmony_ci struct scatterlist *sg = ttinfo->sgl; 205962306a36Sopenharmony_ci unsigned int offset = 0; 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci ttinfo->cid = csk->port_id; 206262306a36Sopenharmony_ci 206362306a36Sopenharmony_ci for (i = 0; i < npods; i += cnt, pidx += cnt) { 206462306a36Sopenharmony_ci cnt = npods - i; 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci if (cnt > ULPMEM_IDATA_MAX_NPPODS) 206762306a36Sopenharmony_ci cnt = ULPMEM_IDATA_MAX_NPPODS; 206862306a36Sopenharmony_ci err = ddp_ppod_write_idata(ppm, csk, ttinfo, pidx, cnt, 206962306a36Sopenharmony_ci &sg, &offset); 207062306a36Sopenharmony_ci if (err < 0) 207162306a36Sopenharmony_ci break; 207262306a36Sopenharmony_ci } 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_ci return err; 207562306a36Sopenharmony_ci} 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_cistatic int ddp_setup_conn_pgidx(struct cxgbi_sock *csk, unsigned int tid, 207862306a36Sopenharmony_ci int pg_idx) 207962306a36Sopenharmony_ci{ 208062306a36Sopenharmony_ci struct sk_buff *skb; 208162306a36Sopenharmony_ci struct cpl_set_tcb_field *req; 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci if (!pg_idx || pg_idx >= DDP_PGIDX_MAX) 208462306a36Sopenharmony_ci return 0; 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci skb = alloc_wr(sizeof(*req), 0, GFP_KERNEL); 208762306a36Sopenharmony_ci if (!skb) 208862306a36Sopenharmony_ci return -ENOMEM; 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_ci /* set up ulp page size */ 209162306a36Sopenharmony_ci req = (struct cpl_set_tcb_field *)skb->head; 209262306a36Sopenharmony_ci INIT_TP_WR(req, csk->tid); 209362306a36Sopenharmony_ci OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, csk->tid)); 209462306a36Sopenharmony_ci req->reply_ctrl = htons(NO_REPLY_V(0) | QUEUENO_V(csk->rss_qid)); 209562306a36Sopenharmony_ci req->word_cookie = htons(0); 209662306a36Sopenharmony_ci req->mask = cpu_to_be64(0x3 << 8); 209762306a36Sopenharmony_ci req->val = cpu_to_be64(pg_idx << 8); 209862306a36Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_CONTROL, csk->port_id); 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 210162306a36Sopenharmony_ci "csk 0x%p, tid 0x%x, pg_idx %u.\n", csk, csk->tid, pg_idx); 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_ci reinit_completion(&csk->cmpl); 210462306a36Sopenharmony_ci cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); 210562306a36Sopenharmony_ci wait_for_completion(&csk->cmpl); 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci return csk->err; 210862306a36Sopenharmony_ci} 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_cistatic int ddp_setup_conn_digest(struct cxgbi_sock *csk, unsigned int tid, 211162306a36Sopenharmony_ci int hcrc, int dcrc) 211262306a36Sopenharmony_ci{ 211362306a36Sopenharmony_ci struct sk_buff *skb; 211462306a36Sopenharmony_ci struct cpl_set_tcb_field *req; 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci if (!hcrc && !dcrc) 211762306a36Sopenharmony_ci return 0; 211862306a36Sopenharmony_ci 211962306a36Sopenharmony_ci skb = alloc_wr(sizeof(*req), 0, GFP_KERNEL); 212062306a36Sopenharmony_ci if (!skb) 212162306a36Sopenharmony_ci return -ENOMEM; 212262306a36Sopenharmony_ci 212362306a36Sopenharmony_ci csk->hcrc_len = (hcrc ? 4 : 0); 212462306a36Sopenharmony_ci csk->dcrc_len = (dcrc ? 4 : 0); 212562306a36Sopenharmony_ci /* set up ulp submode */ 212662306a36Sopenharmony_ci req = (struct cpl_set_tcb_field *)skb->head; 212762306a36Sopenharmony_ci INIT_TP_WR(req, tid); 212862306a36Sopenharmony_ci OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid)); 212962306a36Sopenharmony_ci req->reply_ctrl = htons(NO_REPLY_V(0) | QUEUENO_V(csk->rss_qid)); 213062306a36Sopenharmony_ci req->word_cookie = htons(0); 213162306a36Sopenharmony_ci req->mask = cpu_to_be64(0x3 << 4); 213262306a36Sopenharmony_ci req->val = cpu_to_be64(((hcrc ? ULP_CRC_HEADER : 0) | 213362306a36Sopenharmony_ci (dcrc ? ULP_CRC_DATA : 0)) << 4); 213462306a36Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_CONTROL, csk->port_id); 213562306a36Sopenharmony_ci 213662306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 213762306a36Sopenharmony_ci "csk 0x%p, tid 0x%x, crc %d,%d.\n", csk, csk->tid, hcrc, dcrc); 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci reinit_completion(&csk->cmpl); 214062306a36Sopenharmony_ci cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); 214162306a36Sopenharmony_ci wait_for_completion(&csk->cmpl); 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_ci return csk->err; 214462306a36Sopenharmony_ci} 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_cistatic struct cxgbi_ppm *cdev2ppm(struct cxgbi_device *cdev) 214762306a36Sopenharmony_ci{ 214862306a36Sopenharmony_ci return (struct cxgbi_ppm *)(*((struct cxgb4_lld_info *) 214962306a36Sopenharmony_ci (cxgbi_cdev_priv(cdev)))->iscsi_ppm); 215062306a36Sopenharmony_ci} 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_cistatic int cxgb4i_ddp_init(struct cxgbi_device *cdev) 215362306a36Sopenharmony_ci{ 215462306a36Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 215562306a36Sopenharmony_ci struct net_device *ndev = cdev->ports[0]; 215662306a36Sopenharmony_ci struct cxgbi_tag_format tformat; 215762306a36Sopenharmony_ci int i, err; 215862306a36Sopenharmony_ci 215962306a36Sopenharmony_ci if (!lldi->vr->iscsi.size) { 216062306a36Sopenharmony_ci pr_warn("%s, iscsi NOT enabled, check config!\n", ndev->name); 216162306a36Sopenharmony_ci return -EACCES; 216262306a36Sopenharmony_ci } 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci cdev->flags |= CXGBI_FLAG_USE_PPOD_OFLDQ; 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_ci memset(&tformat, 0, sizeof(struct cxgbi_tag_format)); 216762306a36Sopenharmony_ci for (i = 0; i < 4; i++) 216862306a36Sopenharmony_ci tformat.pgsz_order[i] = (lldi->iscsi_pgsz_order >> (i << 3)) 216962306a36Sopenharmony_ci & 0xF; 217062306a36Sopenharmony_ci cxgbi_tagmask_check(lldi->iscsi_tagmask, &tformat); 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci pr_info("iscsi_edram.start 0x%x iscsi_edram.size 0x%x", 217362306a36Sopenharmony_ci lldi->vr->ppod_edram.start, lldi->vr->ppod_edram.size); 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_ci err = cxgbi_ddp_ppm_setup(lldi->iscsi_ppm, cdev, &tformat, 217662306a36Sopenharmony_ci lldi->vr->iscsi.size, lldi->iscsi_llimit, 217762306a36Sopenharmony_ci lldi->vr->iscsi.start, 2, 217862306a36Sopenharmony_ci lldi->vr->ppod_edram.start, 217962306a36Sopenharmony_ci lldi->vr->ppod_edram.size); 218062306a36Sopenharmony_ci 218162306a36Sopenharmony_ci if (err < 0) 218262306a36Sopenharmony_ci return err; 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_ci cdev->csk_ddp_setup_digest = ddp_setup_conn_digest; 218562306a36Sopenharmony_ci cdev->csk_ddp_setup_pgidx = ddp_setup_conn_pgidx; 218662306a36Sopenharmony_ci cdev->csk_ddp_set_map = ddp_set_map; 218762306a36Sopenharmony_ci cdev->tx_max_size = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD, 218862306a36Sopenharmony_ci lldi->iscsi_iolen - ISCSI_PDU_NONPAYLOAD_LEN); 218962306a36Sopenharmony_ci cdev->rx_max_size = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD, 219062306a36Sopenharmony_ci lldi->iscsi_iolen - ISCSI_PDU_NONPAYLOAD_LEN); 219162306a36Sopenharmony_ci cdev->cdev2ppm = cdev2ppm; 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_ci return 0; 219462306a36Sopenharmony_ci} 219562306a36Sopenharmony_ci 219662306a36Sopenharmony_cistatic bool is_memfree(struct adapter *adap) 219762306a36Sopenharmony_ci{ 219862306a36Sopenharmony_ci u32 io; 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci io = t4_read_reg(adap, MA_TARGET_MEM_ENABLE_A); 220162306a36Sopenharmony_ci if (is_t5(adap->params.chip)) { 220262306a36Sopenharmony_ci if ((io & EXT_MEM0_ENABLE_F) || (io & EXT_MEM1_ENABLE_F)) 220362306a36Sopenharmony_ci return false; 220462306a36Sopenharmony_ci } else if (io & EXT_MEM_ENABLE_F) { 220562306a36Sopenharmony_ci return false; 220662306a36Sopenharmony_ci } 220762306a36Sopenharmony_ci 220862306a36Sopenharmony_ci return true; 220962306a36Sopenharmony_ci} 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_cistatic void *t4_uld_add(const struct cxgb4_lld_info *lldi) 221262306a36Sopenharmony_ci{ 221362306a36Sopenharmony_ci struct cxgbi_device *cdev; 221462306a36Sopenharmony_ci struct port_info *pi; 221562306a36Sopenharmony_ci struct net_device *ndev; 221662306a36Sopenharmony_ci struct adapter *adap; 221762306a36Sopenharmony_ci struct tid_info *t; 221862306a36Sopenharmony_ci u32 max_cmds = CXGB4I_SCSI_HOST_QDEPTH; 221962306a36Sopenharmony_ci u32 max_conn = CXGBI_MAX_CONN; 222062306a36Sopenharmony_ci int i, rc; 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci cdev = cxgbi_device_register(sizeof(*lldi), lldi->nports); 222362306a36Sopenharmony_ci if (!cdev) { 222462306a36Sopenharmony_ci pr_info("t4 device 0x%p, register failed.\n", lldi); 222562306a36Sopenharmony_ci return NULL; 222662306a36Sopenharmony_ci } 222762306a36Sopenharmony_ci pr_info("0x%p,0x%x, ports %u,%s, chan %u, q %u,%u, wr %u.\n", 222862306a36Sopenharmony_ci cdev, lldi->adapter_type, lldi->nports, 222962306a36Sopenharmony_ci lldi->ports[0]->name, lldi->nchan, lldi->ntxq, 223062306a36Sopenharmony_ci lldi->nrxq, lldi->wr_cred); 223162306a36Sopenharmony_ci for (i = 0; i < lldi->nrxq; i++) 223262306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_DEV, 223362306a36Sopenharmony_ci "t4 0x%p, rxq id #%d: %u.\n", 223462306a36Sopenharmony_ci cdev, i, lldi->rxq_ids[i]); 223562306a36Sopenharmony_ci 223662306a36Sopenharmony_ci memcpy(cxgbi_cdev_priv(cdev), lldi, sizeof(*lldi)); 223762306a36Sopenharmony_ci cdev->flags = CXGBI_FLAG_DEV_T4; 223862306a36Sopenharmony_ci cdev->pdev = lldi->pdev; 223962306a36Sopenharmony_ci cdev->ports = lldi->ports; 224062306a36Sopenharmony_ci cdev->nports = lldi->nports; 224162306a36Sopenharmony_ci cdev->mtus = lldi->mtus; 224262306a36Sopenharmony_ci cdev->nmtus = NMTUS; 224362306a36Sopenharmony_ci cdev->rx_credit_thres = (CHELSIO_CHIP_VERSION(lldi->adapter_type) <= 224462306a36Sopenharmony_ci CHELSIO_T5) ? cxgb4i_rx_credit_thres : 0; 224562306a36Sopenharmony_ci cdev->skb_tx_rsvd = CXGB4I_TX_HEADER_LEN; 224662306a36Sopenharmony_ci cdev->skb_rx_extra = sizeof(struct cpl_iscsi_hdr); 224762306a36Sopenharmony_ci cdev->itp = &cxgb4i_iscsi_transport; 224862306a36Sopenharmony_ci cdev->owner = THIS_MODULE; 224962306a36Sopenharmony_ci 225062306a36Sopenharmony_ci cdev->pfvf = FW_PFVF_CMD_PFN_V(lldi->pf); 225162306a36Sopenharmony_ci pr_info("cdev 0x%p,%s, pfvf %u.\n", 225262306a36Sopenharmony_ci cdev, lldi->ports[0]->name, cdev->pfvf); 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci rc = cxgb4i_ddp_init(cdev); 225562306a36Sopenharmony_ci if (rc) { 225662306a36Sopenharmony_ci pr_info("t4 0x%p ddp init failed %d.\n", cdev, rc); 225762306a36Sopenharmony_ci goto err_out; 225862306a36Sopenharmony_ci } 225962306a36Sopenharmony_ci 226062306a36Sopenharmony_ci ndev = cdev->ports[0]; 226162306a36Sopenharmony_ci adap = netdev2adap(ndev); 226262306a36Sopenharmony_ci if (adap) { 226362306a36Sopenharmony_ci t = &adap->tids; 226462306a36Sopenharmony_ci if (t->ntids <= CXGBI_MAX_CONN) 226562306a36Sopenharmony_ci max_conn = t->ntids; 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_ci if (is_memfree(adap)) { 226862306a36Sopenharmony_ci cdev->flags |= CXGBI_FLAG_DEV_ISO_OFF; 226962306a36Sopenharmony_ci max_cmds = CXGB4I_SCSI_HOST_QDEPTH >> 2; 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci pr_info("%s: 0x%p, tid %u, SO adapter.\n", 227262306a36Sopenharmony_ci ndev->name, cdev, t->ntids); 227362306a36Sopenharmony_ci } 227462306a36Sopenharmony_ci } else { 227562306a36Sopenharmony_ci pr_info("%s, 0x%p, NO adapter struct.\n", ndev->name, cdev); 227662306a36Sopenharmony_ci } 227762306a36Sopenharmony_ci 227862306a36Sopenharmony_ci /* ISO is enabled in T5/T6 firmware version >= 1.13.43.0 */ 227962306a36Sopenharmony_ci if (!is_t4(lldi->adapter_type) && 228062306a36Sopenharmony_ci (lldi->fw_vers >= 0x10d2b00) && 228162306a36Sopenharmony_ci !(cdev->flags & CXGBI_FLAG_DEV_ISO_OFF)) 228262306a36Sopenharmony_ci cdev->skb_iso_txhdr = sizeof(struct cpl_tx_data_iso); 228362306a36Sopenharmony_ci 228462306a36Sopenharmony_ci rc = cxgb4i_ofld_init(cdev); 228562306a36Sopenharmony_ci if (rc) { 228662306a36Sopenharmony_ci pr_info("t4 0x%p ofld init failed.\n", cdev); 228762306a36Sopenharmony_ci goto err_out; 228862306a36Sopenharmony_ci } 228962306a36Sopenharmony_ci 229062306a36Sopenharmony_ci cxgb4i_host_template.can_queue = max_cmds; 229162306a36Sopenharmony_ci rc = cxgbi_hbas_add(cdev, CXGB4I_MAX_LUN, max_conn, 229262306a36Sopenharmony_ci &cxgb4i_host_template, cxgb4i_stt); 229362306a36Sopenharmony_ci if (rc) 229462306a36Sopenharmony_ci goto err_out; 229562306a36Sopenharmony_ci 229662306a36Sopenharmony_ci for (i = 0; i < cdev->nports; i++) { 229762306a36Sopenharmony_ci pi = netdev_priv(lldi->ports[i]); 229862306a36Sopenharmony_ci cdev->hbas[i]->port_id = pi->port_id; 229962306a36Sopenharmony_ci } 230062306a36Sopenharmony_ci return cdev; 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_cierr_out: 230362306a36Sopenharmony_ci cxgbi_device_unregister(cdev); 230462306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 230562306a36Sopenharmony_ci} 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ci#define RX_PULL_LEN 128 230862306a36Sopenharmony_cistatic int t4_uld_rx_handler(void *handle, const __be64 *rsp, 230962306a36Sopenharmony_ci const struct pkt_gl *pgl) 231062306a36Sopenharmony_ci{ 231162306a36Sopenharmony_ci const struct cpl_act_establish *rpl; 231262306a36Sopenharmony_ci struct sk_buff *skb; 231362306a36Sopenharmony_ci unsigned int opc; 231462306a36Sopenharmony_ci struct cxgbi_device *cdev = handle; 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci if (pgl == NULL) { 231762306a36Sopenharmony_ci unsigned int len = 64 - sizeof(struct rsp_ctrl) - 8; 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci skb = alloc_wr(len, 0, GFP_ATOMIC); 232062306a36Sopenharmony_ci if (!skb) 232162306a36Sopenharmony_ci goto nomem; 232262306a36Sopenharmony_ci skb_copy_to_linear_data(skb, &rsp[1], len); 232362306a36Sopenharmony_ci } else { 232462306a36Sopenharmony_ci if (unlikely(*(u8 *)rsp != *(u8 *)pgl->va)) { 232562306a36Sopenharmony_ci pr_info("? FL 0x%p,RSS%#llx,FL %#llx,len %u.\n", 232662306a36Sopenharmony_ci pgl->va, be64_to_cpu(*rsp), 232762306a36Sopenharmony_ci be64_to_cpu(*(u64 *)pgl->va), 232862306a36Sopenharmony_ci pgl->tot_len); 232962306a36Sopenharmony_ci return 0; 233062306a36Sopenharmony_ci } 233162306a36Sopenharmony_ci skb = cxgb4_pktgl_to_skb(pgl, RX_PULL_LEN, RX_PULL_LEN); 233262306a36Sopenharmony_ci if (unlikely(!skb)) 233362306a36Sopenharmony_ci goto nomem; 233462306a36Sopenharmony_ci } 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_ci rpl = (struct cpl_act_establish *)skb->data; 233762306a36Sopenharmony_ci opc = rpl->ot.opcode; 233862306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE, 233962306a36Sopenharmony_ci "cdev %p, opcode 0x%x(0x%x,0x%x), skb %p.\n", 234062306a36Sopenharmony_ci cdev, opc, rpl->ot.opcode_tid, ntohl(rpl->ot.opcode_tid), skb); 234162306a36Sopenharmony_ci if (opc >= ARRAY_SIZE(cxgb4i_cplhandlers) || !cxgb4i_cplhandlers[opc]) { 234262306a36Sopenharmony_ci pr_err("No handler for opcode 0x%x.\n", opc); 234362306a36Sopenharmony_ci __kfree_skb(skb); 234462306a36Sopenharmony_ci } else 234562306a36Sopenharmony_ci cxgb4i_cplhandlers[opc](cdev, skb); 234662306a36Sopenharmony_ci 234762306a36Sopenharmony_ci return 0; 234862306a36Sopenharmony_cinomem: 234962306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE, "OOM bailing out.\n"); 235062306a36Sopenharmony_ci return 1; 235162306a36Sopenharmony_ci} 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_cistatic int t4_uld_state_change(void *handle, enum cxgb4_state state) 235462306a36Sopenharmony_ci{ 235562306a36Sopenharmony_ci struct cxgbi_device *cdev = handle; 235662306a36Sopenharmony_ci 235762306a36Sopenharmony_ci switch (state) { 235862306a36Sopenharmony_ci case CXGB4_STATE_UP: 235962306a36Sopenharmony_ci pr_info("cdev 0x%p, UP.\n", cdev); 236062306a36Sopenharmony_ci break; 236162306a36Sopenharmony_ci case CXGB4_STATE_START_RECOVERY: 236262306a36Sopenharmony_ci pr_info("cdev 0x%p, RECOVERY.\n", cdev); 236362306a36Sopenharmony_ci /* close all connections */ 236462306a36Sopenharmony_ci break; 236562306a36Sopenharmony_ci case CXGB4_STATE_DOWN: 236662306a36Sopenharmony_ci pr_info("cdev 0x%p, DOWN.\n", cdev); 236762306a36Sopenharmony_ci break; 236862306a36Sopenharmony_ci case CXGB4_STATE_DETACH: 236962306a36Sopenharmony_ci pr_info("cdev 0x%p, DETACH.\n", cdev); 237062306a36Sopenharmony_ci cxgbi_device_unregister(cdev); 237162306a36Sopenharmony_ci break; 237262306a36Sopenharmony_ci default: 237362306a36Sopenharmony_ci pr_info("cdev 0x%p, unknown state %d.\n", cdev, state); 237462306a36Sopenharmony_ci break; 237562306a36Sopenharmony_ci } 237662306a36Sopenharmony_ci return 0; 237762306a36Sopenharmony_ci} 237862306a36Sopenharmony_ci 237962306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 238062306a36Sopenharmony_cistatic int 238162306a36Sopenharmony_cicxgb4_dcb_change_notify(struct notifier_block *self, unsigned long val, 238262306a36Sopenharmony_ci void *data) 238362306a36Sopenharmony_ci{ 238462306a36Sopenharmony_ci int i, port = 0xFF; 238562306a36Sopenharmony_ci struct net_device *ndev; 238662306a36Sopenharmony_ci struct cxgbi_device *cdev = NULL; 238762306a36Sopenharmony_ci struct dcb_app_type *iscsi_app = data; 238862306a36Sopenharmony_ci struct cxgbi_ports_map *pmap; 238962306a36Sopenharmony_ci u8 priority; 239062306a36Sopenharmony_ci 239162306a36Sopenharmony_ci if (iscsi_app->dcbx & DCB_CAP_DCBX_VER_IEEE) { 239262306a36Sopenharmony_ci if ((iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_STREAM) && 239362306a36Sopenharmony_ci (iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_ANY)) 239462306a36Sopenharmony_ci return NOTIFY_DONE; 239562306a36Sopenharmony_ci 239662306a36Sopenharmony_ci priority = iscsi_app->app.priority; 239762306a36Sopenharmony_ci } else if (iscsi_app->dcbx & DCB_CAP_DCBX_VER_CEE) { 239862306a36Sopenharmony_ci if (iscsi_app->app.selector != DCB_APP_IDTYPE_PORTNUM) 239962306a36Sopenharmony_ci return NOTIFY_DONE; 240062306a36Sopenharmony_ci 240162306a36Sopenharmony_ci if (!iscsi_app->app.priority) 240262306a36Sopenharmony_ci return NOTIFY_DONE; 240362306a36Sopenharmony_ci 240462306a36Sopenharmony_ci priority = ffs(iscsi_app->app.priority) - 1; 240562306a36Sopenharmony_ci } else { 240662306a36Sopenharmony_ci return NOTIFY_DONE; 240762306a36Sopenharmony_ci } 240862306a36Sopenharmony_ci 240962306a36Sopenharmony_ci if (iscsi_app->app.protocol != 3260) 241062306a36Sopenharmony_ci return NOTIFY_DONE; 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, "iSCSI priority for ifid %d is %u\n", 241362306a36Sopenharmony_ci iscsi_app->ifindex, priority); 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_ci ndev = dev_get_by_index(&init_net, iscsi_app->ifindex); 241662306a36Sopenharmony_ci if (!ndev) 241762306a36Sopenharmony_ci return NOTIFY_DONE; 241862306a36Sopenharmony_ci 241962306a36Sopenharmony_ci cdev = cxgbi_device_find_by_netdev_rcu(ndev, &port); 242062306a36Sopenharmony_ci 242162306a36Sopenharmony_ci dev_put(ndev); 242262306a36Sopenharmony_ci if (!cdev) 242362306a36Sopenharmony_ci return NOTIFY_DONE; 242462306a36Sopenharmony_ci 242562306a36Sopenharmony_ci pmap = &cdev->pmap; 242662306a36Sopenharmony_ci 242762306a36Sopenharmony_ci for (i = 0; i < pmap->used; i++) { 242862306a36Sopenharmony_ci if (pmap->port_csk[i]) { 242962306a36Sopenharmony_ci struct cxgbi_sock *csk = pmap->port_csk[i]; 243062306a36Sopenharmony_ci 243162306a36Sopenharmony_ci if (csk->dcb_priority != priority) { 243262306a36Sopenharmony_ci iscsi_conn_failure(csk->user_data, 243362306a36Sopenharmony_ci ISCSI_ERR_CONN_FAILED); 243462306a36Sopenharmony_ci pr_info("Restarting iSCSI connection %p with " 243562306a36Sopenharmony_ci "priority %u->%u.\n", csk, 243662306a36Sopenharmony_ci csk->dcb_priority, priority); 243762306a36Sopenharmony_ci } 243862306a36Sopenharmony_ci } 243962306a36Sopenharmony_ci } 244062306a36Sopenharmony_ci return NOTIFY_OK; 244162306a36Sopenharmony_ci} 244262306a36Sopenharmony_ci#endif 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_cistatic int __init cxgb4i_init_module(void) 244562306a36Sopenharmony_ci{ 244662306a36Sopenharmony_ci int rc; 244762306a36Sopenharmony_ci 244862306a36Sopenharmony_ci printk(KERN_INFO "%s", version); 244962306a36Sopenharmony_ci 245062306a36Sopenharmony_ci rc = cxgbi_iscsi_init(&cxgb4i_iscsi_transport, &cxgb4i_stt); 245162306a36Sopenharmony_ci if (rc < 0) 245262306a36Sopenharmony_ci return rc; 245362306a36Sopenharmony_ci cxgb4_register_uld(CXGB4_ULD_ISCSI, &cxgb4i_uld_info); 245462306a36Sopenharmony_ci 245562306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 245662306a36Sopenharmony_ci pr_info("%s dcb enabled.\n", DRV_MODULE_NAME); 245762306a36Sopenharmony_ci register_dcbevent_notifier(&cxgb4_dcb_change); 245862306a36Sopenharmony_ci#endif 245962306a36Sopenharmony_ci return 0; 246062306a36Sopenharmony_ci} 246162306a36Sopenharmony_ci 246262306a36Sopenharmony_cistatic void __exit cxgb4i_exit_module(void) 246362306a36Sopenharmony_ci{ 246462306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 246562306a36Sopenharmony_ci unregister_dcbevent_notifier(&cxgb4_dcb_change); 246662306a36Sopenharmony_ci#endif 246762306a36Sopenharmony_ci cxgb4_unregister_uld(CXGB4_ULD_ISCSI); 246862306a36Sopenharmony_ci cxgbi_device_unregister_all(CXGBI_FLAG_DEV_T4); 246962306a36Sopenharmony_ci cxgbi_iscsi_cleanup(&cxgb4i_iscsi_transport, &cxgb4i_stt); 247062306a36Sopenharmony_ci} 247162306a36Sopenharmony_ci 247262306a36Sopenharmony_cimodule_init(cxgb4i_init_module); 247362306a36Sopenharmony_cimodule_exit(cxgb4i_exit_module); 2474