18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * cxgb4i.c: Chelsio T4 iSCSI driver. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2010-2015 Chelsio Communications, Inc. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 78c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 88c2ecf20Sopenharmony_ci * the Free Software Foundation. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Written by: Karen Xie (kxie@chelsio.com) 118c2ecf20Sopenharmony_ci * Rakesh Ranjan (rranjan@chelsio.com) 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/kernel.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 198c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 208c2ecf20Sopenharmony_ci#include <net/tcp.h> 218c2ecf20Sopenharmony_ci#include <net/dst.h> 228c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 238c2ecf20Sopenharmony_ci#include <net/addrconf.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "t4_regs.h" 268c2ecf20Sopenharmony_ci#include "t4_msg.h" 278c2ecf20Sopenharmony_ci#include "cxgb4.h" 288c2ecf20Sopenharmony_ci#include "cxgb4_uld.h" 298c2ecf20Sopenharmony_ci#include "t4fw_api.h" 308c2ecf20Sopenharmony_ci#include "l2t.h" 318c2ecf20Sopenharmony_ci#include "cxgb4i.h" 328c2ecf20Sopenharmony_ci#include "clip_tbl.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic unsigned int dbg_level; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include "../libcxgbi.h" 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 398c2ecf20Sopenharmony_ci#include <net/dcbevent.h> 408c2ecf20Sopenharmony_ci#include "cxgb4_dcb.h" 418c2ecf20Sopenharmony_ci#endif 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define DRV_MODULE_NAME "cxgb4i" 448c2ecf20Sopenharmony_ci#define DRV_MODULE_DESC "Chelsio T4-T6 iSCSI Driver" 458c2ecf20Sopenharmony_ci#define DRV_MODULE_VERSION "0.9.5-ko" 468c2ecf20Sopenharmony_ci#define DRV_MODULE_RELDATE "Apr. 2015" 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic char version[] = 498c2ecf20Sopenharmony_ci DRV_MODULE_DESC " " DRV_MODULE_NAME 508c2ecf20Sopenharmony_ci " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ciMODULE_AUTHOR("Chelsio Communications, Inc."); 538c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRV_MODULE_DESC); 548c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_MODULE_VERSION); 558c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cimodule_param(dbg_level, uint, 0644); 588c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dbg_level, "Debug flag (default=0)"); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define CXGB4I_DEFAULT_10G_RCV_WIN (256 * 1024) 618c2ecf20Sopenharmony_cistatic int cxgb4i_rcv_win = -1; 628c2ecf20Sopenharmony_cimodule_param(cxgb4i_rcv_win, int, 0644); 638c2ecf20Sopenharmony_ciMODULE_PARM_DESC(cxgb4i_rcv_win, "TCP receive window in bytes"); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define CXGB4I_DEFAULT_10G_SND_WIN (128 * 1024) 668c2ecf20Sopenharmony_cistatic int cxgb4i_snd_win = -1; 678c2ecf20Sopenharmony_cimodule_param(cxgb4i_snd_win, int, 0644); 688c2ecf20Sopenharmony_ciMODULE_PARM_DESC(cxgb4i_snd_win, "TCP send window in bytes"); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic int cxgb4i_rx_credit_thres = 10 * 1024; 718c2ecf20Sopenharmony_cimodule_param(cxgb4i_rx_credit_thres, int, 0644); 728c2ecf20Sopenharmony_ciMODULE_PARM_DESC(cxgb4i_rx_credit_thres, 738c2ecf20Sopenharmony_ci "RX credits return threshold in bytes (default=10KB)"); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic unsigned int cxgb4i_max_connect = (8 * 1024); 768c2ecf20Sopenharmony_cimodule_param(cxgb4i_max_connect, uint, 0644); 778c2ecf20Sopenharmony_ciMODULE_PARM_DESC(cxgb4i_max_connect, "Maximum number of connections"); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic unsigned short cxgb4i_sport_base = 20000; 808c2ecf20Sopenharmony_cimodule_param(cxgb4i_sport_base, ushort, 0644); 818c2ecf20Sopenharmony_ciMODULE_PARM_DESC(cxgb4i_sport_base, "Starting port number (default 20000)"); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_citypedef void (*cxgb4i_cplhandler_func)(struct cxgbi_device *, struct sk_buff *); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic void *t4_uld_add(const struct cxgb4_lld_info *); 868c2ecf20Sopenharmony_cistatic int t4_uld_rx_handler(void *, const __be64 *, const struct pkt_gl *); 878c2ecf20Sopenharmony_cistatic int t4_uld_state_change(void *, enum cxgb4_state state); 888c2ecf20Sopenharmony_cistatic inline int send_tx_flowc_wr(struct cxgbi_sock *); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic const struct cxgb4_uld_info cxgb4i_uld_info = { 918c2ecf20Sopenharmony_ci .name = DRV_MODULE_NAME, 928c2ecf20Sopenharmony_ci .nrxq = MAX_ULD_QSETS, 938c2ecf20Sopenharmony_ci .ntxq = MAX_ULD_QSETS, 948c2ecf20Sopenharmony_ci .rxq_size = 1024, 958c2ecf20Sopenharmony_ci .lro = false, 968c2ecf20Sopenharmony_ci .add = t4_uld_add, 978c2ecf20Sopenharmony_ci .rx_handler = t4_uld_rx_handler, 988c2ecf20Sopenharmony_ci .state_change = t4_uld_state_change, 998c2ecf20Sopenharmony_ci}; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic struct scsi_host_template cxgb4i_host_template = { 1028c2ecf20Sopenharmony_ci .module = THIS_MODULE, 1038c2ecf20Sopenharmony_ci .name = DRV_MODULE_NAME, 1048c2ecf20Sopenharmony_ci .proc_name = DRV_MODULE_NAME, 1058c2ecf20Sopenharmony_ci .can_queue = CXGB4I_SCSI_HOST_QDEPTH, 1068c2ecf20Sopenharmony_ci .queuecommand = iscsi_queuecommand, 1078c2ecf20Sopenharmony_ci .change_queue_depth = scsi_change_queue_depth, 1088c2ecf20Sopenharmony_ci .sg_tablesize = SG_ALL, 1098c2ecf20Sopenharmony_ci .max_sectors = 0xFFFF, 1108c2ecf20Sopenharmony_ci .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN, 1118c2ecf20Sopenharmony_ci .eh_timed_out = iscsi_eh_cmd_timed_out, 1128c2ecf20Sopenharmony_ci .eh_abort_handler = iscsi_eh_abort, 1138c2ecf20Sopenharmony_ci .eh_device_reset_handler = iscsi_eh_device_reset, 1148c2ecf20Sopenharmony_ci .eh_target_reset_handler = iscsi_eh_recover_target, 1158c2ecf20Sopenharmony_ci .target_alloc = iscsi_target_alloc, 1168c2ecf20Sopenharmony_ci .dma_boundary = PAGE_SIZE - 1, 1178c2ecf20Sopenharmony_ci .this_id = -1, 1188c2ecf20Sopenharmony_ci .track_queue_depth = 1, 1198c2ecf20Sopenharmony_ci}; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic struct iscsi_transport cxgb4i_iscsi_transport = { 1228c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1238c2ecf20Sopenharmony_ci .name = DRV_MODULE_NAME, 1248c2ecf20Sopenharmony_ci .caps = CAP_RECOVERY_L0 | CAP_MULTI_R2T | CAP_HDRDGST | 1258c2ecf20Sopenharmony_ci CAP_DATADGST | CAP_DIGEST_OFFLOAD | 1268c2ecf20Sopenharmony_ci CAP_PADDING_OFFLOAD | CAP_TEXT_NEGO, 1278c2ecf20Sopenharmony_ci .attr_is_visible = cxgbi_attr_is_visible, 1288c2ecf20Sopenharmony_ci .get_host_param = cxgbi_get_host_param, 1298c2ecf20Sopenharmony_ci .set_host_param = cxgbi_set_host_param, 1308c2ecf20Sopenharmony_ci /* session management */ 1318c2ecf20Sopenharmony_ci .create_session = cxgbi_create_session, 1328c2ecf20Sopenharmony_ci .destroy_session = cxgbi_destroy_session, 1338c2ecf20Sopenharmony_ci .get_session_param = iscsi_session_get_param, 1348c2ecf20Sopenharmony_ci /* connection management */ 1358c2ecf20Sopenharmony_ci .create_conn = cxgbi_create_conn, 1368c2ecf20Sopenharmony_ci .bind_conn = cxgbi_bind_conn, 1378c2ecf20Sopenharmony_ci .unbind_conn = iscsi_conn_unbind, 1388c2ecf20Sopenharmony_ci .destroy_conn = iscsi_tcp_conn_teardown, 1398c2ecf20Sopenharmony_ci .start_conn = iscsi_conn_start, 1408c2ecf20Sopenharmony_ci .stop_conn = iscsi_conn_stop, 1418c2ecf20Sopenharmony_ci .get_conn_param = iscsi_conn_get_param, 1428c2ecf20Sopenharmony_ci .set_param = cxgbi_set_conn_param, 1438c2ecf20Sopenharmony_ci .get_stats = cxgbi_get_conn_stats, 1448c2ecf20Sopenharmony_ci /* pdu xmit req from user space */ 1458c2ecf20Sopenharmony_ci .send_pdu = iscsi_conn_send_pdu, 1468c2ecf20Sopenharmony_ci /* task */ 1478c2ecf20Sopenharmony_ci .init_task = iscsi_tcp_task_init, 1488c2ecf20Sopenharmony_ci .xmit_task = iscsi_tcp_task_xmit, 1498c2ecf20Sopenharmony_ci .cleanup_task = cxgbi_cleanup_task, 1508c2ecf20Sopenharmony_ci /* pdu */ 1518c2ecf20Sopenharmony_ci .alloc_pdu = cxgbi_conn_alloc_pdu, 1528c2ecf20Sopenharmony_ci .init_pdu = cxgbi_conn_init_pdu, 1538c2ecf20Sopenharmony_ci .xmit_pdu = cxgbi_conn_xmit_pdu, 1548c2ecf20Sopenharmony_ci .parse_pdu_itt = cxgbi_parse_pdu_itt, 1558c2ecf20Sopenharmony_ci /* TCP connect/disconnect */ 1568c2ecf20Sopenharmony_ci .get_ep_param = cxgbi_get_ep_param, 1578c2ecf20Sopenharmony_ci .ep_connect = cxgbi_ep_connect, 1588c2ecf20Sopenharmony_ci .ep_poll = cxgbi_ep_poll, 1598c2ecf20Sopenharmony_ci .ep_disconnect = cxgbi_ep_disconnect, 1608c2ecf20Sopenharmony_ci /* Error recovery timeout call */ 1618c2ecf20Sopenharmony_ci .session_recovery_timedout = iscsi_session_recovery_timedout, 1628c2ecf20Sopenharmony_ci}; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 1658c2ecf20Sopenharmony_cistatic int 1668c2ecf20Sopenharmony_cicxgb4_dcb_change_notify(struct notifier_block *, unsigned long, void *); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic struct notifier_block cxgb4_dcb_change = { 1698c2ecf20Sopenharmony_ci .notifier_call = cxgb4_dcb_change_notify, 1708c2ecf20Sopenharmony_ci}; 1718c2ecf20Sopenharmony_ci#endif 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic struct scsi_transport_template *cxgb4i_stt; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/* 1768c2ecf20Sopenharmony_ci * CPL (Chelsio Protocol Language) defines a message passing interface between 1778c2ecf20Sopenharmony_ci * the host driver and Chelsio asic. 1788c2ecf20Sopenharmony_ci * The section below implments CPLs that related to iscsi tcp connection 1798c2ecf20Sopenharmony_ci * open/close/abort and data send/receive. 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci#define RCV_BUFSIZ_MASK 0x3FFU 1838c2ecf20Sopenharmony_ci#define MAX_IMM_TX_PKT_LEN 256 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic int push_tx_frames(struct cxgbi_sock *, int); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci/* 1888c2ecf20Sopenharmony_ci * is_ofld_imm - check whether a packet can be sent as immediate data 1898c2ecf20Sopenharmony_ci * @skb: the packet 1908c2ecf20Sopenharmony_ci * 1918c2ecf20Sopenharmony_ci * Returns true if a packet can be sent as an offload WR with immediate 1928c2ecf20Sopenharmony_ci * data. We currently use the same limit as for Ethernet packets. 1938c2ecf20Sopenharmony_ci */ 1948c2ecf20Sopenharmony_cistatic inline bool is_ofld_imm(const struct sk_buff *skb) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci int len = skb->len; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (likely(cxgbi_skcb_test_flag(skb, SKCBF_TX_NEED_HDR))) 1998c2ecf20Sopenharmony_ci len += sizeof(struct fw_ofld_tx_data_wr); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (likely(cxgbi_skcb_test_flag((struct sk_buff *)skb, SKCBF_TX_ISO))) 2028c2ecf20Sopenharmony_ci len += sizeof(struct cpl_tx_data_iso); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci return (len <= MAX_IMM_OFLD_TX_DATA_WR_LEN); 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic void send_act_open_req(struct cxgbi_sock *csk, struct sk_buff *skb, 2088c2ecf20Sopenharmony_ci struct l2t_entry *e) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(csk->cdev); 2118c2ecf20Sopenharmony_ci int wscale = cxgbi_sock_compute_wscale(csk->mss_idx); 2128c2ecf20Sopenharmony_ci unsigned long long opt0; 2138c2ecf20Sopenharmony_ci unsigned int opt2; 2148c2ecf20Sopenharmony_ci unsigned int qid_atid = ((unsigned int)csk->atid) | 2158c2ecf20Sopenharmony_ci (((unsigned int)csk->rss_qid) << 14); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci opt0 = KEEP_ALIVE_F | 2188c2ecf20Sopenharmony_ci WND_SCALE_V(wscale) | 2198c2ecf20Sopenharmony_ci MSS_IDX_V(csk->mss_idx) | 2208c2ecf20Sopenharmony_ci L2T_IDX_V(((struct l2t_entry *)csk->l2t)->idx) | 2218c2ecf20Sopenharmony_ci TX_CHAN_V(csk->tx_chan) | 2228c2ecf20Sopenharmony_ci SMAC_SEL_V(csk->smac_idx) | 2238c2ecf20Sopenharmony_ci ULP_MODE_V(ULP_MODE_ISCSI) | 2248c2ecf20Sopenharmony_ci RCV_BUFSIZ_V(csk->rcv_win >> 10); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci opt2 = RX_CHANNEL_V(0) | 2278c2ecf20Sopenharmony_ci RSS_QUEUE_VALID_F | 2288c2ecf20Sopenharmony_ci RSS_QUEUE_V(csk->rss_qid); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (is_t4(lldi->adapter_type)) { 2318c2ecf20Sopenharmony_ci struct cpl_act_open_req *req = 2328c2ecf20Sopenharmony_ci (struct cpl_act_open_req *)skb->head; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci INIT_TP_WR(req, 0); 2358c2ecf20Sopenharmony_ci OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, 2368c2ecf20Sopenharmony_ci qid_atid)); 2378c2ecf20Sopenharmony_ci req->local_port = csk->saddr.sin_port; 2388c2ecf20Sopenharmony_ci req->peer_port = csk->daddr.sin_port; 2398c2ecf20Sopenharmony_ci req->local_ip = csk->saddr.sin_addr.s_addr; 2408c2ecf20Sopenharmony_ci req->peer_ip = csk->daddr.sin_addr.s_addr; 2418c2ecf20Sopenharmony_ci req->opt0 = cpu_to_be64(opt0); 2428c2ecf20Sopenharmony_ci req->params = cpu_to_be32(cxgb4_select_ntuple( 2438c2ecf20Sopenharmony_ci csk->cdev->ports[csk->port_id], 2448c2ecf20Sopenharmony_ci csk->l2t)); 2458c2ecf20Sopenharmony_ci opt2 |= RX_FC_VALID_F; 2468c2ecf20Sopenharmony_ci req->opt2 = cpu_to_be32(opt2); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 2498c2ecf20Sopenharmony_ci "csk t4 0x%p, %pI4:%u-%pI4:%u, atid %d, qid %u.\n", 2508c2ecf20Sopenharmony_ci csk, &req->local_ip, ntohs(req->local_port), 2518c2ecf20Sopenharmony_ci &req->peer_ip, ntohs(req->peer_port), 2528c2ecf20Sopenharmony_ci csk->atid, csk->rss_qid); 2538c2ecf20Sopenharmony_ci } else if (is_t5(lldi->adapter_type)) { 2548c2ecf20Sopenharmony_ci struct cpl_t5_act_open_req *req = 2558c2ecf20Sopenharmony_ci (struct cpl_t5_act_open_req *)skb->head; 2568c2ecf20Sopenharmony_ci u32 isn = (prandom_u32() & ~7UL) - 1; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci INIT_TP_WR(req, 0); 2598c2ecf20Sopenharmony_ci OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, 2608c2ecf20Sopenharmony_ci qid_atid)); 2618c2ecf20Sopenharmony_ci req->local_port = csk->saddr.sin_port; 2628c2ecf20Sopenharmony_ci req->peer_port = csk->daddr.sin_port; 2638c2ecf20Sopenharmony_ci req->local_ip = csk->saddr.sin_addr.s_addr; 2648c2ecf20Sopenharmony_ci req->peer_ip = csk->daddr.sin_addr.s_addr; 2658c2ecf20Sopenharmony_ci req->opt0 = cpu_to_be64(opt0); 2668c2ecf20Sopenharmony_ci req->params = cpu_to_be64(FILTER_TUPLE_V( 2678c2ecf20Sopenharmony_ci cxgb4_select_ntuple( 2688c2ecf20Sopenharmony_ci csk->cdev->ports[csk->port_id], 2698c2ecf20Sopenharmony_ci csk->l2t))); 2708c2ecf20Sopenharmony_ci req->rsvd = cpu_to_be32(isn); 2718c2ecf20Sopenharmony_ci opt2 |= T5_ISS_VALID; 2728c2ecf20Sopenharmony_ci opt2 |= T5_OPT_2_VALID_F; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci req->opt2 = cpu_to_be32(opt2); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 2778c2ecf20Sopenharmony_ci "csk t5 0x%p, %pI4:%u-%pI4:%u, atid %d, qid %u.\n", 2788c2ecf20Sopenharmony_ci csk, &req->local_ip, ntohs(req->local_port), 2798c2ecf20Sopenharmony_ci &req->peer_ip, ntohs(req->peer_port), 2808c2ecf20Sopenharmony_ci csk->atid, csk->rss_qid); 2818c2ecf20Sopenharmony_ci } else { 2828c2ecf20Sopenharmony_ci struct cpl_t6_act_open_req *req = 2838c2ecf20Sopenharmony_ci (struct cpl_t6_act_open_req *)skb->head; 2848c2ecf20Sopenharmony_ci u32 isn = (prandom_u32() & ~7UL) - 1; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci INIT_TP_WR(req, 0); 2878c2ecf20Sopenharmony_ci OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, 2888c2ecf20Sopenharmony_ci qid_atid)); 2898c2ecf20Sopenharmony_ci req->local_port = csk->saddr.sin_port; 2908c2ecf20Sopenharmony_ci req->peer_port = csk->daddr.sin_port; 2918c2ecf20Sopenharmony_ci req->local_ip = csk->saddr.sin_addr.s_addr; 2928c2ecf20Sopenharmony_ci req->peer_ip = csk->daddr.sin_addr.s_addr; 2938c2ecf20Sopenharmony_ci req->opt0 = cpu_to_be64(opt0); 2948c2ecf20Sopenharmony_ci req->params = cpu_to_be64(FILTER_TUPLE_V( 2958c2ecf20Sopenharmony_ci cxgb4_select_ntuple( 2968c2ecf20Sopenharmony_ci csk->cdev->ports[csk->port_id], 2978c2ecf20Sopenharmony_ci csk->l2t))); 2988c2ecf20Sopenharmony_ci req->rsvd = cpu_to_be32(isn); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci opt2 |= T5_ISS_VALID; 3018c2ecf20Sopenharmony_ci opt2 |= RX_FC_DISABLE_F; 3028c2ecf20Sopenharmony_ci opt2 |= T5_OPT_2_VALID_F; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci req->opt2 = cpu_to_be32(opt2); 3058c2ecf20Sopenharmony_ci req->rsvd2 = cpu_to_be32(0); 3068c2ecf20Sopenharmony_ci req->opt3 = cpu_to_be32(0); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 3098c2ecf20Sopenharmony_ci "csk t6 0x%p, %pI4:%u-%pI4:%u, atid %d, qid %u.\n", 3108c2ecf20Sopenharmony_ci csk, &req->local_ip, ntohs(req->local_port), 3118c2ecf20Sopenharmony_ci &req->peer_ip, ntohs(req->peer_port), 3128c2ecf20Sopenharmony_ci csk->atid, csk->rss_qid); 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_SETUP, csk->port_id); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci pr_info_ipaddr("t%d csk 0x%p,%u,0x%lx,%u, rss_qid %u.\n", 3188c2ecf20Sopenharmony_ci (&csk->saddr), (&csk->daddr), 3198c2ecf20Sopenharmony_ci CHELSIO_CHIP_VERSION(lldi->adapter_type), csk, 3208c2ecf20Sopenharmony_ci csk->state, csk->flags, csk->atid, csk->rss_qid); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci cxgb4_l2t_send(csk->cdev->ports[csk->port_id], skb, csk->l2t); 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 3268c2ecf20Sopenharmony_cistatic void send_act_open_req6(struct cxgbi_sock *csk, struct sk_buff *skb, 3278c2ecf20Sopenharmony_ci struct l2t_entry *e) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(csk->cdev); 3308c2ecf20Sopenharmony_ci int wscale = cxgbi_sock_compute_wscale(csk->mss_idx); 3318c2ecf20Sopenharmony_ci unsigned long long opt0; 3328c2ecf20Sopenharmony_ci unsigned int opt2; 3338c2ecf20Sopenharmony_ci unsigned int qid_atid = ((unsigned int)csk->atid) | 3348c2ecf20Sopenharmony_ci (((unsigned int)csk->rss_qid) << 14); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci opt0 = KEEP_ALIVE_F | 3378c2ecf20Sopenharmony_ci WND_SCALE_V(wscale) | 3388c2ecf20Sopenharmony_ci MSS_IDX_V(csk->mss_idx) | 3398c2ecf20Sopenharmony_ci L2T_IDX_V(((struct l2t_entry *)csk->l2t)->idx) | 3408c2ecf20Sopenharmony_ci TX_CHAN_V(csk->tx_chan) | 3418c2ecf20Sopenharmony_ci SMAC_SEL_V(csk->smac_idx) | 3428c2ecf20Sopenharmony_ci ULP_MODE_V(ULP_MODE_ISCSI) | 3438c2ecf20Sopenharmony_ci RCV_BUFSIZ_V(csk->rcv_win >> 10); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci opt2 = RX_CHANNEL_V(0) | 3468c2ecf20Sopenharmony_ci RSS_QUEUE_VALID_F | 3478c2ecf20Sopenharmony_ci RSS_QUEUE_V(csk->rss_qid); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (is_t4(lldi->adapter_type)) { 3508c2ecf20Sopenharmony_ci struct cpl_act_open_req6 *req = 3518c2ecf20Sopenharmony_ci (struct cpl_act_open_req6 *)skb->head; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci INIT_TP_WR(req, 0); 3548c2ecf20Sopenharmony_ci OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ6, 3558c2ecf20Sopenharmony_ci qid_atid)); 3568c2ecf20Sopenharmony_ci req->local_port = csk->saddr6.sin6_port; 3578c2ecf20Sopenharmony_ci req->peer_port = csk->daddr6.sin6_port; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci req->local_ip_hi = *(__be64 *)(csk->saddr6.sin6_addr.s6_addr); 3608c2ecf20Sopenharmony_ci req->local_ip_lo = *(__be64 *)(csk->saddr6.sin6_addr.s6_addr + 3618c2ecf20Sopenharmony_ci 8); 3628c2ecf20Sopenharmony_ci req->peer_ip_hi = *(__be64 *)(csk->daddr6.sin6_addr.s6_addr); 3638c2ecf20Sopenharmony_ci req->peer_ip_lo = *(__be64 *)(csk->daddr6.sin6_addr.s6_addr + 3648c2ecf20Sopenharmony_ci 8); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci req->opt0 = cpu_to_be64(opt0); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci opt2 |= RX_FC_VALID_F; 3698c2ecf20Sopenharmony_ci req->opt2 = cpu_to_be32(opt2); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci req->params = cpu_to_be32(cxgb4_select_ntuple( 3728c2ecf20Sopenharmony_ci csk->cdev->ports[csk->port_id], 3738c2ecf20Sopenharmony_ci csk->l2t)); 3748c2ecf20Sopenharmony_ci } else if (is_t5(lldi->adapter_type)) { 3758c2ecf20Sopenharmony_ci struct cpl_t5_act_open_req6 *req = 3768c2ecf20Sopenharmony_ci (struct cpl_t5_act_open_req6 *)skb->head; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci INIT_TP_WR(req, 0); 3798c2ecf20Sopenharmony_ci OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ6, 3808c2ecf20Sopenharmony_ci qid_atid)); 3818c2ecf20Sopenharmony_ci req->local_port = csk->saddr6.sin6_port; 3828c2ecf20Sopenharmony_ci req->peer_port = csk->daddr6.sin6_port; 3838c2ecf20Sopenharmony_ci req->local_ip_hi = *(__be64 *)(csk->saddr6.sin6_addr.s6_addr); 3848c2ecf20Sopenharmony_ci req->local_ip_lo = *(__be64 *)(csk->saddr6.sin6_addr.s6_addr + 3858c2ecf20Sopenharmony_ci 8); 3868c2ecf20Sopenharmony_ci req->peer_ip_hi = *(__be64 *)(csk->daddr6.sin6_addr.s6_addr); 3878c2ecf20Sopenharmony_ci req->peer_ip_lo = *(__be64 *)(csk->daddr6.sin6_addr.s6_addr + 3888c2ecf20Sopenharmony_ci 8); 3898c2ecf20Sopenharmony_ci req->opt0 = cpu_to_be64(opt0); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci opt2 |= T5_OPT_2_VALID_F; 3928c2ecf20Sopenharmony_ci req->opt2 = cpu_to_be32(opt2); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci req->params = cpu_to_be64(FILTER_TUPLE_V(cxgb4_select_ntuple( 3958c2ecf20Sopenharmony_ci csk->cdev->ports[csk->port_id], 3968c2ecf20Sopenharmony_ci csk->l2t))); 3978c2ecf20Sopenharmony_ci } else { 3988c2ecf20Sopenharmony_ci struct cpl_t6_act_open_req6 *req = 3998c2ecf20Sopenharmony_ci (struct cpl_t6_act_open_req6 *)skb->head; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci INIT_TP_WR(req, 0); 4028c2ecf20Sopenharmony_ci OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ6, 4038c2ecf20Sopenharmony_ci qid_atid)); 4048c2ecf20Sopenharmony_ci req->local_port = csk->saddr6.sin6_port; 4058c2ecf20Sopenharmony_ci req->peer_port = csk->daddr6.sin6_port; 4068c2ecf20Sopenharmony_ci req->local_ip_hi = *(__be64 *)(csk->saddr6.sin6_addr.s6_addr); 4078c2ecf20Sopenharmony_ci req->local_ip_lo = *(__be64 *)(csk->saddr6.sin6_addr.s6_addr + 4088c2ecf20Sopenharmony_ci 8); 4098c2ecf20Sopenharmony_ci req->peer_ip_hi = *(__be64 *)(csk->daddr6.sin6_addr.s6_addr); 4108c2ecf20Sopenharmony_ci req->peer_ip_lo = *(__be64 *)(csk->daddr6.sin6_addr.s6_addr + 4118c2ecf20Sopenharmony_ci 8); 4128c2ecf20Sopenharmony_ci req->opt0 = cpu_to_be64(opt0); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci opt2 |= RX_FC_DISABLE_F; 4158c2ecf20Sopenharmony_ci opt2 |= T5_OPT_2_VALID_F; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci req->opt2 = cpu_to_be32(opt2); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci req->params = cpu_to_be64(FILTER_TUPLE_V(cxgb4_select_ntuple( 4208c2ecf20Sopenharmony_ci csk->cdev->ports[csk->port_id], 4218c2ecf20Sopenharmony_ci csk->l2t))); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci req->rsvd2 = cpu_to_be32(0); 4248c2ecf20Sopenharmony_ci req->opt3 = cpu_to_be32(0); 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_SETUP, csk->port_id); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci pr_info("t%d csk 0x%p,%u,0x%lx,%u, [%pI6]:%u-[%pI6]:%u, rss_qid %u.\n", 4308c2ecf20Sopenharmony_ci CHELSIO_CHIP_VERSION(lldi->adapter_type), csk, csk->state, 4318c2ecf20Sopenharmony_ci csk->flags, csk->atid, 4328c2ecf20Sopenharmony_ci &csk->saddr6.sin6_addr, ntohs(csk->saddr.sin_port), 4338c2ecf20Sopenharmony_ci &csk->daddr6.sin6_addr, ntohs(csk->daddr.sin_port), 4348c2ecf20Sopenharmony_ci csk->rss_qid); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci cxgb4_l2t_send(csk->cdev->ports[csk->port_id], skb, csk->l2t); 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci#endif 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_cistatic void send_close_req(struct cxgbi_sock *csk) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci struct sk_buff *skb = csk->cpl_close; 4438c2ecf20Sopenharmony_ci struct cpl_close_con_req *req = (struct cpl_close_con_req *)skb->head; 4448c2ecf20Sopenharmony_ci unsigned int tid = csk->tid; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 4478c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx, tid %u.\n", 4488c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 4498c2ecf20Sopenharmony_ci csk->cpl_close = NULL; 4508c2ecf20Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_DATA, csk->port_id); 4518c2ecf20Sopenharmony_ci INIT_TP_WR(req, tid); 4528c2ecf20Sopenharmony_ci OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_CLOSE_CON_REQ, tid)); 4538c2ecf20Sopenharmony_ci req->rsvd = 0; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci cxgbi_sock_skb_entail(csk, skb); 4568c2ecf20Sopenharmony_ci if (csk->state >= CTP_ESTABLISHED) 4578c2ecf20Sopenharmony_ci push_tx_frames(csk, 1); 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic void abort_arp_failure(void *handle, struct sk_buff *skb) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci struct cxgbi_sock *csk = (struct cxgbi_sock *)handle; 4638c2ecf20Sopenharmony_ci struct cpl_abort_req *req; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 4668c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx, tid %u, abort.\n", 4678c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 4688c2ecf20Sopenharmony_ci req = (struct cpl_abort_req *)skb->data; 4698c2ecf20Sopenharmony_ci req->cmd = CPL_ABORT_NO_RST; 4708c2ecf20Sopenharmony_ci cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cistatic void send_abort_req(struct cxgbi_sock *csk) 4748c2ecf20Sopenharmony_ci{ 4758c2ecf20Sopenharmony_ci struct cpl_abort_req *req; 4768c2ecf20Sopenharmony_ci struct sk_buff *skb = csk->cpl_abort_req; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if (unlikely(csk->state == CTP_ABORTING) || !skb || !csk->cdev) 4798c2ecf20Sopenharmony_ci return; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (!cxgbi_sock_flag(csk, CTPF_TX_DATA_SENT)) { 4828c2ecf20Sopenharmony_ci send_tx_flowc_wr(csk); 4838c2ecf20Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_TX_DATA_SENT); 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_ABORTING); 4878c2ecf20Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_ABORT_RPL_PENDING); 4888c2ecf20Sopenharmony_ci cxgbi_sock_purge_write_queue(csk); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci csk->cpl_abort_req = NULL; 4918c2ecf20Sopenharmony_ci req = (struct cpl_abort_req *)skb->head; 4928c2ecf20Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_DATA, csk->port_id); 4938c2ecf20Sopenharmony_ci req->cmd = CPL_ABORT_SEND_RST; 4948c2ecf20Sopenharmony_ci t4_set_arp_err_handler(skb, csk, abort_arp_failure); 4958c2ecf20Sopenharmony_ci INIT_TP_WR(req, csk->tid); 4968c2ecf20Sopenharmony_ci OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ABORT_REQ, csk->tid)); 4978c2ecf20Sopenharmony_ci req->rsvd0 = htonl(csk->snd_nxt); 4988c2ecf20Sopenharmony_ci req->rsvd1 = !cxgbi_sock_flag(csk, CTPF_TX_DATA_SENT); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 5018c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, snd_nxt %u, 0x%x.\n", 5028c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, csk->snd_nxt, 5038c2ecf20Sopenharmony_ci req->rsvd1); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci cxgb4_l2t_send(csk->cdev->ports[csk->port_id], skb, csk->l2t); 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_cistatic void send_abort_rpl(struct cxgbi_sock *csk, int rst_status) 5098c2ecf20Sopenharmony_ci{ 5108c2ecf20Sopenharmony_ci struct sk_buff *skb = csk->cpl_abort_rpl; 5118c2ecf20Sopenharmony_ci struct cpl_abort_rpl *rpl = (struct cpl_abort_rpl *)skb->head; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 5148c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, status %d.\n", 5158c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, rst_status); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci csk->cpl_abort_rpl = NULL; 5188c2ecf20Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_DATA, csk->port_id); 5198c2ecf20Sopenharmony_ci INIT_TP_WR(rpl, csk->tid); 5208c2ecf20Sopenharmony_ci OPCODE_TID(rpl) = cpu_to_be32(MK_OPCODE_TID(CPL_ABORT_RPL, csk->tid)); 5218c2ecf20Sopenharmony_ci rpl->cmd = rst_status; 5228c2ecf20Sopenharmony_ci cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci/* 5268c2ecf20Sopenharmony_ci * CPL connection rx data ack: host -> 5278c2ecf20Sopenharmony_ci * Send RX credits through an RX_DATA_ACK CPL message. Returns the number of 5288c2ecf20Sopenharmony_ci * credits sent. 5298c2ecf20Sopenharmony_ci */ 5308c2ecf20Sopenharmony_cistatic u32 send_rx_credits(struct cxgbi_sock *csk, u32 credits) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci struct sk_buff *skb; 5338c2ecf20Sopenharmony_ci struct cpl_rx_data_ack *req; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, 5368c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, credit %u.\n", 5378c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, credits); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci skb = alloc_wr(sizeof(*req), 0, GFP_ATOMIC); 5408c2ecf20Sopenharmony_ci if (!skb) { 5418c2ecf20Sopenharmony_ci pr_info("csk 0x%p, credit %u, OOM.\n", csk, credits); 5428c2ecf20Sopenharmony_ci return 0; 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci req = (struct cpl_rx_data_ack *)skb->head; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_ACK, csk->port_id); 5478c2ecf20Sopenharmony_ci INIT_TP_WR(req, csk->tid); 5488c2ecf20Sopenharmony_ci OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_RX_DATA_ACK, 5498c2ecf20Sopenharmony_ci csk->tid)); 5508c2ecf20Sopenharmony_ci req->credit_dack = cpu_to_be32(RX_CREDITS_V(credits) 5518c2ecf20Sopenharmony_ci | RX_FORCE_ACK_F); 5528c2ecf20Sopenharmony_ci cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); 5538c2ecf20Sopenharmony_ci return credits; 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci/* 5578c2ecf20Sopenharmony_ci * sgl_len - calculates the size of an SGL of the given capacity 5588c2ecf20Sopenharmony_ci * @n: the number of SGL entries 5598c2ecf20Sopenharmony_ci * Calculates the number of flits needed for a scatter/gather list that 5608c2ecf20Sopenharmony_ci * can hold the given number of entries. 5618c2ecf20Sopenharmony_ci */ 5628c2ecf20Sopenharmony_cistatic inline unsigned int sgl_len(unsigned int n) 5638c2ecf20Sopenharmony_ci{ 5648c2ecf20Sopenharmony_ci n--; 5658c2ecf20Sopenharmony_ci return (3 * n) / 2 + (n & 1) + 2; 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci/* 5698c2ecf20Sopenharmony_ci * calc_tx_flits_ofld - calculate # of flits for an offload packet 5708c2ecf20Sopenharmony_ci * @skb: the packet 5718c2ecf20Sopenharmony_ci * 5728c2ecf20Sopenharmony_ci * Returns the number of flits needed for the given offload packet. 5738c2ecf20Sopenharmony_ci * These packets are already fully constructed and no additional headers 5748c2ecf20Sopenharmony_ci * will be added. 5758c2ecf20Sopenharmony_ci */ 5768c2ecf20Sopenharmony_cistatic inline unsigned int calc_tx_flits_ofld(const struct sk_buff *skb) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci unsigned int flits, cnt; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci if (is_ofld_imm(skb)) 5818c2ecf20Sopenharmony_ci return DIV_ROUND_UP(skb->len, 8); 5828c2ecf20Sopenharmony_ci flits = skb_transport_offset(skb) / 8; 5838c2ecf20Sopenharmony_ci cnt = skb_shinfo(skb)->nr_frags; 5848c2ecf20Sopenharmony_ci if (skb_tail_pointer(skb) != skb_transport_header(skb)) 5858c2ecf20Sopenharmony_ci cnt++; 5868c2ecf20Sopenharmony_ci return flits + sgl_len(cnt); 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci#define FLOWC_WR_NPARAMS_MIN 9 5908c2ecf20Sopenharmony_cistatic inline int tx_flowc_wr_credits(int *nparamsp, int *flowclenp) 5918c2ecf20Sopenharmony_ci{ 5928c2ecf20Sopenharmony_ci int nparams, flowclen16, flowclen; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci nparams = FLOWC_WR_NPARAMS_MIN; 5958c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 5968c2ecf20Sopenharmony_ci nparams++; 5978c2ecf20Sopenharmony_ci#endif 5988c2ecf20Sopenharmony_ci flowclen = offsetof(struct fw_flowc_wr, mnemval[nparams]); 5998c2ecf20Sopenharmony_ci flowclen16 = DIV_ROUND_UP(flowclen, 16); 6008c2ecf20Sopenharmony_ci flowclen = flowclen16 * 16; 6018c2ecf20Sopenharmony_ci /* 6028c2ecf20Sopenharmony_ci * Return the number of 16-byte credits used by the FlowC request. 6038c2ecf20Sopenharmony_ci * Pass back the nparams and actual FlowC length if requested. 6048c2ecf20Sopenharmony_ci */ 6058c2ecf20Sopenharmony_ci if (nparamsp) 6068c2ecf20Sopenharmony_ci *nparamsp = nparams; 6078c2ecf20Sopenharmony_ci if (flowclenp) 6088c2ecf20Sopenharmony_ci *flowclenp = flowclen; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci return flowclen16; 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_cistatic inline int send_tx_flowc_wr(struct cxgbi_sock *csk) 6148c2ecf20Sopenharmony_ci{ 6158c2ecf20Sopenharmony_ci struct sk_buff *skb; 6168c2ecf20Sopenharmony_ci struct fw_flowc_wr *flowc; 6178c2ecf20Sopenharmony_ci int nparams, flowclen16, flowclen; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 6208c2ecf20Sopenharmony_ci u16 vlan = ((struct l2t_entry *)csk->l2t)->vlan; 6218c2ecf20Sopenharmony_ci#endif 6228c2ecf20Sopenharmony_ci flowclen16 = tx_flowc_wr_credits(&nparams, &flowclen); 6238c2ecf20Sopenharmony_ci skb = alloc_wr(flowclen, 0, GFP_ATOMIC); 6248c2ecf20Sopenharmony_ci flowc = (struct fw_flowc_wr *)skb->head; 6258c2ecf20Sopenharmony_ci flowc->op_to_nparams = 6268c2ecf20Sopenharmony_ci htonl(FW_WR_OP_V(FW_FLOWC_WR) | FW_FLOWC_WR_NPARAMS_V(nparams)); 6278c2ecf20Sopenharmony_ci flowc->flowid_len16 = 6288c2ecf20Sopenharmony_ci htonl(FW_WR_LEN16_V(flowclen16) | FW_WR_FLOWID_V(csk->tid)); 6298c2ecf20Sopenharmony_ci flowc->mnemval[0].mnemonic = FW_FLOWC_MNEM_PFNVFN; 6308c2ecf20Sopenharmony_ci flowc->mnemval[0].val = htonl(csk->cdev->pfvf); 6318c2ecf20Sopenharmony_ci flowc->mnemval[1].mnemonic = FW_FLOWC_MNEM_CH; 6328c2ecf20Sopenharmony_ci flowc->mnemval[1].val = htonl(csk->tx_chan); 6338c2ecf20Sopenharmony_ci flowc->mnemval[2].mnemonic = FW_FLOWC_MNEM_PORT; 6348c2ecf20Sopenharmony_ci flowc->mnemval[2].val = htonl(csk->tx_chan); 6358c2ecf20Sopenharmony_ci flowc->mnemval[3].mnemonic = FW_FLOWC_MNEM_IQID; 6368c2ecf20Sopenharmony_ci flowc->mnemval[3].val = htonl(csk->rss_qid); 6378c2ecf20Sopenharmony_ci flowc->mnemval[4].mnemonic = FW_FLOWC_MNEM_SNDNXT; 6388c2ecf20Sopenharmony_ci flowc->mnemval[4].val = htonl(csk->snd_nxt); 6398c2ecf20Sopenharmony_ci flowc->mnemval[5].mnemonic = FW_FLOWC_MNEM_RCVNXT; 6408c2ecf20Sopenharmony_ci flowc->mnemval[5].val = htonl(csk->rcv_nxt); 6418c2ecf20Sopenharmony_ci flowc->mnemval[6].mnemonic = FW_FLOWC_MNEM_SNDBUF; 6428c2ecf20Sopenharmony_ci flowc->mnemval[6].val = htonl(csk->snd_win); 6438c2ecf20Sopenharmony_ci flowc->mnemval[7].mnemonic = FW_FLOWC_MNEM_MSS; 6448c2ecf20Sopenharmony_ci flowc->mnemval[7].val = htonl(csk->advmss); 6458c2ecf20Sopenharmony_ci flowc->mnemval[8].mnemonic = 0; 6468c2ecf20Sopenharmony_ci flowc->mnemval[8].val = 0; 6478c2ecf20Sopenharmony_ci flowc->mnemval[8].mnemonic = FW_FLOWC_MNEM_TXDATAPLEN_MAX; 6488c2ecf20Sopenharmony_ci if (csk->cdev->skb_iso_txhdr) 6498c2ecf20Sopenharmony_ci flowc->mnemval[8].val = cpu_to_be32(CXGBI_MAX_ISO_DATA_IN_SKB); 6508c2ecf20Sopenharmony_ci else 6518c2ecf20Sopenharmony_ci flowc->mnemval[8].val = cpu_to_be32(16128); 6528c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 6538c2ecf20Sopenharmony_ci flowc->mnemval[9].mnemonic = FW_FLOWC_MNEM_DCBPRIO; 6548c2ecf20Sopenharmony_ci if (vlan == CPL_L2T_VLAN_NONE) { 6558c2ecf20Sopenharmony_ci pr_warn_ratelimited("csk %u without VLAN Tag on DCB Link\n", 6568c2ecf20Sopenharmony_ci csk->tid); 6578c2ecf20Sopenharmony_ci flowc->mnemval[9].val = cpu_to_be32(0); 6588c2ecf20Sopenharmony_ci } else { 6598c2ecf20Sopenharmony_ci flowc->mnemval[9].val = cpu_to_be32((vlan & VLAN_PRIO_MASK) >> 6608c2ecf20Sopenharmony_ci VLAN_PRIO_SHIFT); 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci#endif 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_DATA, csk->port_id); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 6678c2ecf20Sopenharmony_ci "csk 0x%p, tid 0x%x, %u,%u,%u,%u,%u,%u,%u.\n", 6688c2ecf20Sopenharmony_ci csk, csk->tid, 0, csk->tx_chan, csk->rss_qid, 6698c2ecf20Sopenharmony_ci csk->snd_nxt, csk->rcv_nxt, csk->snd_win, 6708c2ecf20Sopenharmony_ci csk->advmss); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci return flowclen16; 6758c2ecf20Sopenharmony_ci} 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_cistatic void 6788c2ecf20Sopenharmony_cicxgb4i_make_tx_iso_cpl(struct sk_buff *skb, struct cpl_tx_data_iso *cpl) 6798c2ecf20Sopenharmony_ci{ 6808c2ecf20Sopenharmony_ci struct cxgbi_iso_info *info = (struct cxgbi_iso_info *)skb->head; 6818c2ecf20Sopenharmony_ci u32 imm_en = !!(info->flags & CXGBI_ISO_INFO_IMM_ENABLE); 6828c2ecf20Sopenharmony_ci u32 fslice = !!(info->flags & CXGBI_ISO_INFO_FSLICE); 6838c2ecf20Sopenharmony_ci u32 lslice = !!(info->flags & CXGBI_ISO_INFO_LSLICE); 6848c2ecf20Sopenharmony_ci u32 pdu_type = (info->op == ISCSI_OP_SCSI_CMD) ? 0 : 1; 6858c2ecf20Sopenharmony_ci u32 submode = cxgbi_skcb_tx_ulp_mode(skb) & 0x3; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci cpl->op_to_scsi = cpu_to_be32(CPL_TX_DATA_ISO_OP_V(CPL_TX_DATA_ISO) | 6888c2ecf20Sopenharmony_ci CPL_TX_DATA_ISO_FIRST_V(fslice) | 6898c2ecf20Sopenharmony_ci CPL_TX_DATA_ISO_LAST_V(lslice) | 6908c2ecf20Sopenharmony_ci CPL_TX_DATA_ISO_CPLHDRLEN_V(0) | 6918c2ecf20Sopenharmony_ci CPL_TX_DATA_ISO_HDRCRC_V(submode & 1) | 6928c2ecf20Sopenharmony_ci CPL_TX_DATA_ISO_PLDCRC_V(((submode >> 1) & 1)) | 6938c2ecf20Sopenharmony_ci CPL_TX_DATA_ISO_IMMEDIATE_V(imm_en) | 6948c2ecf20Sopenharmony_ci CPL_TX_DATA_ISO_SCSI_V(pdu_type)); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci cpl->ahs_len = info->ahs; 6978c2ecf20Sopenharmony_ci cpl->mpdu = cpu_to_be16(DIV_ROUND_UP(info->mpdu, 4)); 6988c2ecf20Sopenharmony_ci cpl->burst_size = cpu_to_be32(info->burst_size); 6998c2ecf20Sopenharmony_ci cpl->len = cpu_to_be32(info->len); 7008c2ecf20Sopenharmony_ci cpl->reserved2_seglen_offset = 7018c2ecf20Sopenharmony_ci cpu_to_be32(CPL_TX_DATA_ISO_SEGLEN_OFFSET_V(info->segment_offset)); 7028c2ecf20Sopenharmony_ci cpl->datasn_offset = cpu_to_be32(info->datasn_offset); 7038c2ecf20Sopenharmony_ci cpl->buffer_offset = cpu_to_be32(info->buffer_offset); 7048c2ecf20Sopenharmony_ci cpl->reserved3 = cpu_to_be32(0); 7058c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, 7068c2ecf20Sopenharmony_ci "iso: flags 0x%x, op %u, ahs %u, num_pdu %u, mpdu %u, " 7078c2ecf20Sopenharmony_ci "burst_size %u, iso_len %u\n", 7088c2ecf20Sopenharmony_ci info->flags, info->op, info->ahs, info->num_pdu, 7098c2ecf20Sopenharmony_ci info->mpdu, info->burst_size << 2, info->len); 7108c2ecf20Sopenharmony_ci} 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_cistatic void 7138c2ecf20Sopenharmony_cicxgb4i_make_tx_data_wr(struct cxgbi_sock *csk, struct sk_buff *skb, int dlen, 7148c2ecf20Sopenharmony_ci int len, u32 credits, int compl) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci struct cxgbi_device *cdev = csk->cdev; 7178c2ecf20Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 7188c2ecf20Sopenharmony_ci struct fw_ofld_tx_data_wr *req; 7198c2ecf20Sopenharmony_ci struct cpl_tx_data_iso *cpl; 7208c2ecf20Sopenharmony_ci u32 submode = cxgbi_skcb_tx_ulp_mode(skb) & 0x3; 7218c2ecf20Sopenharmony_ci u32 wr_ulp_mode = 0; 7228c2ecf20Sopenharmony_ci u32 hdr_size = sizeof(*req); 7238c2ecf20Sopenharmony_ci u32 opcode = FW_OFLD_TX_DATA_WR; 7248c2ecf20Sopenharmony_ci u32 immlen = 0; 7258c2ecf20Sopenharmony_ci u32 force = is_t5(lldi->adapter_type) ? TX_FORCE_V(!submode) : 7268c2ecf20Sopenharmony_ci T6_TX_FORCE_F; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci if (cxgbi_skcb_test_flag(skb, SKCBF_TX_ISO)) { 7298c2ecf20Sopenharmony_ci hdr_size += sizeof(struct cpl_tx_data_iso); 7308c2ecf20Sopenharmony_ci opcode = FW_ISCSI_TX_DATA_WR; 7318c2ecf20Sopenharmony_ci immlen += sizeof(struct cpl_tx_data_iso); 7328c2ecf20Sopenharmony_ci submode |= 8; 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci if (is_ofld_imm(skb)) 7368c2ecf20Sopenharmony_ci immlen += dlen; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci req = (struct fw_ofld_tx_data_wr *)__skb_push(skb, hdr_size); 7398c2ecf20Sopenharmony_ci req->op_to_immdlen = cpu_to_be32(FW_WR_OP_V(opcode) | 7408c2ecf20Sopenharmony_ci FW_WR_COMPL_V(compl) | 7418c2ecf20Sopenharmony_ci FW_WR_IMMDLEN_V(immlen)); 7428c2ecf20Sopenharmony_ci req->flowid_len16 = cpu_to_be32(FW_WR_FLOWID_V(csk->tid) | 7438c2ecf20Sopenharmony_ci FW_WR_LEN16_V(credits)); 7448c2ecf20Sopenharmony_ci req->plen = cpu_to_be32(len); 7458c2ecf20Sopenharmony_ci cpl = (struct cpl_tx_data_iso *)(req + 1); 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci if (likely(cxgbi_skcb_test_flag(skb, SKCBF_TX_ISO))) 7488c2ecf20Sopenharmony_ci cxgb4i_make_tx_iso_cpl(skb, cpl); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci if (submode) 7518c2ecf20Sopenharmony_ci wr_ulp_mode = FW_OFLD_TX_DATA_WR_ULPMODE_V(ULP2_MODE_ISCSI) | 7528c2ecf20Sopenharmony_ci FW_OFLD_TX_DATA_WR_ULPSUBMODE_V(submode); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci req->tunnel_to_proxy = cpu_to_be32(wr_ulp_mode | force | 7558c2ecf20Sopenharmony_ci FW_OFLD_TX_DATA_WR_SHOVE_V(1U)); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci if (!cxgbi_sock_flag(csk, CTPF_TX_DATA_SENT)) 7588c2ecf20Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_TX_DATA_SENT); 7598c2ecf20Sopenharmony_ci} 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_cistatic void arp_failure_skb_discard(void *handle, struct sk_buff *skb) 7628c2ecf20Sopenharmony_ci{ 7638c2ecf20Sopenharmony_ci kfree_skb(skb); 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_cistatic int push_tx_frames(struct cxgbi_sock *csk, int req_completion) 7678c2ecf20Sopenharmony_ci{ 7688c2ecf20Sopenharmony_ci int total_size = 0; 7698c2ecf20Sopenharmony_ci struct sk_buff *skb; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci if (unlikely(csk->state < CTP_ESTABLISHED || 7728c2ecf20Sopenharmony_ci csk->state == CTP_CLOSE_WAIT_1 || csk->state >= CTP_ABORTING)) { 7738c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK | 7748c2ecf20Sopenharmony_ci 1 << CXGBI_DBG_PDU_TX, 7758c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, in closing state.\n", 7768c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 7778c2ecf20Sopenharmony_ci return 0; 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci while (csk->wr_cred && ((skb = skb_peek(&csk->write_queue)) != NULL)) { 7818c2ecf20Sopenharmony_ci struct cxgbi_iso_info *iso_cpl; 7828c2ecf20Sopenharmony_ci u32 dlen = skb->len; 7838c2ecf20Sopenharmony_ci u32 len = skb->len; 7848c2ecf20Sopenharmony_ci u32 iso_cpl_len = 0; 7858c2ecf20Sopenharmony_ci u32 flowclen16 = 0; 7868c2ecf20Sopenharmony_ci u32 credits_needed; 7878c2ecf20Sopenharmony_ci u32 num_pdu = 1, hdr_len; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci if (cxgbi_skcb_test_flag(skb, SKCBF_TX_ISO)) 7908c2ecf20Sopenharmony_ci iso_cpl_len = sizeof(struct cpl_tx_data_iso); 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci if (is_ofld_imm(skb)) 7938c2ecf20Sopenharmony_ci credits_needed = DIV_ROUND_UP(dlen + iso_cpl_len, 16); 7948c2ecf20Sopenharmony_ci else 7958c2ecf20Sopenharmony_ci credits_needed = 7968c2ecf20Sopenharmony_ci DIV_ROUND_UP((8 * calc_tx_flits_ofld(skb)) + 7978c2ecf20Sopenharmony_ci iso_cpl_len, 16); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci if (likely(cxgbi_skcb_test_flag(skb, SKCBF_TX_NEED_HDR))) 8008c2ecf20Sopenharmony_ci credits_needed += 8018c2ecf20Sopenharmony_ci DIV_ROUND_UP(sizeof(struct fw_ofld_tx_data_wr), 16); 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci /* 8048c2ecf20Sopenharmony_ci * Assumes the initial credits is large enough to support 8058c2ecf20Sopenharmony_ci * fw_flowc_wr plus largest possible first payload 8068c2ecf20Sopenharmony_ci */ 8078c2ecf20Sopenharmony_ci if (!cxgbi_sock_flag(csk, CTPF_TX_DATA_SENT)) { 8088c2ecf20Sopenharmony_ci flowclen16 = send_tx_flowc_wr(csk); 8098c2ecf20Sopenharmony_ci csk->wr_cred -= flowclen16; 8108c2ecf20Sopenharmony_ci csk->wr_una_cred += flowclen16; 8118c2ecf20Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_TX_DATA_SENT); 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci if (csk->wr_cred < credits_needed) { 8158c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_TX, 8168c2ecf20Sopenharmony_ci "csk 0x%p, skb %u/%u, wr %d < %u.\n", 8178c2ecf20Sopenharmony_ci csk, skb->len, skb->data_len, 8188c2ecf20Sopenharmony_ci credits_needed, csk->wr_cred); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci csk->no_tx_credits++; 8218c2ecf20Sopenharmony_ci break; 8228c2ecf20Sopenharmony_ci } 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci csk->no_tx_credits = 0; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci __skb_unlink(skb, &csk->write_queue); 8278c2ecf20Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_DATA, csk->port_id); 8288c2ecf20Sopenharmony_ci skb->csum = (__force __wsum)(credits_needed + flowclen16); 8298c2ecf20Sopenharmony_ci csk->wr_cred -= credits_needed; 8308c2ecf20Sopenharmony_ci csk->wr_una_cred += credits_needed; 8318c2ecf20Sopenharmony_ci cxgbi_sock_enqueue_wr(csk, skb); 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_TX, 8348c2ecf20Sopenharmony_ci "csk 0x%p, skb %u/%u, wr %d, left %u, unack %u.\n", 8358c2ecf20Sopenharmony_ci csk, skb->len, skb->data_len, credits_needed, 8368c2ecf20Sopenharmony_ci csk->wr_cred, csk->wr_una_cred); 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci if (!req_completion && 8398c2ecf20Sopenharmony_ci ((csk->wr_una_cred >= (csk->wr_max_cred / 2)) || 8408c2ecf20Sopenharmony_ci after(csk->write_seq, (csk->snd_una + csk->snd_win / 2)))) 8418c2ecf20Sopenharmony_ci req_completion = 1; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci if (likely(cxgbi_skcb_test_flag(skb, SKCBF_TX_NEED_HDR))) { 8448c2ecf20Sopenharmony_ci u32 ulp_mode = cxgbi_skcb_tx_ulp_mode(skb); 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci if (cxgbi_skcb_test_flag(skb, SKCBF_TX_ISO)) { 8478c2ecf20Sopenharmony_ci iso_cpl = (struct cxgbi_iso_info *)skb->head; 8488c2ecf20Sopenharmony_ci num_pdu = iso_cpl->num_pdu; 8498c2ecf20Sopenharmony_ci hdr_len = cxgbi_skcb_tx_iscsi_hdrlen(skb); 8508c2ecf20Sopenharmony_ci len += (cxgbi_ulp_extra_len(ulp_mode) * num_pdu) + 8518c2ecf20Sopenharmony_ci (hdr_len * (num_pdu - 1)); 8528c2ecf20Sopenharmony_ci } else { 8538c2ecf20Sopenharmony_ci len += cxgbi_ulp_extra_len(ulp_mode); 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci cxgb4i_make_tx_data_wr(csk, skb, dlen, len, 8578c2ecf20Sopenharmony_ci credits_needed, req_completion); 8588c2ecf20Sopenharmony_ci csk->snd_nxt += len; 8598c2ecf20Sopenharmony_ci cxgbi_skcb_clear_flag(skb, SKCBF_TX_NEED_HDR); 8608c2ecf20Sopenharmony_ci } else if (cxgbi_skcb_test_flag(skb, SKCBF_TX_FLAG_COMPL) && 8618c2ecf20Sopenharmony_ci (csk->wr_una_cred >= (csk->wr_max_cred / 2))) { 8628c2ecf20Sopenharmony_ci struct cpl_close_con_req *req = 8638c2ecf20Sopenharmony_ci (struct cpl_close_con_req *)skb->data; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci req->wr.wr_hi |= cpu_to_be32(FW_WR_COMPL_F); 8668c2ecf20Sopenharmony_ci } 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci total_size += skb->truesize; 8698c2ecf20Sopenharmony_ci t4_set_arp_err_handler(skb, csk, arp_failure_skb_discard); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_TX, 8728c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, skb 0x%p, %u.\n", 8738c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, skb, len); 8748c2ecf20Sopenharmony_ci cxgb4_l2t_send(csk->cdev->ports[csk->port_id], skb, csk->l2t); 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci return total_size; 8778c2ecf20Sopenharmony_ci} 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_cistatic inline void free_atid(struct cxgbi_sock *csk) 8808c2ecf20Sopenharmony_ci{ 8818c2ecf20Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(csk->cdev); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci if (cxgbi_sock_flag(csk, CTPF_HAS_ATID)) { 8848c2ecf20Sopenharmony_ci cxgb4_free_atid(lldi->tids, csk->atid); 8858c2ecf20Sopenharmony_ci cxgbi_sock_clear_flag(csk, CTPF_HAS_ATID); 8868c2ecf20Sopenharmony_ci cxgbi_sock_put(csk); 8878c2ecf20Sopenharmony_ci } 8888c2ecf20Sopenharmony_ci} 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_cistatic void do_act_establish(struct cxgbi_device *cdev, struct sk_buff *skb) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci struct cxgbi_sock *csk; 8938c2ecf20Sopenharmony_ci struct cpl_act_establish *req = (struct cpl_act_establish *)skb->data; 8948c2ecf20Sopenharmony_ci unsigned short tcp_opt = ntohs(req->tcp_opt); 8958c2ecf20Sopenharmony_ci unsigned int tid = GET_TID(req); 8968c2ecf20Sopenharmony_ci unsigned int atid = TID_TID_G(ntohl(req->tos_atid)); 8978c2ecf20Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 8988c2ecf20Sopenharmony_ci struct tid_info *t = lldi->tids; 8998c2ecf20Sopenharmony_ci u32 rcv_isn = be32_to_cpu(req->rcv_isn); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci csk = lookup_atid(t, atid); 9028c2ecf20Sopenharmony_ci if (unlikely(!csk)) { 9038c2ecf20Sopenharmony_ci pr_err("NO conn. for atid %u, cdev 0x%p.\n", atid, cdev); 9048c2ecf20Sopenharmony_ci goto rel_skb; 9058c2ecf20Sopenharmony_ci } 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci if (csk->atid != atid) { 9088c2ecf20Sopenharmony_ci pr_err("bad conn atid %u, csk 0x%p,%u,0x%lx,tid %u, atid %u.\n", 9098c2ecf20Sopenharmony_ci atid, csk, csk->state, csk->flags, csk->tid, csk->atid); 9108c2ecf20Sopenharmony_ci goto rel_skb; 9118c2ecf20Sopenharmony_ci } 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci pr_info_ipaddr("atid 0x%x, tid 0x%x, csk 0x%p,%u,0x%lx, isn %u.\n", 9148c2ecf20Sopenharmony_ci (&csk->saddr), (&csk->daddr), 9158c2ecf20Sopenharmony_ci atid, tid, csk, csk->state, csk->flags, rcv_isn); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci module_put(cdev->owner); 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci cxgbi_sock_get(csk); 9208c2ecf20Sopenharmony_ci csk->tid = tid; 9218c2ecf20Sopenharmony_ci cxgb4_insert_tid(lldi->tids, csk, tid, csk->csk_family); 9228c2ecf20Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_HAS_TID); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci free_atid(csk); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci spin_lock_bh(&csk->lock); 9278c2ecf20Sopenharmony_ci if (unlikely(csk->state != CTP_ACTIVE_OPEN)) 9288c2ecf20Sopenharmony_ci pr_info("csk 0x%p,%u,0x%lx,%u, got EST.\n", 9298c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci if (csk->retry_timer.function) { 9328c2ecf20Sopenharmony_ci del_timer(&csk->retry_timer); 9338c2ecf20Sopenharmony_ci csk->retry_timer.function = NULL; 9348c2ecf20Sopenharmony_ci } 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci csk->copied_seq = csk->rcv_wup = csk->rcv_nxt = rcv_isn; 9378c2ecf20Sopenharmony_ci /* 9388c2ecf20Sopenharmony_ci * Causes the first RX_DATA_ACK to supply any Rx credits we couldn't 9398c2ecf20Sopenharmony_ci * pass through opt0. 9408c2ecf20Sopenharmony_ci */ 9418c2ecf20Sopenharmony_ci if (csk->rcv_win > (RCV_BUFSIZ_MASK << 10)) 9428c2ecf20Sopenharmony_ci csk->rcv_wup -= csk->rcv_win - (RCV_BUFSIZ_MASK << 10); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci csk->advmss = lldi->mtus[TCPOPT_MSS_G(tcp_opt)] - 40; 9458c2ecf20Sopenharmony_ci if (TCPOPT_TSTAMP_G(tcp_opt)) 9468c2ecf20Sopenharmony_ci csk->advmss -= 12; 9478c2ecf20Sopenharmony_ci if (csk->advmss < 128) 9488c2ecf20Sopenharmony_ci csk->advmss = 128; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 9518c2ecf20Sopenharmony_ci "csk 0x%p, mss_idx %u, advmss %u.\n", 9528c2ecf20Sopenharmony_ci csk, TCPOPT_MSS_G(tcp_opt), csk->advmss); 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci cxgbi_sock_established(csk, ntohl(req->snd_isn), ntohs(req->tcp_opt)); 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci if (unlikely(cxgbi_sock_flag(csk, CTPF_ACTIVE_CLOSE_NEEDED))) 9578c2ecf20Sopenharmony_ci send_abort_req(csk); 9588c2ecf20Sopenharmony_ci else { 9598c2ecf20Sopenharmony_ci if (skb_queue_len(&csk->write_queue)) 9608c2ecf20Sopenharmony_ci push_tx_frames(csk, 0); 9618c2ecf20Sopenharmony_ci cxgbi_conn_tx_open(csk); 9628c2ecf20Sopenharmony_ci } 9638c2ecf20Sopenharmony_ci spin_unlock_bh(&csk->lock); 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_cirel_skb: 9668c2ecf20Sopenharmony_ci __kfree_skb(skb); 9678c2ecf20Sopenharmony_ci} 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_cistatic int act_open_rpl_status_to_errno(int status) 9708c2ecf20Sopenharmony_ci{ 9718c2ecf20Sopenharmony_ci switch (status) { 9728c2ecf20Sopenharmony_ci case CPL_ERR_CONN_RESET: 9738c2ecf20Sopenharmony_ci return -ECONNREFUSED; 9748c2ecf20Sopenharmony_ci case CPL_ERR_ARP_MISS: 9758c2ecf20Sopenharmony_ci return -EHOSTUNREACH; 9768c2ecf20Sopenharmony_ci case CPL_ERR_CONN_TIMEDOUT: 9778c2ecf20Sopenharmony_ci return -ETIMEDOUT; 9788c2ecf20Sopenharmony_ci case CPL_ERR_TCAM_FULL: 9798c2ecf20Sopenharmony_ci return -ENOMEM; 9808c2ecf20Sopenharmony_ci case CPL_ERR_CONN_EXIST: 9818c2ecf20Sopenharmony_ci return -EADDRINUSE; 9828c2ecf20Sopenharmony_ci default: 9838c2ecf20Sopenharmony_ci return -EIO; 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci} 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_cistatic void csk_act_open_retry_timer(struct timer_list *t) 9888c2ecf20Sopenharmony_ci{ 9898c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 9908c2ecf20Sopenharmony_ci struct cxgbi_sock *csk = from_timer(csk, t, retry_timer); 9918c2ecf20Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(csk->cdev); 9928c2ecf20Sopenharmony_ci void (*send_act_open_func)(struct cxgbi_sock *, struct sk_buff *, 9938c2ecf20Sopenharmony_ci struct l2t_entry *); 9948c2ecf20Sopenharmony_ci int t4 = is_t4(lldi->adapter_type), size, size6; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 9978c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u.\n", 9988c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci cxgbi_sock_get(csk); 10018c2ecf20Sopenharmony_ci spin_lock_bh(&csk->lock); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci if (t4) { 10048c2ecf20Sopenharmony_ci size = sizeof(struct cpl_act_open_req); 10058c2ecf20Sopenharmony_ci size6 = sizeof(struct cpl_act_open_req6); 10068c2ecf20Sopenharmony_ci } else { 10078c2ecf20Sopenharmony_ci size = sizeof(struct cpl_t5_act_open_req); 10088c2ecf20Sopenharmony_ci size6 = sizeof(struct cpl_t5_act_open_req6); 10098c2ecf20Sopenharmony_ci } 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci if (csk->csk_family == AF_INET) { 10128c2ecf20Sopenharmony_ci send_act_open_func = send_act_open_req; 10138c2ecf20Sopenharmony_ci skb = alloc_wr(size, 0, GFP_ATOMIC); 10148c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 10158c2ecf20Sopenharmony_ci } else { 10168c2ecf20Sopenharmony_ci send_act_open_func = send_act_open_req6; 10178c2ecf20Sopenharmony_ci skb = alloc_wr(size6, 0, GFP_ATOMIC); 10188c2ecf20Sopenharmony_ci#endif 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci if (!skb) 10228c2ecf20Sopenharmony_ci cxgbi_sock_fail_act_open(csk, -ENOMEM); 10238c2ecf20Sopenharmony_ci else { 10248c2ecf20Sopenharmony_ci skb->sk = (struct sock *)csk; 10258c2ecf20Sopenharmony_ci t4_set_arp_err_handler(skb, csk, 10268c2ecf20Sopenharmony_ci cxgbi_sock_act_open_req_arp_failure); 10278c2ecf20Sopenharmony_ci send_act_open_func(csk, skb, csk->l2t); 10288c2ecf20Sopenharmony_ci } 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci spin_unlock_bh(&csk->lock); 10318c2ecf20Sopenharmony_ci cxgbi_sock_put(csk); 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci} 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_cistatic inline bool is_neg_adv(unsigned int status) 10368c2ecf20Sopenharmony_ci{ 10378c2ecf20Sopenharmony_ci return status == CPL_ERR_RTX_NEG_ADVICE || 10388c2ecf20Sopenharmony_ci status == CPL_ERR_KEEPALV_NEG_ADVICE || 10398c2ecf20Sopenharmony_ci status == CPL_ERR_PERSIST_NEG_ADVICE; 10408c2ecf20Sopenharmony_ci} 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_cistatic void do_act_open_rpl(struct cxgbi_device *cdev, struct sk_buff *skb) 10438c2ecf20Sopenharmony_ci{ 10448c2ecf20Sopenharmony_ci struct cxgbi_sock *csk; 10458c2ecf20Sopenharmony_ci struct cpl_act_open_rpl *rpl = (struct cpl_act_open_rpl *)skb->data; 10468c2ecf20Sopenharmony_ci unsigned int tid = GET_TID(rpl); 10478c2ecf20Sopenharmony_ci unsigned int atid = 10488c2ecf20Sopenharmony_ci TID_TID_G(AOPEN_ATID_G(be32_to_cpu(rpl->atid_status))); 10498c2ecf20Sopenharmony_ci unsigned int status = AOPEN_STATUS_G(be32_to_cpu(rpl->atid_status)); 10508c2ecf20Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 10518c2ecf20Sopenharmony_ci struct tid_info *t = lldi->tids; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci csk = lookup_atid(t, atid); 10548c2ecf20Sopenharmony_ci if (unlikely(!csk)) { 10558c2ecf20Sopenharmony_ci pr_err("NO matching conn. atid %u, tid %u.\n", atid, tid); 10568c2ecf20Sopenharmony_ci goto rel_skb; 10578c2ecf20Sopenharmony_ci } 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci pr_info_ipaddr("tid %u/%u, status %u.\n" 10608c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx. ", (&csk->saddr), (&csk->daddr), 10618c2ecf20Sopenharmony_ci atid, tid, status, csk, csk->state, csk->flags); 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci if (is_neg_adv(status)) 10648c2ecf20Sopenharmony_ci goto rel_skb; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci module_put(cdev->owner); 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci if (status && status != CPL_ERR_TCAM_FULL && 10698c2ecf20Sopenharmony_ci status != CPL_ERR_CONN_EXIST && 10708c2ecf20Sopenharmony_ci status != CPL_ERR_ARP_MISS) 10718c2ecf20Sopenharmony_ci cxgb4_remove_tid(lldi->tids, csk->port_id, GET_TID(rpl), 10728c2ecf20Sopenharmony_ci csk->csk_family); 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci cxgbi_sock_get(csk); 10758c2ecf20Sopenharmony_ci spin_lock_bh(&csk->lock); 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci if (status == CPL_ERR_CONN_EXIST && 10788c2ecf20Sopenharmony_ci csk->retry_timer.function != csk_act_open_retry_timer) { 10798c2ecf20Sopenharmony_ci csk->retry_timer.function = csk_act_open_retry_timer; 10808c2ecf20Sopenharmony_ci mod_timer(&csk->retry_timer, jiffies + HZ / 2); 10818c2ecf20Sopenharmony_ci } else 10828c2ecf20Sopenharmony_ci cxgbi_sock_fail_act_open(csk, 10838c2ecf20Sopenharmony_ci act_open_rpl_status_to_errno(status)); 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci spin_unlock_bh(&csk->lock); 10868c2ecf20Sopenharmony_ci cxgbi_sock_put(csk); 10878c2ecf20Sopenharmony_cirel_skb: 10888c2ecf20Sopenharmony_ci __kfree_skb(skb); 10898c2ecf20Sopenharmony_ci} 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_cistatic void do_peer_close(struct cxgbi_device *cdev, struct sk_buff *skb) 10928c2ecf20Sopenharmony_ci{ 10938c2ecf20Sopenharmony_ci struct cxgbi_sock *csk; 10948c2ecf20Sopenharmony_ci struct cpl_peer_close *req = (struct cpl_peer_close *)skb->data; 10958c2ecf20Sopenharmony_ci unsigned int tid = GET_TID(req); 10968c2ecf20Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 10978c2ecf20Sopenharmony_ci struct tid_info *t = lldi->tids; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci csk = lookup_tid(t, tid); 11008c2ecf20Sopenharmony_ci if (unlikely(!csk)) { 11018c2ecf20Sopenharmony_ci pr_err("can't find connection for tid %u.\n", tid); 11028c2ecf20Sopenharmony_ci goto rel_skb; 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci pr_info_ipaddr("csk 0x%p,%u,0x%lx,%u.\n", 11058c2ecf20Sopenharmony_ci (&csk->saddr), (&csk->daddr), 11068c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 11078c2ecf20Sopenharmony_ci cxgbi_sock_rcv_peer_close(csk); 11088c2ecf20Sopenharmony_cirel_skb: 11098c2ecf20Sopenharmony_ci __kfree_skb(skb); 11108c2ecf20Sopenharmony_ci} 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_cistatic void do_close_con_rpl(struct cxgbi_device *cdev, struct sk_buff *skb) 11138c2ecf20Sopenharmony_ci{ 11148c2ecf20Sopenharmony_ci struct cxgbi_sock *csk; 11158c2ecf20Sopenharmony_ci struct cpl_close_con_rpl *rpl = (struct cpl_close_con_rpl *)skb->data; 11168c2ecf20Sopenharmony_ci unsigned int tid = GET_TID(rpl); 11178c2ecf20Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 11188c2ecf20Sopenharmony_ci struct tid_info *t = lldi->tids; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci csk = lookup_tid(t, tid); 11218c2ecf20Sopenharmony_ci if (unlikely(!csk)) { 11228c2ecf20Sopenharmony_ci pr_err("can't find connection for tid %u.\n", tid); 11238c2ecf20Sopenharmony_ci goto rel_skb; 11248c2ecf20Sopenharmony_ci } 11258c2ecf20Sopenharmony_ci pr_info_ipaddr("csk 0x%p,%u,0x%lx,%u.\n", 11268c2ecf20Sopenharmony_ci (&csk->saddr), (&csk->daddr), 11278c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 11288c2ecf20Sopenharmony_ci cxgbi_sock_rcv_close_conn_rpl(csk, ntohl(rpl->snd_nxt)); 11298c2ecf20Sopenharmony_cirel_skb: 11308c2ecf20Sopenharmony_ci __kfree_skb(skb); 11318c2ecf20Sopenharmony_ci} 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_cistatic int abort_status_to_errno(struct cxgbi_sock *csk, int abort_reason, 11348c2ecf20Sopenharmony_ci int *need_rst) 11358c2ecf20Sopenharmony_ci{ 11368c2ecf20Sopenharmony_ci switch (abort_reason) { 11378c2ecf20Sopenharmony_ci case CPL_ERR_BAD_SYN: 11388c2ecf20Sopenharmony_ci case CPL_ERR_CONN_RESET: 11398c2ecf20Sopenharmony_ci return csk->state > CTP_ESTABLISHED ? 11408c2ecf20Sopenharmony_ci -EPIPE : -ECONNRESET; 11418c2ecf20Sopenharmony_ci case CPL_ERR_XMIT_TIMEDOUT: 11428c2ecf20Sopenharmony_ci case CPL_ERR_PERSIST_TIMEDOUT: 11438c2ecf20Sopenharmony_ci case CPL_ERR_FINWAIT2_TIMEDOUT: 11448c2ecf20Sopenharmony_ci case CPL_ERR_KEEPALIVE_TIMEDOUT: 11458c2ecf20Sopenharmony_ci return -ETIMEDOUT; 11468c2ecf20Sopenharmony_ci default: 11478c2ecf20Sopenharmony_ci return -EIO; 11488c2ecf20Sopenharmony_ci } 11498c2ecf20Sopenharmony_ci} 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_cistatic void do_abort_req_rss(struct cxgbi_device *cdev, struct sk_buff *skb) 11528c2ecf20Sopenharmony_ci{ 11538c2ecf20Sopenharmony_ci struct cxgbi_sock *csk; 11548c2ecf20Sopenharmony_ci struct cpl_abort_req_rss *req = (struct cpl_abort_req_rss *)skb->data; 11558c2ecf20Sopenharmony_ci unsigned int tid = GET_TID(req); 11568c2ecf20Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 11578c2ecf20Sopenharmony_ci struct tid_info *t = lldi->tids; 11588c2ecf20Sopenharmony_ci int rst_status = CPL_ABORT_NO_RST; 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci csk = lookup_tid(t, tid); 11618c2ecf20Sopenharmony_ci if (unlikely(!csk)) { 11628c2ecf20Sopenharmony_ci pr_err("can't find connection for tid %u.\n", tid); 11638c2ecf20Sopenharmony_ci goto rel_skb; 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci pr_info_ipaddr("csk 0x%p,%u,0x%lx,%u, status %u.\n", 11678c2ecf20Sopenharmony_ci (&csk->saddr), (&csk->daddr), 11688c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, req->status); 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci if (is_neg_adv(req->status)) 11718c2ecf20Sopenharmony_ci goto rel_skb; 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci cxgbi_sock_get(csk); 11748c2ecf20Sopenharmony_ci spin_lock_bh(&csk->lock); 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci cxgbi_sock_clear_flag(csk, CTPF_ABORT_REQ_RCVD); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci if (!cxgbi_sock_flag(csk, CTPF_TX_DATA_SENT)) { 11798c2ecf20Sopenharmony_ci send_tx_flowc_wr(csk); 11808c2ecf20Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_TX_DATA_SENT); 11818c2ecf20Sopenharmony_ci } 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_ABORT_REQ_RCVD); 11848c2ecf20Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_ABORTING); 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci send_abort_rpl(csk, rst_status); 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci if (!cxgbi_sock_flag(csk, CTPF_ABORT_RPL_PENDING)) { 11898c2ecf20Sopenharmony_ci csk->err = abort_status_to_errno(csk, req->status, &rst_status); 11908c2ecf20Sopenharmony_ci cxgbi_sock_closed(csk); 11918c2ecf20Sopenharmony_ci } 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci spin_unlock_bh(&csk->lock); 11948c2ecf20Sopenharmony_ci cxgbi_sock_put(csk); 11958c2ecf20Sopenharmony_cirel_skb: 11968c2ecf20Sopenharmony_ci __kfree_skb(skb); 11978c2ecf20Sopenharmony_ci} 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_cistatic void do_abort_rpl_rss(struct cxgbi_device *cdev, struct sk_buff *skb) 12008c2ecf20Sopenharmony_ci{ 12018c2ecf20Sopenharmony_ci struct cxgbi_sock *csk; 12028c2ecf20Sopenharmony_ci struct cpl_abort_rpl_rss *rpl = (struct cpl_abort_rpl_rss *)skb->data; 12038c2ecf20Sopenharmony_ci unsigned int tid = GET_TID(rpl); 12048c2ecf20Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 12058c2ecf20Sopenharmony_ci struct tid_info *t = lldi->tids; 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci csk = lookup_tid(t, tid); 12088c2ecf20Sopenharmony_ci if (!csk) 12098c2ecf20Sopenharmony_ci goto rel_skb; 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci pr_info_ipaddr("csk 0x%p,%u,0x%lx,%u, status %u.\n", 12128c2ecf20Sopenharmony_ci (&csk->saddr), (&csk->daddr), csk, 12138c2ecf20Sopenharmony_ci csk->state, csk->flags, csk->tid, rpl->status); 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci if (rpl->status == CPL_ERR_ABORT_FAILED) 12168c2ecf20Sopenharmony_ci goto rel_skb; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci cxgbi_sock_rcv_abort_rpl(csk); 12198c2ecf20Sopenharmony_cirel_skb: 12208c2ecf20Sopenharmony_ci __kfree_skb(skb); 12218c2ecf20Sopenharmony_ci} 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_cistatic void do_rx_data(struct cxgbi_device *cdev, struct sk_buff *skb) 12248c2ecf20Sopenharmony_ci{ 12258c2ecf20Sopenharmony_ci struct cxgbi_sock *csk; 12268c2ecf20Sopenharmony_ci struct cpl_rx_data *cpl = (struct cpl_rx_data *)skb->data; 12278c2ecf20Sopenharmony_ci unsigned int tid = GET_TID(cpl); 12288c2ecf20Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 12298c2ecf20Sopenharmony_ci struct tid_info *t = lldi->tids; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci csk = lookup_tid(t, tid); 12328c2ecf20Sopenharmony_ci if (!csk) { 12338c2ecf20Sopenharmony_ci pr_err("can't find connection for tid %u.\n", tid); 12348c2ecf20Sopenharmony_ci } else { 12358c2ecf20Sopenharmony_ci /* not expecting this, reset the connection. */ 12368c2ecf20Sopenharmony_ci pr_err("csk 0x%p, tid %u, rcv cpl_rx_data.\n", csk, tid); 12378c2ecf20Sopenharmony_ci spin_lock_bh(&csk->lock); 12388c2ecf20Sopenharmony_ci send_abort_req(csk); 12398c2ecf20Sopenharmony_ci spin_unlock_bh(&csk->lock); 12408c2ecf20Sopenharmony_ci } 12418c2ecf20Sopenharmony_ci __kfree_skb(skb); 12428c2ecf20Sopenharmony_ci} 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_cistatic void do_rx_iscsi_hdr(struct cxgbi_device *cdev, struct sk_buff *skb) 12458c2ecf20Sopenharmony_ci{ 12468c2ecf20Sopenharmony_ci struct cxgbi_sock *csk; 12478c2ecf20Sopenharmony_ci struct cpl_iscsi_hdr *cpl = (struct cpl_iscsi_hdr *)skb->data; 12488c2ecf20Sopenharmony_ci unsigned short pdu_len_ddp = be16_to_cpu(cpl->pdu_len_ddp); 12498c2ecf20Sopenharmony_ci unsigned int tid = GET_TID(cpl); 12508c2ecf20Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 12518c2ecf20Sopenharmony_ci struct tid_info *t = lldi->tids; 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci csk = lookup_tid(t, tid); 12548c2ecf20Sopenharmony_ci if (unlikely(!csk)) { 12558c2ecf20Sopenharmony_ci pr_err("can't find conn. for tid %u.\n", tid); 12568c2ecf20Sopenharmony_ci goto rel_skb; 12578c2ecf20Sopenharmony_ci } 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, 12608c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx, tid %u, skb 0x%p,%u, 0x%x.\n", 12618c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, skb, skb->len, 12628c2ecf20Sopenharmony_ci pdu_len_ddp); 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci spin_lock_bh(&csk->lock); 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci if (unlikely(csk->state >= CTP_PASSIVE_CLOSE)) { 12678c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 12688c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, bad state.\n", 12698c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 12708c2ecf20Sopenharmony_ci if (csk->state != CTP_ABORTING) 12718c2ecf20Sopenharmony_ci goto abort_conn; 12728c2ecf20Sopenharmony_ci else 12738c2ecf20Sopenharmony_ci goto discard; 12748c2ecf20Sopenharmony_ci } 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci cxgbi_skcb_tcp_seq(skb) = ntohl(cpl->seq); 12778c2ecf20Sopenharmony_ci cxgbi_skcb_flags(skb) = 0; 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci skb_reset_transport_header(skb); 12808c2ecf20Sopenharmony_ci __skb_pull(skb, sizeof(*cpl)); 12818c2ecf20Sopenharmony_ci __pskb_trim(skb, ntohs(cpl->len)); 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci if (!csk->skb_ulp_lhdr) { 12848c2ecf20Sopenharmony_ci unsigned char *bhs; 12858c2ecf20Sopenharmony_ci unsigned int hlen, dlen, plen; 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, 12888c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx, tid %u, skb 0x%p header.\n", 12898c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, skb); 12908c2ecf20Sopenharmony_ci csk->skb_ulp_lhdr = skb; 12918c2ecf20Sopenharmony_ci cxgbi_skcb_set_flag(skb, SKCBF_RX_HDR); 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci if ((CHELSIO_CHIP_VERSION(lldi->adapter_type) <= CHELSIO_T5) && 12948c2ecf20Sopenharmony_ci (cxgbi_skcb_tcp_seq(skb) != csk->rcv_nxt)) { 12958c2ecf20Sopenharmony_ci pr_info("tid %u, CPL_ISCSI_HDR, bad seq, 0x%x/0x%x.\n", 12968c2ecf20Sopenharmony_ci csk->tid, cxgbi_skcb_tcp_seq(skb), 12978c2ecf20Sopenharmony_ci csk->rcv_nxt); 12988c2ecf20Sopenharmony_ci goto abort_conn; 12998c2ecf20Sopenharmony_ci } 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci bhs = skb->data; 13028c2ecf20Sopenharmony_ci hlen = ntohs(cpl->len); 13038c2ecf20Sopenharmony_ci dlen = ntohl(*(unsigned int *)(bhs + 4)) & 0xFFFFFF; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci plen = ISCSI_PDU_LEN_G(pdu_len_ddp); 13068c2ecf20Sopenharmony_ci if (is_t4(lldi->adapter_type)) 13078c2ecf20Sopenharmony_ci plen -= 40; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci if ((hlen + dlen) != plen) { 13108c2ecf20Sopenharmony_ci pr_info("tid 0x%x, CPL_ISCSI_HDR, pdu len " 13118c2ecf20Sopenharmony_ci "mismatch %u != %u + %u, seq 0x%x.\n", 13128c2ecf20Sopenharmony_ci csk->tid, plen, hlen, dlen, 13138c2ecf20Sopenharmony_ci cxgbi_skcb_tcp_seq(skb)); 13148c2ecf20Sopenharmony_ci goto abort_conn; 13158c2ecf20Sopenharmony_ci } 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci cxgbi_skcb_rx_pdulen(skb) = (hlen + dlen + 3) & (~0x3); 13188c2ecf20Sopenharmony_ci if (dlen) 13198c2ecf20Sopenharmony_ci cxgbi_skcb_rx_pdulen(skb) += csk->dcrc_len; 13208c2ecf20Sopenharmony_ci csk->rcv_nxt += cxgbi_skcb_rx_pdulen(skb); 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, 13238c2ecf20Sopenharmony_ci "csk 0x%p, skb 0x%p, 0x%x,%u+%u,0x%x,0x%x.\n", 13248c2ecf20Sopenharmony_ci csk, skb, *bhs, hlen, dlen, 13258c2ecf20Sopenharmony_ci ntohl(*((unsigned int *)(bhs + 16))), 13268c2ecf20Sopenharmony_ci ntohl(*((unsigned int *)(bhs + 24)))); 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci } else { 13298c2ecf20Sopenharmony_ci struct sk_buff *lskb = csk->skb_ulp_lhdr; 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci cxgbi_skcb_set_flag(lskb, SKCBF_RX_DATA); 13328c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, 13338c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx, skb 0x%p data, 0x%p.\n", 13348c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, skb, lskb); 13358c2ecf20Sopenharmony_ci } 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci __skb_queue_tail(&csk->receive_queue, skb); 13388c2ecf20Sopenharmony_ci spin_unlock_bh(&csk->lock); 13398c2ecf20Sopenharmony_ci return; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ciabort_conn: 13428c2ecf20Sopenharmony_ci send_abort_req(csk); 13438c2ecf20Sopenharmony_cidiscard: 13448c2ecf20Sopenharmony_ci spin_unlock_bh(&csk->lock); 13458c2ecf20Sopenharmony_cirel_skb: 13468c2ecf20Sopenharmony_ci __kfree_skb(skb); 13478c2ecf20Sopenharmony_ci} 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_cistatic void do_rx_iscsi_data(struct cxgbi_device *cdev, struct sk_buff *skb) 13508c2ecf20Sopenharmony_ci{ 13518c2ecf20Sopenharmony_ci struct cxgbi_sock *csk; 13528c2ecf20Sopenharmony_ci struct cpl_iscsi_hdr *cpl = (struct cpl_iscsi_hdr *)skb->data; 13538c2ecf20Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 13548c2ecf20Sopenharmony_ci struct tid_info *t = lldi->tids; 13558c2ecf20Sopenharmony_ci struct sk_buff *lskb; 13568c2ecf20Sopenharmony_ci u32 tid = GET_TID(cpl); 13578c2ecf20Sopenharmony_ci u16 pdu_len_ddp = be16_to_cpu(cpl->pdu_len_ddp); 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci csk = lookup_tid(t, tid); 13608c2ecf20Sopenharmony_ci if (unlikely(!csk)) { 13618c2ecf20Sopenharmony_ci pr_err("can't find conn. for tid %u.\n", tid); 13628c2ecf20Sopenharmony_ci goto rel_skb; 13638c2ecf20Sopenharmony_ci } 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, 13668c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx, tid %u, skb 0x%p,%u, 0x%x.\n", 13678c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, skb, 13688c2ecf20Sopenharmony_ci skb->len, pdu_len_ddp); 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci spin_lock_bh(&csk->lock); 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci if (unlikely(csk->state >= CTP_PASSIVE_CLOSE)) { 13738c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 13748c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, bad state.\n", 13758c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci if (csk->state != CTP_ABORTING) 13788c2ecf20Sopenharmony_ci goto abort_conn; 13798c2ecf20Sopenharmony_ci else 13808c2ecf20Sopenharmony_ci goto discard; 13818c2ecf20Sopenharmony_ci } 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci cxgbi_skcb_tcp_seq(skb) = be32_to_cpu(cpl->seq); 13848c2ecf20Sopenharmony_ci cxgbi_skcb_flags(skb) = 0; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci skb_reset_transport_header(skb); 13878c2ecf20Sopenharmony_ci __skb_pull(skb, sizeof(*cpl)); 13888c2ecf20Sopenharmony_ci __pskb_trim(skb, ntohs(cpl->len)); 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci if (!csk->skb_ulp_lhdr) 13918c2ecf20Sopenharmony_ci csk->skb_ulp_lhdr = skb; 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci lskb = csk->skb_ulp_lhdr; 13948c2ecf20Sopenharmony_ci cxgbi_skcb_set_flag(lskb, SKCBF_RX_DATA); 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, 13978c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx, skb 0x%p data, 0x%p.\n", 13988c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, skb, lskb); 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci __skb_queue_tail(&csk->receive_queue, skb); 14018c2ecf20Sopenharmony_ci spin_unlock_bh(&csk->lock); 14028c2ecf20Sopenharmony_ci return; 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ciabort_conn: 14058c2ecf20Sopenharmony_ci send_abort_req(csk); 14068c2ecf20Sopenharmony_cidiscard: 14078c2ecf20Sopenharmony_ci spin_unlock_bh(&csk->lock); 14088c2ecf20Sopenharmony_cirel_skb: 14098c2ecf20Sopenharmony_ci __kfree_skb(skb); 14108c2ecf20Sopenharmony_ci} 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_cistatic void 14138c2ecf20Sopenharmony_cicxgb4i_process_ddpvld(struct cxgbi_sock *csk, 14148c2ecf20Sopenharmony_ci struct sk_buff *skb, u32 ddpvld) 14158c2ecf20Sopenharmony_ci{ 14168c2ecf20Sopenharmony_ci if (ddpvld & (1 << CPL_RX_DDP_STATUS_HCRC_SHIFT)) { 14178c2ecf20Sopenharmony_ci pr_info("csk 0x%p, lhdr 0x%p, status 0x%x, hcrc bad 0x%lx.\n", 14188c2ecf20Sopenharmony_ci csk, skb, ddpvld, cxgbi_skcb_flags(skb)); 14198c2ecf20Sopenharmony_ci cxgbi_skcb_set_flag(skb, SKCBF_RX_HCRC_ERR); 14208c2ecf20Sopenharmony_ci } 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci if (ddpvld & (1 << CPL_RX_DDP_STATUS_DCRC_SHIFT)) { 14238c2ecf20Sopenharmony_ci pr_info("csk 0x%p, lhdr 0x%p, status 0x%x, dcrc bad 0x%lx.\n", 14248c2ecf20Sopenharmony_ci csk, skb, ddpvld, cxgbi_skcb_flags(skb)); 14258c2ecf20Sopenharmony_ci cxgbi_skcb_set_flag(skb, SKCBF_RX_DCRC_ERR); 14268c2ecf20Sopenharmony_ci } 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci if (ddpvld & (1 << CPL_RX_DDP_STATUS_PAD_SHIFT)) { 14298c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 14308c2ecf20Sopenharmony_ci "csk 0x%p, lhdr 0x%p, status 0x%x, pad bad.\n", 14318c2ecf20Sopenharmony_ci csk, skb, ddpvld); 14328c2ecf20Sopenharmony_ci cxgbi_skcb_set_flag(skb, SKCBF_RX_PAD_ERR); 14338c2ecf20Sopenharmony_ci } 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci if ((ddpvld & (1 << CPL_RX_DDP_STATUS_DDP_SHIFT)) && 14368c2ecf20Sopenharmony_ci !cxgbi_skcb_test_flag(skb, SKCBF_RX_DATA)) { 14378c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 14388c2ecf20Sopenharmony_ci "csk 0x%p, lhdr 0x%p, 0x%x, data ddp'ed.\n", 14398c2ecf20Sopenharmony_ci csk, skb, ddpvld); 14408c2ecf20Sopenharmony_ci cxgbi_skcb_set_flag(skb, SKCBF_RX_DATA_DDPD); 14418c2ecf20Sopenharmony_ci } 14428c2ecf20Sopenharmony_ci} 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_cistatic void do_rx_data_ddp(struct cxgbi_device *cdev, 14458c2ecf20Sopenharmony_ci struct sk_buff *skb) 14468c2ecf20Sopenharmony_ci{ 14478c2ecf20Sopenharmony_ci struct cxgbi_sock *csk; 14488c2ecf20Sopenharmony_ci struct sk_buff *lskb; 14498c2ecf20Sopenharmony_ci struct cpl_rx_data_ddp *rpl = (struct cpl_rx_data_ddp *)skb->data; 14508c2ecf20Sopenharmony_ci unsigned int tid = GET_TID(rpl); 14518c2ecf20Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 14528c2ecf20Sopenharmony_ci struct tid_info *t = lldi->tids; 14538c2ecf20Sopenharmony_ci u32 ddpvld = be32_to_cpu(rpl->ddpvld); 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci csk = lookup_tid(t, tid); 14568c2ecf20Sopenharmony_ci if (unlikely(!csk)) { 14578c2ecf20Sopenharmony_ci pr_err("can't find connection for tid %u.\n", tid); 14588c2ecf20Sopenharmony_ci goto rel_skb; 14598c2ecf20Sopenharmony_ci } 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, 14628c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx, skb 0x%p,0x%x, lhdr 0x%p.\n", 14638c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, skb, ddpvld, csk->skb_ulp_lhdr); 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci spin_lock_bh(&csk->lock); 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci if (unlikely(csk->state >= CTP_PASSIVE_CLOSE)) { 14688c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 14698c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, bad state.\n", 14708c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 14718c2ecf20Sopenharmony_ci if (csk->state != CTP_ABORTING) 14728c2ecf20Sopenharmony_ci goto abort_conn; 14738c2ecf20Sopenharmony_ci else 14748c2ecf20Sopenharmony_ci goto discard; 14758c2ecf20Sopenharmony_ci } 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci if (!csk->skb_ulp_lhdr) { 14788c2ecf20Sopenharmony_ci pr_err("tid 0x%x, rcv RX_DATA_DDP w/o pdu bhs.\n", csk->tid); 14798c2ecf20Sopenharmony_ci goto abort_conn; 14808c2ecf20Sopenharmony_ci } 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci lskb = csk->skb_ulp_lhdr; 14838c2ecf20Sopenharmony_ci csk->skb_ulp_lhdr = NULL; 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci cxgbi_skcb_rx_ddigest(lskb) = ntohl(rpl->ulp_crc); 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci if (ntohs(rpl->len) != cxgbi_skcb_rx_pdulen(lskb)) 14888c2ecf20Sopenharmony_ci pr_info("tid 0x%x, RX_DATA_DDP pdulen %u != %u.\n", 14898c2ecf20Sopenharmony_ci csk->tid, ntohs(rpl->len), cxgbi_skcb_rx_pdulen(lskb)); 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci cxgb4i_process_ddpvld(csk, lskb, ddpvld); 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, 14948c2ecf20Sopenharmony_ci "csk 0x%p, lskb 0x%p, f 0x%lx.\n", 14958c2ecf20Sopenharmony_ci csk, lskb, cxgbi_skcb_flags(lskb)); 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci cxgbi_skcb_set_flag(lskb, SKCBF_RX_STATUS); 14988c2ecf20Sopenharmony_ci cxgbi_conn_pdu_ready(csk); 14998c2ecf20Sopenharmony_ci spin_unlock_bh(&csk->lock); 15008c2ecf20Sopenharmony_ci goto rel_skb; 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ciabort_conn: 15038c2ecf20Sopenharmony_ci send_abort_req(csk); 15048c2ecf20Sopenharmony_cidiscard: 15058c2ecf20Sopenharmony_ci spin_unlock_bh(&csk->lock); 15068c2ecf20Sopenharmony_cirel_skb: 15078c2ecf20Sopenharmony_ci __kfree_skb(skb); 15088c2ecf20Sopenharmony_ci} 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_cistatic void 15118c2ecf20Sopenharmony_cido_rx_iscsi_cmp(struct cxgbi_device *cdev, struct sk_buff *skb) 15128c2ecf20Sopenharmony_ci{ 15138c2ecf20Sopenharmony_ci struct cxgbi_sock *csk; 15148c2ecf20Sopenharmony_ci struct cpl_rx_iscsi_cmp *rpl = (struct cpl_rx_iscsi_cmp *)skb->data; 15158c2ecf20Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 15168c2ecf20Sopenharmony_ci struct tid_info *t = lldi->tids; 15178c2ecf20Sopenharmony_ci struct sk_buff *data_skb = NULL; 15188c2ecf20Sopenharmony_ci u32 tid = GET_TID(rpl); 15198c2ecf20Sopenharmony_ci u32 ddpvld = be32_to_cpu(rpl->ddpvld); 15208c2ecf20Sopenharmony_ci u32 seq = be32_to_cpu(rpl->seq); 15218c2ecf20Sopenharmony_ci u16 pdu_len_ddp = be16_to_cpu(rpl->pdu_len_ddp); 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci csk = lookup_tid(t, tid); 15248c2ecf20Sopenharmony_ci if (unlikely(!csk)) { 15258c2ecf20Sopenharmony_ci pr_err("can't find connection for tid %u.\n", tid); 15268c2ecf20Sopenharmony_ci goto rel_skb; 15278c2ecf20Sopenharmony_ci } 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, 15308c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx, skb 0x%p,0x%x, lhdr 0x%p, len %u, " 15318c2ecf20Sopenharmony_ci "pdu_len_ddp %u, status %u.\n", 15328c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, skb, ddpvld, csk->skb_ulp_lhdr, 15338c2ecf20Sopenharmony_ci ntohs(rpl->len), pdu_len_ddp, rpl->status); 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci spin_lock_bh(&csk->lock); 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci if (unlikely(csk->state >= CTP_PASSIVE_CLOSE)) { 15388c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 15398c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u, bad state.\n", 15408c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci if (csk->state != CTP_ABORTING) 15438c2ecf20Sopenharmony_ci goto abort_conn; 15448c2ecf20Sopenharmony_ci else 15458c2ecf20Sopenharmony_ci goto discard; 15468c2ecf20Sopenharmony_ci } 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci cxgbi_skcb_tcp_seq(skb) = seq; 15498c2ecf20Sopenharmony_ci cxgbi_skcb_flags(skb) = 0; 15508c2ecf20Sopenharmony_ci cxgbi_skcb_rx_pdulen(skb) = 0; 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci skb_reset_transport_header(skb); 15538c2ecf20Sopenharmony_ci __skb_pull(skb, sizeof(*rpl)); 15548c2ecf20Sopenharmony_ci __pskb_trim(skb, be16_to_cpu(rpl->len)); 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci csk->rcv_nxt = seq + pdu_len_ddp; 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci if (csk->skb_ulp_lhdr) { 15598c2ecf20Sopenharmony_ci data_skb = skb_peek(&csk->receive_queue); 15608c2ecf20Sopenharmony_ci if (!data_skb || 15618c2ecf20Sopenharmony_ci !cxgbi_skcb_test_flag(data_skb, SKCBF_RX_DATA)) { 15628c2ecf20Sopenharmony_ci pr_err("Error! freelist data not found 0x%p, tid %u\n", 15638c2ecf20Sopenharmony_ci data_skb, tid); 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci goto abort_conn; 15668c2ecf20Sopenharmony_ci } 15678c2ecf20Sopenharmony_ci __skb_unlink(data_skb, &csk->receive_queue); 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci cxgbi_skcb_set_flag(skb, SKCBF_RX_DATA); 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci __skb_queue_tail(&csk->receive_queue, skb); 15728c2ecf20Sopenharmony_ci __skb_queue_tail(&csk->receive_queue, data_skb); 15738c2ecf20Sopenharmony_ci } else { 15748c2ecf20Sopenharmony_ci __skb_queue_tail(&csk->receive_queue, skb); 15758c2ecf20Sopenharmony_ci } 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci csk->skb_ulp_lhdr = NULL; 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci cxgbi_skcb_set_flag(skb, SKCBF_RX_HDR); 15808c2ecf20Sopenharmony_ci cxgbi_skcb_set_flag(skb, SKCBF_RX_STATUS); 15818c2ecf20Sopenharmony_ci cxgbi_skcb_set_flag(skb, SKCBF_RX_ISCSI_COMPL); 15828c2ecf20Sopenharmony_ci cxgbi_skcb_rx_ddigest(skb) = be32_to_cpu(rpl->ulp_crc); 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci cxgb4i_process_ddpvld(csk, skb, ddpvld); 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_PDU_RX, "csk 0x%p, skb 0x%p, f 0x%lx.\n", 15878c2ecf20Sopenharmony_ci csk, skb, cxgbi_skcb_flags(skb)); 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci cxgbi_conn_pdu_ready(csk); 15908c2ecf20Sopenharmony_ci spin_unlock_bh(&csk->lock); 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci return; 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ciabort_conn: 15958c2ecf20Sopenharmony_ci send_abort_req(csk); 15968c2ecf20Sopenharmony_cidiscard: 15978c2ecf20Sopenharmony_ci spin_unlock_bh(&csk->lock); 15988c2ecf20Sopenharmony_cirel_skb: 15998c2ecf20Sopenharmony_ci __kfree_skb(skb); 16008c2ecf20Sopenharmony_ci} 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_cistatic void do_fw4_ack(struct cxgbi_device *cdev, struct sk_buff *skb) 16038c2ecf20Sopenharmony_ci{ 16048c2ecf20Sopenharmony_ci struct cxgbi_sock *csk; 16058c2ecf20Sopenharmony_ci struct cpl_fw4_ack *rpl = (struct cpl_fw4_ack *)skb->data; 16068c2ecf20Sopenharmony_ci unsigned int tid = GET_TID(rpl); 16078c2ecf20Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 16088c2ecf20Sopenharmony_ci struct tid_info *t = lldi->tids; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci csk = lookup_tid(t, tid); 16118c2ecf20Sopenharmony_ci if (unlikely(!csk)) 16128c2ecf20Sopenharmony_ci pr_err("can't find connection for tid %u.\n", tid); 16138c2ecf20Sopenharmony_ci else { 16148c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 16158c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u.\n", 16168c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 16178c2ecf20Sopenharmony_ci cxgbi_sock_rcv_wr_ack(csk, rpl->credits, ntohl(rpl->snd_una), 16188c2ecf20Sopenharmony_ci rpl->seq_vld); 16198c2ecf20Sopenharmony_ci } 16208c2ecf20Sopenharmony_ci __kfree_skb(skb); 16218c2ecf20Sopenharmony_ci} 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_cistatic void do_set_tcb_rpl(struct cxgbi_device *cdev, struct sk_buff *skb) 16248c2ecf20Sopenharmony_ci{ 16258c2ecf20Sopenharmony_ci struct cpl_set_tcb_rpl *rpl = (struct cpl_set_tcb_rpl *)skb->data; 16268c2ecf20Sopenharmony_ci unsigned int tid = GET_TID(rpl); 16278c2ecf20Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 16288c2ecf20Sopenharmony_ci struct tid_info *t = lldi->tids; 16298c2ecf20Sopenharmony_ci struct cxgbi_sock *csk; 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci csk = lookup_tid(t, tid); 16328c2ecf20Sopenharmony_ci if (!csk) { 16338c2ecf20Sopenharmony_ci pr_err("can't find conn. for tid %u.\n", tid); 16348c2ecf20Sopenharmony_ci return; 16358c2ecf20Sopenharmony_ci } 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 16388c2ecf20Sopenharmony_ci "csk 0x%p,%u,%lx,%u, status 0x%x.\n", 16398c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid, rpl->status); 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci if (rpl->status != CPL_ERR_NONE) { 16428c2ecf20Sopenharmony_ci pr_err("csk 0x%p,%u, SET_TCB_RPL status %u.\n", 16438c2ecf20Sopenharmony_ci csk, tid, rpl->status); 16448c2ecf20Sopenharmony_ci csk->err = -EINVAL; 16458c2ecf20Sopenharmony_ci } 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci complete(&csk->cmpl); 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci __kfree_skb(skb); 16508c2ecf20Sopenharmony_ci} 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_cistatic int alloc_cpls(struct cxgbi_sock *csk) 16538c2ecf20Sopenharmony_ci{ 16548c2ecf20Sopenharmony_ci csk->cpl_close = alloc_wr(sizeof(struct cpl_close_con_req), 16558c2ecf20Sopenharmony_ci 0, GFP_KERNEL); 16568c2ecf20Sopenharmony_ci if (!csk->cpl_close) 16578c2ecf20Sopenharmony_ci return -ENOMEM; 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci csk->cpl_abort_req = alloc_wr(sizeof(struct cpl_abort_req), 16608c2ecf20Sopenharmony_ci 0, GFP_KERNEL); 16618c2ecf20Sopenharmony_ci if (!csk->cpl_abort_req) 16628c2ecf20Sopenharmony_ci goto free_cpls; 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci csk->cpl_abort_rpl = alloc_wr(sizeof(struct cpl_abort_rpl), 16658c2ecf20Sopenharmony_ci 0, GFP_KERNEL); 16668c2ecf20Sopenharmony_ci if (!csk->cpl_abort_rpl) 16678c2ecf20Sopenharmony_ci goto free_cpls; 16688c2ecf20Sopenharmony_ci return 0; 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_cifree_cpls: 16718c2ecf20Sopenharmony_ci cxgbi_sock_free_cpl_skbs(csk); 16728c2ecf20Sopenharmony_ci return -ENOMEM; 16738c2ecf20Sopenharmony_ci} 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_cistatic inline void l2t_put(struct cxgbi_sock *csk) 16768c2ecf20Sopenharmony_ci{ 16778c2ecf20Sopenharmony_ci if (csk->l2t) { 16788c2ecf20Sopenharmony_ci cxgb4_l2t_release(csk->l2t); 16798c2ecf20Sopenharmony_ci csk->l2t = NULL; 16808c2ecf20Sopenharmony_ci cxgbi_sock_put(csk); 16818c2ecf20Sopenharmony_ci } 16828c2ecf20Sopenharmony_ci} 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_cistatic void release_offload_resources(struct cxgbi_sock *csk) 16858c2ecf20Sopenharmony_ci{ 16868c2ecf20Sopenharmony_ci struct cxgb4_lld_info *lldi; 16878c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 16888c2ecf20Sopenharmony_ci struct net_device *ndev = csk->cdev->ports[csk->port_id]; 16898c2ecf20Sopenharmony_ci#endif 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 16928c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u.\n", 16938c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci cxgbi_sock_free_cpl_skbs(csk); 16968c2ecf20Sopenharmony_ci cxgbi_sock_purge_write_queue(csk); 16978c2ecf20Sopenharmony_ci if (csk->wr_cred != csk->wr_max_cred) { 16988c2ecf20Sopenharmony_ci cxgbi_sock_purge_wr_queue(csk); 16998c2ecf20Sopenharmony_ci cxgbi_sock_reset_wr_list(csk); 17008c2ecf20Sopenharmony_ci } 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci l2t_put(csk); 17038c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 17048c2ecf20Sopenharmony_ci if (csk->csk_family == AF_INET6) 17058c2ecf20Sopenharmony_ci cxgb4_clip_release(ndev, 17068c2ecf20Sopenharmony_ci (const u32 *)&csk->saddr6.sin6_addr, 1); 17078c2ecf20Sopenharmony_ci#endif 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci if (cxgbi_sock_flag(csk, CTPF_HAS_ATID)) 17108c2ecf20Sopenharmony_ci free_atid(csk); 17118c2ecf20Sopenharmony_ci else if (cxgbi_sock_flag(csk, CTPF_HAS_TID)) { 17128c2ecf20Sopenharmony_ci lldi = cxgbi_cdev_priv(csk->cdev); 17138c2ecf20Sopenharmony_ci cxgb4_remove_tid(lldi->tids, 0, csk->tid, 17148c2ecf20Sopenharmony_ci csk->csk_family); 17158c2ecf20Sopenharmony_ci cxgbi_sock_clear_flag(csk, CTPF_HAS_TID); 17168c2ecf20Sopenharmony_ci cxgbi_sock_put(csk); 17178c2ecf20Sopenharmony_ci } 17188c2ecf20Sopenharmony_ci csk->dst = NULL; 17198c2ecf20Sopenharmony_ci} 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 17228c2ecf20Sopenharmony_cistatic inline u8 get_iscsi_dcb_state(struct net_device *ndev) 17238c2ecf20Sopenharmony_ci{ 17248c2ecf20Sopenharmony_ci return ndev->dcbnl_ops->getstate(ndev); 17258c2ecf20Sopenharmony_ci} 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_cistatic int select_priority(int pri_mask) 17288c2ecf20Sopenharmony_ci{ 17298c2ecf20Sopenharmony_ci if (!pri_mask) 17308c2ecf20Sopenharmony_ci return 0; 17318c2ecf20Sopenharmony_ci return (ffs(pri_mask) - 1); 17328c2ecf20Sopenharmony_ci} 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_cistatic u8 get_iscsi_dcb_priority(struct net_device *ndev) 17358c2ecf20Sopenharmony_ci{ 17368c2ecf20Sopenharmony_ci int rv; 17378c2ecf20Sopenharmony_ci u8 caps; 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci struct dcb_app iscsi_dcb_app = { 17408c2ecf20Sopenharmony_ci .protocol = 3260 17418c2ecf20Sopenharmony_ci }; 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci rv = (int)ndev->dcbnl_ops->getcap(ndev, DCB_CAP_ATTR_DCBX, &caps); 17448c2ecf20Sopenharmony_ci if (rv) 17458c2ecf20Sopenharmony_ci return 0; 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci if (caps & DCB_CAP_DCBX_VER_IEEE) { 17488c2ecf20Sopenharmony_ci iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_STREAM; 17498c2ecf20Sopenharmony_ci rv = dcb_ieee_getapp_mask(ndev, &iscsi_dcb_app); 17508c2ecf20Sopenharmony_ci if (!rv) { 17518c2ecf20Sopenharmony_ci iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_ANY; 17528c2ecf20Sopenharmony_ci rv = dcb_ieee_getapp_mask(ndev, &iscsi_dcb_app); 17538c2ecf20Sopenharmony_ci } 17548c2ecf20Sopenharmony_ci } else if (caps & DCB_CAP_DCBX_VER_CEE) { 17558c2ecf20Sopenharmony_ci iscsi_dcb_app.selector = DCB_APP_IDTYPE_PORTNUM; 17568c2ecf20Sopenharmony_ci rv = dcb_getapp(ndev, &iscsi_dcb_app); 17578c2ecf20Sopenharmony_ci } 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, 17608c2ecf20Sopenharmony_ci "iSCSI priority is set to %u\n", select_priority(rv)); 17618c2ecf20Sopenharmony_ci return select_priority(rv); 17628c2ecf20Sopenharmony_ci} 17638c2ecf20Sopenharmony_ci#endif 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_cistatic int init_act_open(struct cxgbi_sock *csk) 17668c2ecf20Sopenharmony_ci{ 17678c2ecf20Sopenharmony_ci struct cxgbi_device *cdev = csk->cdev; 17688c2ecf20Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 17698c2ecf20Sopenharmony_ci struct net_device *ndev = cdev->ports[csk->port_id]; 17708c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 17718c2ecf20Sopenharmony_ci struct neighbour *n = NULL; 17728c2ecf20Sopenharmony_ci void *daddr; 17738c2ecf20Sopenharmony_ci unsigned int step; 17748c2ecf20Sopenharmony_ci unsigned int rxq_idx; 17758c2ecf20Sopenharmony_ci unsigned int size, size6; 17768c2ecf20Sopenharmony_ci unsigned int linkspeed; 17778c2ecf20Sopenharmony_ci unsigned int rcv_winf, snd_winf; 17788c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 17798c2ecf20Sopenharmony_ci u8 priority = 0; 17808c2ecf20Sopenharmony_ci#endif 17818c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 17828c2ecf20Sopenharmony_ci "csk 0x%p,%u,0x%lx,%u.\n", 17838c2ecf20Sopenharmony_ci csk, csk->state, csk->flags, csk->tid); 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci if (csk->csk_family == AF_INET) 17868c2ecf20Sopenharmony_ci daddr = &csk->daddr.sin_addr.s_addr; 17878c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 17888c2ecf20Sopenharmony_ci else if (csk->csk_family == AF_INET6) 17898c2ecf20Sopenharmony_ci daddr = &csk->daddr6.sin6_addr; 17908c2ecf20Sopenharmony_ci#endif 17918c2ecf20Sopenharmony_ci else { 17928c2ecf20Sopenharmony_ci pr_err("address family 0x%x not supported\n", csk->csk_family); 17938c2ecf20Sopenharmony_ci goto rel_resource; 17948c2ecf20Sopenharmony_ci } 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci n = dst_neigh_lookup(csk->dst, daddr); 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci if (!n) { 17998c2ecf20Sopenharmony_ci pr_err("%s, can't get neighbour of csk->dst.\n", ndev->name); 18008c2ecf20Sopenharmony_ci goto rel_resource; 18018c2ecf20Sopenharmony_ci } 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci if (!(n->nud_state & NUD_VALID)) 18048c2ecf20Sopenharmony_ci neigh_event_send(n, NULL); 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci csk->atid = cxgb4_alloc_atid(lldi->tids, csk); 18078c2ecf20Sopenharmony_ci if (csk->atid < 0) { 18088c2ecf20Sopenharmony_ci pr_err("%s, NO atid available.\n", ndev->name); 18098c2ecf20Sopenharmony_ci goto rel_resource_without_clip; 18108c2ecf20Sopenharmony_ci } 18118c2ecf20Sopenharmony_ci cxgbi_sock_set_flag(csk, CTPF_HAS_ATID); 18128c2ecf20Sopenharmony_ci cxgbi_sock_get(csk); 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 18158c2ecf20Sopenharmony_ci if (get_iscsi_dcb_state(ndev)) 18168c2ecf20Sopenharmony_ci priority = get_iscsi_dcb_priority(ndev); 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci csk->dcb_priority = priority; 18198c2ecf20Sopenharmony_ci csk->l2t = cxgb4_l2t_get(lldi->l2t, n, ndev, priority); 18208c2ecf20Sopenharmony_ci#else 18218c2ecf20Sopenharmony_ci csk->l2t = cxgb4_l2t_get(lldi->l2t, n, ndev, 0); 18228c2ecf20Sopenharmony_ci#endif 18238c2ecf20Sopenharmony_ci if (!csk->l2t) { 18248c2ecf20Sopenharmony_ci pr_err("%s, cannot alloc l2t.\n", ndev->name); 18258c2ecf20Sopenharmony_ci goto rel_resource_without_clip; 18268c2ecf20Sopenharmony_ci } 18278c2ecf20Sopenharmony_ci cxgbi_sock_get(csk); 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 18308c2ecf20Sopenharmony_ci if (csk->csk_family == AF_INET6) 18318c2ecf20Sopenharmony_ci cxgb4_clip_get(ndev, (const u32 *)&csk->saddr6.sin6_addr, 1); 18328c2ecf20Sopenharmony_ci#endif 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci if (is_t4(lldi->adapter_type)) { 18358c2ecf20Sopenharmony_ci size = sizeof(struct cpl_act_open_req); 18368c2ecf20Sopenharmony_ci size6 = sizeof(struct cpl_act_open_req6); 18378c2ecf20Sopenharmony_ci } else if (is_t5(lldi->adapter_type)) { 18388c2ecf20Sopenharmony_ci size = sizeof(struct cpl_t5_act_open_req); 18398c2ecf20Sopenharmony_ci size6 = sizeof(struct cpl_t5_act_open_req6); 18408c2ecf20Sopenharmony_ci } else { 18418c2ecf20Sopenharmony_ci size = sizeof(struct cpl_t6_act_open_req); 18428c2ecf20Sopenharmony_ci size6 = sizeof(struct cpl_t6_act_open_req6); 18438c2ecf20Sopenharmony_ci } 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci if (csk->csk_family == AF_INET) 18468c2ecf20Sopenharmony_ci skb = alloc_wr(size, 0, GFP_NOIO); 18478c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 18488c2ecf20Sopenharmony_ci else 18498c2ecf20Sopenharmony_ci skb = alloc_wr(size6, 0, GFP_NOIO); 18508c2ecf20Sopenharmony_ci#endif 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci if (!skb) 18538c2ecf20Sopenharmony_ci goto rel_resource; 18548c2ecf20Sopenharmony_ci skb->sk = (struct sock *)csk; 18558c2ecf20Sopenharmony_ci t4_set_arp_err_handler(skb, csk, cxgbi_sock_act_open_req_arp_failure); 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci if (!csk->mtu) 18588c2ecf20Sopenharmony_ci csk->mtu = dst_mtu(csk->dst); 18598c2ecf20Sopenharmony_ci cxgb4_best_mtu(lldi->mtus, csk->mtu, &csk->mss_idx); 18608c2ecf20Sopenharmony_ci csk->tx_chan = cxgb4_port_chan(ndev); 18618c2ecf20Sopenharmony_ci csk->smac_idx = ((struct port_info *)netdev_priv(ndev))->smt_idx; 18628c2ecf20Sopenharmony_ci step = lldi->ntxq / lldi->nchan; 18638c2ecf20Sopenharmony_ci csk->txq_idx = cxgb4_port_idx(ndev) * step; 18648c2ecf20Sopenharmony_ci step = lldi->nrxq / lldi->nchan; 18658c2ecf20Sopenharmony_ci rxq_idx = (cxgb4_port_idx(ndev) * step) + (cdev->rxq_idx_cntr % step); 18668c2ecf20Sopenharmony_ci cdev->rxq_idx_cntr++; 18678c2ecf20Sopenharmony_ci csk->rss_qid = lldi->rxq_ids[rxq_idx]; 18688c2ecf20Sopenharmony_ci linkspeed = ((struct port_info *)netdev_priv(ndev))->link_cfg.speed; 18698c2ecf20Sopenharmony_ci csk->snd_win = cxgb4i_snd_win; 18708c2ecf20Sopenharmony_ci csk->rcv_win = cxgb4i_rcv_win; 18718c2ecf20Sopenharmony_ci if (cxgb4i_rcv_win <= 0) { 18728c2ecf20Sopenharmony_ci csk->rcv_win = CXGB4I_DEFAULT_10G_RCV_WIN; 18738c2ecf20Sopenharmony_ci rcv_winf = linkspeed / SPEED_10000; 18748c2ecf20Sopenharmony_ci if (rcv_winf) 18758c2ecf20Sopenharmony_ci csk->rcv_win *= rcv_winf; 18768c2ecf20Sopenharmony_ci } 18778c2ecf20Sopenharmony_ci if (cxgb4i_snd_win <= 0) { 18788c2ecf20Sopenharmony_ci csk->snd_win = CXGB4I_DEFAULT_10G_SND_WIN; 18798c2ecf20Sopenharmony_ci snd_winf = linkspeed / SPEED_10000; 18808c2ecf20Sopenharmony_ci if (snd_winf) 18818c2ecf20Sopenharmony_ci csk->snd_win *= snd_winf; 18828c2ecf20Sopenharmony_ci } 18838c2ecf20Sopenharmony_ci csk->wr_cred = lldi->wr_cred - 18848c2ecf20Sopenharmony_ci DIV_ROUND_UP(sizeof(struct cpl_abort_req), 16); 18858c2ecf20Sopenharmony_ci csk->wr_max_cred = csk->wr_cred; 18868c2ecf20Sopenharmony_ci csk->wr_una_cred = 0; 18878c2ecf20Sopenharmony_ci cxgbi_sock_reset_wr_list(csk); 18888c2ecf20Sopenharmony_ci csk->err = 0; 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci pr_info_ipaddr("csk 0x%p,%u,0x%lx,%u,%u,%u, mtu %u,%u, smac %u.\n", 18918c2ecf20Sopenharmony_ci (&csk->saddr), (&csk->daddr), csk, csk->state, 18928c2ecf20Sopenharmony_ci csk->flags, csk->tx_chan, csk->txq_idx, csk->rss_qid, 18938c2ecf20Sopenharmony_ci csk->mtu, csk->mss_idx, csk->smac_idx); 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci /* must wait for either a act_open_rpl or act_open_establish */ 18968c2ecf20Sopenharmony_ci if (!try_module_get(cdev->owner)) { 18978c2ecf20Sopenharmony_ci pr_err("%s, try_module_get failed.\n", ndev->name); 18988c2ecf20Sopenharmony_ci goto rel_resource; 18998c2ecf20Sopenharmony_ci } 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci cxgbi_sock_set_state(csk, CTP_ACTIVE_OPEN); 19028c2ecf20Sopenharmony_ci if (csk->csk_family == AF_INET) 19038c2ecf20Sopenharmony_ci send_act_open_req(csk, skb, csk->l2t); 19048c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 19058c2ecf20Sopenharmony_ci else 19068c2ecf20Sopenharmony_ci send_act_open_req6(csk, skb, csk->l2t); 19078c2ecf20Sopenharmony_ci#endif 19088c2ecf20Sopenharmony_ci neigh_release(n); 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci return 0; 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_cirel_resource: 19138c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 19148c2ecf20Sopenharmony_ci if (csk->csk_family == AF_INET6) 19158c2ecf20Sopenharmony_ci cxgb4_clip_release(ndev, 19168c2ecf20Sopenharmony_ci (const u32 *)&csk->saddr6.sin6_addr, 1); 19178c2ecf20Sopenharmony_ci#endif 19188c2ecf20Sopenharmony_cirel_resource_without_clip: 19198c2ecf20Sopenharmony_ci if (n) 19208c2ecf20Sopenharmony_ci neigh_release(n); 19218c2ecf20Sopenharmony_ci if (skb) 19228c2ecf20Sopenharmony_ci __kfree_skb(skb); 19238c2ecf20Sopenharmony_ci return -EINVAL; 19248c2ecf20Sopenharmony_ci} 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_cistatic cxgb4i_cplhandler_func cxgb4i_cplhandlers[NUM_CPL_CMDS] = { 19278c2ecf20Sopenharmony_ci [CPL_ACT_ESTABLISH] = do_act_establish, 19288c2ecf20Sopenharmony_ci [CPL_ACT_OPEN_RPL] = do_act_open_rpl, 19298c2ecf20Sopenharmony_ci [CPL_PEER_CLOSE] = do_peer_close, 19308c2ecf20Sopenharmony_ci [CPL_ABORT_REQ_RSS] = do_abort_req_rss, 19318c2ecf20Sopenharmony_ci [CPL_ABORT_RPL_RSS] = do_abort_rpl_rss, 19328c2ecf20Sopenharmony_ci [CPL_CLOSE_CON_RPL] = do_close_con_rpl, 19338c2ecf20Sopenharmony_ci [CPL_FW4_ACK] = do_fw4_ack, 19348c2ecf20Sopenharmony_ci [CPL_ISCSI_HDR] = do_rx_iscsi_hdr, 19358c2ecf20Sopenharmony_ci [CPL_ISCSI_DATA] = do_rx_iscsi_data, 19368c2ecf20Sopenharmony_ci [CPL_SET_TCB_RPL] = do_set_tcb_rpl, 19378c2ecf20Sopenharmony_ci [CPL_RX_DATA_DDP] = do_rx_data_ddp, 19388c2ecf20Sopenharmony_ci [CPL_RX_ISCSI_DDP] = do_rx_data_ddp, 19398c2ecf20Sopenharmony_ci [CPL_RX_ISCSI_CMP] = do_rx_iscsi_cmp, 19408c2ecf20Sopenharmony_ci [CPL_RX_DATA] = do_rx_data, 19418c2ecf20Sopenharmony_ci}; 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_cistatic int cxgb4i_ofld_init(struct cxgbi_device *cdev) 19448c2ecf20Sopenharmony_ci{ 19458c2ecf20Sopenharmony_ci int rc; 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci if (cxgb4i_max_connect > CXGB4I_MAX_CONN) 19488c2ecf20Sopenharmony_ci cxgb4i_max_connect = CXGB4I_MAX_CONN; 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci rc = cxgbi_device_portmap_create(cdev, cxgb4i_sport_base, 19518c2ecf20Sopenharmony_ci cxgb4i_max_connect); 19528c2ecf20Sopenharmony_ci if (rc < 0) 19538c2ecf20Sopenharmony_ci return rc; 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci cdev->csk_release_offload_resources = release_offload_resources; 19568c2ecf20Sopenharmony_ci cdev->csk_push_tx_frames = push_tx_frames; 19578c2ecf20Sopenharmony_ci cdev->csk_send_abort_req = send_abort_req; 19588c2ecf20Sopenharmony_ci cdev->csk_send_close_req = send_close_req; 19598c2ecf20Sopenharmony_ci cdev->csk_send_rx_credits = send_rx_credits; 19608c2ecf20Sopenharmony_ci cdev->csk_alloc_cpls = alloc_cpls; 19618c2ecf20Sopenharmony_ci cdev->csk_init_act_open = init_act_open; 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci pr_info("cdev 0x%p, offload up, added.\n", cdev); 19648c2ecf20Sopenharmony_ci return 0; 19658c2ecf20Sopenharmony_ci} 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_cistatic inline void 19688c2ecf20Sopenharmony_ciulp_mem_io_set_hdr(struct cxgbi_device *cdev, 19698c2ecf20Sopenharmony_ci struct ulp_mem_io *req, 19708c2ecf20Sopenharmony_ci unsigned int wr_len, unsigned int dlen, 19718c2ecf20Sopenharmony_ci unsigned int pm_addr, 19728c2ecf20Sopenharmony_ci int tid) 19738c2ecf20Sopenharmony_ci{ 19748c2ecf20Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 19758c2ecf20Sopenharmony_ci struct ulptx_idata *idata = (struct ulptx_idata *)(req + 1); 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_ci INIT_ULPTX_WR(req, wr_len, 0, tid); 19788c2ecf20Sopenharmony_ci req->wr.wr_hi = htonl(FW_WR_OP_V(FW_ULPTX_WR) | 19798c2ecf20Sopenharmony_ci FW_WR_ATOMIC_V(0)); 19808c2ecf20Sopenharmony_ci req->cmd = htonl(ULPTX_CMD_V(ULP_TX_MEM_WRITE) | 19818c2ecf20Sopenharmony_ci ULP_MEMIO_ORDER_V(is_t4(lldi->adapter_type)) | 19828c2ecf20Sopenharmony_ci T5_ULP_MEMIO_IMM_V(!is_t4(lldi->adapter_type))); 19838c2ecf20Sopenharmony_ci req->dlen = htonl(ULP_MEMIO_DATA_LEN_V(dlen >> 5)); 19848c2ecf20Sopenharmony_ci req->lock_addr = htonl(ULP_MEMIO_ADDR_V(pm_addr >> 5)); 19858c2ecf20Sopenharmony_ci req->len16 = htonl(DIV_ROUND_UP(wr_len - sizeof(req->wr), 16)); 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci idata->cmd_more = htonl(ULPTX_CMD_V(ULP_TX_SC_IMM)); 19888c2ecf20Sopenharmony_ci idata->len = htonl(dlen); 19898c2ecf20Sopenharmony_ci} 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_cistatic struct sk_buff * 19928c2ecf20Sopenharmony_ciddp_ppod_init_idata(struct cxgbi_device *cdev, 19938c2ecf20Sopenharmony_ci struct cxgbi_ppm *ppm, 19948c2ecf20Sopenharmony_ci unsigned int idx, unsigned int npods, 19958c2ecf20Sopenharmony_ci unsigned int tid) 19968c2ecf20Sopenharmony_ci{ 19978c2ecf20Sopenharmony_ci unsigned int pm_addr = (idx << PPOD_SIZE_SHIFT) + ppm->llimit; 19988c2ecf20Sopenharmony_ci unsigned int dlen = npods << PPOD_SIZE_SHIFT; 19998c2ecf20Sopenharmony_ci unsigned int wr_len = roundup(sizeof(struct ulp_mem_io) + 20008c2ecf20Sopenharmony_ci sizeof(struct ulptx_idata) + dlen, 16); 20018c2ecf20Sopenharmony_ci struct sk_buff *skb = alloc_wr(wr_len, 0, GFP_ATOMIC); 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ci if (!skb) { 20048c2ecf20Sopenharmony_ci pr_err("%s: %s idx %u, npods %u, OOM.\n", 20058c2ecf20Sopenharmony_ci __func__, ppm->ndev->name, idx, npods); 20068c2ecf20Sopenharmony_ci return NULL; 20078c2ecf20Sopenharmony_ci } 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci ulp_mem_io_set_hdr(cdev, (struct ulp_mem_io *)skb->head, wr_len, dlen, 20108c2ecf20Sopenharmony_ci pm_addr, tid); 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci return skb; 20138c2ecf20Sopenharmony_ci} 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_cistatic int ddp_ppod_write_idata(struct cxgbi_ppm *ppm, struct cxgbi_sock *csk, 20168c2ecf20Sopenharmony_ci struct cxgbi_task_tag_info *ttinfo, 20178c2ecf20Sopenharmony_ci unsigned int idx, unsigned int npods, 20188c2ecf20Sopenharmony_ci struct scatterlist **sg_pp, 20198c2ecf20Sopenharmony_ci unsigned int *sg_off) 20208c2ecf20Sopenharmony_ci{ 20218c2ecf20Sopenharmony_ci struct cxgbi_device *cdev = csk->cdev; 20228c2ecf20Sopenharmony_ci struct sk_buff *skb = ddp_ppod_init_idata(cdev, ppm, idx, npods, 20238c2ecf20Sopenharmony_ci csk->tid); 20248c2ecf20Sopenharmony_ci struct ulp_mem_io *req; 20258c2ecf20Sopenharmony_ci struct ulptx_idata *idata; 20268c2ecf20Sopenharmony_ci struct cxgbi_pagepod *ppod; 20278c2ecf20Sopenharmony_ci int i; 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci if (!skb) 20308c2ecf20Sopenharmony_ci return -ENOMEM; 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci req = (struct ulp_mem_io *)skb->head; 20338c2ecf20Sopenharmony_ci idata = (struct ulptx_idata *)(req + 1); 20348c2ecf20Sopenharmony_ci ppod = (struct cxgbi_pagepod *)(idata + 1); 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci for (i = 0; i < npods; i++, ppod++) 20378c2ecf20Sopenharmony_ci cxgbi_ddp_set_one_ppod(ppod, ttinfo, sg_pp, sg_off); 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_ci cxgbi_skcb_set_flag(skb, SKCBF_TX_MEM_WRITE); 20408c2ecf20Sopenharmony_ci cxgbi_skcb_set_flag(skb, SKCBF_TX_FLAG_COMPL); 20418c2ecf20Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_DATA, csk->port_id); 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci spin_lock_bh(&csk->lock); 20448c2ecf20Sopenharmony_ci cxgbi_sock_skb_entail(csk, skb); 20458c2ecf20Sopenharmony_ci spin_unlock_bh(&csk->lock); 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci return 0; 20488c2ecf20Sopenharmony_ci} 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_cistatic int ddp_set_map(struct cxgbi_ppm *ppm, struct cxgbi_sock *csk, 20518c2ecf20Sopenharmony_ci struct cxgbi_task_tag_info *ttinfo) 20528c2ecf20Sopenharmony_ci{ 20538c2ecf20Sopenharmony_ci unsigned int pidx = ttinfo->idx; 20548c2ecf20Sopenharmony_ci unsigned int npods = ttinfo->npods; 20558c2ecf20Sopenharmony_ci unsigned int i, cnt; 20568c2ecf20Sopenharmony_ci int err = 0; 20578c2ecf20Sopenharmony_ci struct scatterlist *sg = ttinfo->sgl; 20588c2ecf20Sopenharmony_ci unsigned int offset = 0; 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci ttinfo->cid = csk->port_id; 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci for (i = 0; i < npods; i += cnt, pidx += cnt) { 20638c2ecf20Sopenharmony_ci cnt = npods - i; 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci if (cnt > ULPMEM_IDATA_MAX_NPPODS) 20668c2ecf20Sopenharmony_ci cnt = ULPMEM_IDATA_MAX_NPPODS; 20678c2ecf20Sopenharmony_ci err = ddp_ppod_write_idata(ppm, csk, ttinfo, pidx, cnt, 20688c2ecf20Sopenharmony_ci &sg, &offset); 20698c2ecf20Sopenharmony_ci if (err < 0) 20708c2ecf20Sopenharmony_ci break; 20718c2ecf20Sopenharmony_ci } 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci return err; 20748c2ecf20Sopenharmony_ci} 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_cistatic int ddp_setup_conn_pgidx(struct cxgbi_sock *csk, unsigned int tid, 20778c2ecf20Sopenharmony_ci int pg_idx) 20788c2ecf20Sopenharmony_ci{ 20798c2ecf20Sopenharmony_ci struct sk_buff *skb; 20808c2ecf20Sopenharmony_ci struct cpl_set_tcb_field *req; 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci if (!pg_idx || pg_idx >= DDP_PGIDX_MAX) 20838c2ecf20Sopenharmony_ci return 0; 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ci skb = alloc_wr(sizeof(*req), 0, GFP_KERNEL); 20868c2ecf20Sopenharmony_ci if (!skb) 20878c2ecf20Sopenharmony_ci return -ENOMEM; 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci /* set up ulp page size */ 20908c2ecf20Sopenharmony_ci req = (struct cpl_set_tcb_field *)skb->head; 20918c2ecf20Sopenharmony_ci INIT_TP_WR(req, csk->tid); 20928c2ecf20Sopenharmony_ci OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, csk->tid)); 20938c2ecf20Sopenharmony_ci req->reply_ctrl = htons(NO_REPLY_V(0) | QUEUENO_V(csk->rss_qid)); 20948c2ecf20Sopenharmony_ci req->word_cookie = htons(0); 20958c2ecf20Sopenharmony_ci req->mask = cpu_to_be64(0x3 << 8); 20968c2ecf20Sopenharmony_ci req->val = cpu_to_be64(pg_idx << 8); 20978c2ecf20Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_CONTROL, csk->port_id); 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 21008c2ecf20Sopenharmony_ci "csk 0x%p, tid 0x%x, pg_idx %u.\n", csk, csk->tid, pg_idx); 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci reinit_completion(&csk->cmpl); 21038c2ecf20Sopenharmony_ci cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); 21048c2ecf20Sopenharmony_ci wait_for_completion(&csk->cmpl); 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci return csk->err; 21078c2ecf20Sopenharmony_ci} 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_cistatic int ddp_setup_conn_digest(struct cxgbi_sock *csk, unsigned int tid, 21108c2ecf20Sopenharmony_ci int hcrc, int dcrc) 21118c2ecf20Sopenharmony_ci{ 21128c2ecf20Sopenharmony_ci struct sk_buff *skb; 21138c2ecf20Sopenharmony_ci struct cpl_set_tcb_field *req; 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci if (!hcrc && !dcrc) 21168c2ecf20Sopenharmony_ci return 0; 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci skb = alloc_wr(sizeof(*req), 0, GFP_KERNEL); 21198c2ecf20Sopenharmony_ci if (!skb) 21208c2ecf20Sopenharmony_ci return -ENOMEM; 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci csk->hcrc_len = (hcrc ? 4 : 0); 21238c2ecf20Sopenharmony_ci csk->dcrc_len = (dcrc ? 4 : 0); 21248c2ecf20Sopenharmony_ci /* set up ulp submode */ 21258c2ecf20Sopenharmony_ci req = (struct cpl_set_tcb_field *)skb->head; 21268c2ecf20Sopenharmony_ci INIT_TP_WR(req, tid); 21278c2ecf20Sopenharmony_ci OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid)); 21288c2ecf20Sopenharmony_ci req->reply_ctrl = htons(NO_REPLY_V(0) | QUEUENO_V(csk->rss_qid)); 21298c2ecf20Sopenharmony_ci req->word_cookie = htons(0); 21308c2ecf20Sopenharmony_ci req->mask = cpu_to_be64(0x3 << 4); 21318c2ecf20Sopenharmony_ci req->val = cpu_to_be64(((hcrc ? ULP_CRC_HEADER : 0) | 21328c2ecf20Sopenharmony_ci (dcrc ? ULP_CRC_DATA : 0)) << 4); 21338c2ecf20Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_CONTROL, csk->port_id); 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, 21368c2ecf20Sopenharmony_ci "csk 0x%p, tid 0x%x, crc %d,%d.\n", csk, csk->tid, hcrc, dcrc); 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci reinit_completion(&csk->cmpl); 21398c2ecf20Sopenharmony_ci cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); 21408c2ecf20Sopenharmony_ci wait_for_completion(&csk->cmpl); 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ci return csk->err; 21438c2ecf20Sopenharmony_ci} 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_cistatic struct cxgbi_ppm *cdev2ppm(struct cxgbi_device *cdev) 21468c2ecf20Sopenharmony_ci{ 21478c2ecf20Sopenharmony_ci return (struct cxgbi_ppm *)(*((struct cxgb4_lld_info *) 21488c2ecf20Sopenharmony_ci (cxgbi_cdev_priv(cdev)))->iscsi_ppm); 21498c2ecf20Sopenharmony_ci} 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_cistatic int cxgb4i_ddp_init(struct cxgbi_device *cdev) 21528c2ecf20Sopenharmony_ci{ 21538c2ecf20Sopenharmony_ci struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); 21548c2ecf20Sopenharmony_ci struct net_device *ndev = cdev->ports[0]; 21558c2ecf20Sopenharmony_ci struct cxgbi_tag_format tformat; 21568c2ecf20Sopenharmony_ci int i, err; 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci if (!lldi->vr->iscsi.size) { 21598c2ecf20Sopenharmony_ci pr_warn("%s, iscsi NOT enabled, check config!\n", ndev->name); 21608c2ecf20Sopenharmony_ci return -EACCES; 21618c2ecf20Sopenharmony_ci } 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_ci cdev->flags |= CXGBI_FLAG_USE_PPOD_OFLDQ; 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci memset(&tformat, 0, sizeof(struct cxgbi_tag_format)); 21668c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) 21678c2ecf20Sopenharmony_ci tformat.pgsz_order[i] = (lldi->iscsi_pgsz_order >> (i << 3)) 21688c2ecf20Sopenharmony_ci & 0xF; 21698c2ecf20Sopenharmony_ci cxgbi_tagmask_check(lldi->iscsi_tagmask, &tformat); 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci pr_info("iscsi_edram.start 0x%x iscsi_edram.size 0x%x", 21728c2ecf20Sopenharmony_ci lldi->vr->ppod_edram.start, lldi->vr->ppod_edram.size); 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci err = cxgbi_ddp_ppm_setup(lldi->iscsi_ppm, cdev, &tformat, 21758c2ecf20Sopenharmony_ci lldi->vr->iscsi.size, lldi->iscsi_llimit, 21768c2ecf20Sopenharmony_ci lldi->vr->iscsi.start, 2, 21778c2ecf20Sopenharmony_ci lldi->vr->ppod_edram.start, 21788c2ecf20Sopenharmony_ci lldi->vr->ppod_edram.size); 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_ci if (err < 0) 21818c2ecf20Sopenharmony_ci return err; 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_ci cdev->csk_ddp_setup_digest = ddp_setup_conn_digest; 21848c2ecf20Sopenharmony_ci cdev->csk_ddp_setup_pgidx = ddp_setup_conn_pgidx; 21858c2ecf20Sopenharmony_ci cdev->csk_ddp_set_map = ddp_set_map; 21868c2ecf20Sopenharmony_ci cdev->tx_max_size = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD, 21878c2ecf20Sopenharmony_ci lldi->iscsi_iolen - ISCSI_PDU_NONPAYLOAD_LEN); 21888c2ecf20Sopenharmony_ci cdev->rx_max_size = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD, 21898c2ecf20Sopenharmony_ci lldi->iscsi_iolen - ISCSI_PDU_NONPAYLOAD_LEN); 21908c2ecf20Sopenharmony_ci cdev->cdev2ppm = cdev2ppm; 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci return 0; 21938c2ecf20Sopenharmony_ci} 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_cistatic bool is_memfree(struct adapter *adap) 21968c2ecf20Sopenharmony_ci{ 21978c2ecf20Sopenharmony_ci u32 io; 21988c2ecf20Sopenharmony_ci 21998c2ecf20Sopenharmony_ci io = t4_read_reg(adap, MA_TARGET_MEM_ENABLE_A); 22008c2ecf20Sopenharmony_ci if (is_t5(adap->params.chip)) { 22018c2ecf20Sopenharmony_ci if ((io & EXT_MEM0_ENABLE_F) || (io & EXT_MEM1_ENABLE_F)) 22028c2ecf20Sopenharmony_ci return false; 22038c2ecf20Sopenharmony_ci } else if (io & EXT_MEM_ENABLE_F) { 22048c2ecf20Sopenharmony_ci return false; 22058c2ecf20Sopenharmony_ci } 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_ci return true; 22088c2ecf20Sopenharmony_ci} 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_cistatic void *t4_uld_add(const struct cxgb4_lld_info *lldi) 22118c2ecf20Sopenharmony_ci{ 22128c2ecf20Sopenharmony_ci struct cxgbi_device *cdev; 22138c2ecf20Sopenharmony_ci struct port_info *pi; 22148c2ecf20Sopenharmony_ci struct net_device *ndev; 22158c2ecf20Sopenharmony_ci struct adapter *adap; 22168c2ecf20Sopenharmony_ci struct tid_info *t; 22178c2ecf20Sopenharmony_ci u32 max_cmds = CXGB4I_SCSI_HOST_QDEPTH; 22188c2ecf20Sopenharmony_ci u32 max_conn = CXGBI_MAX_CONN; 22198c2ecf20Sopenharmony_ci int i, rc; 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ci cdev = cxgbi_device_register(sizeof(*lldi), lldi->nports); 22228c2ecf20Sopenharmony_ci if (!cdev) { 22238c2ecf20Sopenharmony_ci pr_info("t4 device 0x%p, register failed.\n", lldi); 22248c2ecf20Sopenharmony_ci return NULL; 22258c2ecf20Sopenharmony_ci } 22268c2ecf20Sopenharmony_ci pr_info("0x%p,0x%x, ports %u,%s, chan %u, q %u,%u, wr %u.\n", 22278c2ecf20Sopenharmony_ci cdev, lldi->adapter_type, lldi->nports, 22288c2ecf20Sopenharmony_ci lldi->ports[0]->name, lldi->nchan, lldi->ntxq, 22298c2ecf20Sopenharmony_ci lldi->nrxq, lldi->wr_cred); 22308c2ecf20Sopenharmony_ci for (i = 0; i < lldi->nrxq; i++) 22318c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_DEV, 22328c2ecf20Sopenharmony_ci "t4 0x%p, rxq id #%d: %u.\n", 22338c2ecf20Sopenharmony_ci cdev, i, lldi->rxq_ids[i]); 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_ci memcpy(cxgbi_cdev_priv(cdev), lldi, sizeof(*lldi)); 22368c2ecf20Sopenharmony_ci cdev->flags = CXGBI_FLAG_DEV_T4; 22378c2ecf20Sopenharmony_ci cdev->pdev = lldi->pdev; 22388c2ecf20Sopenharmony_ci cdev->ports = lldi->ports; 22398c2ecf20Sopenharmony_ci cdev->nports = lldi->nports; 22408c2ecf20Sopenharmony_ci cdev->mtus = lldi->mtus; 22418c2ecf20Sopenharmony_ci cdev->nmtus = NMTUS; 22428c2ecf20Sopenharmony_ci cdev->rx_credit_thres = (CHELSIO_CHIP_VERSION(lldi->adapter_type) <= 22438c2ecf20Sopenharmony_ci CHELSIO_T5) ? cxgb4i_rx_credit_thres : 0; 22448c2ecf20Sopenharmony_ci cdev->skb_tx_rsvd = CXGB4I_TX_HEADER_LEN; 22458c2ecf20Sopenharmony_ci cdev->skb_rx_extra = sizeof(struct cpl_iscsi_hdr); 22468c2ecf20Sopenharmony_ci cdev->itp = &cxgb4i_iscsi_transport; 22478c2ecf20Sopenharmony_ci cdev->owner = THIS_MODULE; 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci cdev->pfvf = FW_PFVF_CMD_PFN_V(lldi->pf); 22508c2ecf20Sopenharmony_ci pr_info("cdev 0x%p,%s, pfvf %u.\n", 22518c2ecf20Sopenharmony_ci cdev, lldi->ports[0]->name, cdev->pfvf); 22528c2ecf20Sopenharmony_ci 22538c2ecf20Sopenharmony_ci rc = cxgb4i_ddp_init(cdev); 22548c2ecf20Sopenharmony_ci if (rc) { 22558c2ecf20Sopenharmony_ci pr_info("t4 0x%p ddp init failed %d.\n", cdev, rc); 22568c2ecf20Sopenharmony_ci goto err_out; 22578c2ecf20Sopenharmony_ci } 22588c2ecf20Sopenharmony_ci 22598c2ecf20Sopenharmony_ci ndev = cdev->ports[0]; 22608c2ecf20Sopenharmony_ci adap = netdev2adap(ndev); 22618c2ecf20Sopenharmony_ci if (adap) { 22628c2ecf20Sopenharmony_ci t = &adap->tids; 22638c2ecf20Sopenharmony_ci if (t->ntids <= CXGBI_MAX_CONN) 22648c2ecf20Sopenharmony_ci max_conn = t->ntids; 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_ci if (is_memfree(adap)) { 22678c2ecf20Sopenharmony_ci cdev->flags |= CXGBI_FLAG_DEV_ISO_OFF; 22688c2ecf20Sopenharmony_ci max_cmds = CXGB4I_SCSI_HOST_QDEPTH >> 2; 22698c2ecf20Sopenharmony_ci 22708c2ecf20Sopenharmony_ci pr_info("%s: 0x%p, tid %u, SO adapter.\n", 22718c2ecf20Sopenharmony_ci ndev->name, cdev, t->ntids); 22728c2ecf20Sopenharmony_ci } 22738c2ecf20Sopenharmony_ci } else { 22748c2ecf20Sopenharmony_ci pr_info("%s, 0x%p, NO adapter struct.\n", ndev->name, cdev); 22758c2ecf20Sopenharmony_ci } 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_ci /* ISO is enabled in T5/T6 firmware version >= 1.13.43.0 */ 22788c2ecf20Sopenharmony_ci if (!is_t4(lldi->adapter_type) && 22798c2ecf20Sopenharmony_ci (lldi->fw_vers >= 0x10d2b00) && 22808c2ecf20Sopenharmony_ci !(cdev->flags & CXGBI_FLAG_DEV_ISO_OFF)) 22818c2ecf20Sopenharmony_ci cdev->skb_iso_txhdr = sizeof(struct cpl_tx_data_iso); 22828c2ecf20Sopenharmony_ci 22838c2ecf20Sopenharmony_ci rc = cxgb4i_ofld_init(cdev); 22848c2ecf20Sopenharmony_ci if (rc) { 22858c2ecf20Sopenharmony_ci pr_info("t4 0x%p ofld init failed.\n", cdev); 22868c2ecf20Sopenharmony_ci goto err_out; 22878c2ecf20Sopenharmony_ci } 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci cxgb4i_host_template.can_queue = max_cmds; 22908c2ecf20Sopenharmony_ci rc = cxgbi_hbas_add(cdev, CXGB4I_MAX_LUN, max_conn, 22918c2ecf20Sopenharmony_ci &cxgb4i_host_template, cxgb4i_stt); 22928c2ecf20Sopenharmony_ci if (rc) 22938c2ecf20Sopenharmony_ci goto err_out; 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_ci for (i = 0; i < cdev->nports; i++) { 22968c2ecf20Sopenharmony_ci pi = netdev_priv(lldi->ports[i]); 22978c2ecf20Sopenharmony_ci cdev->hbas[i]->port_id = pi->port_id; 22988c2ecf20Sopenharmony_ci } 22998c2ecf20Sopenharmony_ci return cdev; 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_cierr_out: 23028c2ecf20Sopenharmony_ci cxgbi_device_unregister(cdev); 23038c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 23048c2ecf20Sopenharmony_ci} 23058c2ecf20Sopenharmony_ci 23068c2ecf20Sopenharmony_ci#define RX_PULL_LEN 128 23078c2ecf20Sopenharmony_cistatic int t4_uld_rx_handler(void *handle, const __be64 *rsp, 23088c2ecf20Sopenharmony_ci const struct pkt_gl *pgl) 23098c2ecf20Sopenharmony_ci{ 23108c2ecf20Sopenharmony_ci const struct cpl_act_establish *rpl; 23118c2ecf20Sopenharmony_ci struct sk_buff *skb; 23128c2ecf20Sopenharmony_ci unsigned int opc; 23138c2ecf20Sopenharmony_ci struct cxgbi_device *cdev = handle; 23148c2ecf20Sopenharmony_ci 23158c2ecf20Sopenharmony_ci if (pgl == NULL) { 23168c2ecf20Sopenharmony_ci unsigned int len = 64 - sizeof(struct rsp_ctrl) - 8; 23178c2ecf20Sopenharmony_ci 23188c2ecf20Sopenharmony_ci skb = alloc_wr(len, 0, GFP_ATOMIC); 23198c2ecf20Sopenharmony_ci if (!skb) 23208c2ecf20Sopenharmony_ci goto nomem; 23218c2ecf20Sopenharmony_ci skb_copy_to_linear_data(skb, &rsp[1], len); 23228c2ecf20Sopenharmony_ci } else { 23238c2ecf20Sopenharmony_ci if (unlikely(*(u8 *)rsp != *(u8 *)pgl->va)) { 23248c2ecf20Sopenharmony_ci pr_info("? FL 0x%p,RSS%#llx,FL %#llx,len %u.\n", 23258c2ecf20Sopenharmony_ci pgl->va, be64_to_cpu(*rsp), 23268c2ecf20Sopenharmony_ci be64_to_cpu(*(u64 *)pgl->va), 23278c2ecf20Sopenharmony_ci pgl->tot_len); 23288c2ecf20Sopenharmony_ci return 0; 23298c2ecf20Sopenharmony_ci } 23308c2ecf20Sopenharmony_ci skb = cxgb4_pktgl_to_skb(pgl, RX_PULL_LEN, RX_PULL_LEN); 23318c2ecf20Sopenharmony_ci if (unlikely(!skb)) 23328c2ecf20Sopenharmony_ci goto nomem; 23338c2ecf20Sopenharmony_ci } 23348c2ecf20Sopenharmony_ci 23358c2ecf20Sopenharmony_ci rpl = (struct cpl_act_establish *)skb->data; 23368c2ecf20Sopenharmony_ci opc = rpl->ot.opcode; 23378c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE, 23388c2ecf20Sopenharmony_ci "cdev %p, opcode 0x%x(0x%x,0x%x), skb %p.\n", 23398c2ecf20Sopenharmony_ci cdev, opc, rpl->ot.opcode_tid, ntohl(rpl->ot.opcode_tid), skb); 23408c2ecf20Sopenharmony_ci if (opc >= ARRAY_SIZE(cxgb4i_cplhandlers) || !cxgb4i_cplhandlers[opc]) { 23418c2ecf20Sopenharmony_ci pr_err("No handler for opcode 0x%x.\n", opc); 23428c2ecf20Sopenharmony_ci __kfree_skb(skb); 23438c2ecf20Sopenharmony_ci } else 23448c2ecf20Sopenharmony_ci cxgb4i_cplhandlers[opc](cdev, skb); 23458c2ecf20Sopenharmony_ci 23468c2ecf20Sopenharmony_ci return 0; 23478c2ecf20Sopenharmony_cinomem: 23488c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_TOE, "OOM bailing out.\n"); 23498c2ecf20Sopenharmony_ci return 1; 23508c2ecf20Sopenharmony_ci} 23518c2ecf20Sopenharmony_ci 23528c2ecf20Sopenharmony_cistatic int t4_uld_state_change(void *handle, enum cxgb4_state state) 23538c2ecf20Sopenharmony_ci{ 23548c2ecf20Sopenharmony_ci struct cxgbi_device *cdev = handle; 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ci switch (state) { 23578c2ecf20Sopenharmony_ci case CXGB4_STATE_UP: 23588c2ecf20Sopenharmony_ci pr_info("cdev 0x%p, UP.\n", cdev); 23598c2ecf20Sopenharmony_ci break; 23608c2ecf20Sopenharmony_ci case CXGB4_STATE_START_RECOVERY: 23618c2ecf20Sopenharmony_ci pr_info("cdev 0x%p, RECOVERY.\n", cdev); 23628c2ecf20Sopenharmony_ci /* close all connections */ 23638c2ecf20Sopenharmony_ci break; 23648c2ecf20Sopenharmony_ci case CXGB4_STATE_DOWN: 23658c2ecf20Sopenharmony_ci pr_info("cdev 0x%p, DOWN.\n", cdev); 23668c2ecf20Sopenharmony_ci break; 23678c2ecf20Sopenharmony_ci case CXGB4_STATE_DETACH: 23688c2ecf20Sopenharmony_ci pr_info("cdev 0x%p, DETACH.\n", cdev); 23698c2ecf20Sopenharmony_ci cxgbi_device_unregister(cdev); 23708c2ecf20Sopenharmony_ci break; 23718c2ecf20Sopenharmony_ci default: 23728c2ecf20Sopenharmony_ci pr_info("cdev 0x%p, unknown state %d.\n", cdev, state); 23738c2ecf20Sopenharmony_ci break; 23748c2ecf20Sopenharmony_ci } 23758c2ecf20Sopenharmony_ci return 0; 23768c2ecf20Sopenharmony_ci} 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 23798c2ecf20Sopenharmony_cistatic int 23808c2ecf20Sopenharmony_cicxgb4_dcb_change_notify(struct notifier_block *self, unsigned long val, 23818c2ecf20Sopenharmony_ci void *data) 23828c2ecf20Sopenharmony_ci{ 23838c2ecf20Sopenharmony_ci int i, port = 0xFF; 23848c2ecf20Sopenharmony_ci struct net_device *ndev; 23858c2ecf20Sopenharmony_ci struct cxgbi_device *cdev = NULL; 23868c2ecf20Sopenharmony_ci struct dcb_app_type *iscsi_app = data; 23878c2ecf20Sopenharmony_ci struct cxgbi_ports_map *pmap; 23888c2ecf20Sopenharmony_ci u8 priority; 23898c2ecf20Sopenharmony_ci 23908c2ecf20Sopenharmony_ci if (iscsi_app->dcbx & DCB_CAP_DCBX_VER_IEEE) { 23918c2ecf20Sopenharmony_ci if ((iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_STREAM) && 23928c2ecf20Sopenharmony_ci (iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_ANY)) 23938c2ecf20Sopenharmony_ci return NOTIFY_DONE; 23948c2ecf20Sopenharmony_ci 23958c2ecf20Sopenharmony_ci priority = iscsi_app->app.priority; 23968c2ecf20Sopenharmony_ci } else if (iscsi_app->dcbx & DCB_CAP_DCBX_VER_CEE) { 23978c2ecf20Sopenharmony_ci if (iscsi_app->app.selector != DCB_APP_IDTYPE_PORTNUM) 23988c2ecf20Sopenharmony_ci return NOTIFY_DONE; 23998c2ecf20Sopenharmony_ci 24008c2ecf20Sopenharmony_ci if (!iscsi_app->app.priority) 24018c2ecf20Sopenharmony_ci return NOTIFY_DONE; 24028c2ecf20Sopenharmony_ci 24038c2ecf20Sopenharmony_ci priority = ffs(iscsi_app->app.priority) - 1; 24048c2ecf20Sopenharmony_ci } else { 24058c2ecf20Sopenharmony_ci return NOTIFY_DONE; 24068c2ecf20Sopenharmony_ci } 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci if (iscsi_app->app.protocol != 3260) 24098c2ecf20Sopenharmony_ci return NOTIFY_DONE; 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_ci log_debug(1 << CXGBI_DBG_ISCSI, "iSCSI priority for ifid %d is %u\n", 24128c2ecf20Sopenharmony_ci iscsi_app->ifindex, priority); 24138c2ecf20Sopenharmony_ci 24148c2ecf20Sopenharmony_ci ndev = dev_get_by_index(&init_net, iscsi_app->ifindex); 24158c2ecf20Sopenharmony_ci if (!ndev) 24168c2ecf20Sopenharmony_ci return NOTIFY_DONE; 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_ci cdev = cxgbi_device_find_by_netdev_rcu(ndev, &port); 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_ci dev_put(ndev); 24218c2ecf20Sopenharmony_ci if (!cdev) 24228c2ecf20Sopenharmony_ci return NOTIFY_DONE; 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci pmap = &cdev->pmap; 24258c2ecf20Sopenharmony_ci 24268c2ecf20Sopenharmony_ci for (i = 0; i < pmap->used; i++) { 24278c2ecf20Sopenharmony_ci if (pmap->port_csk[i]) { 24288c2ecf20Sopenharmony_ci struct cxgbi_sock *csk = pmap->port_csk[i]; 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci if (csk->dcb_priority != priority) { 24318c2ecf20Sopenharmony_ci iscsi_conn_failure(csk->user_data, 24328c2ecf20Sopenharmony_ci ISCSI_ERR_CONN_FAILED); 24338c2ecf20Sopenharmony_ci pr_info("Restarting iSCSI connection %p with " 24348c2ecf20Sopenharmony_ci "priority %u->%u.\n", csk, 24358c2ecf20Sopenharmony_ci csk->dcb_priority, priority); 24368c2ecf20Sopenharmony_ci } 24378c2ecf20Sopenharmony_ci } 24388c2ecf20Sopenharmony_ci } 24398c2ecf20Sopenharmony_ci return NOTIFY_OK; 24408c2ecf20Sopenharmony_ci} 24418c2ecf20Sopenharmony_ci#endif 24428c2ecf20Sopenharmony_ci 24438c2ecf20Sopenharmony_cistatic int __init cxgb4i_init_module(void) 24448c2ecf20Sopenharmony_ci{ 24458c2ecf20Sopenharmony_ci int rc; 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci printk(KERN_INFO "%s", version); 24488c2ecf20Sopenharmony_ci 24498c2ecf20Sopenharmony_ci rc = cxgbi_iscsi_init(&cxgb4i_iscsi_transport, &cxgb4i_stt); 24508c2ecf20Sopenharmony_ci if (rc < 0) 24518c2ecf20Sopenharmony_ci return rc; 24528c2ecf20Sopenharmony_ci cxgb4_register_uld(CXGB4_ULD_ISCSI, &cxgb4i_uld_info); 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 24558c2ecf20Sopenharmony_ci pr_info("%s dcb enabled.\n", DRV_MODULE_NAME); 24568c2ecf20Sopenharmony_ci register_dcbevent_notifier(&cxgb4_dcb_change); 24578c2ecf20Sopenharmony_ci#endif 24588c2ecf20Sopenharmony_ci return 0; 24598c2ecf20Sopenharmony_ci} 24608c2ecf20Sopenharmony_ci 24618c2ecf20Sopenharmony_cistatic void __exit cxgb4i_exit_module(void) 24628c2ecf20Sopenharmony_ci{ 24638c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 24648c2ecf20Sopenharmony_ci unregister_dcbevent_notifier(&cxgb4_dcb_change); 24658c2ecf20Sopenharmony_ci#endif 24668c2ecf20Sopenharmony_ci cxgb4_unregister_uld(CXGB4_ULD_ISCSI); 24678c2ecf20Sopenharmony_ci cxgbi_device_unregister_all(CXGBI_FLAG_DEV_T4); 24688c2ecf20Sopenharmony_ci cxgbi_iscsi_cleanup(&cxgb4i_iscsi_transport, &cxgb4i_stt); 24698c2ecf20Sopenharmony_ci} 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_cimodule_init(cxgb4i_init_module); 24728c2ecf20Sopenharmony_cimodule_exit(cxgb4i_exit_module); 2473