162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2016 Chelsio Communications, Inc.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/workqueue.h>
762306a36Sopenharmony_ci#include <linux/kthread.h>
862306a36Sopenharmony_ci#include <linux/sched/signal.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <asm/unaligned.h>
1162306a36Sopenharmony_ci#include <net/tcp.h>
1262306a36Sopenharmony_ci#include <target/target_core_base.h>
1362306a36Sopenharmony_ci#include <target/target_core_fabric.h>
1462306a36Sopenharmony_ci#include "cxgbit.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistruct sge_opaque_hdr {
1762306a36Sopenharmony_ci	void *dev;
1862306a36Sopenharmony_ci	dma_addr_t addr[MAX_SKB_FRAGS + 1];
1962306a36Sopenharmony_ci};
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic const u8 cxgbit_digest_len[] = {0, 4, 4, 8};
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define TX_HDR_LEN (sizeof(struct sge_opaque_hdr) + \
2462306a36Sopenharmony_ci		    sizeof(struct fw_ofld_tx_data_wr))
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic struct sk_buff *
2762306a36Sopenharmony_ci__cxgbit_alloc_skb(struct cxgbit_sock *csk, u32 len, bool iso)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	struct sk_buff *skb = NULL;
3062306a36Sopenharmony_ci	u8 submode = 0;
3162306a36Sopenharmony_ci	int errcode;
3262306a36Sopenharmony_ci	static const u32 hdr_len = TX_HDR_LEN + ISCSI_HDR_LEN;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	if (len) {
3562306a36Sopenharmony_ci		skb = alloc_skb_with_frags(hdr_len, len,
3662306a36Sopenharmony_ci					   0, &errcode,
3762306a36Sopenharmony_ci					   GFP_KERNEL);
3862306a36Sopenharmony_ci		if (!skb)
3962306a36Sopenharmony_ci			return NULL;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci		skb_reserve(skb, TX_HDR_LEN);
4262306a36Sopenharmony_ci		skb_reset_transport_header(skb);
4362306a36Sopenharmony_ci		__skb_put(skb, ISCSI_HDR_LEN);
4462306a36Sopenharmony_ci		skb->data_len = len;
4562306a36Sopenharmony_ci		skb->len += len;
4662306a36Sopenharmony_ci		submode |= (csk->submode & CXGBIT_SUBMODE_DCRC);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	} else {
4962306a36Sopenharmony_ci		u32 iso_len = iso ? sizeof(struct cpl_tx_data_iso) : 0;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci		skb = alloc_skb(hdr_len + iso_len, GFP_KERNEL);
5262306a36Sopenharmony_ci		if (!skb)
5362306a36Sopenharmony_ci			return NULL;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci		skb_reserve(skb, TX_HDR_LEN + iso_len);
5662306a36Sopenharmony_ci		skb_reset_transport_header(skb);
5762306a36Sopenharmony_ci		__skb_put(skb, ISCSI_HDR_LEN);
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	submode |= (csk->submode & CXGBIT_SUBMODE_HCRC);
6162306a36Sopenharmony_ci	cxgbit_skcb_submode(skb) = submode;
6262306a36Sopenharmony_ci	cxgbit_skcb_tx_extralen(skb) = cxgbit_digest_len[submode];
6362306a36Sopenharmony_ci	cxgbit_skcb_flags(skb) |= SKCBF_TX_NEED_HDR;
6462306a36Sopenharmony_ci	return skb;
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic struct sk_buff *cxgbit_alloc_skb(struct cxgbit_sock *csk, u32 len)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	return __cxgbit_alloc_skb(csk, len, false);
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci/*
7362306a36Sopenharmony_ci * cxgbit_is_ofld_imm - check whether a packet can be sent as immediate data
7462306a36Sopenharmony_ci * @skb: the packet
7562306a36Sopenharmony_ci *
7662306a36Sopenharmony_ci * Returns true if a packet can be sent as an offload WR with immediate
7762306a36Sopenharmony_ci * data.  We currently use the same limit as for Ethernet packets.
7862306a36Sopenharmony_ci */
7962306a36Sopenharmony_cistatic int cxgbit_is_ofld_imm(const struct sk_buff *skb)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	int length = skb->len;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	if (likely(cxgbit_skcb_flags(skb) & SKCBF_TX_NEED_HDR))
8462306a36Sopenharmony_ci		length += sizeof(struct fw_ofld_tx_data_wr);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	if (likely(cxgbit_skcb_flags(skb) & SKCBF_TX_ISO))
8762306a36Sopenharmony_ci		length += sizeof(struct cpl_tx_data_iso);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	return length <= MAX_IMM_OFLD_TX_DATA_WR_LEN;
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/*
9362306a36Sopenharmony_ci * cxgbit_sgl_len - calculates the size of an SGL of the given capacity
9462306a36Sopenharmony_ci * @n: the number of SGL entries
9562306a36Sopenharmony_ci * Calculates the number of flits needed for a scatter/gather list that
9662306a36Sopenharmony_ci * can hold the given number of entries.
9762306a36Sopenharmony_ci */
9862306a36Sopenharmony_cistatic inline unsigned int cxgbit_sgl_len(unsigned int n)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	n--;
10162306a36Sopenharmony_ci	return (3 * n) / 2 + (n & 1) + 2;
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci/*
10562306a36Sopenharmony_ci * cxgbit_calc_tx_flits_ofld - calculate # of flits for an offload packet
10662306a36Sopenharmony_ci * @skb: the packet
10762306a36Sopenharmony_ci *
10862306a36Sopenharmony_ci * Returns the number of flits needed for the given offload packet.
10962306a36Sopenharmony_ci * These packets are already fully constructed and no additional headers
11062306a36Sopenharmony_ci * will be added.
11162306a36Sopenharmony_ci */
11262306a36Sopenharmony_cistatic unsigned int cxgbit_calc_tx_flits_ofld(const struct sk_buff *skb)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	unsigned int flits, cnt;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	if (cxgbit_is_ofld_imm(skb))
11762306a36Sopenharmony_ci		return DIV_ROUND_UP(skb->len, 8);
11862306a36Sopenharmony_ci	flits = skb_transport_offset(skb) / 8;
11962306a36Sopenharmony_ci	cnt = skb_shinfo(skb)->nr_frags;
12062306a36Sopenharmony_ci	if (skb_tail_pointer(skb) != skb_transport_header(skb))
12162306a36Sopenharmony_ci		cnt++;
12262306a36Sopenharmony_ci	return flits + cxgbit_sgl_len(cnt);
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci#define CXGBIT_ISO_FSLICE 0x1
12662306a36Sopenharmony_ci#define CXGBIT_ISO_LSLICE 0x2
12762306a36Sopenharmony_cistatic void
12862306a36Sopenharmony_cicxgbit_cpl_tx_data_iso(struct sk_buff *skb, struct cxgbit_iso_info *iso_info)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	struct cpl_tx_data_iso *cpl;
13162306a36Sopenharmony_ci	unsigned int submode = cxgbit_skcb_submode(skb);
13262306a36Sopenharmony_ci	unsigned int fslice = !!(iso_info->flags & CXGBIT_ISO_FSLICE);
13362306a36Sopenharmony_ci	unsigned int lslice = !!(iso_info->flags & CXGBIT_ISO_LSLICE);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	cpl = __skb_push(skb, sizeof(*cpl));
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	cpl->op_to_scsi = htonl(CPL_TX_DATA_ISO_OP_V(CPL_TX_DATA_ISO) |
13862306a36Sopenharmony_ci			CPL_TX_DATA_ISO_FIRST_V(fslice) |
13962306a36Sopenharmony_ci			CPL_TX_DATA_ISO_LAST_V(lslice) |
14062306a36Sopenharmony_ci			CPL_TX_DATA_ISO_CPLHDRLEN_V(0) |
14162306a36Sopenharmony_ci			CPL_TX_DATA_ISO_HDRCRC_V(submode & 1) |
14262306a36Sopenharmony_ci			CPL_TX_DATA_ISO_PLDCRC_V(((submode >> 1) & 1)) |
14362306a36Sopenharmony_ci			CPL_TX_DATA_ISO_IMMEDIATE_V(0) |
14462306a36Sopenharmony_ci			CPL_TX_DATA_ISO_SCSI_V(2));
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	cpl->ahs_len = 0;
14762306a36Sopenharmony_ci	cpl->mpdu = htons(DIV_ROUND_UP(iso_info->mpdu, 4));
14862306a36Sopenharmony_ci	cpl->burst_size = htonl(DIV_ROUND_UP(iso_info->burst_len, 4));
14962306a36Sopenharmony_ci	cpl->len = htonl(iso_info->len);
15062306a36Sopenharmony_ci	cpl->reserved2_seglen_offset = htonl(0);
15162306a36Sopenharmony_ci	cpl->datasn_offset = htonl(0);
15262306a36Sopenharmony_ci	cpl->buffer_offset = htonl(0);
15362306a36Sopenharmony_ci	cpl->reserved3 = 0;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	__skb_pull(skb, sizeof(*cpl));
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic void
15962306a36Sopenharmony_cicxgbit_tx_data_wr(struct cxgbit_sock *csk, struct sk_buff *skb, u32 dlen,
16062306a36Sopenharmony_ci		  u32 len, u32 credits, u32 compl)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	struct fw_ofld_tx_data_wr *req;
16362306a36Sopenharmony_ci	const struct cxgb4_lld_info *lldi = &csk->com.cdev->lldi;
16462306a36Sopenharmony_ci	u32 submode = cxgbit_skcb_submode(skb);
16562306a36Sopenharmony_ci	u32 wr_ulp_mode = 0;
16662306a36Sopenharmony_ci	u32 hdr_size = sizeof(*req);
16762306a36Sopenharmony_ci	u32 opcode = FW_OFLD_TX_DATA_WR;
16862306a36Sopenharmony_ci	u32 immlen = 0;
16962306a36Sopenharmony_ci	u32 force = is_t5(lldi->adapter_type) ? TX_FORCE_V(!submode) :
17062306a36Sopenharmony_ci		    T6_TX_FORCE_F;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	if (cxgbit_skcb_flags(skb) & SKCBF_TX_ISO) {
17362306a36Sopenharmony_ci		opcode = FW_ISCSI_TX_DATA_WR;
17462306a36Sopenharmony_ci		immlen += sizeof(struct cpl_tx_data_iso);
17562306a36Sopenharmony_ci		hdr_size += sizeof(struct cpl_tx_data_iso);
17662306a36Sopenharmony_ci		submode |= 8;
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	if (cxgbit_is_ofld_imm(skb))
18062306a36Sopenharmony_ci		immlen += dlen;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	req = __skb_push(skb, hdr_size);
18362306a36Sopenharmony_ci	req->op_to_immdlen = cpu_to_be32(FW_WR_OP_V(opcode) |
18462306a36Sopenharmony_ci					FW_WR_COMPL_V(compl) |
18562306a36Sopenharmony_ci					FW_WR_IMMDLEN_V(immlen));
18662306a36Sopenharmony_ci	req->flowid_len16 = cpu_to_be32(FW_WR_FLOWID_V(csk->tid) |
18762306a36Sopenharmony_ci					FW_WR_LEN16_V(credits));
18862306a36Sopenharmony_ci	req->plen = htonl(len);
18962306a36Sopenharmony_ci	wr_ulp_mode = FW_OFLD_TX_DATA_WR_ULPMODE_V(ULP_MODE_ISCSI) |
19062306a36Sopenharmony_ci				FW_OFLD_TX_DATA_WR_ULPSUBMODE_V(submode);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	req->tunnel_to_proxy = htonl(wr_ulp_mode | force |
19362306a36Sopenharmony_ci				     FW_OFLD_TX_DATA_WR_SHOVE_F);
19462306a36Sopenharmony_ci}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_cistatic void cxgbit_arp_failure_skb_discard(void *handle, struct sk_buff *skb)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	kfree_skb(skb);
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_civoid cxgbit_push_tx_frames(struct cxgbit_sock *csk)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	struct sk_buff *skb;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	while (csk->wr_cred && ((skb = skb_peek(&csk->txq)) != NULL)) {
20662306a36Sopenharmony_ci		u32 dlen = skb->len;
20762306a36Sopenharmony_ci		u32 len = skb->len;
20862306a36Sopenharmony_ci		u32 credits_needed;
20962306a36Sopenharmony_ci		u32 compl = 0;
21062306a36Sopenharmony_ci		u32 flowclen16 = 0;
21162306a36Sopenharmony_ci		u32 iso_cpl_len = 0;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci		if (cxgbit_skcb_flags(skb) & SKCBF_TX_ISO)
21462306a36Sopenharmony_ci			iso_cpl_len = sizeof(struct cpl_tx_data_iso);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci		if (cxgbit_is_ofld_imm(skb))
21762306a36Sopenharmony_ci			credits_needed = DIV_ROUND_UP(dlen + iso_cpl_len, 16);
21862306a36Sopenharmony_ci		else
21962306a36Sopenharmony_ci			credits_needed = DIV_ROUND_UP((8 *
22062306a36Sopenharmony_ci					cxgbit_calc_tx_flits_ofld(skb)) +
22162306a36Sopenharmony_ci					iso_cpl_len, 16);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci		if (likely(cxgbit_skcb_flags(skb) & SKCBF_TX_NEED_HDR))
22462306a36Sopenharmony_ci			credits_needed += DIV_ROUND_UP(
22562306a36Sopenharmony_ci				sizeof(struct fw_ofld_tx_data_wr), 16);
22662306a36Sopenharmony_ci		/*
22762306a36Sopenharmony_ci		 * Assumes the initial credits is large enough to support
22862306a36Sopenharmony_ci		 * fw_flowc_wr plus largest possible first payload
22962306a36Sopenharmony_ci		 */
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci		if (!test_and_set_bit(CSK_TX_DATA_SENT, &csk->com.flags)) {
23262306a36Sopenharmony_ci			flowclen16 = cxgbit_send_tx_flowc_wr(csk);
23362306a36Sopenharmony_ci			csk->wr_cred -= flowclen16;
23462306a36Sopenharmony_ci			csk->wr_una_cred += flowclen16;
23562306a36Sopenharmony_ci		}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci		if (csk->wr_cred < credits_needed) {
23862306a36Sopenharmony_ci			pr_debug("csk 0x%p, skb %u/%u, wr %d < %u.\n",
23962306a36Sopenharmony_ci				 csk, skb->len, skb->data_len,
24062306a36Sopenharmony_ci				 credits_needed, csk->wr_cred);
24162306a36Sopenharmony_ci			break;
24262306a36Sopenharmony_ci		}
24362306a36Sopenharmony_ci		__skb_unlink(skb, &csk->txq);
24462306a36Sopenharmony_ci		set_wr_txq(skb, CPL_PRIORITY_DATA, csk->txq_idx);
24562306a36Sopenharmony_ci		skb->csum = (__force __wsum)(credits_needed + flowclen16);
24662306a36Sopenharmony_ci		csk->wr_cred -= credits_needed;
24762306a36Sopenharmony_ci		csk->wr_una_cred += credits_needed;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci		pr_debug("csk 0x%p, skb %u/%u, wr %d, left %u, unack %u.\n",
25062306a36Sopenharmony_ci			 csk, skb->len, skb->data_len, credits_needed,
25162306a36Sopenharmony_ci			 csk->wr_cred, csk->wr_una_cred);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci		if (likely(cxgbit_skcb_flags(skb) & SKCBF_TX_NEED_HDR)) {
25462306a36Sopenharmony_ci			len += cxgbit_skcb_tx_extralen(skb);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci			if ((csk->wr_una_cred >= (csk->wr_max_cred / 2)) ||
25762306a36Sopenharmony_ci			    (!before(csk->write_seq,
25862306a36Sopenharmony_ci				     csk->snd_una + csk->snd_win))) {
25962306a36Sopenharmony_ci				compl = 1;
26062306a36Sopenharmony_ci				csk->wr_una_cred = 0;
26162306a36Sopenharmony_ci			}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci			cxgbit_tx_data_wr(csk, skb, dlen, len, credits_needed,
26462306a36Sopenharmony_ci					  compl);
26562306a36Sopenharmony_ci			csk->snd_nxt += len;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci		} else if ((cxgbit_skcb_flags(skb) & SKCBF_TX_FLAG_COMPL) ||
26862306a36Sopenharmony_ci			   (csk->wr_una_cred >= (csk->wr_max_cred / 2))) {
26962306a36Sopenharmony_ci			struct cpl_close_con_req *req =
27062306a36Sopenharmony_ci				(struct cpl_close_con_req *)skb->data;
27162306a36Sopenharmony_ci			req->wr.wr_hi |= htonl(FW_WR_COMPL_F);
27262306a36Sopenharmony_ci			csk->wr_una_cred = 0;
27362306a36Sopenharmony_ci		}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci		cxgbit_sock_enqueue_wr(csk, skb);
27662306a36Sopenharmony_ci		t4_set_arp_err_handler(skb, csk,
27762306a36Sopenharmony_ci				       cxgbit_arp_failure_skb_discard);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci		pr_debug("csk 0x%p,%u, skb 0x%p, %u.\n",
28062306a36Sopenharmony_ci			 csk, csk->tid, skb, len);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci		cxgbit_l2t_send(csk->com.cdev, skb, csk->l2t);
28362306a36Sopenharmony_ci	}
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistatic void cxgbit_unlock_sock(struct cxgbit_sock *csk)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	struct sk_buff_head backlogq;
28962306a36Sopenharmony_ci	struct sk_buff *skb;
29062306a36Sopenharmony_ci	void (*fn)(struct cxgbit_sock *, struct sk_buff *);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	skb_queue_head_init(&backlogq);
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	spin_lock_bh(&csk->lock);
29562306a36Sopenharmony_ci	while (skb_queue_len(&csk->backlogq)) {
29662306a36Sopenharmony_ci		skb_queue_splice_init(&csk->backlogq, &backlogq);
29762306a36Sopenharmony_ci		spin_unlock_bh(&csk->lock);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci		while ((skb = __skb_dequeue(&backlogq))) {
30062306a36Sopenharmony_ci			fn = cxgbit_skcb_rx_backlog_fn(skb);
30162306a36Sopenharmony_ci			fn(csk, skb);
30262306a36Sopenharmony_ci		}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci		spin_lock_bh(&csk->lock);
30562306a36Sopenharmony_ci	}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	csk->lock_owner = false;
30862306a36Sopenharmony_ci	spin_unlock_bh(&csk->lock);
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic int cxgbit_queue_skb(struct cxgbit_sock *csk, struct sk_buff *skb)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	int ret = 0;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	spin_lock_bh(&csk->lock);
31662306a36Sopenharmony_ci	csk->lock_owner = true;
31762306a36Sopenharmony_ci	spin_unlock_bh(&csk->lock);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	if (unlikely((csk->com.state != CSK_STATE_ESTABLISHED) ||
32062306a36Sopenharmony_ci		     signal_pending(current))) {
32162306a36Sopenharmony_ci		__kfree_skb(skb);
32262306a36Sopenharmony_ci		__skb_queue_purge(&csk->ppodq);
32362306a36Sopenharmony_ci		ret = -1;
32462306a36Sopenharmony_ci		goto unlock;
32562306a36Sopenharmony_ci	}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	csk->write_seq += skb->len +
32862306a36Sopenharmony_ci			  cxgbit_skcb_tx_extralen(skb);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	skb_queue_splice_tail_init(&csk->ppodq, &csk->txq);
33162306a36Sopenharmony_ci	__skb_queue_tail(&csk->txq, skb);
33262306a36Sopenharmony_ci	cxgbit_push_tx_frames(csk);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ciunlock:
33562306a36Sopenharmony_ci	cxgbit_unlock_sock(csk);
33662306a36Sopenharmony_ci	return ret;
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cistatic int
34062306a36Sopenharmony_cicxgbit_map_skb(struct iscsit_cmd *cmd, struct sk_buff *skb, u32 data_offset,
34162306a36Sopenharmony_ci	       u32 data_length)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	u32 i = 0, nr_frags = MAX_SKB_FRAGS;
34462306a36Sopenharmony_ci	u32 padding = ((-data_length) & 3);
34562306a36Sopenharmony_ci	struct scatterlist *sg;
34662306a36Sopenharmony_ci	struct page *page;
34762306a36Sopenharmony_ci	unsigned int page_off;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	if (padding)
35062306a36Sopenharmony_ci		nr_frags--;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	/*
35362306a36Sopenharmony_ci	 * We know each entry in t_data_sg contains a page.
35462306a36Sopenharmony_ci	 */
35562306a36Sopenharmony_ci	sg = &cmd->se_cmd.t_data_sg[data_offset / PAGE_SIZE];
35662306a36Sopenharmony_ci	page_off = (data_offset % PAGE_SIZE);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	while (data_length && (i < nr_frags)) {
35962306a36Sopenharmony_ci		u32 cur_len = min_t(u32, data_length, sg->length - page_off);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci		page = sg_page(sg);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci		get_page(page);
36462306a36Sopenharmony_ci		skb_fill_page_desc(skb, i, page, sg->offset + page_off,
36562306a36Sopenharmony_ci				   cur_len);
36662306a36Sopenharmony_ci		skb->data_len += cur_len;
36762306a36Sopenharmony_ci		skb->len += cur_len;
36862306a36Sopenharmony_ci		skb->truesize += cur_len;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci		data_length -= cur_len;
37162306a36Sopenharmony_ci		page_off = 0;
37262306a36Sopenharmony_ci		sg = sg_next(sg);
37362306a36Sopenharmony_ci		i++;
37462306a36Sopenharmony_ci	}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	if (data_length)
37762306a36Sopenharmony_ci		return -1;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	if (padding) {
38062306a36Sopenharmony_ci		page = alloc_page(GFP_KERNEL | __GFP_ZERO);
38162306a36Sopenharmony_ci		if (!page)
38262306a36Sopenharmony_ci			return -1;
38362306a36Sopenharmony_ci		skb_fill_page_desc(skb, i, page, 0, padding);
38462306a36Sopenharmony_ci		skb->data_len += padding;
38562306a36Sopenharmony_ci		skb->len += padding;
38662306a36Sopenharmony_ci		skb->truesize += padding;
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	return 0;
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic int
39362306a36Sopenharmony_cicxgbit_tx_datain_iso(struct cxgbit_sock *csk, struct iscsit_cmd *cmd,
39462306a36Sopenharmony_ci		     struct iscsi_datain_req *dr)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	struct iscsit_conn *conn = csk->conn;
39762306a36Sopenharmony_ci	struct sk_buff *skb;
39862306a36Sopenharmony_ci	struct iscsi_datain datain;
39962306a36Sopenharmony_ci	struct cxgbit_iso_info iso_info;
40062306a36Sopenharmony_ci	u32 data_length = cmd->se_cmd.data_length;
40162306a36Sopenharmony_ci	u32 mrdsl = conn->conn_ops->MaxRecvDataSegmentLength;
40262306a36Sopenharmony_ci	u32 num_pdu, plen, tx_data = 0;
40362306a36Sopenharmony_ci	bool task_sense = !!(cmd->se_cmd.se_cmd_flags &
40462306a36Sopenharmony_ci		SCF_TRANSPORT_TASK_SENSE);
40562306a36Sopenharmony_ci	bool set_statsn = false;
40662306a36Sopenharmony_ci	int ret = -1;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	while (data_length) {
40962306a36Sopenharmony_ci		num_pdu = (data_length + mrdsl - 1) / mrdsl;
41062306a36Sopenharmony_ci		if (num_pdu > csk->max_iso_npdu)
41162306a36Sopenharmony_ci			num_pdu = csk->max_iso_npdu;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci		plen = num_pdu * mrdsl;
41462306a36Sopenharmony_ci		if (plen > data_length)
41562306a36Sopenharmony_ci			plen = data_length;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci		skb = __cxgbit_alloc_skb(csk, 0, true);
41862306a36Sopenharmony_ci		if (unlikely(!skb))
41962306a36Sopenharmony_ci			return -ENOMEM;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci		memset(skb->data, 0, ISCSI_HDR_LEN);
42262306a36Sopenharmony_ci		cxgbit_skcb_flags(skb) |= SKCBF_TX_ISO;
42362306a36Sopenharmony_ci		cxgbit_skcb_submode(skb) |= (csk->submode &
42462306a36Sopenharmony_ci				CXGBIT_SUBMODE_DCRC);
42562306a36Sopenharmony_ci		cxgbit_skcb_tx_extralen(skb) = (num_pdu *
42662306a36Sopenharmony_ci				cxgbit_digest_len[cxgbit_skcb_submode(skb)]) +
42762306a36Sopenharmony_ci						((num_pdu - 1) * ISCSI_HDR_LEN);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci		memset(&datain, 0, sizeof(struct iscsi_datain));
43062306a36Sopenharmony_ci		memset(&iso_info, 0, sizeof(iso_info));
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci		if (!tx_data)
43362306a36Sopenharmony_ci			iso_info.flags |= CXGBIT_ISO_FSLICE;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci		if (!(data_length - plen)) {
43662306a36Sopenharmony_ci			iso_info.flags |= CXGBIT_ISO_LSLICE;
43762306a36Sopenharmony_ci			if (!task_sense) {
43862306a36Sopenharmony_ci				datain.flags = ISCSI_FLAG_DATA_STATUS;
43962306a36Sopenharmony_ci				iscsit_increment_maxcmdsn(cmd, conn->sess);
44062306a36Sopenharmony_ci				cmd->stat_sn = conn->stat_sn++;
44162306a36Sopenharmony_ci				set_statsn = true;
44262306a36Sopenharmony_ci			}
44362306a36Sopenharmony_ci		}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci		iso_info.burst_len = num_pdu * mrdsl;
44662306a36Sopenharmony_ci		iso_info.mpdu = mrdsl;
44762306a36Sopenharmony_ci		iso_info.len = ISCSI_HDR_LEN + plen;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci		cxgbit_cpl_tx_data_iso(skb, &iso_info);
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci		datain.offset = tx_data;
45262306a36Sopenharmony_ci		datain.data_sn = cmd->data_sn - 1;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci		iscsit_build_datain_pdu(cmd, conn, &datain,
45562306a36Sopenharmony_ci					(struct iscsi_data_rsp *)skb->data,
45662306a36Sopenharmony_ci					set_statsn);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci		ret = cxgbit_map_skb(cmd, skb, tx_data, plen);
45962306a36Sopenharmony_ci		if (unlikely(ret)) {
46062306a36Sopenharmony_ci			__kfree_skb(skb);
46162306a36Sopenharmony_ci			goto out;
46262306a36Sopenharmony_ci		}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci		ret = cxgbit_queue_skb(csk, skb);
46562306a36Sopenharmony_ci		if (unlikely(ret))
46662306a36Sopenharmony_ci			goto out;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci		tx_data += plen;
46962306a36Sopenharmony_ci		data_length -= plen;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci		cmd->read_data_done += plen;
47262306a36Sopenharmony_ci		cmd->data_sn += num_pdu;
47362306a36Sopenharmony_ci	}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	dr->dr_complete = DATAIN_COMPLETE_NORMAL;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	return 0;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ciout:
48062306a36Sopenharmony_ci	return ret;
48162306a36Sopenharmony_ci}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_cistatic int
48462306a36Sopenharmony_cicxgbit_tx_datain(struct cxgbit_sock *csk, struct iscsit_cmd *cmd,
48562306a36Sopenharmony_ci		 const struct iscsi_datain *datain)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	struct sk_buff *skb;
48862306a36Sopenharmony_ci	int ret = 0;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	skb = cxgbit_alloc_skb(csk, 0);
49162306a36Sopenharmony_ci	if (unlikely(!skb))
49262306a36Sopenharmony_ci		return -ENOMEM;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	memcpy(skb->data, cmd->pdu, ISCSI_HDR_LEN);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	if (datain->length) {
49762306a36Sopenharmony_ci		cxgbit_skcb_submode(skb) |= (csk->submode &
49862306a36Sopenharmony_ci				CXGBIT_SUBMODE_DCRC);
49962306a36Sopenharmony_ci		cxgbit_skcb_tx_extralen(skb) =
50062306a36Sopenharmony_ci				cxgbit_digest_len[cxgbit_skcb_submode(skb)];
50162306a36Sopenharmony_ci	}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	ret = cxgbit_map_skb(cmd, skb, datain->offset, datain->length);
50462306a36Sopenharmony_ci	if (ret < 0) {
50562306a36Sopenharmony_ci		__kfree_skb(skb);
50662306a36Sopenharmony_ci		return ret;
50762306a36Sopenharmony_ci	}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	return cxgbit_queue_skb(csk, skb);
51062306a36Sopenharmony_ci}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_cistatic int
51362306a36Sopenharmony_cicxgbit_xmit_datain_pdu(struct iscsit_conn *conn, struct iscsit_cmd *cmd,
51462306a36Sopenharmony_ci		       struct iscsi_datain_req *dr,
51562306a36Sopenharmony_ci		       const struct iscsi_datain *datain)
51662306a36Sopenharmony_ci{
51762306a36Sopenharmony_ci	struct cxgbit_sock *csk = conn->context;
51862306a36Sopenharmony_ci	u32 data_length = cmd->se_cmd.data_length;
51962306a36Sopenharmony_ci	u32 padding = ((-data_length) & 3);
52062306a36Sopenharmony_ci	u32 mrdsl = conn->conn_ops->MaxRecvDataSegmentLength;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	if ((data_length > mrdsl) && (!dr->recovery) &&
52362306a36Sopenharmony_ci	    (!padding) && (!datain->offset) && csk->max_iso_npdu) {
52462306a36Sopenharmony_ci		atomic_long_add(data_length - datain->length,
52562306a36Sopenharmony_ci				&conn->sess->tx_data_octets);
52662306a36Sopenharmony_ci		return cxgbit_tx_datain_iso(csk, cmd, dr);
52762306a36Sopenharmony_ci	}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	return cxgbit_tx_datain(csk, cmd, datain);
53062306a36Sopenharmony_ci}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_cistatic int
53362306a36Sopenharmony_cicxgbit_xmit_nondatain_pdu(struct iscsit_conn *conn, struct iscsit_cmd *cmd,
53462306a36Sopenharmony_ci			  const void *data_buf, u32 data_buf_len)
53562306a36Sopenharmony_ci{
53662306a36Sopenharmony_ci	struct cxgbit_sock *csk = conn->context;
53762306a36Sopenharmony_ci	struct sk_buff *skb;
53862306a36Sopenharmony_ci	u32 padding = ((-data_buf_len) & 3);
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	skb = cxgbit_alloc_skb(csk, data_buf_len + padding);
54162306a36Sopenharmony_ci	if (unlikely(!skb))
54262306a36Sopenharmony_ci		return -ENOMEM;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	memcpy(skb->data, cmd->pdu, ISCSI_HDR_LEN);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	if (data_buf_len) {
54762306a36Sopenharmony_ci		u32 pad_bytes = 0;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci		skb_store_bits(skb, ISCSI_HDR_LEN, data_buf, data_buf_len);
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci		if (padding)
55262306a36Sopenharmony_ci			skb_store_bits(skb, ISCSI_HDR_LEN + data_buf_len,
55362306a36Sopenharmony_ci				       &pad_bytes, padding);
55462306a36Sopenharmony_ci	}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	cxgbit_skcb_tx_extralen(skb) = cxgbit_digest_len[
55762306a36Sopenharmony_ci				       cxgbit_skcb_submode(skb)];
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	return cxgbit_queue_skb(csk, skb);
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ciint
56362306a36Sopenharmony_cicxgbit_xmit_pdu(struct iscsit_conn *conn, struct iscsit_cmd *cmd,
56462306a36Sopenharmony_ci		struct iscsi_datain_req *dr, const void *buf, u32 buf_len)
56562306a36Sopenharmony_ci{
56662306a36Sopenharmony_ci	if (dr)
56762306a36Sopenharmony_ci		return cxgbit_xmit_datain_pdu(conn, cmd, dr, buf);
56862306a36Sopenharmony_ci	else
56962306a36Sopenharmony_ci		return cxgbit_xmit_nondatain_pdu(conn, cmd, buf, buf_len);
57062306a36Sopenharmony_ci}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ciint cxgbit_validate_params(struct iscsit_conn *conn)
57362306a36Sopenharmony_ci{
57462306a36Sopenharmony_ci	struct cxgbit_sock *csk = conn->context;
57562306a36Sopenharmony_ci	struct cxgbit_device *cdev = csk->com.cdev;
57662306a36Sopenharmony_ci	struct iscsi_param *param;
57762306a36Sopenharmony_ci	u32 max_xmitdsl;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	param = iscsi_find_param_from_key(MAXXMITDATASEGMENTLENGTH,
58062306a36Sopenharmony_ci					  conn->param_list);
58162306a36Sopenharmony_ci	if (!param)
58262306a36Sopenharmony_ci		return -1;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	if (kstrtou32(param->value, 0, &max_xmitdsl) < 0)
58562306a36Sopenharmony_ci		return -1;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	if (max_xmitdsl > cdev->mdsl) {
58862306a36Sopenharmony_ci		if (iscsi_change_param_sprintf(
58962306a36Sopenharmony_ci			conn, "MaxXmitDataSegmentLength=%u", cdev->mdsl))
59062306a36Sopenharmony_ci			return -1;
59162306a36Sopenharmony_ci	}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	return 0;
59462306a36Sopenharmony_ci}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_cistatic int cxgbit_set_digest(struct cxgbit_sock *csk)
59762306a36Sopenharmony_ci{
59862306a36Sopenharmony_ci	struct iscsit_conn *conn = csk->conn;
59962306a36Sopenharmony_ci	struct iscsi_param *param;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	param = iscsi_find_param_from_key(HEADERDIGEST, conn->param_list);
60262306a36Sopenharmony_ci	if (!param) {
60362306a36Sopenharmony_ci		pr_err("param not found key %s\n", HEADERDIGEST);
60462306a36Sopenharmony_ci		return -1;
60562306a36Sopenharmony_ci	}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	if (!strcmp(param->value, CRC32C))
60862306a36Sopenharmony_ci		csk->submode |= CXGBIT_SUBMODE_HCRC;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	param = iscsi_find_param_from_key(DATADIGEST, conn->param_list);
61162306a36Sopenharmony_ci	if (!param) {
61262306a36Sopenharmony_ci		csk->submode = 0;
61362306a36Sopenharmony_ci		pr_err("param not found key %s\n", DATADIGEST);
61462306a36Sopenharmony_ci		return -1;
61562306a36Sopenharmony_ci	}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	if (!strcmp(param->value, CRC32C))
61862306a36Sopenharmony_ci		csk->submode |= CXGBIT_SUBMODE_DCRC;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	if (cxgbit_setup_conn_digest(csk)) {
62162306a36Sopenharmony_ci		csk->submode = 0;
62262306a36Sopenharmony_ci		return -1;
62362306a36Sopenharmony_ci	}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	return 0;
62662306a36Sopenharmony_ci}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_cistatic int cxgbit_set_iso_npdu(struct cxgbit_sock *csk)
62962306a36Sopenharmony_ci{
63062306a36Sopenharmony_ci	struct iscsit_conn *conn = csk->conn;
63162306a36Sopenharmony_ci	struct iscsi_conn_ops *conn_ops = conn->conn_ops;
63262306a36Sopenharmony_ci	struct iscsi_param *param;
63362306a36Sopenharmony_ci	u32 mrdsl, mbl;
63462306a36Sopenharmony_ci	u32 max_npdu, max_iso_npdu;
63562306a36Sopenharmony_ci	u32 max_iso_payload;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	if (conn->login->leading_connection) {
63862306a36Sopenharmony_ci		param = iscsi_find_param_from_key(MAXBURSTLENGTH,
63962306a36Sopenharmony_ci						  conn->param_list);
64062306a36Sopenharmony_ci		if (!param) {
64162306a36Sopenharmony_ci			pr_err("param not found key %s\n", MAXBURSTLENGTH);
64262306a36Sopenharmony_ci			return -1;
64362306a36Sopenharmony_ci		}
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci		if (kstrtou32(param->value, 0, &mbl) < 0)
64662306a36Sopenharmony_ci			return -1;
64762306a36Sopenharmony_ci	} else {
64862306a36Sopenharmony_ci		mbl = conn->sess->sess_ops->MaxBurstLength;
64962306a36Sopenharmony_ci	}
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	mrdsl = conn_ops->MaxRecvDataSegmentLength;
65262306a36Sopenharmony_ci	max_npdu = mbl / mrdsl;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	max_iso_payload = rounddown(CXGBIT_MAX_ISO_PAYLOAD, csk->emss);
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	max_iso_npdu = max_iso_payload /
65762306a36Sopenharmony_ci		       (ISCSI_HDR_LEN + mrdsl +
65862306a36Sopenharmony_ci			cxgbit_digest_len[csk->submode]);
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	csk->max_iso_npdu = min(max_npdu, max_iso_npdu);
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	if (csk->max_iso_npdu <= 1)
66362306a36Sopenharmony_ci		csk->max_iso_npdu = 0;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	return 0;
66662306a36Sopenharmony_ci}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci/*
66962306a36Sopenharmony_ci * cxgbit_seq_pdu_inorder()
67062306a36Sopenharmony_ci * @csk: pointer to cxgbit socket structure
67162306a36Sopenharmony_ci *
67262306a36Sopenharmony_ci * This function checks whether data sequence and data
67362306a36Sopenharmony_ci * pdu are in order.
67462306a36Sopenharmony_ci *
67562306a36Sopenharmony_ci * Return: returns -1 on error, 0 if data sequence and
67662306a36Sopenharmony_ci * data pdu are in order, 1 if data sequence or data pdu
67762306a36Sopenharmony_ci * is not in order.
67862306a36Sopenharmony_ci */
67962306a36Sopenharmony_cistatic int cxgbit_seq_pdu_inorder(struct cxgbit_sock *csk)
68062306a36Sopenharmony_ci{
68162306a36Sopenharmony_ci	struct iscsit_conn *conn = csk->conn;
68262306a36Sopenharmony_ci	struct iscsi_param *param;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	if (conn->login->leading_connection) {
68562306a36Sopenharmony_ci		param = iscsi_find_param_from_key(DATASEQUENCEINORDER,
68662306a36Sopenharmony_ci						  conn->param_list);
68762306a36Sopenharmony_ci		if (!param) {
68862306a36Sopenharmony_ci			pr_err("param not found key %s\n", DATASEQUENCEINORDER);
68962306a36Sopenharmony_ci			return -1;
69062306a36Sopenharmony_ci		}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci		if (strcmp(param->value, YES))
69362306a36Sopenharmony_ci			return 1;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci		param = iscsi_find_param_from_key(DATAPDUINORDER,
69662306a36Sopenharmony_ci						  conn->param_list);
69762306a36Sopenharmony_ci		if (!param) {
69862306a36Sopenharmony_ci			pr_err("param not found key %s\n", DATAPDUINORDER);
69962306a36Sopenharmony_ci			return -1;
70062306a36Sopenharmony_ci		}
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci		if (strcmp(param->value, YES))
70362306a36Sopenharmony_ci			return 1;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	} else {
70662306a36Sopenharmony_ci		if (!conn->sess->sess_ops->DataSequenceInOrder)
70762306a36Sopenharmony_ci			return 1;
70862306a36Sopenharmony_ci		if (!conn->sess->sess_ops->DataPDUInOrder)
70962306a36Sopenharmony_ci			return 1;
71062306a36Sopenharmony_ci	}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	return 0;
71362306a36Sopenharmony_ci}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_cistatic int cxgbit_set_params(struct iscsit_conn *conn)
71662306a36Sopenharmony_ci{
71762306a36Sopenharmony_ci	struct cxgbit_sock *csk = conn->context;
71862306a36Sopenharmony_ci	struct cxgbit_device *cdev = csk->com.cdev;
71962306a36Sopenharmony_ci	struct cxgbi_ppm *ppm = *csk->com.cdev->lldi.iscsi_ppm;
72062306a36Sopenharmony_ci	struct iscsi_conn_ops *conn_ops = conn->conn_ops;
72162306a36Sopenharmony_ci	struct iscsi_param *param;
72262306a36Sopenharmony_ci	u8 erl;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	if (conn_ops->MaxRecvDataSegmentLength > cdev->mdsl)
72562306a36Sopenharmony_ci		conn_ops->MaxRecvDataSegmentLength = cdev->mdsl;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	if (cxgbit_set_digest(csk))
72862306a36Sopenharmony_ci		return -1;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	if (conn->login->leading_connection) {
73162306a36Sopenharmony_ci		param = iscsi_find_param_from_key(ERRORRECOVERYLEVEL,
73262306a36Sopenharmony_ci						  conn->param_list);
73362306a36Sopenharmony_ci		if (!param) {
73462306a36Sopenharmony_ci			pr_err("param not found key %s\n", ERRORRECOVERYLEVEL);
73562306a36Sopenharmony_ci			return -1;
73662306a36Sopenharmony_ci		}
73762306a36Sopenharmony_ci		if (kstrtou8(param->value, 0, &erl) < 0)
73862306a36Sopenharmony_ci			return -1;
73962306a36Sopenharmony_ci	} else {
74062306a36Sopenharmony_ci		erl = conn->sess->sess_ops->ErrorRecoveryLevel;
74162306a36Sopenharmony_ci	}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	if (!erl) {
74462306a36Sopenharmony_ci		int ret;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci		ret = cxgbit_seq_pdu_inorder(csk);
74762306a36Sopenharmony_ci		if (ret < 0) {
74862306a36Sopenharmony_ci			return -1;
74962306a36Sopenharmony_ci		} else if (ret > 0) {
75062306a36Sopenharmony_ci			if (is_t5(cdev->lldi.adapter_type))
75162306a36Sopenharmony_ci				goto enable_ddp;
75262306a36Sopenharmony_ci			else
75362306a36Sopenharmony_ci				return 0;
75462306a36Sopenharmony_ci		}
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci		if (test_bit(CDEV_ISO_ENABLE, &cdev->flags)) {
75762306a36Sopenharmony_ci			if (cxgbit_set_iso_npdu(csk))
75862306a36Sopenharmony_ci				return -1;
75962306a36Sopenharmony_ci		}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_cienable_ddp:
76262306a36Sopenharmony_ci		if (test_bit(CDEV_DDP_ENABLE, &cdev->flags)) {
76362306a36Sopenharmony_ci			if (cxgbit_setup_conn_pgidx(csk,
76462306a36Sopenharmony_ci						    ppm->tformat.pgsz_idx_dflt))
76562306a36Sopenharmony_ci				return -1;
76662306a36Sopenharmony_ci			set_bit(CSK_DDP_ENABLE, &csk->com.flags);
76762306a36Sopenharmony_ci		}
76862306a36Sopenharmony_ci	}
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	return 0;
77162306a36Sopenharmony_ci}
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ciint
77462306a36Sopenharmony_cicxgbit_put_login_tx(struct iscsit_conn *conn, struct iscsi_login *login,
77562306a36Sopenharmony_ci		    u32 length)
77662306a36Sopenharmony_ci{
77762306a36Sopenharmony_ci	struct cxgbit_sock *csk = conn->context;
77862306a36Sopenharmony_ci	struct sk_buff *skb;
77962306a36Sopenharmony_ci	u32 padding_buf = 0;
78062306a36Sopenharmony_ci	u8 padding = ((-length) & 3);
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	skb = cxgbit_alloc_skb(csk, length + padding);
78362306a36Sopenharmony_ci	if (!skb)
78462306a36Sopenharmony_ci		return -ENOMEM;
78562306a36Sopenharmony_ci	skb_store_bits(skb, 0, login->rsp, ISCSI_HDR_LEN);
78662306a36Sopenharmony_ci	skb_store_bits(skb, ISCSI_HDR_LEN, login->rsp_buf, length);
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	if (padding)
78962306a36Sopenharmony_ci		skb_store_bits(skb, ISCSI_HDR_LEN + length,
79062306a36Sopenharmony_ci			       &padding_buf, padding);
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	if (login->login_complete) {
79362306a36Sopenharmony_ci		if (cxgbit_set_params(conn)) {
79462306a36Sopenharmony_ci			kfree_skb(skb);
79562306a36Sopenharmony_ci			return -1;
79662306a36Sopenharmony_ci		}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci		set_bit(CSK_LOGIN_DONE, &csk->com.flags);
79962306a36Sopenharmony_ci	}
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	if (cxgbit_queue_skb(csk, skb))
80262306a36Sopenharmony_ci		return -1;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	if ((!login->login_complete) && (!login->login_failed))
80562306a36Sopenharmony_ci		schedule_delayed_work(&conn->login_work, 0);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	return 0;
80862306a36Sopenharmony_ci}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_cistatic void
81162306a36Sopenharmony_cicxgbit_skb_copy_to_sg(struct sk_buff *skb, struct scatterlist *sg,
81262306a36Sopenharmony_ci		      unsigned int nents, u32 skip)
81362306a36Sopenharmony_ci{
81462306a36Sopenharmony_ci	struct skb_seq_state st;
81562306a36Sopenharmony_ci	const u8 *buf;
81662306a36Sopenharmony_ci	unsigned int consumed = 0, buf_len;
81762306a36Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(skb);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	skb_prepare_seq_read(skb, pdu_cb->doffset,
82062306a36Sopenharmony_ci			     pdu_cb->doffset + pdu_cb->dlen,
82162306a36Sopenharmony_ci			     &st);
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	while (true) {
82462306a36Sopenharmony_ci		buf_len = skb_seq_read(consumed, &buf, &st);
82562306a36Sopenharmony_ci		if (!buf_len) {
82662306a36Sopenharmony_ci			skb_abort_seq_read(&st);
82762306a36Sopenharmony_ci			break;
82862306a36Sopenharmony_ci		}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci		consumed += sg_pcopy_from_buffer(sg, nents, (void *)buf,
83162306a36Sopenharmony_ci						 buf_len, skip + consumed);
83262306a36Sopenharmony_ci	}
83362306a36Sopenharmony_ci}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_cistatic struct iscsit_cmd *cxgbit_allocate_cmd(struct cxgbit_sock *csk)
83662306a36Sopenharmony_ci{
83762306a36Sopenharmony_ci	struct iscsit_conn *conn = csk->conn;
83862306a36Sopenharmony_ci	struct cxgbi_ppm *ppm = cdev2ppm(csk->com.cdev);
83962306a36Sopenharmony_ci	struct cxgbit_cmd *ccmd;
84062306a36Sopenharmony_ci	struct iscsit_cmd *cmd;
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
84362306a36Sopenharmony_ci	if (!cmd) {
84462306a36Sopenharmony_ci		pr_err("Unable to allocate iscsit_cmd + cxgbit_cmd\n");
84562306a36Sopenharmony_ci		return NULL;
84662306a36Sopenharmony_ci	}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	ccmd = iscsit_priv_cmd(cmd);
84962306a36Sopenharmony_ci	ccmd->ttinfo.tag = ppm->tformat.no_ddp_mask;
85062306a36Sopenharmony_ci	ccmd->setup_ddp = true;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	return cmd;
85362306a36Sopenharmony_ci}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_cistatic int
85662306a36Sopenharmony_cicxgbit_handle_immediate_data(struct iscsit_cmd *cmd, struct iscsi_scsi_req *hdr,
85762306a36Sopenharmony_ci			     u32 length)
85862306a36Sopenharmony_ci{
85962306a36Sopenharmony_ci	struct iscsit_conn *conn = cmd->conn;
86062306a36Sopenharmony_ci	struct cxgbit_sock *csk = conn->context;
86162306a36Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	if (pdu_cb->flags & PDUCBF_RX_DCRC_ERR) {
86462306a36Sopenharmony_ci		pr_err("ImmediateData CRC32C DataDigest error\n");
86562306a36Sopenharmony_ci		if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
86662306a36Sopenharmony_ci			pr_err("Unable to recover from"
86762306a36Sopenharmony_ci			       " Immediate Data digest failure while"
86862306a36Sopenharmony_ci			       " in ERL=0.\n");
86962306a36Sopenharmony_ci			iscsit_reject_cmd(cmd, ISCSI_REASON_DATA_DIGEST_ERROR,
87062306a36Sopenharmony_ci					  (unsigned char *)hdr);
87162306a36Sopenharmony_ci			return IMMEDIATE_DATA_CANNOT_RECOVER;
87262306a36Sopenharmony_ci		}
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci		iscsit_reject_cmd(cmd, ISCSI_REASON_DATA_DIGEST_ERROR,
87562306a36Sopenharmony_ci				  (unsigned char *)hdr);
87662306a36Sopenharmony_ci		return IMMEDIATE_DATA_ERL1_CRC_FAILURE;
87762306a36Sopenharmony_ci	}
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	if (cmd->se_cmd.se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) {
88062306a36Sopenharmony_ci		struct cxgbit_cmd *ccmd = iscsit_priv_cmd(cmd);
88162306a36Sopenharmony_ci		struct skb_shared_info *ssi = skb_shinfo(csk->skb);
88262306a36Sopenharmony_ci		skb_frag_t *dfrag = &ssi->frags[pdu_cb->dfrag_idx];
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci		sg_init_table(&ccmd->sg, 1);
88562306a36Sopenharmony_ci		sg_set_page(&ccmd->sg, skb_frag_page(dfrag),
88662306a36Sopenharmony_ci				skb_frag_size(dfrag), skb_frag_off(dfrag));
88762306a36Sopenharmony_ci		get_page(skb_frag_page(dfrag));
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci		cmd->se_cmd.t_data_sg = &ccmd->sg;
89062306a36Sopenharmony_ci		cmd->se_cmd.t_data_nents = 1;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci		ccmd->release = true;
89362306a36Sopenharmony_ci	} else {
89462306a36Sopenharmony_ci		struct scatterlist *sg = &cmd->se_cmd.t_data_sg[0];
89562306a36Sopenharmony_ci		u32 sg_nents = max(1UL, DIV_ROUND_UP(pdu_cb->dlen, PAGE_SIZE));
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci		cxgbit_skb_copy_to_sg(csk->skb, sg, sg_nents, 0);
89862306a36Sopenharmony_ci	}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	cmd->write_data_done += pdu_cb->dlen;
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	if (cmd->write_data_done == cmd->se_cmd.data_length) {
90362306a36Sopenharmony_ci		spin_lock_bh(&cmd->istate_lock);
90462306a36Sopenharmony_ci		cmd->cmd_flags |= ICF_GOT_LAST_DATAOUT;
90562306a36Sopenharmony_ci		cmd->i_state = ISTATE_RECEIVED_LAST_DATAOUT;
90662306a36Sopenharmony_ci		spin_unlock_bh(&cmd->istate_lock);
90762306a36Sopenharmony_ci	}
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	return IMMEDIATE_DATA_NORMAL_OPERATION;
91062306a36Sopenharmony_ci}
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_cistatic int
91362306a36Sopenharmony_cicxgbit_get_immediate_data(struct iscsit_cmd *cmd, struct iscsi_scsi_req *hdr,
91462306a36Sopenharmony_ci			  bool dump_payload)
91562306a36Sopenharmony_ci{
91662306a36Sopenharmony_ci	struct iscsit_conn *conn = cmd->conn;
91762306a36Sopenharmony_ci	int cmdsn_ret = 0, immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION;
91862306a36Sopenharmony_ci	/*
91962306a36Sopenharmony_ci	 * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes.
92062306a36Sopenharmony_ci	 */
92162306a36Sopenharmony_ci	if (dump_payload)
92262306a36Sopenharmony_ci		goto after_immediate_data;
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	immed_ret = cxgbit_handle_immediate_data(cmd, hdr,
92562306a36Sopenharmony_ci						 cmd->first_burst_len);
92662306a36Sopenharmony_ciafter_immediate_data:
92762306a36Sopenharmony_ci	if (immed_ret == IMMEDIATE_DATA_NORMAL_OPERATION) {
92862306a36Sopenharmony_ci		/*
92962306a36Sopenharmony_ci		 * A PDU/CmdSN carrying Immediate Data passed
93062306a36Sopenharmony_ci		 * DataCRC, check against ExpCmdSN/MaxCmdSN if
93162306a36Sopenharmony_ci		 * Immediate Bit is not set.
93262306a36Sopenharmony_ci		 */
93362306a36Sopenharmony_ci		cmdsn_ret = iscsit_sequence_cmd(conn, cmd,
93462306a36Sopenharmony_ci						(unsigned char *)hdr,
93562306a36Sopenharmony_ci						hdr->cmdsn);
93662306a36Sopenharmony_ci		if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
93762306a36Sopenharmony_ci			return -1;
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci		if (cmd->sense_reason || cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
94062306a36Sopenharmony_ci			target_put_sess_cmd(&cmd->se_cmd);
94162306a36Sopenharmony_ci			return 0;
94262306a36Sopenharmony_ci		} else if (cmd->unsolicited_data) {
94362306a36Sopenharmony_ci			iscsit_set_unsolicited_dataout(cmd);
94462306a36Sopenharmony_ci		}
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	} else if (immed_ret == IMMEDIATE_DATA_ERL1_CRC_FAILURE) {
94762306a36Sopenharmony_ci		/*
94862306a36Sopenharmony_ci		 * Immediate Data failed DataCRC and ERL>=1,
94962306a36Sopenharmony_ci		 * silently drop this PDU and let the initiator
95062306a36Sopenharmony_ci		 * plug the CmdSN gap.
95162306a36Sopenharmony_ci		 *
95262306a36Sopenharmony_ci		 * FIXME: Send Unsolicited NOPIN with reserved
95362306a36Sopenharmony_ci		 * TTT here to help the initiator figure out
95462306a36Sopenharmony_ci		 * the missing CmdSN, although they should be
95562306a36Sopenharmony_ci		 * intelligent enough to determine the missing
95662306a36Sopenharmony_ci		 * CmdSN and issue a retry to plug the sequence.
95762306a36Sopenharmony_ci		 */
95862306a36Sopenharmony_ci		cmd->i_state = ISTATE_REMOVE;
95962306a36Sopenharmony_ci		iscsit_add_cmd_to_immediate_queue(cmd, conn, cmd->i_state);
96062306a36Sopenharmony_ci	} else /* immed_ret == IMMEDIATE_DATA_CANNOT_RECOVER */
96162306a36Sopenharmony_ci		return -1;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	return 0;
96462306a36Sopenharmony_ci}
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_cistatic int
96762306a36Sopenharmony_cicxgbit_handle_scsi_cmd(struct cxgbit_sock *csk, struct iscsit_cmd *cmd)
96862306a36Sopenharmony_ci{
96962306a36Sopenharmony_ci	struct iscsit_conn *conn = csk->conn;
97062306a36Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
97162306a36Sopenharmony_ci	struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)pdu_cb->hdr;
97262306a36Sopenharmony_ci	int rc;
97362306a36Sopenharmony_ci	bool dump_payload = false;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	rc = iscsit_setup_scsi_cmd(conn, cmd, (unsigned char *)hdr);
97662306a36Sopenharmony_ci	if (rc < 0)
97762306a36Sopenharmony_ci		return rc;
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	if (pdu_cb->dlen && (pdu_cb->dlen == cmd->se_cmd.data_length) &&
98062306a36Sopenharmony_ci	    (pdu_cb->nr_dfrags == 1))
98162306a36Sopenharmony_ci		cmd->se_cmd.se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	rc = iscsit_process_scsi_cmd(conn, cmd, hdr);
98462306a36Sopenharmony_ci	if (rc < 0)
98562306a36Sopenharmony_ci		return 0;
98662306a36Sopenharmony_ci	else if (rc > 0)
98762306a36Sopenharmony_ci		dump_payload = true;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	if (!pdu_cb->dlen)
99062306a36Sopenharmony_ci		return 0;
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	return cxgbit_get_immediate_data(cmd, hdr, dump_payload);
99362306a36Sopenharmony_ci}
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_cistatic int cxgbit_handle_iscsi_dataout(struct cxgbit_sock *csk)
99662306a36Sopenharmony_ci{
99762306a36Sopenharmony_ci	struct scatterlist *sg_start;
99862306a36Sopenharmony_ci	struct iscsit_conn *conn = csk->conn;
99962306a36Sopenharmony_ci	struct iscsit_cmd *cmd = NULL;
100062306a36Sopenharmony_ci	struct cxgbit_cmd *ccmd;
100162306a36Sopenharmony_ci	struct cxgbi_task_tag_info *ttinfo;
100262306a36Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
100362306a36Sopenharmony_ci	struct iscsi_data *hdr = (struct iscsi_data *)pdu_cb->hdr;
100462306a36Sopenharmony_ci	u32 data_offset = be32_to_cpu(hdr->offset);
100562306a36Sopenharmony_ci	u32 data_len = ntoh24(hdr->dlength);
100662306a36Sopenharmony_ci	int rc, sg_nents, sg_off;
100762306a36Sopenharmony_ci	bool dcrc_err = false;
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	if (pdu_cb->flags & PDUCBF_RX_DDP_CMP) {
101062306a36Sopenharmony_ci		u32 offset = be32_to_cpu(hdr->offset);
101162306a36Sopenharmony_ci		u32 ddp_data_len;
101262306a36Sopenharmony_ci		bool success = false;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci		cmd = iscsit_find_cmd_from_itt_or_dump(conn, hdr->itt, 0);
101562306a36Sopenharmony_ci		if (!cmd)
101662306a36Sopenharmony_ci			return 0;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci		ddp_data_len = offset - cmd->write_data_done;
101962306a36Sopenharmony_ci		atomic_long_add(ddp_data_len, &conn->sess->rx_data_octets);
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci		cmd->write_data_done = offset;
102262306a36Sopenharmony_ci		cmd->next_burst_len = ddp_data_len;
102362306a36Sopenharmony_ci		cmd->data_sn = be32_to_cpu(hdr->datasn);
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci		rc = __iscsit_check_dataout_hdr(conn, (unsigned char *)hdr,
102662306a36Sopenharmony_ci						cmd, data_len, &success);
102762306a36Sopenharmony_ci		if (rc < 0)
102862306a36Sopenharmony_ci			return rc;
102962306a36Sopenharmony_ci		else if (!success)
103062306a36Sopenharmony_ci			return 0;
103162306a36Sopenharmony_ci	} else {
103262306a36Sopenharmony_ci		rc = iscsit_check_dataout_hdr(conn, (unsigned char *)hdr, &cmd);
103362306a36Sopenharmony_ci		if (rc < 0)
103462306a36Sopenharmony_ci			return rc;
103562306a36Sopenharmony_ci		else if (!cmd)
103662306a36Sopenharmony_ci			return 0;
103762306a36Sopenharmony_ci	}
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	if (pdu_cb->flags & PDUCBF_RX_DCRC_ERR) {
104062306a36Sopenharmony_ci		pr_err("ITT: 0x%08x, Offset: %u, Length: %u,"
104162306a36Sopenharmony_ci		       " DataSN: 0x%08x\n",
104262306a36Sopenharmony_ci		       hdr->itt, hdr->offset, data_len,
104362306a36Sopenharmony_ci		       hdr->datasn);
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci		dcrc_err = true;
104662306a36Sopenharmony_ci		goto check_payload;
104762306a36Sopenharmony_ci	}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	pr_debug("DataOut data_len: %u, "
105062306a36Sopenharmony_ci		"write_data_done: %u, data_length: %u\n",
105162306a36Sopenharmony_ci		  data_len,  cmd->write_data_done,
105262306a36Sopenharmony_ci		  cmd->se_cmd.data_length);
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	if (!(pdu_cb->flags & PDUCBF_RX_DATA_DDPD)) {
105562306a36Sopenharmony_ci		u32 skip = data_offset % PAGE_SIZE;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci		sg_off = data_offset / PAGE_SIZE;
105862306a36Sopenharmony_ci		sg_start = &cmd->se_cmd.t_data_sg[sg_off];
105962306a36Sopenharmony_ci		sg_nents = max(1UL, DIV_ROUND_UP(skip + data_len, PAGE_SIZE));
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci		cxgbit_skb_copy_to_sg(csk->skb, sg_start, sg_nents, skip);
106262306a36Sopenharmony_ci	}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	ccmd = iscsit_priv_cmd(cmd);
106562306a36Sopenharmony_ci	ttinfo = &ccmd->ttinfo;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	if (ccmd->release && ttinfo->sgl &&
106862306a36Sopenharmony_ci	    (cmd->se_cmd.data_length ==	(cmd->write_data_done + data_len))) {
106962306a36Sopenharmony_ci		struct cxgbit_device *cdev = csk->com.cdev;
107062306a36Sopenharmony_ci		struct cxgbi_ppm *ppm = cdev2ppm(cdev);
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci		dma_unmap_sg(&ppm->pdev->dev, ttinfo->sgl, ttinfo->nents,
107362306a36Sopenharmony_ci			     DMA_FROM_DEVICE);
107462306a36Sopenharmony_ci		ttinfo->nents = 0;
107562306a36Sopenharmony_ci		ttinfo->sgl = NULL;
107662306a36Sopenharmony_ci	}
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_cicheck_payload:
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	rc = iscsit_check_dataout_payload(cmd, hdr, dcrc_err);
108162306a36Sopenharmony_ci	if (rc < 0)
108262306a36Sopenharmony_ci		return rc;
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	return 0;
108562306a36Sopenharmony_ci}
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_cistatic int cxgbit_handle_nop_out(struct cxgbit_sock *csk, struct iscsit_cmd *cmd)
108862306a36Sopenharmony_ci{
108962306a36Sopenharmony_ci	struct iscsit_conn *conn = csk->conn;
109062306a36Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
109162306a36Sopenharmony_ci	struct iscsi_nopout *hdr = (struct iscsi_nopout *)pdu_cb->hdr;
109262306a36Sopenharmony_ci	unsigned char *ping_data = NULL;
109362306a36Sopenharmony_ci	u32 payload_length = pdu_cb->dlen;
109462306a36Sopenharmony_ci	int ret;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	ret = iscsit_setup_nop_out(conn, cmd, hdr);
109762306a36Sopenharmony_ci	if (ret < 0)
109862306a36Sopenharmony_ci		return 0;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	if (pdu_cb->flags & PDUCBF_RX_DCRC_ERR) {
110162306a36Sopenharmony_ci		if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
110262306a36Sopenharmony_ci			pr_err("Unable to recover from"
110362306a36Sopenharmony_ci			       " NOPOUT Ping DataCRC failure while in"
110462306a36Sopenharmony_ci			       " ERL=0.\n");
110562306a36Sopenharmony_ci			ret = -1;
110662306a36Sopenharmony_ci			goto out;
110762306a36Sopenharmony_ci		} else {
110862306a36Sopenharmony_ci			/*
110962306a36Sopenharmony_ci			 * drop this PDU and let the
111062306a36Sopenharmony_ci			 * initiator plug the CmdSN gap.
111162306a36Sopenharmony_ci			 */
111262306a36Sopenharmony_ci			pr_info("Dropping NOPOUT"
111362306a36Sopenharmony_ci				" Command CmdSN: 0x%08x due to"
111462306a36Sopenharmony_ci				" DataCRC error.\n", hdr->cmdsn);
111562306a36Sopenharmony_ci			ret = 0;
111662306a36Sopenharmony_ci			goto out;
111762306a36Sopenharmony_ci		}
111862306a36Sopenharmony_ci	}
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	/*
112162306a36Sopenharmony_ci	 * Handle NOP-OUT payload for traditional iSCSI sockets
112262306a36Sopenharmony_ci	 */
112362306a36Sopenharmony_ci	if (payload_length && hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
112462306a36Sopenharmony_ci		ping_data = kzalloc(payload_length + 1, GFP_KERNEL);
112562306a36Sopenharmony_ci		if (!ping_data) {
112662306a36Sopenharmony_ci			pr_err("Unable to allocate memory for"
112762306a36Sopenharmony_ci				" NOPOUT ping data.\n");
112862306a36Sopenharmony_ci			ret = -1;
112962306a36Sopenharmony_ci			goto out;
113062306a36Sopenharmony_ci		}
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci		skb_copy_bits(csk->skb, pdu_cb->doffset,
113362306a36Sopenharmony_ci			      ping_data, payload_length);
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci		ping_data[payload_length] = '\0';
113662306a36Sopenharmony_ci		/*
113762306a36Sopenharmony_ci		 * Attach ping data to struct iscsit_cmd->buf_ptr.
113862306a36Sopenharmony_ci		 */
113962306a36Sopenharmony_ci		cmd->buf_ptr = ping_data;
114062306a36Sopenharmony_ci		cmd->buf_ptr_size = payload_length;
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci		pr_debug("Got %u bytes of NOPOUT ping"
114362306a36Sopenharmony_ci			" data.\n", payload_length);
114462306a36Sopenharmony_ci		pr_debug("Ping Data: \"%s\"\n", ping_data);
114562306a36Sopenharmony_ci	}
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	return iscsit_process_nop_out(conn, cmd, hdr);
114862306a36Sopenharmony_ciout:
114962306a36Sopenharmony_ci	if (cmd)
115062306a36Sopenharmony_ci		iscsit_free_cmd(cmd, false);
115162306a36Sopenharmony_ci	return ret;
115262306a36Sopenharmony_ci}
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_cistatic int
115562306a36Sopenharmony_cicxgbit_handle_text_cmd(struct cxgbit_sock *csk, struct iscsit_cmd *cmd)
115662306a36Sopenharmony_ci{
115762306a36Sopenharmony_ci	struct iscsit_conn *conn = csk->conn;
115862306a36Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
115962306a36Sopenharmony_ci	struct iscsi_text *hdr = (struct iscsi_text *)pdu_cb->hdr;
116062306a36Sopenharmony_ci	u32 payload_length = pdu_cb->dlen;
116162306a36Sopenharmony_ci	int rc;
116262306a36Sopenharmony_ci	unsigned char *text_in = NULL;
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	rc = iscsit_setup_text_cmd(conn, cmd, hdr);
116562306a36Sopenharmony_ci	if (rc < 0)
116662306a36Sopenharmony_ci		return rc;
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	if (pdu_cb->flags & PDUCBF_RX_DCRC_ERR) {
116962306a36Sopenharmony_ci		if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
117062306a36Sopenharmony_ci			pr_err("Unable to recover from"
117162306a36Sopenharmony_ci			       " Text Data digest failure while in"
117262306a36Sopenharmony_ci			       " ERL=0.\n");
117362306a36Sopenharmony_ci			goto reject;
117462306a36Sopenharmony_ci		} else {
117562306a36Sopenharmony_ci			/*
117662306a36Sopenharmony_ci			 * drop this PDU and let the
117762306a36Sopenharmony_ci			 * initiator plug the CmdSN gap.
117862306a36Sopenharmony_ci			 */
117962306a36Sopenharmony_ci			pr_info("Dropping Text"
118062306a36Sopenharmony_ci				" Command CmdSN: 0x%08x due to"
118162306a36Sopenharmony_ci				" DataCRC error.\n", hdr->cmdsn);
118262306a36Sopenharmony_ci			return 0;
118362306a36Sopenharmony_ci		}
118462306a36Sopenharmony_ci	}
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	if (payload_length) {
118762306a36Sopenharmony_ci		text_in = kzalloc(payload_length, GFP_KERNEL);
118862306a36Sopenharmony_ci		if (!text_in) {
118962306a36Sopenharmony_ci			pr_err("Unable to allocate text_in of payload_length: %u\n",
119062306a36Sopenharmony_ci			       payload_length);
119162306a36Sopenharmony_ci			return -ENOMEM;
119262306a36Sopenharmony_ci		}
119362306a36Sopenharmony_ci		skb_copy_bits(csk->skb, pdu_cb->doffset,
119462306a36Sopenharmony_ci			      text_in, payload_length);
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci		text_in[payload_length - 1] = '\0';
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci		cmd->text_in_ptr = text_in;
119962306a36Sopenharmony_ci	}
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	return iscsit_process_text_cmd(conn, cmd, hdr);
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_cireject:
120462306a36Sopenharmony_ci	return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
120562306a36Sopenharmony_ci				 pdu_cb->hdr);
120662306a36Sopenharmony_ci}
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_cistatic int cxgbit_target_rx_opcode(struct cxgbit_sock *csk)
120962306a36Sopenharmony_ci{
121062306a36Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
121162306a36Sopenharmony_ci	struct iscsi_hdr *hdr = (struct iscsi_hdr *)pdu_cb->hdr;
121262306a36Sopenharmony_ci	struct iscsit_conn *conn = csk->conn;
121362306a36Sopenharmony_ci	struct iscsit_cmd *cmd = NULL;
121462306a36Sopenharmony_ci	u8 opcode = (hdr->opcode & ISCSI_OPCODE_MASK);
121562306a36Sopenharmony_ci	int ret = -EINVAL;
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	switch (opcode) {
121862306a36Sopenharmony_ci	case ISCSI_OP_SCSI_CMD:
121962306a36Sopenharmony_ci		cmd = cxgbit_allocate_cmd(csk);
122062306a36Sopenharmony_ci		if (!cmd)
122162306a36Sopenharmony_ci			goto reject;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci		ret = cxgbit_handle_scsi_cmd(csk, cmd);
122462306a36Sopenharmony_ci		break;
122562306a36Sopenharmony_ci	case ISCSI_OP_SCSI_DATA_OUT:
122662306a36Sopenharmony_ci		ret = cxgbit_handle_iscsi_dataout(csk);
122762306a36Sopenharmony_ci		break;
122862306a36Sopenharmony_ci	case ISCSI_OP_NOOP_OUT:
122962306a36Sopenharmony_ci		if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
123062306a36Sopenharmony_ci			cmd = cxgbit_allocate_cmd(csk);
123162306a36Sopenharmony_ci			if (!cmd)
123262306a36Sopenharmony_ci				goto reject;
123362306a36Sopenharmony_ci		}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci		ret = cxgbit_handle_nop_out(csk, cmd);
123662306a36Sopenharmony_ci		break;
123762306a36Sopenharmony_ci	case ISCSI_OP_SCSI_TMFUNC:
123862306a36Sopenharmony_ci		cmd = cxgbit_allocate_cmd(csk);
123962306a36Sopenharmony_ci		if (!cmd)
124062306a36Sopenharmony_ci			goto reject;
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci		ret = iscsit_handle_task_mgt_cmd(conn, cmd,
124362306a36Sopenharmony_ci						 (unsigned char *)hdr);
124462306a36Sopenharmony_ci		break;
124562306a36Sopenharmony_ci	case ISCSI_OP_TEXT:
124662306a36Sopenharmony_ci		if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) {
124762306a36Sopenharmony_ci			cmd = iscsit_find_cmd_from_itt(conn, hdr->itt);
124862306a36Sopenharmony_ci			if (!cmd)
124962306a36Sopenharmony_ci				goto reject;
125062306a36Sopenharmony_ci		} else {
125162306a36Sopenharmony_ci			cmd = cxgbit_allocate_cmd(csk);
125262306a36Sopenharmony_ci			if (!cmd)
125362306a36Sopenharmony_ci				goto reject;
125462306a36Sopenharmony_ci		}
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci		ret = cxgbit_handle_text_cmd(csk, cmd);
125762306a36Sopenharmony_ci		break;
125862306a36Sopenharmony_ci	case ISCSI_OP_LOGOUT:
125962306a36Sopenharmony_ci		cmd = cxgbit_allocate_cmd(csk);
126062306a36Sopenharmony_ci		if (!cmd)
126162306a36Sopenharmony_ci			goto reject;
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci		ret = iscsit_handle_logout_cmd(conn, cmd, (unsigned char *)hdr);
126462306a36Sopenharmony_ci		if (ret > 0)
126562306a36Sopenharmony_ci			wait_for_completion_timeout(&conn->conn_logout_comp,
126662306a36Sopenharmony_ci						    SECONDS_FOR_LOGOUT_COMP
126762306a36Sopenharmony_ci						    * HZ);
126862306a36Sopenharmony_ci		break;
126962306a36Sopenharmony_ci	case ISCSI_OP_SNACK:
127062306a36Sopenharmony_ci		ret = iscsit_handle_snack(conn, (unsigned char *)hdr);
127162306a36Sopenharmony_ci		break;
127262306a36Sopenharmony_ci	default:
127362306a36Sopenharmony_ci		pr_err("Got unknown iSCSI OpCode: 0x%02x\n", opcode);
127462306a36Sopenharmony_ci		dump_stack();
127562306a36Sopenharmony_ci		break;
127662306a36Sopenharmony_ci	}
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	return ret;
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_cireject:
128162306a36Sopenharmony_ci	return iscsit_add_reject(conn, ISCSI_REASON_BOOKMARK_NO_RESOURCES,
128262306a36Sopenharmony_ci				 (unsigned char *)hdr);
128362306a36Sopenharmony_ci	return ret;
128462306a36Sopenharmony_ci}
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_cistatic int cxgbit_rx_opcode(struct cxgbit_sock *csk)
128762306a36Sopenharmony_ci{
128862306a36Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
128962306a36Sopenharmony_ci	struct iscsit_conn *conn = csk->conn;
129062306a36Sopenharmony_ci	struct iscsi_hdr *hdr = pdu_cb->hdr;
129162306a36Sopenharmony_ci	u8 opcode;
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	if (pdu_cb->flags & PDUCBF_RX_HCRC_ERR) {
129462306a36Sopenharmony_ci		atomic_long_inc(&conn->sess->conn_digest_errors);
129562306a36Sopenharmony_ci		goto transport_err;
129662306a36Sopenharmony_ci	}
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT)
129962306a36Sopenharmony_ci		goto transport_err;
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	opcode = hdr->opcode & ISCSI_OPCODE_MASK;
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	if (conn->sess->sess_ops->SessionType &&
130462306a36Sopenharmony_ci	    ((!(opcode & ISCSI_OP_TEXT)) ||
130562306a36Sopenharmony_ci	     (!(opcode & ISCSI_OP_LOGOUT)))) {
130662306a36Sopenharmony_ci		pr_err("Received illegal iSCSI Opcode: 0x%02x"
130762306a36Sopenharmony_ci			" while in Discovery Session, rejecting.\n", opcode);
130862306a36Sopenharmony_ci		iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
130962306a36Sopenharmony_ci				  (unsigned char *)hdr);
131062306a36Sopenharmony_ci		goto transport_err;
131162306a36Sopenharmony_ci	}
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	if (cxgbit_target_rx_opcode(csk) < 0)
131462306a36Sopenharmony_ci		goto transport_err;
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	return 0;
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_citransport_err:
131962306a36Sopenharmony_ci	return -1;
132062306a36Sopenharmony_ci}
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_cistatic int cxgbit_rx_login_pdu(struct cxgbit_sock *csk)
132362306a36Sopenharmony_ci{
132462306a36Sopenharmony_ci	struct iscsit_conn *conn = csk->conn;
132562306a36Sopenharmony_ci	struct iscsi_login *login = conn->login;
132662306a36Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
132762306a36Sopenharmony_ci	struct iscsi_login_req *login_req;
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	login_req = (struct iscsi_login_req *)login->req;
133062306a36Sopenharmony_ci	memcpy(login_req, pdu_cb->hdr, sizeof(*login_req));
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x,"
133362306a36Sopenharmony_ci		" CmdSN: 0x%08x, ExpStatSN: 0x%08x, CID: %hu, Length: %u\n",
133462306a36Sopenharmony_ci		login_req->flags, login_req->itt, login_req->cmdsn,
133562306a36Sopenharmony_ci		login_req->exp_statsn, login_req->cid, pdu_cb->dlen);
133662306a36Sopenharmony_ci	/*
133762306a36Sopenharmony_ci	 * Setup the initial iscsi_login values from the leading
133862306a36Sopenharmony_ci	 * login request PDU.
133962306a36Sopenharmony_ci	 */
134062306a36Sopenharmony_ci	if (login->first_request) {
134162306a36Sopenharmony_ci		login_req = (struct iscsi_login_req *)login->req;
134262306a36Sopenharmony_ci		login->leading_connection = (!login_req->tsih) ? 1 : 0;
134362306a36Sopenharmony_ci		login->current_stage	= ISCSI_LOGIN_CURRENT_STAGE(
134462306a36Sopenharmony_ci				login_req->flags);
134562306a36Sopenharmony_ci		login->version_min	= login_req->min_version;
134662306a36Sopenharmony_ci		login->version_max	= login_req->max_version;
134762306a36Sopenharmony_ci		memcpy(login->isid, login_req->isid, 6);
134862306a36Sopenharmony_ci		login->cmd_sn		= be32_to_cpu(login_req->cmdsn);
134962306a36Sopenharmony_ci		login->init_task_tag	= login_req->itt;
135062306a36Sopenharmony_ci		login->initial_exp_statsn = be32_to_cpu(login_req->exp_statsn);
135162306a36Sopenharmony_ci		login->cid		= be16_to_cpu(login_req->cid);
135262306a36Sopenharmony_ci		login->tsih		= be16_to_cpu(login_req->tsih);
135362306a36Sopenharmony_ci	}
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	if (iscsi_target_check_login_request(conn, login) < 0)
135662306a36Sopenharmony_ci		return -1;
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	memset(login->req_buf, 0, MAX_KEY_VALUE_PAIRS);
135962306a36Sopenharmony_ci	skb_copy_bits(csk->skb, pdu_cb->doffset, login->req_buf, pdu_cb->dlen);
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	return 0;
136262306a36Sopenharmony_ci}
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_cistatic int
136562306a36Sopenharmony_cicxgbit_process_iscsi_pdu(struct cxgbit_sock *csk, struct sk_buff *skb, int idx)
136662306a36Sopenharmony_ci{
136762306a36Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, idx);
136862306a36Sopenharmony_ci	int ret;
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	cxgbit_rx_pdu_cb(skb) = pdu_cb;
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	csk->skb = skb;
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	if (!test_bit(CSK_LOGIN_DONE, &csk->com.flags)) {
137562306a36Sopenharmony_ci		ret = cxgbit_rx_login_pdu(csk);
137662306a36Sopenharmony_ci		set_bit(CSK_LOGIN_PDU_DONE, &csk->com.flags);
137762306a36Sopenharmony_ci	} else {
137862306a36Sopenharmony_ci		ret = cxgbit_rx_opcode(csk);
137962306a36Sopenharmony_ci	}
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	return ret;
138262306a36Sopenharmony_ci}
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_cistatic void cxgbit_lro_skb_dump(struct sk_buff *skb)
138562306a36Sopenharmony_ci{
138662306a36Sopenharmony_ci	struct skb_shared_info *ssi = skb_shinfo(skb);
138762306a36Sopenharmony_ci	struct cxgbit_lro_cb *lro_cb = cxgbit_skb_lro_cb(skb);
138862306a36Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, 0);
138962306a36Sopenharmony_ci	u8 i;
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	pr_info("skb 0x%p, head 0x%p, 0x%p, len %u,%u, frags %u.\n",
139262306a36Sopenharmony_ci		skb, skb->head, skb->data, skb->len, skb->data_len,
139362306a36Sopenharmony_ci		ssi->nr_frags);
139462306a36Sopenharmony_ci	pr_info("skb 0x%p, lro_cb, csk 0x%p, pdu %u, %u.\n",
139562306a36Sopenharmony_ci		skb, lro_cb->csk, lro_cb->pdu_idx, lro_cb->pdu_totallen);
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	for (i = 0; i < lro_cb->pdu_idx; i++, pdu_cb++)
139862306a36Sopenharmony_ci		pr_info("skb 0x%p, pdu %d, %u, f 0x%x, seq 0x%x, dcrc 0x%x, "
139962306a36Sopenharmony_ci			"frags %u.\n",
140062306a36Sopenharmony_ci			skb, i, pdu_cb->pdulen, pdu_cb->flags, pdu_cb->seq,
140162306a36Sopenharmony_ci			pdu_cb->ddigest, pdu_cb->frags);
140262306a36Sopenharmony_ci	for (i = 0; i < ssi->nr_frags; i++)
140362306a36Sopenharmony_ci		pr_info("skb 0x%p, frag %d, off %u, sz %u.\n",
140462306a36Sopenharmony_ci			skb, i, skb_frag_off(&ssi->frags[i]),
140562306a36Sopenharmony_ci			skb_frag_size(&ssi->frags[i]));
140662306a36Sopenharmony_ci}
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_cistatic void cxgbit_lro_hskb_reset(struct cxgbit_sock *csk)
140962306a36Sopenharmony_ci{
141062306a36Sopenharmony_ci	struct sk_buff *skb = csk->lro_hskb;
141162306a36Sopenharmony_ci	struct skb_shared_info *ssi = skb_shinfo(skb);
141262306a36Sopenharmony_ci	u8 i;
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	memset(skb->data, 0, LRO_SKB_MIN_HEADROOM);
141562306a36Sopenharmony_ci	for (i = 0; i < ssi->nr_frags; i++)
141662306a36Sopenharmony_ci		put_page(skb_frag_page(&ssi->frags[i]));
141762306a36Sopenharmony_ci	ssi->nr_frags = 0;
141862306a36Sopenharmony_ci	skb->data_len = 0;
141962306a36Sopenharmony_ci	skb->truesize -= skb->len;
142062306a36Sopenharmony_ci	skb->len = 0;
142162306a36Sopenharmony_ci}
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_cistatic void
142462306a36Sopenharmony_cicxgbit_lro_skb_merge(struct cxgbit_sock *csk, struct sk_buff *skb, u8 pdu_idx)
142562306a36Sopenharmony_ci{
142662306a36Sopenharmony_ci	struct sk_buff *hskb = csk->lro_hskb;
142762306a36Sopenharmony_ci	struct cxgbit_lro_pdu_cb *hpdu_cb = cxgbit_skb_lro_pdu_cb(hskb, 0);
142862306a36Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, pdu_idx);
142962306a36Sopenharmony_ci	struct skb_shared_info *hssi = skb_shinfo(hskb);
143062306a36Sopenharmony_ci	struct skb_shared_info *ssi = skb_shinfo(skb);
143162306a36Sopenharmony_ci	unsigned int len = 0;
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci	if (pdu_cb->flags & PDUCBF_RX_HDR) {
143462306a36Sopenharmony_ci		u8 hfrag_idx = hssi->nr_frags;
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci		hpdu_cb->flags |= pdu_cb->flags;
143762306a36Sopenharmony_ci		hpdu_cb->seq = pdu_cb->seq;
143862306a36Sopenharmony_ci		hpdu_cb->hdr = pdu_cb->hdr;
143962306a36Sopenharmony_ci		hpdu_cb->hlen = pdu_cb->hlen;
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci		memcpy(&hssi->frags[hfrag_idx], &ssi->frags[pdu_cb->hfrag_idx],
144262306a36Sopenharmony_ci		       sizeof(skb_frag_t));
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci		get_page(skb_frag_page(&hssi->frags[hfrag_idx]));
144562306a36Sopenharmony_ci		hssi->nr_frags++;
144662306a36Sopenharmony_ci		hpdu_cb->frags++;
144762306a36Sopenharmony_ci		hpdu_cb->hfrag_idx = hfrag_idx;
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci		len = skb_frag_size(&hssi->frags[hfrag_idx]);
145062306a36Sopenharmony_ci		hskb->len += len;
145162306a36Sopenharmony_ci		hskb->data_len += len;
145262306a36Sopenharmony_ci		hskb->truesize += len;
145362306a36Sopenharmony_ci	}
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	if (pdu_cb->flags & PDUCBF_RX_DATA) {
145662306a36Sopenharmony_ci		u8 dfrag_idx = hssi->nr_frags, i;
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci		hpdu_cb->flags |= pdu_cb->flags;
145962306a36Sopenharmony_ci		hpdu_cb->dfrag_idx = dfrag_idx;
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci		len = 0;
146262306a36Sopenharmony_ci		for (i = 0; i < pdu_cb->nr_dfrags; dfrag_idx++, i++) {
146362306a36Sopenharmony_ci			memcpy(&hssi->frags[dfrag_idx],
146462306a36Sopenharmony_ci			       &ssi->frags[pdu_cb->dfrag_idx + i],
146562306a36Sopenharmony_ci			       sizeof(skb_frag_t));
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci			get_page(skb_frag_page(&hssi->frags[dfrag_idx]));
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci			len += skb_frag_size(&hssi->frags[dfrag_idx]);
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci			hssi->nr_frags++;
147262306a36Sopenharmony_ci			hpdu_cb->frags++;
147362306a36Sopenharmony_ci		}
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci		hpdu_cb->dlen = pdu_cb->dlen;
147662306a36Sopenharmony_ci		hpdu_cb->doffset = hpdu_cb->hlen;
147762306a36Sopenharmony_ci		hpdu_cb->nr_dfrags = pdu_cb->nr_dfrags;
147862306a36Sopenharmony_ci		hskb->len += len;
147962306a36Sopenharmony_ci		hskb->data_len += len;
148062306a36Sopenharmony_ci		hskb->truesize += len;
148162306a36Sopenharmony_ci	}
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	if (pdu_cb->flags & PDUCBF_RX_STATUS) {
148462306a36Sopenharmony_ci		hpdu_cb->flags |= pdu_cb->flags;
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci		if (hpdu_cb->flags & PDUCBF_RX_DATA)
148762306a36Sopenharmony_ci			hpdu_cb->flags &= ~PDUCBF_RX_DATA_DDPD;
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci		hpdu_cb->ddigest = pdu_cb->ddigest;
149062306a36Sopenharmony_ci		hpdu_cb->pdulen = pdu_cb->pdulen;
149162306a36Sopenharmony_ci	}
149262306a36Sopenharmony_ci}
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_cistatic int cxgbit_process_lro_skb(struct cxgbit_sock *csk, struct sk_buff *skb)
149562306a36Sopenharmony_ci{
149662306a36Sopenharmony_ci	struct cxgbit_lro_cb *lro_cb = cxgbit_skb_lro_cb(skb);
149762306a36Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, 0);
149862306a36Sopenharmony_ci	u8 pdu_idx = 0, last_idx = 0;
149962306a36Sopenharmony_ci	int ret = 0;
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci	if (!pdu_cb->complete) {
150262306a36Sopenharmony_ci		cxgbit_lro_skb_merge(csk, skb, 0);
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci		if (pdu_cb->flags & PDUCBF_RX_STATUS) {
150562306a36Sopenharmony_ci			struct sk_buff *hskb = csk->lro_hskb;
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci			ret = cxgbit_process_iscsi_pdu(csk, hskb, 0);
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci			cxgbit_lro_hskb_reset(csk);
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci			if (ret < 0)
151262306a36Sopenharmony_ci				goto out;
151362306a36Sopenharmony_ci		}
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci		pdu_idx = 1;
151662306a36Sopenharmony_ci	}
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	if (lro_cb->pdu_idx)
151962306a36Sopenharmony_ci		last_idx = lro_cb->pdu_idx - 1;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	for (; pdu_idx <= last_idx; pdu_idx++) {
152262306a36Sopenharmony_ci		ret = cxgbit_process_iscsi_pdu(csk, skb, pdu_idx);
152362306a36Sopenharmony_ci		if (ret < 0)
152462306a36Sopenharmony_ci			goto out;
152562306a36Sopenharmony_ci	}
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci	if ((!lro_cb->complete) && lro_cb->pdu_idx)
152862306a36Sopenharmony_ci		cxgbit_lro_skb_merge(csk, skb, lro_cb->pdu_idx);
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ciout:
153162306a36Sopenharmony_ci	return ret;
153262306a36Sopenharmony_ci}
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_cistatic int cxgbit_t5_rx_lro_skb(struct cxgbit_sock *csk, struct sk_buff *skb)
153562306a36Sopenharmony_ci{
153662306a36Sopenharmony_ci	struct cxgbit_lro_cb *lro_cb = cxgbit_skb_lro_cb(skb);
153762306a36Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, 0);
153862306a36Sopenharmony_ci	int ret = -1;
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci	if ((pdu_cb->flags & PDUCBF_RX_HDR) &&
154162306a36Sopenharmony_ci	    (pdu_cb->seq != csk->rcv_nxt)) {
154262306a36Sopenharmony_ci		pr_info("csk 0x%p, tid 0x%x, seq 0x%x != 0x%x.\n",
154362306a36Sopenharmony_ci			csk, csk->tid, pdu_cb->seq, csk->rcv_nxt);
154462306a36Sopenharmony_ci		cxgbit_lro_skb_dump(skb);
154562306a36Sopenharmony_ci		return ret;
154662306a36Sopenharmony_ci	}
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	csk->rcv_nxt += lro_cb->pdu_totallen;
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	ret = cxgbit_process_lro_skb(csk, skb);
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	csk->rx_credits += lro_cb->pdu_totallen;
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	if (csk->rx_credits >= (csk->rcv_win / 4))
155562306a36Sopenharmony_ci		cxgbit_rx_data_ack(csk);
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	return ret;
155862306a36Sopenharmony_ci}
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_cistatic int cxgbit_rx_lro_skb(struct cxgbit_sock *csk, struct sk_buff *skb)
156162306a36Sopenharmony_ci{
156262306a36Sopenharmony_ci	struct cxgbit_lro_cb *lro_cb = cxgbit_skb_lro_cb(skb);
156362306a36Sopenharmony_ci	int ret;
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	ret = cxgbit_process_lro_skb(csk, skb);
156662306a36Sopenharmony_ci	if (ret)
156762306a36Sopenharmony_ci		return ret;
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci	csk->rx_credits += lro_cb->pdu_totallen;
157062306a36Sopenharmony_ci	if (csk->rx_credits >= csk->rcv_win) {
157162306a36Sopenharmony_ci		csk->rx_credits = 0;
157262306a36Sopenharmony_ci		cxgbit_rx_data_ack(csk);
157362306a36Sopenharmony_ci	}
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	return 0;
157662306a36Sopenharmony_ci}
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_cistatic int cxgbit_rx_skb(struct cxgbit_sock *csk, struct sk_buff *skb)
157962306a36Sopenharmony_ci{
158062306a36Sopenharmony_ci	struct cxgb4_lld_info *lldi = &csk->com.cdev->lldi;
158162306a36Sopenharmony_ci	int ret = -1;
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci	if (likely(cxgbit_skcb_flags(skb) & SKCBF_RX_LRO)) {
158462306a36Sopenharmony_ci		if (is_t5(lldi->adapter_type))
158562306a36Sopenharmony_ci			ret = cxgbit_t5_rx_lro_skb(csk, skb);
158662306a36Sopenharmony_ci		else
158762306a36Sopenharmony_ci			ret = cxgbit_rx_lro_skb(csk, skb);
158862306a36Sopenharmony_ci	}
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	__kfree_skb(skb);
159162306a36Sopenharmony_ci	return ret;
159262306a36Sopenharmony_ci}
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_cistatic bool cxgbit_rxq_len(struct cxgbit_sock *csk, struct sk_buff_head *rxq)
159562306a36Sopenharmony_ci{
159662306a36Sopenharmony_ci	spin_lock_bh(&csk->rxq.lock);
159762306a36Sopenharmony_ci	if (skb_queue_len(&csk->rxq)) {
159862306a36Sopenharmony_ci		skb_queue_splice_init(&csk->rxq, rxq);
159962306a36Sopenharmony_ci		spin_unlock_bh(&csk->rxq.lock);
160062306a36Sopenharmony_ci		return true;
160162306a36Sopenharmony_ci	}
160262306a36Sopenharmony_ci	spin_unlock_bh(&csk->rxq.lock);
160362306a36Sopenharmony_ci	return false;
160462306a36Sopenharmony_ci}
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_cistatic int cxgbit_wait_rxq(struct cxgbit_sock *csk)
160762306a36Sopenharmony_ci{
160862306a36Sopenharmony_ci	struct sk_buff *skb;
160962306a36Sopenharmony_ci	struct sk_buff_head rxq;
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	skb_queue_head_init(&rxq);
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	wait_event_interruptible(csk->waitq, cxgbit_rxq_len(csk, &rxq));
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci	if (signal_pending(current))
161662306a36Sopenharmony_ci		goto out;
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci	while ((skb = __skb_dequeue(&rxq))) {
161962306a36Sopenharmony_ci		if (cxgbit_rx_skb(csk, skb))
162062306a36Sopenharmony_ci			goto out;
162162306a36Sopenharmony_ci	}
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	return 0;
162462306a36Sopenharmony_ciout:
162562306a36Sopenharmony_ci	__skb_queue_purge(&rxq);
162662306a36Sopenharmony_ci	return -1;
162762306a36Sopenharmony_ci}
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ciint cxgbit_get_login_rx(struct iscsit_conn *conn, struct iscsi_login *login)
163062306a36Sopenharmony_ci{
163162306a36Sopenharmony_ci	struct cxgbit_sock *csk = conn->context;
163262306a36Sopenharmony_ci	int ret = -1;
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	while (!test_and_clear_bit(CSK_LOGIN_PDU_DONE, &csk->com.flags)) {
163562306a36Sopenharmony_ci		ret = cxgbit_wait_rxq(csk);
163662306a36Sopenharmony_ci		if (ret) {
163762306a36Sopenharmony_ci			clear_bit(CSK_LOGIN_PDU_DONE, &csk->com.flags);
163862306a36Sopenharmony_ci			break;
163962306a36Sopenharmony_ci		}
164062306a36Sopenharmony_ci	}
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	return ret;
164362306a36Sopenharmony_ci}
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_civoid cxgbit_get_rx_pdu(struct iscsit_conn *conn)
164662306a36Sopenharmony_ci{
164762306a36Sopenharmony_ci	struct cxgbit_sock *csk = conn->context;
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci	while (!kthread_should_stop()) {
165062306a36Sopenharmony_ci		iscsit_thread_check_cpumask(conn, current, 0);
165162306a36Sopenharmony_ci		if (cxgbit_wait_rxq(csk))
165262306a36Sopenharmony_ci			return;
165362306a36Sopenharmony_ci	}
165462306a36Sopenharmony_ci}
1655