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