18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2016 Chelsio Communications, Inc.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
78c2ecf20Sopenharmony_ci#include <linux/kthread.h>
88c2ecf20Sopenharmony_ci#include <linux/sched/signal.h>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <asm/unaligned.h>
118c2ecf20Sopenharmony_ci#include <net/tcp.h>
128c2ecf20Sopenharmony_ci#include <target/target_core_base.h>
138c2ecf20Sopenharmony_ci#include <target/target_core_fabric.h>
148c2ecf20Sopenharmony_ci#include "cxgbit.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cistruct sge_opaque_hdr {
178c2ecf20Sopenharmony_ci	void *dev;
188c2ecf20Sopenharmony_ci	dma_addr_t addr[MAX_SKB_FRAGS + 1];
198c2ecf20Sopenharmony_ci};
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic const u8 cxgbit_digest_len[] = {0, 4, 4, 8};
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define TX_HDR_LEN (sizeof(struct sge_opaque_hdr) + \
248c2ecf20Sopenharmony_ci		    sizeof(struct fw_ofld_tx_data_wr))
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic struct sk_buff *
278c2ecf20Sopenharmony_ci__cxgbit_alloc_skb(struct cxgbit_sock *csk, u32 len, bool iso)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	struct sk_buff *skb = NULL;
308c2ecf20Sopenharmony_ci	u8 submode = 0;
318c2ecf20Sopenharmony_ci	int errcode;
328c2ecf20Sopenharmony_ci	static const u32 hdr_len = TX_HDR_LEN + ISCSI_HDR_LEN;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	if (len) {
358c2ecf20Sopenharmony_ci		skb = alloc_skb_with_frags(hdr_len, len,
368c2ecf20Sopenharmony_ci					   0, &errcode,
378c2ecf20Sopenharmony_ci					   GFP_KERNEL);
388c2ecf20Sopenharmony_ci		if (!skb)
398c2ecf20Sopenharmony_ci			return NULL;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci		skb_reserve(skb, TX_HDR_LEN);
428c2ecf20Sopenharmony_ci		skb_reset_transport_header(skb);
438c2ecf20Sopenharmony_ci		__skb_put(skb, ISCSI_HDR_LEN);
448c2ecf20Sopenharmony_ci		skb->data_len = len;
458c2ecf20Sopenharmony_ci		skb->len += len;
468c2ecf20Sopenharmony_ci		submode |= (csk->submode & CXGBIT_SUBMODE_DCRC);
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	} else {
498c2ecf20Sopenharmony_ci		u32 iso_len = iso ? sizeof(struct cpl_tx_data_iso) : 0;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci		skb = alloc_skb(hdr_len + iso_len, GFP_KERNEL);
528c2ecf20Sopenharmony_ci		if (!skb)
538c2ecf20Sopenharmony_ci			return NULL;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci		skb_reserve(skb, TX_HDR_LEN + iso_len);
568c2ecf20Sopenharmony_ci		skb_reset_transport_header(skb);
578c2ecf20Sopenharmony_ci		__skb_put(skb, ISCSI_HDR_LEN);
588c2ecf20Sopenharmony_ci	}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	submode |= (csk->submode & CXGBIT_SUBMODE_HCRC);
618c2ecf20Sopenharmony_ci	cxgbit_skcb_submode(skb) = submode;
628c2ecf20Sopenharmony_ci	cxgbit_skcb_tx_extralen(skb) = cxgbit_digest_len[submode];
638c2ecf20Sopenharmony_ci	cxgbit_skcb_flags(skb) |= SKCBF_TX_NEED_HDR;
648c2ecf20Sopenharmony_ci	return skb;
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic struct sk_buff *cxgbit_alloc_skb(struct cxgbit_sock *csk, u32 len)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	return __cxgbit_alloc_skb(csk, len, false);
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci/*
738c2ecf20Sopenharmony_ci * cxgbit_is_ofld_imm - check whether a packet can be sent as immediate data
748c2ecf20Sopenharmony_ci * @skb: the packet
758c2ecf20Sopenharmony_ci *
768c2ecf20Sopenharmony_ci * Returns true if a packet can be sent as an offload WR with immediate
778c2ecf20Sopenharmony_ci * data.  We currently use the same limit as for Ethernet packets.
788c2ecf20Sopenharmony_ci */
798c2ecf20Sopenharmony_cistatic int cxgbit_is_ofld_imm(const struct sk_buff *skb)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	int length = skb->len;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	if (likely(cxgbit_skcb_flags(skb) & SKCBF_TX_NEED_HDR))
848c2ecf20Sopenharmony_ci		length += sizeof(struct fw_ofld_tx_data_wr);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	if (likely(cxgbit_skcb_flags(skb) & SKCBF_TX_ISO))
878c2ecf20Sopenharmony_ci		length += sizeof(struct cpl_tx_data_iso);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	return length <= MAX_IMM_OFLD_TX_DATA_WR_LEN;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci/*
938c2ecf20Sopenharmony_ci * cxgbit_sgl_len - calculates the size of an SGL of the given capacity
948c2ecf20Sopenharmony_ci * @n: the number of SGL entries
958c2ecf20Sopenharmony_ci * Calculates the number of flits needed for a scatter/gather list that
968c2ecf20Sopenharmony_ci * can hold the given number of entries.
978c2ecf20Sopenharmony_ci */
988c2ecf20Sopenharmony_cistatic inline unsigned int cxgbit_sgl_len(unsigned int n)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	n--;
1018c2ecf20Sopenharmony_ci	return (3 * n) / 2 + (n & 1) + 2;
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci/*
1058c2ecf20Sopenharmony_ci * cxgbit_calc_tx_flits_ofld - calculate # of flits for an offload packet
1068c2ecf20Sopenharmony_ci * @skb: the packet
1078c2ecf20Sopenharmony_ci *
1088c2ecf20Sopenharmony_ci * Returns the number of flits needed for the given offload packet.
1098c2ecf20Sopenharmony_ci * These packets are already fully constructed and no additional headers
1108c2ecf20Sopenharmony_ci * will be added.
1118c2ecf20Sopenharmony_ci */
1128c2ecf20Sopenharmony_cistatic unsigned int cxgbit_calc_tx_flits_ofld(const struct sk_buff *skb)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	unsigned int flits, cnt;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	if (cxgbit_is_ofld_imm(skb))
1178c2ecf20Sopenharmony_ci		return DIV_ROUND_UP(skb->len, 8);
1188c2ecf20Sopenharmony_ci	flits = skb_transport_offset(skb) / 8;
1198c2ecf20Sopenharmony_ci	cnt = skb_shinfo(skb)->nr_frags;
1208c2ecf20Sopenharmony_ci	if (skb_tail_pointer(skb) != skb_transport_header(skb))
1218c2ecf20Sopenharmony_ci		cnt++;
1228c2ecf20Sopenharmony_ci	return flits + cxgbit_sgl_len(cnt);
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci#define CXGBIT_ISO_FSLICE 0x1
1268c2ecf20Sopenharmony_ci#define CXGBIT_ISO_LSLICE 0x2
1278c2ecf20Sopenharmony_cistatic void
1288c2ecf20Sopenharmony_cicxgbit_cpl_tx_data_iso(struct sk_buff *skb, struct cxgbit_iso_info *iso_info)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	struct cpl_tx_data_iso *cpl;
1318c2ecf20Sopenharmony_ci	unsigned int submode = cxgbit_skcb_submode(skb);
1328c2ecf20Sopenharmony_ci	unsigned int fslice = !!(iso_info->flags & CXGBIT_ISO_FSLICE);
1338c2ecf20Sopenharmony_ci	unsigned int lslice = !!(iso_info->flags & CXGBIT_ISO_LSLICE);
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	cpl = __skb_push(skb, sizeof(*cpl));
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	cpl->op_to_scsi = htonl(CPL_TX_DATA_ISO_OP_V(CPL_TX_DATA_ISO) |
1388c2ecf20Sopenharmony_ci			CPL_TX_DATA_ISO_FIRST_V(fslice) |
1398c2ecf20Sopenharmony_ci			CPL_TX_DATA_ISO_LAST_V(lslice) |
1408c2ecf20Sopenharmony_ci			CPL_TX_DATA_ISO_CPLHDRLEN_V(0) |
1418c2ecf20Sopenharmony_ci			CPL_TX_DATA_ISO_HDRCRC_V(submode & 1) |
1428c2ecf20Sopenharmony_ci			CPL_TX_DATA_ISO_PLDCRC_V(((submode >> 1) & 1)) |
1438c2ecf20Sopenharmony_ci			CPL_TX_DATA_ISO_IMMEDIATE_V(0) |
1448c2ecf20Sopenharmony_ci			CPL_TX_DATA_ISO_SCSI_V(2));
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	cpl->ahs_len = 0;
1478c2ecf20Sopenharmony_ci	cpl->mpdu = htons(DIV_ROUND_UP(iso_info->mpdu, 4));
1488c2ecf20Sopenharmony_ci	cpl->burst_size = htonl(DIV_ROUND_UP(iso_info->burst_len, 4));
1498c2ecf20Sopenharmony_ci	cpl->len = htonl(iso_info->len);
1508c2ecf20Sopenharmony_ci	cpl->reserved2_seglen_offset = htonl(0);
1518c2ecf20Sopenharmony_ci	cpl->datasn_offset = htonl(0);
1528c2ecf20Sopenharmony_ci	cpl->buffer_offset = htonl(0);
1538c2ecf20Sopenharmony_ci	cpl->reserved3 = 0;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	__skb_pull(skb, sizeof(*cpl));
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistatic void
1598c2ecf20Sopenharmony_cicxgbit_tx_data_wr(struct cxgbit_sock *csk, struct sk_buff *skb, u32 dlen,
1608c2ecf20Sopenharmony_ci		  u32 len, u32 credits, u32 compl)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	struct fw_ofld_tx_data_wr *req;
1638c2ecf20Sopenharmony_ci	const struct cxgb4_lld_info *lldi = &csk->com.cdev->lldi;
1648c2ecf20Sopenharmony_ci	u32 submode = cxgbit_skcb_submode(skb);
1658c2ecf20Sopenharmony_ci	u32 wr_ulp_mode = 0;
1668c2ecf20Sopenharmony_ci	u32 hdr_size = sizeof(*req);
1678c2ecf20Sopenharmony_ci	u32 opcode = FW_OFLD_TX_DATA_WR;
1688c2ecf20Sopenharmony_ci	u32 immlen = 0;
1698c2ecf20Sopenharmony_ci	u32 force = is_t5(lldi->adapter_type) ? TX_FORCE_V(!submode) :
1708c2ecf20Sopenharmony_ci		    T6_TX_FORCE_F;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	if (cxgbit_skcb_flags(skb) & SKCBF_TX_ISO) {
1738c2ecf20Sopenharmony_ci		opcode = FW_ISCSI_TX_DATA_WR;
1748c2ecf20Sopenharmony_ci		immlen += sizeof(struct cpl_tx_data_iso);
1758c2ecf20Sopenharmony_ci		hdr_size += sizeof(struct cpl_tx_data_iso);
1768c2ecf20Sopenharmony_ci		submode |= 8;
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	if (cxgbit_is_ofld_imm(skb))
1808c2ecf20Sopenharmony_ci		immlen += dlen;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	req = __skb_push(skb, hdr_size);
1838c2ecf20Sopenharmony_ci	req->op_to_immdlen = cpu_to_be32(FW_WR_OP_V(opcode) |
1848c2ecf20Sopenharmony_ci					FW_WR_COMPL_V(compl) |
1858c2ecf20Sopenharmony_ci					FW_WR_IMMDLEN_V(immlen));
1868c2ecf20Sopenharmony_ci	req->flowid_len16 = cpu_to_be32(FW_WR_FLOWID_V(csk->tid) |
1878c2ecf20Sopenharmony_ci					FW_WR_LEN16_V(credits));
1888c2ecf20Sopenharmony_ci	req->plen = htonl(len);
1898c2ecf20Sopenharmony_ci	wr_ulp_mode = FW_OFLD_TX_DATA_WR_ULPMODE_V(ULP_MODE_ISCSI) |
1908c2ecf20Sopenharmony_ci				FW_OFLD_TX_DATA_WR_ULPSUBMODE_V(submode);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	req->tunnel_to_proxy = htonl((wr_ulp_mode) | force |
1938c2ecf20Sopenharmony_ci		 FW_OFLD_TX_DATA_WR_SHOVE_V(skb_peek(&csk->txq) ? 0 : 1));
1948c2ecf20Sopenharmony_ci}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_cistatic void cxgbit_arp_failure_skb_discard(void *handle, struct sk_buff *skb)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	kfree_skb(skb);
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_civoid cxgbit_push_tx_frames(struct cxgbit_sock *csk)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	struct sk_buff *skb;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	while (csk->wr_cred && ((skb = skb_peek(&csk->txq)) != NULL)) {
2068c2ecf20Sopenharmony_ci		u32 dlen = skb->len;
2078c2ecf20Sopenharmony_ci		u32 len = skb->len;
2088c2ecf20Sopenharmony_ci		u32 credits_needed;
2098c2ecf20Sopenharmony_ci		u32 compl = 0;
2108c2ecf20Sopenharmony_ci		u32 flowclen16 = 0;
2118c2ecf20Sopenharmony_ci		u32 iso_cpl_len = 0;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci		if (cxgbit_skcb_flags(skb) & SKCBF_TX_ISO)
2148c2ecf20Sopenharmony_ci			iso_cpl_len = sizeof(struct cpl_tx_data_iso);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci		if (cxgbit_is_ofld_imm(skb))
2178c2ecf20Sopenharmony_ci			credits_needed = DIV_ROUND_UP(dlen + iso_cpl_len, 16);
2188c2ecf20Sopenharmony_ci		else
2198c2ecf20Sopenharmony_ci			credits_needed = DIV_ROUND_UP((8 *
2208c2ecf20Sopenharmony_ci					cxgbit_calc_tx_flits_ofld(skb)) +
2218c2ecf20Sopenharmony_ci					iso_cpl_len, 16);
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci		if (likely(cxgbit_skcb_flags(skb) & SKCBF_TX_NEED_HDR))
2248c2ecf20Sopenharmony_ci			credits_needed += DIV_ROUND_UP(
2258c2ecf20Sopenharmony_ci				sizeof(struct fw_ofld_tx_data_wr), 16);
2268c2ecf20Sopenharmony_ci		/*
2278c2ecf20Sopenharmony_ci		 * Assumes the initial credits is large enough to support
2288c2ecf20Sopenharmony_ci		 * fw_flowc_wr plus largest possible first payload
2298c2ecf20Sopenharmony_ci		 */
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci		if (!test_and_set_bit(CSK_TX_DATA_SENT, &csk->com.flags)) {
2328c2ecf20Sopenharmony_ci			flowclen16 = cxgbit_send_tx_flowc_wr(csk);
2338c2ecf20Sopenharmony_ci			csk->wr_cred -= flowclen16;
2348c2ecf20Sopenharmony_ci			csk->wr_una_cred += flowclen16;
2358c2ecf20Sopenharmony_ci		}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci		if (csk->wr_cred < credits_needed) {
2388c2ecf20Sopenharmony_ci			pr_debug("csk 0x%p, skb %u/%u, wr %d < %u.\n",
2398c2ecf20Sopenharmony_ci				 csk, skb->len, skb->data_len,
2408c2ecf20Sopenharmony_ci				 credits_needed, csk->wr_cred);
2418c2ecf20Sopenharmony_ci			break;
2428c2ecf20Sopenharmony_ci		}
2438c2ecf20Sopenharmony_ci		__skb_unlink(skb, &csk->txq);
2448c2ecf20Sopenharmony_ci		set_wr_txq(skb, CPL_PRIORITY_DATA, csk->txq_idx);
2458c2ecf20Sopenharmony_ci		skb->csum = (__force __wsum)(credits_needed + flowclen16);
2468c2ecf20Sopenharmony_ci		csk->wr_cred -= credits_needed;
2478c2ecf20Sopenharmony_ci		csk->wr_una_cred += credits_needed;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci		pr_debug("csk 0x%p, skb %u/%u, wr %d, left %u, unack %u.\n",
2508c2ecf20Sopenharmony_ci			 csk, skb->len, skb->data_len, credits_needed,
2518c2ecf20Sopenharmony_ci			 csk->wr_cred, csk->wr_una_cred);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci		if (likely(cxgbit_skcb_flags(skb) & SKCBF_TX_NEED_HDR)) {
2548c2ecf20Sopenharmony_ci			len += cxgbit_skcb_tx_extralen(skb);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci			if ((csk->wr_una_cred >= (csk->wr_max_cred / 2)) ||
2578c2ecf20Sopenharmony_ci			    (!before(csk->write_seq,
2588c2ecf20Sopenharmony_ci				     csk->snd_una + csk->snd_win))) {
2598c2ecf20Sopenharmony_ci				compl = 1;
2608c2ecf20Sopenharmony_ci				csk->wr_una_cred = 0;
2618c2ecf20Sopenharmony_ci			}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci			cxgbit_tx_data_wr(csk, skb, dlen, len, credits_needed,
2648c2ecf20Sopenharmony_ci					  compl);
2658c2ecf20Sopenharmony_ci			csk->snd_nxt += len;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci		} else if ((cxgbit_skcb_flags(skb) & SKCBF_TX_FLAG_COMPL) ||
2688c2ecf20Sopenharmony_ci			   (csk->wr_una_cred >= (csk->wr_max_cred / 2))) {
2698c2ecf20Sopenharmony_ci			struct cpl_close_con_req *req =
2708c2ecf20Sopenharmony_ci				(struct cpl_close_con_req *)skb->data;
2718c2ecf20Sopenharmony_ci			req->wr.wr_hi |= htonl(FW_WR_COMPL_F);
2728c2ecf20Sopenharmony_ci			csk->wr_una_cred = 0;
2738c2ecf20Sopenharmony_ci		}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci		cxgbit_sock_enqueue_wr(csk, skb);
2768c2ecf20Sopenharmony_ci		t4_set_arp_err_handler(skb, csk,
2778c2ecf20Sopenharmony_ci				       cxgbit_arp_failure_skb_discard);
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci		pr_debug("csk 0x%p,%u, skb 0x%p, %u.\n",
2808c2ecf20Sopenharmony_ci			 csk, csk->tid, skb, len);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci		cxgbit_l2t_send(csk->com.cdev, skb, csk->l2t);
2838c2ecf20Sopenharmony_ci	}
2848c2ecf20Sopenharmony_ci}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_cistatic void cxgbit_unlock_sock(struct cxgbit_sock *csk)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	struct sk_buff_head backlogq;
2898c2ecf20Sopenharmony_ci	struct sk_buff *skb;
2908c2ecf20Sopenharmony_ci	void (*fn)(struct cxgbit_sock *, struct sk_buff *);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	skb_queue_head_init(&backlogq);
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	spin_lock_bh(&csk->lock);
2958c2ecf20Sopenharmony_ci	while (skb_queue_len(&csk->backlogq)) {
2968c2ecf20Sopenharmony_ci		skb_queue_splice_init(&csk->backlogq, &backlogq);
2978c2ecf20Sopenharmony_ci		spin_unlock_bh(&csk->lock);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci		while ((skb = __skb_dequeue(&backlogq))) {
3008c2ecf20Sopenharmony_ci			fn = cxgbit_skcb_rx_backlog_fn(skb);
3018c2ecf20Sopenharmony_ci			fn(csk, skb);
3028c2ecf20Sopenharmony_ci		}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci		spin_lock_bh(&csk->lock);
3058c2ecf20Sopenharmony_ci	}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	csk->lock_owner = false;
3088c2ecf20Sopenharmony_ci	spin_unlock_bh(&csk->lock);
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_cistatic int cxgbit_queue_skb(struct cxgbit_sock *csk, struct sk_buff *skb)
3128c2ecf20Sopenharmony_ci{
3138c2ecf20Sopenharmony_ci	int ret = 0;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	spin_lock_bh(&csk->lock);
3168c2ecf20Sopenharmony_ci	csk->lock_owner = true;
3178c2ecf20Sopenharmony_ci	spin_unlock_bh(&csk->lock);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	if (unlikely((csk->com.state != CSK_STATE_ESTABLISHED) ||
3208c2ecf20Sopenharmony_ci		     signal_pending(current))) {
3218c2ecf20Sopenharmony_ci		__kfree_skb(skb);
3228c2ecf20Sopenharmony_ci		__skb_queue_purge(&csk->ppodq);
3238c2ecf20Sopenharmony_ci		ret = -1;
3248c2ecf20Sopenharmony_ci		goto unlock;
3258c2ecf20Sopenharmony_ci	}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	csk->write_seq += skb->len +
3288c2ecf20Sopenharmony_ci			  cxgbit_skcb_tx_extralen(skb);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	skb_queue_splice_tail_init(&csk->ppodq, &csk->txq);
3318c2ecf20Sopenharmony_ci	__skb_queue_tail(&csk->txq, skb);
3328c2ecf20Sopenharmony_ci	cxgbit_push_tx_frames(csk);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ciunlock:
3358c2ecf20Sopenharmony_ci	cxgbit_unlock_sock(csk);
3368c2ecf20Sopenharmony_ci	return ret;
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_cistatic int
3408c2ecf20Sopenharmony_cicxgbit_map_skb(struct iscsi_cmd *cmd, struct sk_buff *skb, u32 data_offset,
3418c2ecf20Sopenharmony_ci	       u32 data_length)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	u32 i = 0, nr_frags = MAX_SKB_FRAGS;
3448c2ecf20Sopenharmony_ci	u32 padding = ((-data_length) & 3);
3458c2ecf20Sopenharmony_ci	struct scatterlist *sg;
3468c2ecf20Sopenharmony_ci	struct page *page;
3478c2ecf20Sopenharmony_ci	unsigned int page_off;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	if (padding)
3508c2ecf20Sopenharmony_ci		nr_frags--;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	/*
3538c2ecf20Sopenharmony_ci	 * We know each entry in t_data_sg contains a page.
3548c2ecf20Sopenharmony_ci	 */
3558c2ecf20Sopenharmony_ci	sg = &cmd->se_cmd.t_data_sg[data_offset / PAGE_SIZE];
3568c2ecf20Sopenharmony_ci	page_off = (data_offset % PAGE_SIZE);
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	while (data_length && (i < nr_frags)) {
3598c2ecf20Sopenharmony_ci		u32 cur_len = min_t(u32, data_length, sg->length - page_off);
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci		page = sg_page(sg);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci		get_page(page);
3648c2ecf20Sopenharmony_ci		skb_fill_page_desc(skb, i, page, sg->offset + page_off,
3658c2ecf20Sopenharmony_ci				   cur_len);
3668c2ecf20Sopenharmony_ci		skb->data_len += cur_len;
3678c2ecf20Sopenharmony_ci		skb->len += cur_len;
3688c2ecf20Sopenharmony_ci		skb->truesize += cur_len;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci		data_length -= cur_len;
3718c2ecf20Sopenharmony_ci		page_off = 0;
3728c2ecf20Sopenharmony_ci		sg = sg_next(sg);
3738c2ecf20Sopenharmony_ci		i++;
3748c2ecf20Sopenharmony_ci	}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	if (data_length)
3778c2ecf20Sopenharmony_ci		return -1;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	if (padding) {
3808c2ecf20Sopenharmony_ci		page = alloc_page(GFP_KERNEL | __GFP_ZERO);
3818c2ecf20Sopenharmony_ci		if (!page)
3828c2ecf20Sopenharmony_ci			return -1;
3838c2ecf20Sopenharmony_ci		skb_fill_page_desc(skb, i, page, 0, padding);
3848c2ecf20Sopenharmony_ci		skb->data_len += padding;
3858c2ecf20Sopenharmony_ci		skb->len += padding;
3868c2ecf20Sopenharmony_ci		skb->truesize += padding;
3878c2ecf20Sopenharmony_ci	}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	return 0;
3908c2ecf20Sopenharmony_ci}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_cistatic int
3938c2ecf20Sopenharmony_cicxgbit_tx_datain_iso(struct cxgbit_sock *csk, struct iscsi_cmd *cmd,
3948c2ecf20Sopenharmony_ci		     struct iscsi_datain_req *dr)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = csk->conn;
3978c2ecf20Sopenharmony_ci	struct sk_buff *skb;
3988c2ecf20Sopenharmony_ci	struct iscsi_datain datain;
3998c2ecf20Sopenharmony_ci	struct cxgbit_iso_info iso_info;
4008c2ecf20Sopenharmony_ci	u32 data_length = cmd->se_cmd.data_length;
4018c2ecf20Sopenharmony_ci	u32 mrdsl = conn->conn_ops->MaxRecvDataSegmentLength;
4028c2ecf20Sopenharmony_ci	u32 num_pdu, plen, tx_data = 0;
4038c2ecf20Sopenharmony_ci	bool task_sense = !!(cmd->se_cmd.se_cmd_flags &
4048c2ecf20Sopenharmony_ci		SCF_TRANSPORT_TASK_SENSE);
4058c2ecf20Sopenharmony_ci	bool set_statsn = false;
4068c2ecf20Sopenharmony_ci	int ret = -1;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	while (data_length) {
4098c2ecf20Sopenharmony_ci		num_pdu = (data_length + mrdsl - 1) / mrdsl;
4108c2ecf20Sopenharmony_ci		if (num_pdu > csk->max_iso_npdu)
4118c2ecf20Sopenharmony_ci			num_pdu = csk->max_iso_npdu;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci		plen = num_pdu * mrdsl;
4148c2ecf20Sopenharmony_ci		if (plen > data_length)
4158c2ecf20Sopenharmony_ci			plen = data_length;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci		skb = __cxgbit_alloc_skb(csk, 0, true);
4188c2ecf20Sopenharmony_ci		if (unlikely(!skb))
4198c2ecf20Sopenharmony_ci			return -ENOMEM;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci		memset(skb->data, 0, ISCSI_HDR_LEN);
4228c2ecf20Sopenharmony_ci		cxgbit_skcb_flags(skb) |= SKCBF_TX_ISO;
4238c2ecf20Sopenharmony_ci		cxgbit_skcb_submode(skb) |= (csk->submode &
4248c2ecf20Sopenharmony_ci				CXGBIT_SUBMODE_DCRC);
4258c2ecf20Sopenharmony_ci		cxgbit_skcb_tx_extralen(skb) = (num_pdu *
4268c2ecf20Sopenharmony_ci				cxgbit_digest_len[cxgbit_skcb_submode(skb)]) +
4278c2ecf20Sopenharmony_ci						((num_pdu - 1) * ISCSI_HDR_LEN);
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci		memset(&datain, 0, sizeof(struct iscsi_datain));
4308c2ecf20Sopenharmony_ci		memset(&iso_info, 0, sizeof(iso_info));
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci		if (!tx_data)
4338c2ecf20Sopenharmony_ci			iso_info.flags |= CXGBIT_ISO_FSLICE;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci		if (!(data_length - plen)) {
4368c2ecf20Sopenharmony_ci			iso_info.flags |= CXGBIT_ISO_LSLICE;
4378c2ecf20Sopenharmony_ci			if (!task_sense) {
4388c2ecf20Sopenharmony_ci				datain.flags = ISCSI_FLAG_DATA_STATUS;
4398c2ecf20Sopenharmony_ci				iscsit_increment_maxcmdsn(cmd, conn->sess);
4408c2ecf20Sopenharmony_ci				cmd->stat_sn = conn->stat_sn++;
4418c2ecf20Sopenharmony_ci				set_statsn = true;
4428c2ecf20Sopenharmony_ci			}
4438c2ecf20Sopenharmony_ci		}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci		iso_info.burst_len = num_pdu * mrdsl;
4468c2ecf20Sopenharmony_ci		iso_info.mpdu = mrdsl;
4478c2ecf20Sopenharmony_ci		iso_info.len = ISCSI_HDR_LEN + plen;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci		cxgbit_cpl_tx_data_iso(skb, &iso_info);
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci		datain.offset = tx_data;
4528c2ecf20Sopenharmony_ci		datain.data_sn = cmd->data_sn - 1;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci		iscsit_build_datain_pdu(cmd, conn, &datain,
4558c2ecf20Sopenharmony_ci					(struct iscsi_data_rsp *)skb->data,
4568c2ecf20Sopenharmony_ci					set_statsn);
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci		ret = cxgbit_map_skb(cmd, skb, tx_data, plen);
4598c2ecf20Sopenharmony_ci		if (unlikely(ret)) {
4608c2ecf20Sopenharmony_ci			__kfree_skb(skb);
4618c2ecf20Sopenharmony_ci			goto out;
4628c2ecf20Sopenharmony_ci		}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci		ret = cxgbit_queue_skb(csk, skb);
4658c2ecf20Sopenharmony_ci		if (unlikely(ret))
4668c2ecf20Sopenharmony_ci			goto out;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci		tx_data += plen;
4698c2ecf20Sopenharmony_ci		data_length -= plen;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci		cmd->read_data_done += plen;
4728c2ecf20Sopenharmony_ci		cmd->data_sn += num_pdu;
4738c2ecf20Sopenharmony_ci	}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	dr->dr_complete = DATAIN_COMPLETE_NORMAL;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	return 0;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ciout:
4808c2ecf20Sopenharmony_ci	return ret;
4818c2ecf20Sopenharmony_ci}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_cistatic int
4848c2ecf20Sopenharmony_cicxgbit_tx_datain(struct cxgbit_sock *csk, struct iscsi_cmd *cmd,
4858c2ecf20Sopenharmony_ci		 const struct iscsi_datain *datain)
4868c2ecf20Sopenharmony_ci{
4878c2ecf20Sopenharmony_ci	struct sk_buff *skb;
4888c2ecf20Sopenharmony_ci	int ret = 0;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	skb = cxgbit_alloc_skb(csk, 0);
4918c2ecf20Sopenharmony_ci	if (unlikely(!skb))
4928c2ecf20Sopenharmony_ci		return -ENOMEM;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	memcpy(skb->data, cmd->pdu, ISCSI_HDR_LEN);
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	if (datain->length) {
4978c2ecf20Sopenharmony_ci		cxgbit_skcb_submode(skb) |= (csk->submode &
4988c2ecf20Sopenharmony_ci				CXGBIT_SUBMODE_DCRC);
4998c2ecf20Sopenharmony_ci		cxgbit_skcb_tx_extralen(skb) =
5008c2ecf20Sopenharmony_ci				cxgbit_digest_len[cxgbit_skcb_submode(skb)];
5018c2ecf20Sopenharmony_ci	}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	ret = cxgbit_map_skb(cmd, skb, datain->offset, datain->length);
5048c2ecf20Sopenharmony_ci	if (ret < 0) {
5058c2ecf20Sopenharmony_ci		__kfree_skb(skb);
5068c2ecf20Sopenharmony_ci		return ret;
5078c2ecf20Sopenharmony_ci	}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	return cxgbit_queue_skb(csk, skb);
5108c2ecf20Sopenharmony_ci}
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_cistatic int
5138c2ecf20Sopenharmony_cicxgbit_xmit_datain_pdu(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
5148c2ecf20Sopenharmony_ci		       struct iscsi_datain_req *dr,
5158c2ecf20Sopenharmony_ci		       const struct iscsi_datain *datain)
5168c2ecf20Sopenharmony_ci{
5178c2ecf20Sopenharmony_ci	struct cxgbit_sock *csk = conn->context;
5188c2ecf20Sopenharmony_ci	u32 data_length = cmd->se_cmd.data_length;
5198c2ecf20Sopenharmony_ci	u32 padding = ((-data_length) & 3);
5208c2ecf20Sopenharmony_ci	u32 mrdsl = conn->conn_ops->MaxRecvDataSegmentLength;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	if ((data_length > mrdsl) && (!dr->recovery) &&
5238c2ecf20Sopenharmony_ci	    (!padding) && (!datain->offset) && csk->max_iso_npdu) {
5248c2ecf20Sopenharmony_ci		atomic_long_add(data_length - datain->length,
5258c2ecf20Sopenharmony_ci				&conn->sess->tx_data_octets);
5268c2ecf20Sopenharmony_ci		return cxgbit_tx_datain_iso(csk, cmd, dr);
5278c2ecf20Sopenharmony_ci	}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	return cxgbit_tx_datain(csk, cmd, datain);
5308c2ecf20Sopenharmony_ci}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_cistatic int
5338c2ecf20Sopenharmony_cicxgbit_xmit_nondatain_pdu(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
5348c2ecf20Sopenharmony_ci			  const void *data_buf, u32 data_buf_len)
5358c2ecf20Sopenharmony_ci{
5368c2ecf20Sopenharmony_ci	struct cxgbit_sock *csk = conn->context;
5378c2ecf20Sopenharmony_ci	struct sk_buff *skb;
5388c2ecf20Sopenharmony_ci	u32 padding = ((-data_buf_len) & 3);
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	skb = cxgbit_alloc_skb(csk, data_buf_len + padding);
5418c2ecf20Sopenharmony_ci	if (unlikely(!skb))
5428c2ecf20Sopenharmony_ci		return -ENOMEM;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	memcpy(skb->data, cmd->pdu, ISCSI_HDR_LEN);
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	if (data_buf_len) {
5478c2ecf20Sopenharmony_ci		u32 pad_bytes = 0;
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci		skb_store_bits(skb, ISCSI_HDR_LEN, data_buf, data_buf_len);
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci		if (padding)
5528c2ecf20Sopenharmony_ci			skb_store_bits(skb, ISCSI_HDR_LEN + data_buf_len,
5538c2ecf20Sopenharmony_ci				       &pad_bytes, padding);
5548c2ecf20Sopenharmony_ci	}
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	cxgbit_skcb_tx_extralen(skb) = cxgbit_digest_len[
5578c2ecf20Sopenharmony_ci				       cxgbit_skcb_submode(skb)];
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	return cxgbit_queue_skb(csk, skb);
5608c2ecf20Sopenharmony_ci}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ciint
5638c2ecf20Sopenharmony_cicxgbit_xmit_pdu(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
5648c2ecf20Sopenharmony_ci		struct iscsi_datain_req *dr, const void *buf, u32 buf_len)
5658c2ecf20Sopenharmony_ci{
5668c2ecf20Sopenharmony_ci	if (dr)
5678c2ecf20Sopenharmony_ci		return cxgbit_xmit_datain_pdu(conn, cmd, dr, buf);
5688c2ecf20Sopenharmony_ci	else
5698c2ecf20Sopenharmony_ci		return cxgbit_xmit_nondatain_pdu(conn, cmd, buf, buf_len);
5708c2ecf20Sopenharmony_ci}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ciint cxgbit_validate_params(struct iscsi_conn *conn)
5738c2ecf20Sopenharmony_ci{
5748c2ecf20Sopenharmony_ci	struct cxgbit_sock *csk = conn->context;
5758c2ecf20Sopenharmony_ci	struct cxgbit_device *cdev = csk->com.cdev;
5768c2ecf20Sopenharmony_ci	struct iscsi_param *param;
5778c2ecf20Sopenharmony_ci	u32 max_xmitdsl;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	param = iscsi_find_param_from_key(MAXXMITDATASEGMENTLENGTH,
5808c2ecf20Sopenharmony_ci					  conn->param_list);
5818c2ecf20Sopenharmony_ci	if (!param)
5828c2ecf20Sopenharmony_ci		return -1;
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	if (kstrtou32(param->value, 0, &max_xmitdsl) < 0)
5858c2ecf20Sopenharmony_ci		return -1;
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	if (max_xmitdsl > cdev->mdsl) {
5888c2ecf20Sopenharmony_ci		if (iscsi_change_param_sprintf(
5898c2ecf20Sopenharmony_ci			conn, "MaxXmitDataSegmentLength=%u", cdev->mdsl))
5908c2ecf20Sopenharmony_ci			return -1;
5918c2ecf20Sopenharmony_ci	}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	return 0;
5948c2ecf20Sopenharmony_ci}
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_cistatic int cxgbit_set_digest(struct cxgbit_sock *csk)
5978c2ecf20Sopenharmony_ci{
5988c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = csk->conn;
5998c2ecf20Sopenharmony_ci	struct iscsi_param *param;
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	param = iscsi_find_param_from_key(HEADERDIGEST, conn->param_list);
6028c2ecf20Sopenharmony_ci	if (!param) {
6038c2ecf20Sopenharmony_ci		pr_err("param not found key %s\n", HEADERDIGEST);
6048c2ecf20Sopenharmony_ci		return -1;
6058c2ecf20Sopenharmony_ci	}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	if (!strcmp(param->value, CRC32C))
6088c2ecf20Sopenharmony_ci		csk->submode |= CXGBIT_SUBMODE_HCRC;
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	param = iscsi_find_param_from_key(DATADIGEST, conn->param_list);
6118c2ecf20Sopenharmony_ci	if (!param) {
6128c2ecf20Sopenharmony_ci		csk->submode = 0;
6138c2ecf20Sopenharmony_ci		pr_err("param not found key %s\n", DATADIGEST);
6148c2ecf20Sopenharmony_ci		return -1;
6158c2ecf20Sopenharmony_ci	}
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	if (!strcmp(param->value, CRC32C))
6188c2ecf20Sopenharmony_ci		csk->submode |= CXGBIT_SUBMODE_DCRC;
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	if (cxgbit_setup_conn_digest(csk)) {
6218c2ecf20Sopenharmony_ci		csk->submode = 0;
6228c2ecf20Sopenharmony_ci		return -1;
6238c2ecf20Sopenharmony_ci	}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	return 0;
6268c2ecf20Sopenharmony_ci}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_cistatic int cxgbit_set_iso_npdu(struct cxgbit_sock *csk)
6298c2ecf20Sopenharmony_ci{
6308c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = csk->conn;
6318c2ecf20Sopenharmony_ci	struct iscsi_conn_ops *conn_ops = conn->conn_ops;
6328c2ecf20Sopenharmony_ci	struct iscsi_param *param;
6338c2ecf20Sopenharmony_ci	u32 mrdsl, mbl;
6348c2ecf20Sopenharmony_ci	u32 max_npdu, max_iso_npdu;
6358c2ecf20Sopenharmony_ci	u32 max_iso_payload;
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	if (conn->login->leading_connection) {
6388c2ecf20Sopenharmony_ci		param = iscsi_find_param_from_key(MAXBURSTLENGTH,
6398c2ecf20Sopenharmony_ci						  conn->param_list);
6408c2ecf20Sopenharmony_ci		if (!param) {
6418c2ecf20Sopenharmony_ci			pr_err("param not found key %s\n", MAXBURSTLENGTH);
6428c2ecf20Sopenharmony_ci			return -1;
6438c2ecf20Sopenharmony_ci		}
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci		if (kstrtou32(param->value, 0, &mbl) < 0)
6468c2ecf20Sopenharmony_ci			return -1;
6478c2ecf20Sopenharmony_ci	} else {
6488c2ecf20Sopenharmony_ci		mbl = conn->sess->sess_ops->MaxBurstLength;
6498c2ecf20Sopenharmony_ci	}
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	mrdsl = conn_ops->MaxRecvDataSegmentLength;
6528c2ecf20Sopenharmony_ci	max_npdu = mbl / mrdsl;
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	max_iso_payload = rounddown(CXGBIT_MAX_ISO_PAYLOAD, csk->emss);
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	max_iso_npdu = max_iso_payload /
6578c2ecf20Sopenharmony_ci		       (ISCSI_HDR_LEN + mrdsl +
6588c2ecf20Sopenharmony_ci			cxgbit_digest_len[csk->submode]);
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	csk->max_iso_npdu = min(max_npdu, max_iso_npdu);
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	if (csk->max_iso_npdu <= 1)
6638c2ecf20Sopenharmony_ci		csk->max_iso_npdu = 0;
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	return 0;
6668c2ecf20Sopenharmony_ci}
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci/*
6698c2ecf20Sopenharmony_ci * cxgbit_seq_pdu_inorder()
6708c2ecf20Sopenharmony_ci * @csk: pointer to cxgbit socket structure
6718c2ecf20Sopenharmony_ci *
6728c2ecf20Sopenharmony_ci * This function checks whether data sequence and data
6738c2ecf20Sopenharmony_ci * pdu are in order.
6748c2ecf20Sopenharmony_ci *
6758c2ecf20Sopenharmony_ci * Return: returns -1 on error, 0 if data sequence and
6768c2ecf20Sopenharmony_ci * data pdu are in order, 1 if data sequence or data pdu
6778c2ecf20Sopenharmony_ci * is not in order.
6788c2ecf20Sopenharmony_ci */
6798c2ecf20Sopenharmony_cistatic int cxgbit_seq_pdu_inorder(struct cxgbit_sock *csk)
6808c2ecf20Sopenharmony_ci{
6818c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = csk->conn;
6828c2ecf20Sopenharmony_ci	struct iscsi_param *param;
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	if (conn->login->leading_connection) {
6858c2ecf20Sopenharmony_ci		param = iscsi_find_param_from_key(DATASEQUENCEINORDER,
6868c2ecf20Sopenharmony_ci						  conn->param_list);
6878c2ecf20Sopenharmony_ci		if (!param) {
6888c2ecf20Sopenharmony_ci			pr_err("param not found key %s\n", DATASEQUENCEINORDER);
6898c2ecf20Sopenharmony_ci			return -1;
6908c2ecf20Sopenharmony_ci		}
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci		if (strcmp(param->value, YES))
6938c2ecf20Sopenharmony_ci			return 1;
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci		param = iscsi_find_param_from_key(DATAPDUINORDER,
6968c2ecf20Sopenharmony_ci						  conn->param_list);
6978c2ecf20Sopenharmony_ci		if (!param) {
6988c2ecf20Sopenharmony_ci			pr_err("param not found key %s\n", DATAPDUINORDER);
6998c2ecf20Sopenharmony_ci			return -1;
7008c2ecf20Sopenharmony_ci		}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci		if (strcmp(param->value, YES))
7038c2ecf20Sopenharmony_ci			return 1;
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	} else {
7068c2ecf20Sopenharmony_ci		if (!conn->sess->sess_ops->DataSequenceInOrder)
7078c2ecf20Sopenharmony_ci			return 1;
7088c2ecf20Sopenharmony_ci		if (!conn->sess->sess_ops->DataPDUInOrder)
7098c2ecf20Sopenharmony_ci			return 1;
7108c2ecf20Sopenharmony_ci	}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	return 0;
7138c2ecf20Sopenharmony_ci}
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_cistatic int cxgbit_set_params(struct iscsi_conn *conn)
7168c2ecf20Sopenharmony_ci{
7178c2ecf20Sopenharmony_ci	struct cxgbit_sock *csk = conn->context;
7188c2ecf20Sopenharmony_ci	struct cxgbit_device *cdev = csk->com.cdev;
7198c2ecf20Sopenharmony_ci	struct cxgbi_ppm *ppm = *csk->com.cdev->lldi.iscsi_ppm;
7208c2ecf20Sopenharmony_ci	struct iscsi_conn_ops *conn_ops = conn->conn_ops;
7218c2ecf20Sopenharmony_ci	struct iscsi_param *param;
7228c2ecf20Sopenharmony_ci	u8 erl;
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	if (conn_ops->MaxRecvDataSegmentLength > cdev->mdsl)
7258c2ecf20Sopenharmony_ci		conn_ops->MaxRecvDataSegmentLength = cdev->mdsl;
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	if (cxgbit_set_digest(csk))
7288c2ecf20Sopenharmony_ci		return -1;
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	if (conn->login->leading_connection) {
7318c2ecf20Sopenharmony_ci		param = iscsi_find_param_from_key(ERRORRECOVERYLEVEL,
7328c2ecf20Sopenharmony_ci						  conn->param_list);
7338c2ecf20Sopenharmony_ci		if (!param) {
7348c2ecf20Sopenharmony_ci			pr_err("param not found key %s\n", ERRORRECOVERYLEVEL);
7358c2ecf20Sopenharmony_ci			return -1;
7368c2ecf20Sopenharmony_ci		}
7378c2ecf20Sopenharmony_ci		if (kstrtou8(param->value, 0, &erl) < 0)
7388c2ecf20Sopenharmony_ci			return -1;
7398c2ecf20Sopenharmony_ci	} else {
7408c2ecf20Sopenharmony_ci		erl = conn->sess->sess_ops->ErrorRecoveryLevel;
7418c2ecf20Sopenharmony_ci	}
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	if (!erl) {
7448c2ecf20Sopenharmony_ci		int ret;
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci		ret = cxgbit_seq_pdu_inorder(csk);
7478c2ecf20Sopenharmony_ci		if (ret < 0) {
7488c2ecf20Sopenharmony_ci			return -1;
7498c2ecf20Sopenharmony_ci		} else if (ret > 0) {
7508c2ecf20Sopenharmony_ci			if (is_t5(cdev->lldi.adapter_type))
7518c2ecf20Sopenharmony_ci				goto enable_ddp;
7528c2ecf20Sopenharmony_ci			else
7538c2ecf20Sopenharmony_ci				return 0;
7548c2ecf20Sopenharmony_ci		}
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci		if (test_bit(CDEV_ISO_ENABLE, &cdev->flags)) {
7578c2ecf20Sopenharmony_ci			if (cxgbit_set_iso_npdu(csk))
7588c2ecf20Sopenharmony_ci				return -1;
7598c2ecf20Sopenharmony_ci		}
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_cienable_ddp:
7628c2ecf20Sopenharmony_ci		if (test_bit(CDEV_DDP_ENABLE, &cdev->flags)) {
7638c2ecf20Sopenharmony_ci			if (cxgbit_setup_conn_pgidx(csk,
7648c2ecf20Sopenharmony_ci						    ppm->tformat.pgsz_idx_dflt))
7658c2ecf20Sopenharmony_ci				return -1;
7668c2ecf20Sopenharmony_ci			set_bit(CSK_DDP_ENABLE, &csk->com.flags);
7678c2ecf20Sopenharmony_ci		}
7688c2ecf20Sopenharmony_ci	}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	return 0;
7718c2ecf20Sopenharmony_ci}
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ciint
7748c2ecf20Sopenharmony_cicxgbit_put_login_tx(struct iscsi_conn *conn, struct iscsi_login *login,
7758c2ecf20Sopenharmony_ci		    u32 length)
7768c2ecf20Sopenharmony_ci{
7778c2ecf20Sopenharmony_ci	struct cxgbit_sock *csk = conn->context;
7788c2ecf20Sopenharmony_ci	struct sk_buff *skb;
7798c2ecf20Sopenharmony_ci	u32 padding_buf = 0;
7808c2ecf20Sopenharmony_ci	u8 padding = ((-length) & 3);
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	skb = cxgbit_alloc_skb(csk, length + padding);
7838c2ecf20Sopenharmony_ci	if (!skb)
7848c2ecf20Sopenharmony_ci		return -ENOMEM;
7858c2ecf20Sopenharmony_ci	skb_store_bits(skb, 0, login->rsp, ISCSI_HDR_LEN);
7868c2ecf20Sopenharmony_ci	skb_store_bits(skb, ISCSI_HDR_LEN, login->rsp_buf, length);
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	if (padding)
7898c2ecf20Sopenharmony_ci		skb_store_bits(skb, ISCSI_HDR_LEN + length,
7908c2ecf20Sopenharmony_ci			       &padding_buf, padding);
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci	if (login->login_complete) {
7938c2ecf20Sopenharmony_ci		if (cxgbit_set_params(conn)) {
7948c2ecf20Sopenharmony_ci			kfree_skb(skb);
7958c2ecf20Sopenharmony_ci			return -1;
7968c2ecf20Sopenharmony_ci		}
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci		set_bit(CSK_LOGIN_DONE, &csk->com.flags);
7998c2ecf20Sopenharmony_ci	}
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	if (cxgbit_queue_skb(csk, skb))
8028c2ecf20Sopenharmony_ci		return -1;
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	if ((!login->login_complete) && (!login->login_failed))
8058c2ecf20Sopenharmony_ci		schedule_delayed_work(&conn->login_work, 0);
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	return 0;
8088c2ecf20Sopenharmony_ci}
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_cistatic void
8118c2ecf20Sopenharmony_cicxgbit_skb_copy_to_sg(struct sk_buff *skb, struct scatterlist *sg,
8128c2ecf20Sopenharmony_ci		      unsigned int nents, u32 skip)
8138c2ecf20Sopenharmony_ci{
8148c2ecf20Sopenharmony_ci	struct skb_seq_state st;
8158c2ecf20Sopenharmony_ci	const u8 *buf;
8168c2ecf20Sopenharmony_ci	unsigned int consumed = 0, buf_len;
8178c2ecf20Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(skb);
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	skb_prepare_seq_read(skb, pdu_cb->doffset,
8208c2ecf20Sopenharmony_ci			     pdu_cb->doffset + pdu_cb->dlen,
8218c2ecf20Sopenharmony_ci			     &st);
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	while (true) {
8248c2ecf20Sopenharmony_ci		buf_len = skb_seq_read(consumed, &buf, &st);
8258c2ecf20Sopenharmony_ci		if (!buf_len) {
8268c2ecf20Sopenharmony_ci			skb_abort_seq_read(&st);
8278c2ecf20Sopenharmony_ci			break;
8288c2ecf20Sopenharmony_ci		}
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci		consumed += sg_pcopy_from_buffer(sg, nents, (void *)buf,
8318c2ecf20Sopenharmony_ci						 buf_len, skip + consumed);
8328c2ecf20Sopenharmony_ci	}
8338c2ecf20Sopenharmony_ci}
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_cistatic struct iscsi_cmd *cxgbit_allocate_cmd(struct cxgbit_sock *csk)
8368c2ecf20Sopenharmony_ci{
8378c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = csk->conn;
8388c2ecf20Sopenharmony_ci	struct cxgbi_ppm *ppm = cdev2ppm(csk->com.cdev);
8398c2ecf20Sopenharmony_ci	struct cxgbit_cmd *ccmd;
8408c2ecf20Sopenharmony_ci	struct iscsi_cmd *cmd;
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
8438c2ecf20Sopenharmony_ci	if (!cmd) {
8448c2ecf20Sopenharmony_ci		pr_err("Unable to allocate iscsi_cmd + cxgbit_cmd\n");
8458c2ecf20Sopenharmony_ci		return NULL;
8468c2ecf20Sopenharmony_ci	}
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	ccmd = iscsit_priv_cmd(cmd);
8498c2ecf20Sopenharmony_ci	ccmd->ttinfo.tag = ppm->tformat.no_ddp_mask;
8508c2ecf20Sopenharmony_ci	ccmd->setup_ddp = true;
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	return cmd;
8538c2ecf20Sopenharmony_ci}
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_cistatic int
8568c2ecf20Sopenharmony_cicxgbit_handle_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr,
8578c2ecf20Sopenharmony_ci			     u32 length)
8588c2ecf20Sopenharmony_ci{
8598c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = cmd->conn;
8608c2ecf20Sopenharmony_ci	struct cxgbit_sock *csk = conn->context;
8618c2ecf20Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	if (pdu_cb->flags & PDUCBF_RX_DCRC_ERR) {
8648c2ecf20Sopenharmony_ci		pr_err("ImmediateData CRC32C DataDigest error\n");
8658c2ecf20Sopenharmony_ci		if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
8668c2ecf20Sopenharmony_ci			pr_err("Unable to recover from"
8678c2ecf20Sopenharmony_ci			       " Immediate Data digest failure while"
8688c2ecf20Sopenharmony_ci			       " in ERL=0.\n");
8698c2ecf20Sopenharmony_ci			iscsit_reject_cmd(cmd, ISCSI_REASON_DATA_DIGEST_ERROR,
8708c2ecf20Sopenharmony_ci					  (unsigned char *)hdr);
8718c2ecf20Sopenharmony_ci			return IMMEDIATE_DATA_CANNOT_RECOVER;
8728c2ecf20Sopenharmony_ci		}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci		iscsit_reject_cmd(cmd, ISCSI_REASON_DATA_DIGEST_ERROR,
8758c2ecf20Sopenharmony_ci				  (unsigned char *)hdr);
8768c2ecf20Sopenharmony_ci		return IMMEDIATE_DATA_ERL1_CRC_FAILURE;
8778c2ecf20Sopenharmony_ci	}
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	if (cmd->se_cmd.se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) {
8808c2ecf20Sopenharmony_ci		struct cxgbit_cmd *ccmd = iscsit_priv_cmd(cmd);
8818c2ecf20Sopenharmony_ci		struct skb_shared_info *ssi = skb_shinfo(csk->skb);
8828c2ecf20Sopenharmony_ci		skb_frag_t *dfrag = &ssi->frags[pdu_cb->dfrag_idx];
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci		sg_init_table(&ccmd->sg, 1);
8858c2ecf20Sopenharmony_ci		sg_set_page(&ccmd->sg, skb_frag_page(dfrag),
8868c2ecf20Sopenharmony_ci				skb_frag_size(dfrag), skb_frag_off(dfrag));
8878c2ecf20Sopenharmony_ci		get_page(skb_frag_page(dfrag));
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci		cmd->se_cmd.t_data_sg = &ccmd->sg;
8908c2ecf20Sopenharmony_ci		cmd->se_cmd.t_data_nents = 1;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci		ccmd->release = true;
8938c2ecf20Sopenharmony_ci	} else {
8948c2ecf20Sopenharmony_ci		struct scatterlist *sg = &cmd->se_cmd.t_data_sg[0];
8958c2ecf20Sopenharmony_ci		u32 sg_nents = max(1UL, DIV_ROUND_UP(pdu_cb->dlen, PAGE_SIZE));
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci		cxgbit_skb_copy_to_sg(csk->skb, sg, sg_nents, 0);
8988c2ecf20Sopenharmony_ci	}
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	cmd->write_data_done += pdu_cb->dlen;
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	if (cmd->write_data_done == cmd->se_cmd.data_length) {
9038c2ecf20Sopenharmony_ci		spin_lock_bh(&cmd->istate_lock);
9048c2ecf20Sopenharmony_ci		cmd->cmd_flags |= ICF_GOT_LAST_DATAOUT;
9058c2ecf20Sopenharmony_ci		cmd->i_state = ISTATE_RECEIVED_LAST_DATAOUT;
9068c2ecf20Sopenharmony_ci		spin_unlock_bh(&cmd->istate_lock);
9078c2ecf20Sopenharmony_ci	}
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	return IMMEDIATE_DATA_NORMAL_OPERATION;
9108c2ecf20Sopenharmony_ci}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_cistatic int
9138c2ecf20Sopenharmony_cicxgbit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr,
9148c2ecf20Sopenharmony_ci			  bool dump_payload)
9158c2ecf20Sopenharmony_ci{
9168c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = cmd->conn;
9178c2ecf20Sopenharmony_ci	int cmdsn_ret = 0, immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION;
9188c2ecf20Sopenharmony_ci	/*
9198c2ecf20Sopenharmony_ci	 * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes.
9208c2ecf20Sopenharmony_ci	 */
9218c2ecf20Sopenharmony_ci	if (dump_payload)
9228c2ecf20Sopenharmony_ci		goto after_immediate_data;
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	immed_ret = cxgbit_handle_immediate_data(cmd, hdr,
9258c2ecf20Sopenharmony_ci						 cmd->first_burst_len);
9268c2ecf20Sopenharmony_ciafter_immediate_data:
9278c2ecf20Sopenharmony_ci	if (immed_ret == IMMEDIATE_DATA_NORMAL_OPERATION) {
9288c2ecf20Sopenharmony_ci		/*
9298c2ecf20Sopenharmony_ci		 * A PDU/CmdSN carrying Immediate Data passed
9308c2ecf20Sopenharmony_ci		 * DataCRC, check against ExpCmdSN/MaxCmdSN if
9318c2ecf20Sopenharmony_ci		 * Immediate Bit is not set.
9328c2ecf20Sopenharmony_ci		 */
9338c2ecf20Sopenharmony_ci		cmdsn_ret = iscsit_sequence_cmd(conn, cmd,
9348c2ecf20Sopenharmony_ci						(unsigned char *)hdr,
9358c2ecf20Sopenharmony_ci						hdr->cmdsn);
9368c2ecf20Sopenharmony_ci		if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
9378c2ecf20Sopenharmony_ci			return -1;
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci		if (cmd->sense_reason || cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
9408c2ecf20Sopenharmony_ci			target_put_sess_cmd(&cmd->se_cmd);
9418c2ecf20Sopenharmony_ci			return 0;
9428c2ecf20Sopenharmony_ci		} else if (cmd->unsolicited_data) {
9438c2ecf20Sopenharmony_ci			iscsit_set_unsolicited_dataout(cmd);
9448c2ecf20Sopenharmony_ci		}
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	} else if (immed_ret == IMMEDIATE_DATA_ERL1_CRC_FAILURE) {
9478c2ecf20Sopenharmony_ci		/*
9488c2ecf20Sopenharmony_ci		 * Immediate Data failed DataCRC and ERL>=1,
9498c2ecf20Sopenharmony_ci		 * silently drop this PDU and let the initiator
9508c2ecf20Sopenharmony_ci		 * plug the CmdSN gap.
9518c2ecf20Sopenharmony_ci		 *
9528c2ecf20Sopenharmony_ci		 * FIXME: Send Unsolicited NOPIN with reserved
9538c2ecf20Sopenharmony_ci		 * TTT here to help the initiator figure out
9548c2ecf20Sopenharmony_ci		 * the missing CmdSN, although they should be
9558c2ecf20Sopenharmony_ci		 * intelligent enough to determine the missing
9568c2ecf20Sopenharmony_ci		 * CmdSN and issue a retry to plug the sequence.
9578c2ecf20Sopenharmony_ci		 */
9588c2ecf20Sopenharmony_ci		cmd->i_state = ISTATE_REMOVE;
9598c2ecf20Sopenharmony_ci		iscsit_add_cmd_to_immediate_queue(cmd, conn, cmd->i_state);
9608c2ecf20Sopenharmony_ci	} else /* immed_ret == IMMEDIATE_DATA_CANNOT_RECOVER */
9618c2ecf20Sopenharmony_ci		return -1;
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	return 0;
9648c2ecf20Sopenharmony_ci}
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_cistatic int
9678c2ecf20Sopenharmony_cicxgbit_handle_scsi_cmd(struct cxgbit_sock *csk, struct iscsi_cmd *cmd)
9688c2ecf20Sopenharmony_ci{
9698c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = csk->conn;
9708c2ecf20Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
9718c2ecf20Sopenharmony_ci	struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)pdu_cb->hdr;
9728c2ecf20Sopenharmony_ci	int rc;
9738c2ecf20Sopenharmony_ci	bool dump_payload = false;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	rc = iscsit_setup_scsi_cmd(conn, cmd, (unsigned char *)hdr);
9768c2ecf20Sopenharmony_ci	if (rc < 0)
9778c2ecf20Sopenharmony_ci		return rc;
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	if (pdu_cb->dlen && (pdu_cb->dlen == cmd->se_cmd.data_length) &&
9808c2ecf20Sopenharmony_ci	    (pdu_cb->nr_dfrags == 1))
9818c2ecf20Sopenharmony_ci		cmd->se_cmd.se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	rc = iscsit_process_scsi_cmd(conn, cmd, hdr);
9848c2ecf20Sopenharmony_ci	if (rc < 0)
9858c2ecf20Sopenharmony_ci		return 0;
9868c2ecf20Sopenharmony_ci	else if (rc > 0)
9878c2ecf20Sopenharmony_ci		dump_payload = true;
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	if (!pdu_cb->dlen)
9908c2ecf20Sopenharmony_ci		return 0;
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	return cxgbit_get_immediate_data(cmd, hdr, dump_payload);
9938c2ecf20Sopenharmony_ci}
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_cistatic int cxgbit_handle_iscsi_dataout(struct cxgbit_sock *csk)
9968c2ecf20Sopenharmony_ci{
9978c2ecf20Sopenharmony_ci	struct scatterlist *sg_start;
9988c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = csk->conn;
9998c2ecf20Sopenharmony_ci	struct iscsi_cmd *cmd = NULL;
10008c2ecf20Sopenharmony_ci	struct cxgbit_cmd *ccmd;
10018c2ecf20Sopenharmony_ci	struct cxgbi_task_tag_info *ttinfo;
10028c2ecf20Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
10038c2ecf20Sopenharmony_ci	struct iscsi_data *hdr = (struct iscsi_data *)pdu_cb->hdr;
10048c2ecf20Sopenharmony_ci	u32 data_offset = be32_to_cpu(hdr->offset);
10058c2ecf20Sopenharmony_ci	u32 data_len = ntoh24(hdr->dlength);
10068c2ecf20Sopenharmony_ci	int rc, sg_nents, sg_off;
10078c2ecf20Sopenharmony_ci	bool dcrc_err = false;
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci	if (pdu_cb->flags & PDUCBF_RX_DDP_CMP) {
10108c2ecf20Sopenharmony_ci		u32 offset = be32_to_cpu(hdr->offset);
10118c2ecf20Sopenharmony_ci		u32 ddp_data_len;
10128c2ecf20Sopenharmony_ci		bool success = false;
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci		cmd = iscsit_find_cmd_from_itt_or_dump(conn, hdr->itt, 0);
10158c2ecf20Sopenharmony_ci		if (!cmd)
10168c2ecf20Sopenharmony_ci			return 0;
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci		ddp_data_len = offset - cmd->write_data_done;
10198c2ecf20Sopenharmony_ci		atomic_long_add(ddp_data_len, &conn->sess->rx_data_octets);
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci		cmd->write_data_done = offset;
10228c2ecf20Sopenharmony_ci		cmd->next_burst_len = ddp_data_len;
10238c2ecf20Sopenharmony_ci		cmd->data_sn = be32_to_cpu(hdr->datasn);
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci		rc = __iscsit_check_dataout_hdr(conn, (unsigned char *)hdr,
10268c2ecf20Sopenharmony_ci						cmd, data_len, &success);
10278c2ecf20Sopenharmony_ci		if (rc < 0)
10288c2ecf20Sopenharmony_ci			return rc;
10298c2ecf20Sopenharmony_ci		else if (!success)
10308c2ecf20Sopenharmony_ci			return 0;
10318c2ecf20Sopenharmony_ci	} else {
10328c2ecf20Sopenharmony_ci		rc = iscsit_check_dataout_hdr(conn, (unsigned char *)hdr, &cmd);
10338c2ecf20Sopenharmony_ci		if (rc < 0)
10348c2ecf20Sopenharmony_ci			return rc;
10358c2ecf20Sopenharmony_ci		else if (!cmd)
10368c2ecf20Sopenharmony_ci			return 0;
10378c2ecf20Sopenharmony_ci	}
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	if (pdu_cb->flags & PDUCBF_RX_DCRC_ERR) {
10408c2ecf20Sopenharmony_ci		pr_err("ITT: 0x%08x, Offset: %u, Length: %u,"
10418c2ecf20Sopenharmony_ci		       " DataSN: 0x%08x\n",
10428c2ecf20Sopenharmony_ci		       hdr->itt, hdr->offset, data_len,
10438c2ecf20Sopenharmony_ci		       hdr->datasn);
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci		dcrc_err = true;
10468c2ecf20Sopenharmony_ci		goto check_payload;
10478c2ecf20Sopenharmony_ci	}
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	pr_debug("DataOut data_len: %u, "
10508c2ecf20Sopenharmony_ci		"write_data_done: %u, data_length: %u\n",
10518c2ecf20Sopenharmony_ci		  data_len,  cmd->write_data_done,
10528c2ecf20Sopenharmony_ci		  cmd->se_cmd.data_length);
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	if (!(pdu_cb->flags & PDUCBF_RX_DATA_DDPD)) {
10558c2ecf20Sopenharmony_ci		u32 skip = data_offset % PAGE_SIZE;
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci		sg_off = data_offset / PAGE_SIZE;
10588c2ecf20Sopenharmony_ci		sg_start = &cmd->se_cmd.t_data_sg[sg_off];
10598c2ecf20Sopenharmony_ci		sg_nents = max(1UL, DIV_ROUND_UP(skip + data_len, PAGE_SIZE));
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci		cxgbit_skb_copy_to_sg(csk->skb, sg_start, sg_nents, skip);
10628c2ecf20Sopenharmony_ci	}
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	ccmd = iscsit_priv_cmd(cmd);
10658c2ecf20Sopenharmony_ci	ttinfo = &ccmd->ttinfo;
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	if (ccmd->release && ttinfo->sgl &&
10688c2ecf20Sopenharmony_ci	    (cmd->se_cmd.data_length ==	(cmd->write_data_done + data_len))) {
10698c2ecf20Sopenharmony_ci		struct cxgbit_device *cdev = csk->com.cdev;
10708c2ecf20Sopenharmony_ci		struct cxgbi_ppm *ppm = cdev2ppm(cdev);
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci		dma_unmap_sg(&ppm->pdev->dev, ttinfo->sgl, ttinfo->nents,
10738c2ecf20Sopenharmony_ci			     DMA_FROM_DEVICE);
10748c2ecf20Sopenharmony_ci		ttinfo->nents = 0;
10758c2ecf20Sopenharmony_ci		ttinfo->sgl = NULL;
10768c2ecf20Sopenharmony_ci	}
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_cicheck_payload:
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	rc = iscsit_check_dataout_payload(cmd, hdr, dcrc_err);
10818c2ecf20Sopenharmony_ci	if (rc < 0)
10828c2ecf20Sopenharmony_ci		return rc;
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	return 0;
10858c2ecf20Sopenharmony_ci}
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_cistatic int cxgbit_handle_nop_out(struct cxgbit_sock *csk, struct iscsi_cmd *cmd)
10888c2ecf20Sopenharmony_ci{
10898c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = csk->conn;
10908c2ecf20Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
10918c2ecf20Sopenharmony_ci	struct iscsi_nopout *hdr = (struct iscsi_nopout *)pdu_cb->hdr;
10928c2ecf20Sopenharmony_ci	unsigned char *ping_data = NULL;
10938c2ecf20Sopenharmony_ci	u32 payload_length = pdu_cb->dlen;
10948c2ecf20Sopenharmony_ci	int ret;
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	ret = iscsit_setup_nop_out(conn, cmd, hdr);
10978c2ecf20Sopenharmony_ci	if (ret < 0)
10988c2ecf20Sopenharmony_ci		return 0;
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci	if (pdu_cb->flags & PDUCBF_RX_DCRC_ERR) {
11018c2ecf20Sopenharmony_ci		if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
11028c2ecf20Sopenharmony_ci			pr_err("Unable to recover from"
11038c2ecf20Sopenharmony_ci			       " NOPOUT Ping DataCRC failure while in"
11048c2ecf20Sopenharmony_ci			       " ERL=0.\n");
11058c2ecf20Sopenharmony_ci			ret = -1;
11068c2ecf20Sopenharmony_ci			goto out;
11078c2ecf20Sopenharmony_ci		} else {
11088c2ecf20Sopenharmony_ci			/*
11098c2ecf20Sopenharmony_ci			 * drop this PDU and let the
11108c2ecf20Sopenharmony_ci			 * initiator plug the CmdSN gap.
11118c2ecf20Sopenharmony_ci			 */
11128c2ecf20Sopenharmony_ci			pr_info("Dropping NOPOUT"
11138c2ecf20Sopenharmony_ci				" Command CmdSN: 0x%08x due to"
11148c2ecf20Sopenharmony_ci				" DataCRC error.\n", hdr->cmdsn);
11158c2ecf20Sopenharmony_ci			ret = 0;
11168c2ecf20Sopenharmony_ci			goto out;
11178c2ecf20Sopenharmony_ci		}
11188c2ecf20Sopenharmony_ci	}
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	/*
11218c2ecf20Sopenharmony_ci	 * Handle NOP-OUT payload for traditional iSCSI sockets
11228c2ecf20Sopenharmony_ci	 */
11238c2ecf20Sopenharmony_ci	if (payload_length && hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
11248c2ecf20Sopenharmony_ci		ping_data = kzalloc(payload_length + 1, GFP_KERNEL);
11258c2ecf20Sopenharmony_ci		if (!ping_data) {
11268c2ecf20Sopenharmony_ci			pr_err("Unable to allocate memory for"
11278c2ecf20Sopenharmony_ci				" NOPOUT ping data.\n");
11288c2ecf20Sopenharmony_ci			ret = -1;
11298c2ecf20Sopenharmony_ci			goto out;
11308c2ecf20Sopenharmony_ci		}
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci		skb_copy_bits(csk->skb, pdu_cb->doffset,
11338c2ecf20Sopenharmony_ci			      ping_data, payload_length);
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci		ping_data[payload_length] = '\0';
11368c2ecf20Sopenharmony_ci		/*
11378c2ecf20Sopenharmony_ci		 * Attach ping data to struct iscsi_cmd->buf_ptr.
11388c2ecf20Sopenharmony_ci		 */
11398c2ecf20Sopenharmony_ci		cmd->buf_ptr = ping_data;
11408c2ecf20Sopenharmony_ci		cmd->buf_ptr_size = payload_length;
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci		pr_debug("Got %u bytes of NOPOUT ping"
11438c2ecf20Sopenharmony_ci			" data.\n", payload_length);
11448c2ecf20Sopenharmony_ci		pr_debug("Ping Data: \"%s\"\n", ping_data);
11458c2ecf20Sopenharmony_ci	}
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	return iscsit_process_nop_out(conn, cmd, hdr);
11488c2ecf20Sopenharmony_ciout:
11498c2ecf20Sopenharmony_ci	if (cmd)
11508c2ecf20Sopenharmony_ci		iscsit_free_cmd(cmd, false);
11518c2ecf20Sopenharmony_ci	return ret;
11528c2ecf20Sopenharmony_ci}
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_cistatic int
11558c2ecf20Sopenharmony_cicxgbit_handle_text_cmd(struct cxgbit_sock *csk, struct iscsi_cmd *cmd)
11568c2ecf20Sopenharmony_ci{
11578c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = csk->conn;
11588c2ecf20Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
11598c2ecf20Sopenharmony_ci	struct iscsi_text *hdr = (struct iscsi_text *)pdu_cb->hdr;
11608c2ecf20Sopenharmony_ci	u32 payload_length = pdu_cb->dlen;
11618c2ecf20Sopenharmony_ci	int rc;
11628c2ecf20Sopenharmony_ci	unsigned char *text_in = NULL;
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ci	rc = iscsit_setup_text_cmd(conn, cmd, hdr);
11658c2ecf20Sopenharmony_ci	if (rc < 0)
11668c2ecf20Sopenharmony_ci		return rc;
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci	if (pdu_cb->flags & PDUCBF_RX_DCRC_ERR) {
11698c2ecf20Sopenharmony_ci		if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
11708c2ecf20Sopenharmony_ci			pr_err("Unable to recover from"
11718c2ecf20Sopenharmony_ci			       " Text Data digest failure while in"
11728c2ecf20Sopenharmony_ci			       " ERL=0.\n");
11738c2ecf20Sopenharmony_ci			goto reject;
11748c2ecf20Sopenharmony_ci		} else {
11758c2ecf20Sopenharmony_ci			/*
11768c2ecf20Sopenharmony_ci			 * drop this PDU and let the
11778c2ecf20Sopenharmony_ci			 * initiator plug the CmdSN gap.
11788c2ecf20Sopenharmony_ci			 */
11798c2ecf20Sopenharmony_ci			pr_info("Dropping Text"
11808c2ecf20Sopenharmony_ci				" Command CmdSN: 0x%08x due to"
11818c2ecf20Sopenharmony_ci				" DataCRC error.\n", hdr->cmdsn);
11828c2ecf20Sopenharmony_ci			return 0;
11838c2ecf20Sopenharmony_ci		}
11848c2ecf20Sopenharmony_ci	}
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci	if (payload_length) {
11878c2ecf20Sopenharmony_ci		text_in = kzalloc(payload_length, GFP_KERNEL);
11888c2ecf20Sopenharmony_ci		if (!text_in) {
11898c2ecf20Sopenharmony_ci			pr_err("Unable to allocate text_in of payload_length: %u\n",
11908c2ecf20Sopenharmony_ci			       payload_length);
11918c2ecf20Sopenharmony_ci			return -ENOMEM;
11928c2ecf20Sopenharmony_ci		}
11938c2ecf20Sopenharmony_ci		skb_copy_bits(csk->skb, pdu_cb->doffset,
11948c2ecf20Sopenharmony_ci			      text_in, payload_length);
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci		text_in[payload_length - 1] = '\0';
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci		cmd->text_in_ptr = text_in;
11998c2ecf20Sopenharmony_ci	}
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci	return iscsit_process_text_cmd(conn, cmd, hdr);
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_cireject:
12048c2ecf20Sopenharmony_ci	return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
12058c2ecf20Sopenharmony_ci				 pdu_cb->hdr);
12068c2ecf20Sopenharmony_ci}
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_cistatic int cxgbit_target_rx_opcode(struct cxgbit_sock *csk)
12098c2ecf20Sopenharmony_ci{
12108c2ecf20Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
12118c2ecf20Sopenharmony_ci	struct iscsi_hdr *hdr = (struct iscsi_hdr *)pdu_cb->hdr;
12128c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = csk->conn;
12138c2ecf20Sopenharmony_ci	struct iscsi_cmd *cmd = NULL;
12148c2ecf20Sopenharmony_ci	u8 opcode = (hdr->opcode & ISCSI_OPCODE_MASK);
12158c2ecf20Sopenharmony_ci	int ret = -EINVAL;
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci	switch (opcode) {
12188c2ecf20Sopenharmony_ci	case ISCSI_OP_SCSI_CMD:
12198c2ecf20Sopenharmony_ci		cmd = cxgbit_allocate_cmd(csk);
12208c2ecf20Sopenharmony_ci		if (!cmd)
12218c2ecf20Sopenharmony_ci			goto reject;
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci		ret = cxgbit_handle_scsi_cmd(csk, cmd);
12248c2ecf20Sopenharmony_ci		break;
12258c2ecf20Sopenharmony_ci	case ISCSI_OP_SCSI_DATA_OUT:
12268c2ecf20Sopenharmony_ci		ret = cxgbit_handle_iscsi_dataout(csk);
12278c2ecf20Sopenharmony_ci		break;
12288c2ecf20Sopenharmony_ci	case ISCSI_OP_NOOP_OUT:
12298c2ecf20Sopenharmony_ci		if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
12308c2ecf20Sopenharmony_ci			cmd = cxgbit_allocate_cmd(csk);
12318c2ecf20Sopenharmony_ci			if (!cmd)
12328c2ecf20Sopenharmony_ci				goto reject;
12338c2ecf20Sopenharmony_ci		}
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci		ret = cxgbit_handle_nop_out(csk, cmd);
12368c2ecf20Sopenharmony_ci		break;
12378c2ecf20Sopenharmony_ci	case ISCSI_OP_SCSI_TMFUNC:
12388c2ecf20Sopenharmony_ci		cmd = cxgbit_allocate_cmd(csk);
12398c2ecf20Sopenharmony_ci		if (!cmd)
12408c2ecf20Sopenharmony_ci			goto reject;
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci		ret = iscsit_handle_task_mgt_cmd(conn, cmd,
12438c2ecf20Sopenharmony_ci						 (unsigned char *)hdr);
12448c2ecf20Sopenharmony_ci		break;
12458c2ecf20Sopenharmony_ci	case ISCSI_OP_TEXT:
12468c2ecf20Sopenharmony_ci		if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) {
12478c2ecf20Sopenharmony_ci			cmd = iscsit_find_cmd_from_itt(conn, hdr->itt);
12488c2ecf20Sopenharmony_ci			if (!cmd)
12498c2ecf20Sopenharmony_ci				goto reject;
12508c2ecf20Sopenharmony_ci		} else {
12518c2ecf20Sopenharmony_ci			cmd = cxgbit_allocate_cmd(csk);
12528c2ecf20Sopenharmony_ci			if (!cmd)
12538c2ecf20Sopenharmony_ci				goto reject;
12548c2ecf20Sopenharmony_ci		}
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci		ret = cxgbit_handle_text_cmd(csk, cmd);
12578c2ecf20Sopenharmony_ci		break;
12588c2ecf20Sopenharmony_ci	case ISCSI_OP_LOGOUT:
12598c2ecf20Sopenharmony_ci		cmd = cxgbit_allocate_cmd(csk);
12608c2ecf20Sopenharmony_ci		if (!cmd)
12618c2ecf20Sopenharmony_ci			goto reject;
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci		ret = iscsit_handle_logout_cmd(conn, cmd, (unsigned char *)hdr);
12648c2ecf20Sopenharmony_ci		if (ret > 0)
12658c2ecf20Sopenharmony_ci			wait_for_completion_timeout(&conn->conn_logout_comp,
12668c2ecf20Sopenharmony_ci						    SECONDS_FOR_LOGOUT_COMP
12678c2ecf20Sopenharmony_ci						    * HZ);
12688c2ecf20Sopenharmony_ci		break;
12698c2ecf20Sopenharmony_ci	case ISCSI_OP_SNACK:
12708c2ecf20Sopenharmony_ci		ret = iscsit_handle_snack(conn, (unsigned char *)hdr);
12718c2ecf20Sopenharmony_ci		break;
12728c2ecf20Sopenharmony_ci	default:
12738c2ecf20Sopenharmony_ci		pr_err("Got unknown iSCSI OpCode: 0x%02x\n", opcode);
12748c2ecf20Sopenharmony_ci		dump_stack();
12758c2ecf20Sopenharmony_ci		break;
12768c2ecf20Sopenharmony_ci	}
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	return ret;
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_cireject:
12818c2ecf20Sopenharmony_ci	return iscsit_add_reject(conn, ISCSI_REASON_BOOKMARK_NO_RESOURCES,
12828c2ecf20Sopenharmony_ci				 (unsigned char *)hdr);
12838c2ecf20Sopenharmony_ci	return ret;
12848c2ecf20Sopenharmony_ci}
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_cistatic int cxgbit_rx_opcode(struct cxgbit_sock *csk)
12878c2ecf20Sopenharmony_ci{
12888c2ecf20Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
12898c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = csk->conn;
12908c2ecf20Sopenharmony_ci	struct iscsi_hdr *hdr = pdu_cb->hdr;
12918c2ecf20Sopenharmony_ci	u8 opcode;
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci	if (pdu_cb->flags & PDUCBF_RX_HCRC_ERR) {
12948c2ecf20Sopenharmony_ci		atomic_long_inc(&conn->sess->conn_digest_errors);
12958c2ecf20Sopenharmony_ci		goto transport_err;
12968c2ecf20Sopenharmony_ci	}
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci	if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT)
12998c2ecf20Sopenharmony_ci		goto transport_err;
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci	opcode = hdr->opcode & ISCSI_OPCODE_MASK;
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	if (conn->sess->sess_ops->SessionType &&
13048c2ecf20Sopenharmony_ci	    ((!(opcode & ISCSI_OP_TEXT)) ||
13058c2ecf20Sopenharmony_ci	     (!(opcode & ISCSI_OP_LOGOUT)))) {
13068c2ecf20Sopenharmony_ci		pr_err("Received illegal iSCSI Opcode: 0x%02x"
13078c2ecf20Sopenharmony_ci			" while in Discovery Session, rejecting.\n", opcode);
13088c2ecf20Sopenharmony_ci		iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
13098c2ecf20Sopenharmony_ci				  (unsigned char *)hdr);
13108c2ecf20Sopenharmony_ci		goto transport_err;
13118c2ecf20Sopenharmony_ci	}
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ci	if (cxgbit_target_rx_opcode(csk) < 0)
13148c2ecf20Sopenharmony_ci		goto transport_err;
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci	return 0;
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_citransport_err:
13198c2ecf20Sopenharmony_ci	return -1;
13208c2ecf20Sopenharmony_ci}
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_cistatic int cxgbit_rx_login_pdu(struct cxgbit_sock *csk)
13238c2ecf20Sopenharmony_ci{
13248c2ecf20Sopenharmony_ci	struct iscsi_conn *conn = csk->conn;
13258c2ecf20Sopenharmony_ci	struct iscsi_login *login = conn->login;
13268c2ecf20Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
13278c2ecf20Sopenharmony_ci	struct iscsi_login_req *login_req;
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci	login_req = (struct iscsi_login_req *)login->req;
13308c2ecf20Sopenharmony_ci	memcpy(login_req, pdu_cb->hdr, sizeof(*login_req));
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci	pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x,"
13338c2ecf20Sopenharmony_ci		" CmdSN: 0x%08x, ExpStatSN: 0x%08x, CID: %hu, Length: %u\n",
13348c2ecf20Sopenharmony_ci		login_req->flags, login_req->itt, login_req->cmdsn,
13358c2ecf20Sopenharmony_ci		login_req->exp_statsn, login_req->cid, pdu_cb->dlen);
13368c2ecf20Sopenharmony_ci	/*
13378c2ecf20Sopenharmony_ci	 * Setup the initial iscsi_login values from the leading
13388c2ecf20Sopenharmony_ci	 * login request PDU.
13398c2ecf20Sopenharmony_ci	 */
13408c2ecf20Sopenharmony_ci	if (login->first_request) {
13418c2ecf20Sopenharmony_ci		login_req = (struct iscsi_login_req *)login->req;
13428c2ecf20Sopenharmony_ci		login->leading_connection = (!login_req->tsih) ? 1 : 0;
13438c2ecf20Sopenharmony_ci		login->current_stage	= ISCSI_LOGIN_CURRENT_STAGE(
13448c2ecf20Sopenharmony_ci				login_req->flags);
13458c2ecf20Sopenharmony_ci		login->version_min	= login_req->min_version;
13468c2ecf20Sopenharmony_ci		login->version_max	= login_req->max_version;
13478c2ecf20Sopenharmony_ci		memcpy(login->isid, login_req->isid, 6);
13488c2ecf20Sopenharmony_ci		login->cmd_sn		= be32_to_cpu(login_req->cmdsn);
13498c2ecf20Sopenharmony_ci		login->init_task_tag	= login_req->itt;
13508c2ecf20Sopenharmony_ci		login->initial_exp_statsn = be32_to_cpu(login_req->exp_statsn);
13518c2ecf20Sopenharmony_ci		login->cid		= be16_to_cpu(login_req->cid);
13528c2ecf20Sopenharmony_ci		login->tsih		= be16_to_cpu(login_req->tsih);
13538c2ecf20Sopenharmony_ci	}
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci	if (iscsi_target_check_login_request(conn, login) < 0)
13568c2ecf20Sopenharmony_ci		return -1;
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci	memset(login->req_buf, 0, MAX_KEY_VALUE_PAIRS);
13598c2ecf20Sopenharmony_ci	skb_copy_bits(csk->skb, pdu_cb->doffset, login->req_buf, pdu_cb->dlen);
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	return 0;
13628c2ecf20Sopenharmony_ci}
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_cistatic int
13658c2ecf20Sopenharmony_cicxgbit_process_iscsi_pdu(struct cxgbit_sock *csk, struct sk_buff *skb, int idx)
13668c2ecf20Sopenharmony_ci{
13678c2ecf20Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, idx);
13688c2ecf20Sopenharmony_ci	int ret;
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci	cxgbit_rx_pdu_cb(skb) = pdu_cb;
13718c2ecf20Sopenharmony_ci
13728c2ecf20Sopenharmony_ci	csk->skb = skb;
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	if (!test_bit(CSK_LOGIN_DONE, &csk->com.flags)) {
13758c2ecf20Sopenharmony_ci		ret = cxgbit_rx_login_pdu(csk);
13768c2ecf20Sopenharmony_ci		set_bit(CSK_LOGIN_PDU_DONE, &csk->com.flags);
13778c2ecf20Sopenharmony_ci	} else {
13788c2ecf20Sopenharmony_ci		ret = cxgbit_rx_opcode(csk);
13798c2ecf20Sopenharmony_ci	}
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci	return ret;
13828c2ecf20Sopenharmony_ci}
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_cistatic void cxgbit_lro_skb_dump(struct sk_buff *skb)
13858c2ecf20Sopenharmony_ci{
13868c2ecf20Sopenharmony_ci	struct skb_shared_info *ssi = skb_shinfo(skb);
13878c2ecf20Sopenharmony_ci	struct cxgbit_lro_cb *lro_cb = cxgbit_skb_lro_cb(skb);
13888c2ecf20Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, 0);
13898c2ecf20Sopenharmony_ci	u8 i;
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci	pr_info("skb 0x%p, head 0x%p, 0x%p, len %u,%u, frags %u.\n",
13928c2ecf20Sopenharmony_ci		skb, skb->head, skb->data, skb->len, skb->data_len,
13938c2ecf20Sopenharmony_ci		ssi->nr_frags);
13948c2ecf20Sopenharmony_ci	pr_info("skb 0x%p, lro_cb, csk 0x%p, pdu %u, %u.\n",
13958c2ecf20Sopenharmony_ci		skb, lro_cb->csk, lro_cb->pdu_idx, lro_cb->pdu_totallen);
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci	for (i = 0; i < lro_cb->pdu_idx; i++, pdu_cb++)
13988c2ecf20Sopenharmony_ci		pr_info("skb 0x%p, pdu %d, %u, f 0x%x, seq 0x%x, dcrc 0x%x, "
13998c2ecf20Sopenharmony_ci			"frags %u.\n",
14008c2ecf20Sopenharmony_ci			skb, i, pdu_cb->pdulen, pdu_cb->flags, pdu_cb->seq,
14018c2ecf20Sopenharmony_ci			pdu_cb->ddigest, pdu_cb->frags);
14028c2ecf20Sopenharmony_ci	for (i = 0; i < ssi->nr_frags; i++)
14038c2ecf20Sopenharmony_ci		pr_info("skb 0x%p, frag %d, off %u, sz %u.\n",
14048c2ecf20Sopenharmony_ci			skb, i, skb_frag_off(&ssi->frags[i]),
14058c2ecf20Sopenharmony_ci			skb_frag_size(&ssi->frags[i]));
14068c2ecf20Sopenharmony_ci}
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_cistatic void cxgbit_lro_hskb_reset(struct cxgbit_sock *csk)
14098c2ecf20Sopenharmony_ci{
14108c2ecf20Sopenharmony_ci	struct sk_buff *skb = csk->lro_hskb;
14118c2ecf20Sopenharmony_ci	struct skb_shared_info *ssi = skb_shinfo(skb);
14128c2ecf20Sopenharmony_ci	u8 i;
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_ci	memset(skb->data, 0, LRO_SKB_MIN_HEADROOM);
14158c2ecf20Sopenharmony_ci	for (i = 0; i < ssi->nr_frags; i++)
14168c2ecf20Sopenharmony_ci		put_page(skb_frag_page(&ssi->frags[i]));
14178c2ecf20Sopenharmony_ci	ssi->nr_frags = 0;
14188c2ecf20Sopenharmony_ci	skb->data_len = 0;
14198c2ecf20Sopenharmony_ci	skb->truesize -= skb->len;
14208c2ecf20Sopenharmony_ci	skb->len = 0;
14218c2ecf20Sopenharmony_ci}
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_cistatic void
14248c2ecf20Sopenharmony_cicxgbit_lro_skb_merge(struct cxgbit_sock *csk, struct sk_buff *skb, u8 pdu_idx)
14258c2ecf20Sopenharmony_ci{
14268c2ecf20Sopenharmony_ci	struct sk_buff *hskb = csk->lro_hskb;
14278c2ecf20Sopenharmony_ci	struct cxgbit_lro_pdu_cb *hpdu_cb = cxgbit_skb_lro_pdu_cb(hskb, 0);
14288c2ecf20Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, pdu_idx);
14298c2ecf20Sopenharmony_ci	struct skb_shared_info *hssi = skb_shinfo(hskb);
14308c2ecf20Sopenharmony_ci	struct skb_shared_info *ssi = skb_shinfo(skb);
14318c2ecf20Sopenharmony_ci	unsigned int len = 0;
14328c2ecf20Sopenharmony_ci
14338c2ecf20Sopenharmony_ci	if (pdu_cb->flags & PDUCBF_RX_HDR) {
14348c2ecf20Sopenharmony_ci		u8 hfrag_idx = hssi->nr_frags;
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci		hpdu_cb->flags |= pdu_cb->flags;
14378c2ecf20Sopenharmony_ci		hpdu_cb->seq = pdu_cb->seq;
14388c2ecf20Sopenharmony_ci		hpdu_cb->hdr = pdu_cb->hdr;
14398c2ecf20Sopenharmony_ci		hpdu_cb->hlen = pdu_cb->hlen;
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci		memcpy(&hssi->frags[hfrag_idx], &ssi->frags[pdu_cb->hfrag_idx],
14428c2ecf20Sopenharmony_ci		       sizeof(skb_frag_t));
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci		get_page(skb_frag_page(&hssi->frags[hfrag_idx]));
14458c2ecf20Sopenharmony_ci		hssi->nr_frags++;
14468c2ecf20Sopenharmony_ci		hpdu_cb->frags++;
14478c2ecf20Sopenharmony_ci		hpdu_cb->hfrag_idx = hfrag_idx;
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci		len = skb_frag_size(&hssi->frags[hfrag_idx]);
14508c2ecf20Sopenharmony_ci		hskb->len += len;
14518c2ecf20Sopenharmony_ci		hskb->data_len += len;
14528c2ecf20Sopenharmony_ci		hskb->truesize += len;
14538c2ecf20Sopenharmony_ci	}
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci	if (pdu_cb->flags & PDUCBF_RX_DATA) {
14568c2ecf20Sopenharmony_ci		u8 dfrag_idx = hssi->nr_frags, i;
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci		hpdu_cb->flags |= pdu_cb->flags;
14598c2ecf20Sopenharmony_ci		hpdu_cb->dfrag_idx = dfrag_idx;
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci		len = 0;
14628c2ecf20Sopenharmony_ci		for (i = 0; i < pdu_cb->nr_dfrags; dfrag_idx++, i++) {
14638c2ecf20Sopenharmony_ci			memcpy(&hssi->frags[dfrag_idx],
14648c2ecf20Sopenharmony_ci			       &ssi->frags[pdu_cb->dfrag_idx + i],
14658c2ecf20Sopenharmony_ci			       sizeof(skb_frag_t));
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci			get_page(skb_frag_page(&hssi->frags[dfrag_idx]));
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_ci			len += skb_frag_size(&hssi->frags[dfrag_idx]);
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_ci			hssi->nr_frags++;
14728c2ecf20Sopenharmony_ci			hpdu_cb->frags++;
14738c2ecf20Sopenharmony_ci		}
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci		hpdu_cb->dlen = pdu_cb->dlen;
14768c2ecf20Sopenharmony_ci		hpdu_cb->doffset = hpdu_cb->hlen;
14778c2ecf20Sopenharmony_ci		hpdu_cb->nr_dfrags = pdu_cb->nr_dfrags;
14788c2ecf20Sopenharmony_ci		hskb->len += len;
14798c2ecf20Sopenharmony_ci		hskb->data_len += len;
14808c2ecf20Sopenharmony_ci		hskb->truesize += len;
14818c2ecf20Sopenharmony_ci	}
14828c2ecf20Sopenharmony_ci
14838c2ecf20Sopenharmony_ci	if (pdu_cb->flags & PDUCBF_RX_STATUS) {
14848c2ecf20Sopenharmony_ci		hpdu_cb->flags |= pdu_cb->flags;
14858c2ecf20Sopenharmony_ci
14868c2ecf20Sopenharmony_ci		if (hpdu_cb->flags & PDUCBF_RX_DATA)
14878c2ecf20Sopenharmony_ci			hpdu_cb->flags &= ~PDUCBF_RX_DATA_DDPD;
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci		hpdu_cb->ddigest = pdu_cb->ddigest;
14908c2ecf20Sopenharmony_ci		hpdu_cb->pdulen = pdu_cb->pdulen;
14918c2ecf20Sopenharmony_ci	}
14928c2ecf20Sopenharmony_ci}
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_cistatic int cxgbit_process_lro_skb(struct cxgbit_sock *csk, struct sk_buff *skb)
14958c2ecf20Sopenharmony_ci{
14968c2ecf20Sopenharmony_ci	struct cxgbit_lro_cb *lro_cb = cxgbit_skb_lro_cb(skb);
14978c2ecf20Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, 0);
14988c2ecf20Sopenharmony_ci	u8 pdu_idx = 0, last_idx = 0;
14998c2ecf20Sopenharmony_ci	int ret = 0;
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci	if (!pdu_cb->complete) {
15028c2ecf20Sopenharmony_ci		cxgbit_lro_skb_merge(csk, skb, 0);
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci		if (pdu_cb->flags & PDUCBF_RX_STATUS) {
15058c2ecf20Sopenharmony_ci			struct sk_buff *hskb = csk->lro_hskb;
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_ci			ret = cxgbit_process_iscsi_pdu(csk, hskb, 0);
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ci			cxgbit_lro_hskb_reset(csk);
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci			if (ret < 0)
15128c2ecf20Sopenharmony_ci				goto out;
15138c2ecf20Sopenharmony_ci		}
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci		pdu_idx = 1;
15168c2ecf20Sopenharmony_ci	}
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci	if (lro_cb->pdu_idx)
15198c2ecf20Sopenharmony_ci		last_idx = lro_cb->pdu_idx - 1;
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_ci	for (; pdu_idx <= last_idx; pdu_idx++) {
15228c2ecf20Sopenharmony_ci		ret = cxgbit_process_iscsi_pdu(csk, skb, pdu_idx);
15238c2ecf20Sopenharmony_ci		if (ret < 0)
15248c2ecf20Sopenharmony_ci			goto out;
15258c2ecf20Sopenharmony_ci	}
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci	if ((!lro_cb->complete) && lro_cb->pdu_idx)
15288c2ecf20Sopenharmony_ci		cxgbit_lro_skb_merge(csk, skb, lro_cb->pdu_idx);
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ciout:
15318c2ecf20Sopenharmony_ci	return ret;
15328c2ecf20Sopenharmony_ci}
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_cistatic int cxgbit_rx_lro_skb(struct cxgbit_sock *csk, struct sk_buff *skb)
15358c2ecf20Sopenharmony_ci{
15368c2ecf20Sopenharmony_ci	struct cxgbit_lro_cb *lro_cb = cxgbit_skb_lro_cb(skb);
15378c2ecf20Sopenharmony_ci	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, 0);
15388c2ecf20Sopenharmony_ci	int ret = -1;
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci	if ((pdu_cb->flags & PDUCBF_RX_HDR) &&
15418c2ecf20Sopenharmony_ci	    (pdu_cb->seq != csk->rcv_nxt)) {
15428c2ecf20Sopenharmony_ci		pr_info("csk 0x%p, tid 0x%x, seq 0x%x != 0x%x.\n",
15438c2ecf20Sopenharmony_ci			csk, csk->tid, pdu_cb->seq, csk->rcv_nxt);
15448c2ecf20Sopenharmony_ci		cxgbit_lro_skb_dump(skb);
15458c2ecf20Sopenharmony_ci		return ret;
15468c2ecf20Sopenharmony_ci	}
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci	csk->rcv_nxt += lro_cb->pdu_totallen;
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_ci	ret = cxgbit_process_lro_skb(csk, skb);
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci	csk->rx_credits += lro_cb->pdu_totallen;
15538c2ecf20Sopenharmony_ci
15548c2ecf20Sopenharmony_ci	if (csk->rx_credits >= (csk->rcv_win / 4))
15558c2ecf20Sopenharmony_ci		cxgbit_rx_data_ack(csk);
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_ci	return ret;
15588c2ecf20Sopenharmony_ci}
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_cistatic int cxgbit_rx_skb(struct cxgbit_sock *csk, struct sk_buff *skb)
15618c2ecf20Sopenharmony_ci{
15628c2ecf20Sopenharmony_ci	struct cxgb4_lld_info *lldi = &csk->com.cdev->lldi;
15638c2ecf20Sopenharmony_ci	int ret = -1;
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_ci	if (likely(cxgbit_skcb_flags(skb) & SKCBF_RX_LRO)) {
15668c2ecf20Sopenharmony_ci		if (is_t5(lldi->adapter_type))
15678c2ecf20Sopenharmony_ci			ret = cxgbit_rx_lro_skb(csk, skb);
15688c2ecf20Sopenharmony_ci		else
15698c2ecf20Sopenharmony_ci			ret = cxgbit_process_lro_skb(csk, skb);
15708c2ecf20Sopenharmony_ci	}
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci	__kfree_skb(skb);
15738c2ecf20Sopenharmony_ci	return ret;
15748c2ecf20Sopenharmony_ci}
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_cistatic bool cxgbit_rxq_len(struct cxgbit_sock *csk, struct sk_buff_head *rxq)
15778c2ecf20Sopenharmony_ci{
15788c2ecf20Sopenharmony_ci	spin_lock_bh(&csk->rxq.lock);
15798c2ecf20Sopenharmony_ci	if (skb_queue_len(&csk->rxq)) {
15808c2ecf20Sopenharmony_ci		skb_queue_splice_init(&csk->rxq, rxq);
15818c2ecf20Sopenharmony_ci		spin_unlock_bh(&csk->rxq.lock);
15828c2ecf20Sopenharmony_ci		return true;
15838c2ecf20Sopenharmony_ci	}
15848c2ecf20Sopenharmony_ci	spin_unlock_bh(&csk->rxq.lock);
15858c2ecf20Sopenharmony_ci	return false;
15868c2ecf20Sopenharmony_ci}
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_cistatic int cxgbit_wait_rxq(struct cxgbit_sock *csk)
15898c2ecf20Sopenharmony_ci{
15908c2ecf20Sopenharmony_ci	struct sk_buff *skb;
15918c2ecf20Sopenharmony_ci	struct sk_buff_head rxq;
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci	skb_queue_head_init(&rxq);
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_ci	wait_event_interruptible(csk->waitq, cxgbit_rxq_len(csk, &rxq));
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci	if (signal_pending(current))
15988c2ecf20Sopenharmony_ci		goto out;
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_ci	while ((skb = __skb_dequeue(&rxq))) {
16018c2ecf20Sopenharmony_ci		if (cxgbit_rx_skb(csk, skb))
16028c2ecf20Sopenharmony_ci			goto out;
16038c2ecf20Sopenharmony_ci	}
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci	return 0;
16068c2ecf20Sopenharmony_ciout:
16078c2ecf20Sopenharmony_ci	__skb_queue_purge(&rxq);
16088c2ecf20Sopenharmony_ci	return -1;
16098c2ecf20Sopenharmony_ci}
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_ciint cxgbit_get_login_rx(struct iscsi_conn *conn, struct iscsi_login *login)
16128c2ecf20Sopenharmony_ci{
16138c2ecf20Sopenharmony_ci	struct cxgbit_sock *csk = conn->context;
16148c2ecf20Sopenharmony_ci	int ret = -1;
16158c2ecf20Sopenharmony_ci
16168c2ecf20Sopenharmony_ci	while (!test_and_clear_bit(CSK_LOGIN_PDU_DONE, &csk->com.flags)) {
16178c2ecf20Sopenharmony_ci		ret = cxgbit_wait_rxq(csk);
16188c2ecf20Sopenharmony_ci		if (ret) {
16198c2ecf20Sopenharmony_ci			clear_bit(CSK_LOGIN_PDU_DONE, &csk->com.flags);
16208c2ecf20Sopenharmony_ci			break;
16218c2ecf20Sopenharmony_ci		}
16228c2ecf20Sopenharmony_ci	}
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci	return ret;
16258c2ecf20Sopenharmony_ci}
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_civoid cxgbit_get_rx_pdu(struct iscsi_conn *conn)
16288c2ecf20Sopenharmony_ci{
16298c2ecf20Sopenharmony_ci	struct cxgbit_sock *csk = conn->context;
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_ci	while (!kthread_should_stop()) {
16328c2ecf20Sopenharmony_ci		iscsit_thread_check_cpumask(conn, current, 0);
16338c2ecf20Sopenharmony_ci		if (cxgbit_wait_rxq(csk))
16348c2ecf20Sopenharmony_ci			return;
16358c2ecf20Sopenharmony_ci	}
16368c2ecf20Sopenharmony_ci}
1637