1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
29730ffcbSVarun Prakash /*
39730ffcbSVarun Prakash  * Copyright (c) 2016 Chelsio Communications, Inc.
49730ffcbSVarun Prakash  */
59730ffcbSVarun Prakash 
69730ffcbSVarun Prakash #include <linux/workqueue.h>
79730ffcbSVarun Prakash #include <linux/kthread.h>
8174cd4b1SIngo Molnar #include <linux/sched/signal.h>
9174cd4b1SIngo Molnar 
109730ffcbSVarun Prakash #include <asm/unaligned.h>
113bc71e1fSBart Van Assche #include <net/tcp.h>
129730ffcbSVarun Prakash #include <target/target_core_base.h>
139730ffcbSVarun Prakash #include <target/target_core_fabric.h>
149730ffcbSVarun Prakash #include "cxgbit.h"
159730ffcbSVarun Prakash 
169730ffcbSVarun Prakash struct sge_opaque_hdr {
179730ffcbSVarun Prakash 	void *dev;
189730ffcbSVarun Prakash 	dma_addr_t addr[MAX_SKB_FRAGS + 1];
199730ffcbSVarun Prakash };
209730ffcbSVarun Prakash 
219730ffcbSVarun Prakash static const u8 cxgbit_digest_len[] = {0, 4, 4, 8};
229730ffcbSVarun Prakash 
239730ffcbSVarun Prakash #define TX_HDR_LEN (sizeof(struct sge_opaque_hdr) + \
249730ffcbSVarun Prakash 		    sizeof(struct fw_ofld_tx_data_wr))
259730ffcbSVarun Prakash 
269730ffcbSVarun Prakash static struct sk_buff *
__cxgbit_alloc_skb(struct cxgbit_sock * csk,u32 len,bool iso)279730ffcbSVarun Prakash __cxgbit_alloc_skb(struct cxgbit_sock *csk, u32 len, bool iso)
289730ffcbSVarun Prakash {
299730ffcbSVarun Prakash 	struct sk_buff *skb = NULL;
309730ffcbSVarun Prakash 	u8 submode = 0;
319730ffcbSVarun Prakash 	int errcode;
329730ffcbSVarun Prakash 	static const u32 hdr_len = TX_HDR_LEN + ISCSI_HDR_LEN;
339730ffcbSVarun Prakash 
349730ffcbSVarun Prakash 	if (len) {
359730ffcbSVarun Prakash 		skb = alloc_skb_with_frags(hdr_len, len,
369730ffcbSVarun Prakash 					   0, &errcode,
379730ffcbSVarun Prakash 					   GFP_KERNEL);
389730ffcbSVarun Prakash 		if (!skb)
399730ffcbSVarun Prakash 			return NULL;
409730ffcbSVarun Prakash 
419730ffcbSVarun Prakash 		skb_reserve(skb, TX_HDR_LEN);
429730ffcbSVarun Prakash 		skb_reset_transport_header(skb);
439730ffcbSVarun Prakash 		__skb_put(skb, ISCSI_HDR_LEN);
449730ffcbSVarun Prakash 		skb->data_len = len;
459730ffcbSVarun Prakash 		skb->len += len;
469730ffcbSVarun Prakash 		submode |= (csk->submode & CXGBIT_SUBMODE_DCRC);
479730ffcbSVarun Prakash 
489730ffcbSVarun Prakash 	} else {
499730ffcbSVarun Prakash 		u32 iso_len = iso ? sizeof(struct cpl_tx_data_iso) : 0;
509730ffcbSVarun Prakash 
519730ffcbSVarun Prakash 		skb = alloc_skb(hdr_len + iso_len, GFP_KERNEL);
529730ffcbSVarun Prakash 		if (!skb)
539730ffcbSVarun Prakash 			return NULL;
549730ffcbSVarun Prakash 
559730ffcbSVarun Prakash 		skb_reserve(skb, TX_HDR_LEN + iso_len);
569730ffcbSVarun Prakash 		skb_reset_transport_header(skb);
579730ffcbSVarun Prakash 		__skb_put(skb, ISCSI_HDR_LEN);
589730ffcbSVarun Prakash 	}
599730ffcbSVarun Prakash 
609730ffcbSVarun Prakash 	submode |= (csk->submode & CXGBIT_SUBMODE_HCRC);
619730ffcbSVarun Prakash 	cxgbit_skcb_submode(skb) = submode;
629730ffcbSVarun Prakash 	cxgbit_skcb_tx_extralen(skb) = cxgbit_digest_len[submode];
639730ffcbSVarun Prakash 	cxgbit_skcb_flags(skb) |= SKCBF_TX_NEED_HDR;
649730ffcbSVarun Prakash 	return skb;
659730ffcbSVarun Prakash }
669730ffcbSVarun Prakash 
cxgbit_alloc_skb(struct cxgbit_sock * csk,u32 len)679730ffcbSVarun Prakash static struct sk_buff *cxgbit_alloc_skb(struct cxgbit_sock *csk, u32 len)
689730ffcbSVarun Prakash {
699730ffcbSVarun Prakash 	return __cxgbit_alloc_skb(csk, len, false);
709730ffcbSVarun Prakash }
719730ffcbSVarun Prakash 
729730ffcbSVarun Prakash /*
739730ffcbSVarun Prakash  * cxgbit_is_ofld_imm - check whether a packet can be sent as immediate data
749730ffcbSVarun Prakash  * @skb: the packet
759730ffcbSVarun Prakash  *
769730ffcbSVarun Prakash  * Returns true if a packet can be sent as an offload WR with immediate
779730ffcbSVarun Prakash  * data.  We currently use the same limit as for Ethernet packets.
789730ffcbSVarun Prakash  */
cxgbit_is_ofld_imm(const struct sk_buff * skb)799730ffcbSVarun Prakash static int cxgbit_is_ofld_imm(const struct sk_buff *skb)
809730ffcbSVarun Prakash {
819730ffcbSVarun Prakash 	int length = skb->len;
829730ffcbSVarun Prakash 
839730ffcbSVarun Prakash 	if (likely(cxgbit_skcb_flags(skb) & SKCBF_TX_NEED_HDR))
849730ffcbSVarun Prakash 		length += sizeof(struct fw_ofld_tx_data_wr);
859730ffcbSVarun Prakash 
869730ffcbSVarun Prakash 	if (likely(cxgbit_skcb_flags(skb) & SKCBF_TX_ISO))
879730ffcbSVarun Prakash 		length += sizeof(struct cpl_tx_data_iso);
889730ffcbSVarun Prakash 
892355a677SAyush Sawal 	return length <= MAX_IMM_OFLD_TX_DATA_WR_LEN;
909730ffcbSVarun Prakash }
919730ffcbSVarun Prakash 
929730ffcbSVarun Prakash /*
939730ffcbSVarun Prakash  * cxgbit_sgl_len - calculates the size of an SGL of the given capacity
949730ffcbSVarun Prakash  * @n: the number of SGL entries
959730ffcbSVarun Prakash  * Calculates the number of flits needed for a scatter/gather list that
969730ffcbSVarun Prakash  * can hold the given number of entries.
979730ffcbSVarun Prakash  */
cxgbit_sgl_len(unsigned int n)989730ffcbSVarun Prakash static inline unsigned int cxgbit_sgl_len(unsigned int n)
999730ffcbSVarun Prakash {
1009730ffcbSVarun Prakash 	n--;
1019730ffcbSVarun Prakash 	return (3 * n) / 2 + (n & 1) + 2;
1029730ffcbSVarun Prakash }
1039730ffcbSVarun Prakash 
1049730ffcbSVarun Prakash /*
1059730ffcbSVarun Prakash  * cxgbit_calc_tx_flits_ofld - calculate # of flits for an offload packet
1069730ffcbSVarun Prakash  * @skb: the packet
1079730ffcbSVarun Prakash  *
1089730ffcbSVarun Prakash  * Returns the number of flits needed for the given offload packet.
1099730ffcbSVarun Prakash  * These packets are already fully constructed and no additional headers
1109730ffcbSVarun Prakash  * will be added.
1119730ffcbSVarun Prakash  */
cxgbit_calc_tx_flits_ofld(const struct sk_buff * skb)1129730ffcbSVarun Prakash static unsigned int cxgbit_calc_tx_flits_ofld(const struct sk_buff *skb)
1139730ffcbSVarun Prakash {
1149730ffcbSVarun Prakash 	unsigned int flits, cnt;
1159730ffcbSVarun Prakash 
1169730ffcbSVarun Prakash 	if (cxgbit_is_ofld_imm(skb))
1179730ffcbSVarun Prakash 		return DIV_ROUND_UP(skb->len, 8);
1189730ffcbSVarun Prakash 	flits = skb_transport_offset(skb) / 8;
1199730ffcbSVarun Prakash 	cnt = skb_shinfo(skb)->nr_frags;
1209730ffcbSVarun Prakash 	if (skb_tail_pointer(skb) != skb_transport_header(skb))
1219730ffcbSVarun Prakash 		cnt++;
1229730ffcbSVarun Prakash 	return flits + cxgbit_sgl_len(cnt);
1239730ffcbSVarun Prakash }
1249730ffcbSVarun Prakash 
1259730ffcbSVarun Prakash #define CXGBIT_ISO_FSLICE 0x1
1269730ffcbSVarun Prakash #define CXGBIT_ISO_LSLICE 0x2
1279730ffcbSVarun Prakash static void
cxgbit_cpl_tx_data_iso(struct sk_buff * skb,struct cxgbit_iso_info * iso_info)1289730ffcbSVarun Prakash cxgbit_cpl_tx_data_iso(struct sk_buff *skb, struct cxgbit_iso_info *iso_info)
1299730ffcbSVarun Prakash {
1309730ffcbSVarun Prakash 	struct cpl_tx_data_iso *cpl;
1319730ffcbSVarun Prakash 	unsigned int submode = cxgbit_skcb_submode(skb);
1329730ffcbSVarun Prakash 	unsigned int fslice = !!(iso_info->flags & CXGBIT_ISO_FSLICE);
1339730ffcbSVarun Prakash 	unsigned int lslice = !!(iso_info->flags & CXGBIT_ISO_LSLICE);
1349730ffcbSVarun Prakash 
135d58ff351SJohannes Berg 	cpl = __skb_push(skb, sizeof(*cpl));
1369730ffcbSVarun Prakash 
1379730ffcbSVarun Prakash 	cpl->op_to_scsi = htonl(CPL_TX_DATA_ISO_OP_V(CPL_TX_DATA_ISO) |
1389730ffcbSVarun Prakash 			CPL_TX_DATA_ISO_FIRST_V(fslice) |
1399730ffcbSVarun Prakash 			CPL_TX_DATA_ISO_LAST_V(lslice) |
1409730ffcbSVarun Prakash 			CPL_TX_DATA_ISO_CPLHDRLEN_V(0) |
1419730ffcbSVarun Prakash 			CPL_TX_DATA_ISO_HDRCRC_V(submode & 1) |
1429730ffcbSVarun Prakash 			CPL_TX_DATA_ISO_PLDCRC_V(((submode >> 1) & 1)) |
1439730ffcbSVarun Prakash 			CPL_TX_DATA_ISO_IMMEDIATE_V(0) |
1449730ffcbSVarun Prakash 			CPL_TX_DATA_ISO_SCSI_V(2));
1459730ffcbSVarun Prakash 
1469730ffcbSVarun Prakash 	cpl->ahs_len = 0;
1479730ffcbSVarun Prakash 	cpl->mpdu = htons(DIV_ROUND_UP(iso_info->mpdu, 4));
1489730ffcbSVarun Prakash 	cpl->burst_size = htonl(DIV_ROUND_UP(iso_info->burst_len, 4));
1499730ffcbSVarun Prakash 	cpl->len = htonl(iso_info->len);
1509730ffcbSVarun Prakash 	cpl->reserved2_seglen_offset = htonl(0);
1519730ffcbSVarun Prakash 	cpl->datasn_offset = htonl(0);
1529730ffcbSVarun Prakash 	cpl->buffer_offset = htonl(0);
1539730ffcbSVarun Prakash 	cpl->reserved3 = 0;
1549730ffcbSVarun Prakash 
1559730ffcbSVarun Prakash 	__skb_pull(skb, sizeof(*cpl));
1569730ffcbSVarun Prakash }
1579730ffcbSVarun Prakash 
1589730ffcbSVarun Prakash static void
cxgbit_tx_data_wr(struct cxgbit_sock * csk,struct sk_buff * skb,u32 dlen,u32 len,u32 credits,u32 compl)1599730ffcbSVarun Prakash cxgbit_tx_data_wr(struct cxgbit_sock *csk, struct sk_buff *skb, u32 dlen,
1609730ffcbSVarun Prakash 		  u32 len, u32 credits, u32 compl)
1619730ffcbSVarun Prakash {
1629730ffcbSVarun Prakash 	struct fw_ofld_tx_data_wr *req;
163bdec5188SVarun Prakash 	const struct cxgb4_lld_info *lldi = &csk->com.cdev->lldi;
1649730ffcbSVarun Prakash 	u32 submode = cxgbit_skcb_submode(skb);
1659730ffcbSVarun Prakash 	u32 wr_ulp_mode = 0;
1669730ffcbSVarun Prakash 	u32 hdr_size = sizeof(*req);
1679730ffcbSVarun Prakash 	u32 opcode = FW_OFLD_TX_DATA_WR;
1689730ffcbSVarun Prakash 	u32 immlen = 0;
169bdec5188SVarun Prakash 	u32 force = is_t5(lldi->adapter_type) ? TX_FORCE_V(!submode) :
170bdec5188SVarun Prakash 		    T6_TX_FORCE_F;
1719730ffcbSVarun Prakash 
1729730ffcbSVarun Prakash 	if (cxgbit_skcb_flags(skb) & SKCBF_TX_ISO) {
1739730ffcbSVarun Prakash 		opcode = FW_ISCSI_TX_DATA_WR;
1749730ffcbSVarun Prakash 		immlen += sizeof(struct cpl_tx_data_iso);
1759730ffcbSVarun Prakash 		hdr_size += sizeof(struct cpl_tx_data_iso);
1769730ffcbSVarun Prakash 		submode |= 8;
1779730ffcbSVarun Prakash 	}
1789730ffcbSVarun Prakash 
1799730ffcbSVarun Prakash 	if (cxgbit_is_ofld_imm(skb))
1809730ffcbSVarun Prakash 		immlen += dlen;
1819730ffcbSVarun Prakash 
182d58ff351SJohannes Berg 	req = __skb_push(skb, hdr_size);
1839730ffcbSVarun Prakash 	req->op_to_immdlen = cpu_to_be32(FW_WR_OP_V(opcode) |
1849730ffcbSVarun Prakash 					FW_WR_COMPL_V(compl) |
1859730ffcbSVarun Prakash 					FW_WR_IMMDLEN_V(immlen));
1869730ffcbSVarun Prakash 	req->flowid_len16 = cpu_to_be32(FW_WR_FLOWID_V(csk->tid) |
1879730ffcbSVarun Prakash 					FW_WR_LEN16_V(credits));
1889730ffcbSVarun Prakash 	req->plen = htonl(len);
1899730ffcbSVarun Prakash 	wr_ulp_mode = FW_OFLD_TX_DATA_WR_ULPMODE_V(ULP_MODE_ISCSI) |
1909730ffcbSVarun Prakash 				FW_OFLD_TX_DATA_WR_ULPSUBMODE_V(submode);
1919730ffcbSVarun Prakash 
192d1e51ea6SVarun Prakash 	req->tunnel_to_proxy = htonl(wr_ulp_mode | force |
193d1e51ea6SVarun Prakash 				     FW_OFLD_TX_DATA_WR_SHOVE_F);
1949730ffcbSVarun Prakash }
1959730ffcbSVarun Prakash 
cxgbit_arp_failure_skb_discard(void * handle,struct sk_buff * skb)1969730ffcbSVarun Prakash static void cxgbit_arp_failure_skb_discard(void *handle, struct sk_buff *skb)
1979730ffcbSVarun Prakash {
1989730ffcbSVarun Prakash 	kfree_skb(skb);
1999730ffcbSVarun Prakash }
2009730ffcbSVarun Prakash 
cxgbit_push_tx_frames(struct cxgbit_sock * csk)2019730ffcbSVarun Prakash void cxgbit_push_tx_frames(struct cxgbit_sock *csk)
2029730ffcbSVarun Prakash {
2039730ffcbSVarun Prakash 	struct sk_buff *skb;
2049730ffcbSVarun Prakash 
2059730ffcbSVarun Prakash 	while (csk->wr_cred && ((skb = skb_peek(&csk->txq)) != NULL)) {
2069730ffcbSVarun Prakash 		u32 dlen = skb->len;
2079730ffcbSVarun Prakash 		u32 len = skb->len;
2089730ffcbSVarun Prakash 		u32 credits_needed;
2099730ffcbSVarun Prakash 		u32 compl = 0;
2109730ffcbSVarun Prakash 		u32 flowclen16 = 0;
2119730ffcbSVarun Prakash 		u32 iso_cpl_len = 0;
2129730ffcbSVarun Prakash 
2139730ffcbSVarun Prakash 		if (cxgbit_skcb_flags(skb) & SKCBF_TX_ISO)
2149730ffcbSVarun Prakash 			iso_cpl_len = sizeof(struct cpl_tx_data_iso);
2159730ffcbSVarun Prakash 
2169730ffcbSVarun Prakash 		if (cxgbit_is_ofld_imm(skb))
2179730ffcbSVarun Prakash 			credits_needed = DIV_ROUND_UP(dlen + iso_cpl_len, 16);
2189730ffcbSVarun Prakash 		else
2199730ffcbSVarun Prakash 			credits_needed = DIV_ROUND_UP((8 *
2209730ffcbSVarun Prakash 					cxgbit_calc_tx_flits_ofld(skb)) +
2219730ffcbSVarun Prakash 					iso_cpl_len, 16);
2229730ffcbSVarun Prakash 
2239730ffcbSVarun Prakash 		if (likely(cxgbit_skcb_flags(skb) & SKCBF_TX_NEED_HDR))
2249730ffcbSVarun Prakash 			credits_needed += DIV_ROUND_UP(
2259730ffcbSVarun Prakash 				sizeof(struct fw_ofld_tx_data_wr), 16);
2269730ffcbSVarun Prakash 		/*
2279730ffcbSVarun Prakash 		 * Assumes the initial credits is large enough to support
2289730ffcbSVarun Prakash 		 * fw_flowc_wr plus largest possible first payload
2299730ffcbSVarun Prakash 		 */
2309730ffcbSVarun Prakash 
2319730ffcbSVarun Prakash 		if (!test_and_set_bit(CSK_TX_DATA_SENT, &csk->com.flags)) {
2329730ffcbSVarun Prakash 			flowclen16 = cxgbit_send_tx_flowc_wr(csk);
2339730ffcbSVarun Prakash 			csk->wr_cred -= flowclen16;
2349730ffcbSVarun Prakash 			csk->wr_una_cred += flowclen16;
2359730ffcbSVarun Prakash 		}
2369730ffcbSVarun Prakash 
2379730ffcbSVarun Prakash 		if (csk->wr_cred < credits_needed) {
2389730ffcbSVarun Prakash 			pr_debug("csk 0x%p, skb %u/%u, wr %d < %u.\n",
2399730ffcbSVarun Prakash 				 csk, skb->len, skb->data_len,
2409730ffcbSVarun Prakash 				 credits_needed, csk->wr_cred);
2419730ffcbSVarun Prakash 			break;
2429730ffcbSVarun Prakash 		}
2439730ffcbSVarun Prakash 		__skb_unlink(skb, &csk->txq);
2449730ffcbSVarun Prakash 		set_wr_txq(skb, CPL_PRIORITY_DATA, csk->txq_idx);
2455cadafb2SBart Van Assche 		skb->csum = (__force __wsum)(credits_needed + flowclen16);
2469730ffcbSVarun Prakash 		csk->wr_cred -= credits_needed;
2479730ffcbSVarun Prakash 		csk->wr_una_cred += credits_needed;
2489730ffcbSVarun Prakash 
2499730ffcbSVarun Prakash 		pr_debug("csk 0x%p, skb %u/%u, wr %d, left %u, unack %u.\n",
2509730ffcbSVarun Prakash 			 csk, skb->len, skb->data_len, credits_needed,
2519730ffcbSVarun Prakash 			 csk->wr_cred, csk->wr_una_cred);
2529730ffcbSVarun Prakash 
2539730ffcbSVarun Prakash 		if (likely(cxgbit_skcb_flags(skb) & SKCBF_TX_NEED_HDR)) {
2549730ffcbSVarun Prakash 			len += cxgbit_skcb_tx_extralen(skb);
2559730ffcbSVarun Prakash 
2569730ffcbSVarun Prakash 			if ((csk->wr_una_cred >= (csk->wr_max_cred / 2)) ||
2579730ffcbSVarun Prakash 			    (!before(csk->write_seq,
2589730ffcbSVarun Prakash 				     csk->snd_una + csk->snd_win))) {
2599730ffcbSVarun Prakash 				compl = 1;
2609730ffcbSVarun Prakash 				csk->wr_una_cred = 0;
2619730ffcbSVarun Prakash 			}
2629730ffcbSVarun Prakash 
2639730ffcbSVarun Prakash 			cxgbit_tx_data_wr(csk, skb, dlen, len, credits_needed,
2649730ffcbSVarun Prakash 					  compl);
2659730ffcbSVarun Prakash 			csk->snd_nxt += len;
2669730ffcbSVarun Prakash 
2679730ffcbSVarun Prakash 		} else if ((cxgbit_skcb_flags(skb) & SKCBF_TX_FLAG_COMPL) ||
2689730ffcbSVarun Prakash 			   (csk->wr_una_cred >= (csk->wr_max_cred / 2))) {
2699730ffcbSVarun Prakash 			struct cpl_close_con_req *req =
2709730ffcbSVarun Prakash 				(struct cpl_close_con_req *)skb->data;
2719730ffcbSVarun Prakash 			req->wr.wr_hi |= htonl(FW_WR_COMPL_F);
2729730ffcbSVarun Prakash 			csk->wr_una_cred = 0;
2739730ffcbSVarun Prakash 		}
2749730ffcbSVarun Prakash 
2759730ffcbSVarun Prakash 		cxgbit_sock_enqueue_wr(csk, skb);
2769730ffcbSVarun Prakash 		t4_set_arp_err_handler(skb, csk,
2779730ffcbSVarun Prakash 				       cxgbit_arp_failure_skb_discard);
2789730ffcbSVarun Prakash 
2799730ffcbSVarun Prakash 		pr_debug("csk 0x%p,%u, skb 0x%p, %u.\n",
2809730ffcbSVarun Prakash 			 csk, csk->tid, skb, len);
2819730ffcbSVarun Prakash 
2829730ffcbSVarun Prakash 		cxgbit_l2t_send(csk->com.cdev, skb, csk->l2t);
2839730ffcbSVarun Prakash 	}
2849730ffcbSVarun Prakash }
2859730ffcbSVarun Prakash 
cxgbit_unlock_sock(struct cxgbit_sock * csk)2869730ffcbSVarun Prakash static void cxgbit_unlock_sock(struct cxgbit_sock *csk)
2879730ffcbSVarun Prakash {
2889730ffcbSVarun Prakash 	struct sk_buff_head backlogq;
2899730ffcbSVarun Prakash 	struct sk_buff *skb;
2909730ffcbSVarun Prakash 	void (*fn)(struct cxgbit_sock *, struct sk_buff *);
2919730ffcbSVarun Prakash 
2929730ffcbSVarun Prakash 	skb_queue_head_init(&backlogq);
2939730ffcbSVarun Prakash 
2949730ffcbSVarun Prakash 	spin_lock_bh(&csk->lock);
2959730ffcbSVarun Prakash 	while (skb_queue_len(&csk->backlogq)) {
2969730ffcbSVarun Prakash 		skb_queue_splice_init(&csk->backlogq, &backlogq);
2979730ffcbSVarun Prakash 		spin_unlock_bh(&csk->lock);
2989730ffcbSVarun Prakash 
2999730ffcbSVarun Prakash 		while ((skb = __skb_dequeue(&backlogq))) {
3009730ffcbSVarun Prakash 			fn = cxgbit_skcb_rx_backlog_fn(skb);
3019730ffcbSVarun Prakash 			fn(csk, skb);
3029730ffcbSVarun Prakash 		}
3039730ffcbSVarun Prakash 
3049730ffcbSVarun Prakash 		spin_lock_bh(&csk->lock);
3059730ffcbSVarun Prakash 	}
3069730ffcbSVarun Prakash 
3079730ffcbSVarun Prakash 	csk->lock_owner = false;
3089730ffcbSVarun Prakash 	spin_unlock_bh(&csk->lock);
3099730ffcbSVarun Prakash }
3109730ffcbSVarun Prakash 
cxgbit_queue_skb(struct cxgbit_sock * csk,struct sk_buff * skb)3119730ffcbSVarun Prakash static int cxgbit_queue_skb(struct cxgbit_sock *csk, struct sk_buff *skb)
3129730ffcbSVarun Prakash {
3139730ffcbSVarun Prakash 	int ret = 0;
3149730ffcbSVarun Prakash 
315b53293faSVarun Prakash 	spin_lock_bh(&csk->lock);
316b53293faSVarun Prakash 	csk->lock_owner = true;
317b53293faSVarun Prakash 	spin_unlock_bh(&csk->lock);
3189730ffcbSVarun Prakash 
3199730ffcbSVarun Prakash 	if (unlikely((csk->com.state != CSK_STATE_ESTABLISHED) ||
3209730ffcbSVarun Prakash 		     signal_pending(current))) {
3219730ffcbSVarun Prakash 		__kfree_skb(skb);
3229730ffcbSVarun Prakash 		__skb_queue_purge(&csk->ppodq);
3239730ffcbSVarun Prakash 		ret = -1;
3249730ffcbSVarun Prakash 		goto unlock;
3259730ffcbSVarun Prakash 	}
3269730ffcbSVarun Prakash 
3279730ffcbSVarun Prakash 	csk->write_seq += skb->len +
3289730ffcbSVarun Prakash 			  cxgbit_skcb_tx_extralen(skb);
3299730ffcbSVarun Prakash 
3309730ffcbSVarun Prakash 	skb_queue_splice_tail_init(&csk->ppodq, &csk->txq);
3319730ffcbSVarun Prakash 	__skb_queue_tail(&csk->txq, skb);
3329730ffcbSVarun Prakash 	cxgbit_push_tx_frames(csk);
3339730ffcbSVarun Prakash 
3349730ffcbSVarun Prakash unlock:
3359730ffcbSVarun Prakash 	cxgbit_unlock_sock(csk);
3369730ffcbSVarun Prakash 	return ret;
3379730ffcbSVarun Prakash }
3389730ffcbSVarun Prakash 
3399730ffcbSVarun Prakash static int
cxgbit_map_skb(struct iscsit_cmd * cmd,struct sk_buff * skb,u32 data_offset,u32 data_length)34066cd9d4eSMax Gurtovoy cxgbit_map_skb(struct iscsit_cmd *cmd, struct sk_buff *skb, u32 data_offset,
3419730ffcbSVarun Prakash 	       u32 data_length)
3429730ffcbSVarun Prakash {
3439730ffcbSVarun Prakash 	u32 i = 0, nr_frags = MAX_SKB_FRAGS;
3449730ffcbSVarun Prakash 	u32 padding = ((-data_length) & 3);
3459730ffcbSVarun Prakash 	struct scatterlist *sg;
3469730ffcbSVarun Prakash 	struct page *page;
3479730ffcbSVarun Prakash 	unsigned int page_off;
3489730ffcbSVarun Prakash 
3499730ffcbSVarun Prakash 	if (padding)
3509730ffcbSVarun Prakash 		nr_frags--;
3519730ffcbSVarun Prakash 
3529730ffcbSVarun Prakash 	/*
3539730ffcbSVarun Prakash 	 * We know each entry in t_data_sg contains a page.
3549730ffcbSVarun Prakash 	 */
3559730ffcbSVarun Prakash 	sg = &cmd->se_cmd.t_data_sg[data_offset / PAGE_SIZE];
3569730ffcbSVarun Prakash 	page_off = (data_offset % PAGE_SIZE);
3579730ffcbSVarun Prakash 
3589730ffcbSVarun Prakash 	while (data_length && (i < nr_frags)) {
3599730ffcbSVarun Prakash 		u32 cur_len = min_t(u32, data_length, sg->length - page_off);
3609730ffcbSVarun Prakash 
3619730ffcbSVarun Prakash 		page = sg_page(sg);
3629730ffcbSVarun Prakash 
3639730ffcbSVarun Prakash 		get_page(page);
3649730ffcbSVarun Prakash 		skb_fill_page_desc(skb, i, page, sg->offset + page_off,
3659730ffcbSVarun Prakash 				   cur_len);
3669730ffcbSVarun Prakash 		skb->data_len += cur_len;
3679730ffcbSVarun Prakash 		skb->len += cur_len;
3689730ffcbSVarun Prakash 		skb->truesize += cur_len;
3699730ffcbSVarun Prakash 
3709730ffcbSVarun Prakash 		data_length -= cur_len;
3719730ffcbSVarun Prakash 		page_off = 0;
3729730ffcbSVarun Prakash 		sg = sg_next(sg);
3739730ffcbSVarun Prakash 		i++;
3749730ffcbSVarun Prakash 	}
3759730ffcbSVarun Prakash 
3769730ffcbSVarun Prakash 	if (data_length)
3779730ffcbSVarun Prakash 		return -1;
3789730ffcbSVarun Prakash 
3799730ffcbSVarun Prakash 	if (padding) {
3809730ffcbSVarun Prakash 		page = alloc_page(GFP_KERNEL | __GFP_ZERO);
3819730ffcbSVarun Prakash 		if (!page)
3829730ffcbSVarun Prakash 			return -1;
3839730ffcbSVarun Prakash 		skb_fill_page_desc(skb, i, page, 0, padding);
3849730ffcbSVarun Prakash 		skb->data_len += padding;
3859730ffcbSVarun Prakash 		skb->len += padding;
3869730ffcbSVarun Prakash 		skb->truesize += padding;
3879730ffcbSVarun Prakash 	}
3889730ffcbSVarun Prakash 
3899730ffcbSVarun Prakash 	return 0;
3909730ffcbSVarun Prakash }
3919730ffcbSVarun Prakash 
3929730ffcbSVarun Prakash static int
cxgbit_tx_datain_iso(struct cxgbit_sock * csk,struct iscsit_cmd * cmd,struct iscsi_datain_req * dr)39366cd9d4eSMax Gurtovoy cxgbit_tx_datain_iso(struct cxgbit_sock *csk, struct iscsit_cmd *cmd,
3949730ffcbSVarun Prakash 		     struct iscsi_datain_req *dr)
3959730ffcbSVarun Prakash {
396*be36d683SMax Gurtovoy 	struct iscsit_conn *conn = csk->conn;
3979730ffcbSVarun Prakash 	struct sk_buff *skb;
3989730ffcbSVarun Prakash 	struct iscsi_datain datain;
3999730ffcbSVarun Prakash 	struct cxgbit_iso_info iso_info;
4009730ffcbSVarun Prakash 	u32 data_length = cmd->se_cmd.data_length;
4019730ffcbSVarun Prakash 	u32 mrdsl = conn->conn_ops->MaxRecvDataSegmentLength;
4029730ffcbSVarun Prakash 	u32 num_pdu, plen, tx_data = 0;
4039730ffcbSVarun Prakash 	bool task_sense = !!(cmd->se_cmd.se_cmd_flags &
4049730ffcbSVarun Prakash 		SCF_TRANSPORT_TASK_SENSE);
4059730ffcbSVarun Prakash 	bool set_statsn = false;
4069730ffcbSVarun Prakash 	int ret = -1;
4079730ffcbSVarun Prakash 
4089730ffcbSVarun Prakash 	while (data_length) {
4099730ffcbSVarun Prakash 		num_pdu = (data_length + mrdsl - 1) / mrdsl;
4109730ffcbSVarun Prakash 		if (num_pdu > csk->max_iso_npdu)
4119730ffcbSVarun Prakash 			num_pdu = csk->max_iso_npdu;
4129730ffcbSVarun Prakash 
4139730ffcbSVarun Prakash 		plen = num_pdu * mrdsl;
4149730ffcbSVarun Prakash 		if (plen > data_length)
4159730ffcbSVarun Prakash 			plen = data_length;
4169730ffcbSVarun Prakash 
4179730ffcbSVarun Prakash 		skb = __cxgbit_alloc_skb(csk, 0, true);
4189730ffcbSVarun Prakash 		if (unlikely(!skb))
4199730ffcbSVarun Prakash 			return -ENOMEM;
4209730ffcbSVarun Prakash 
4219730ffcbSVarun Prakash 		memset(skb->data, 0, ISCSI_HDR_LEN);
4229730ffcbSVarun Prakash 		cxgbit_skcb_flags(skb) |= SKCBF_TX_ISO;
4239730ffcbSVarun Prakash 		cxgbit_skcb_submode(skb) |= (csk->submode &
4249730ffcbSVarun Prakash 				CXGBIT_SUBMODE_DCRC);
4259730ffcbSVarun Prakash 		cxgbit_skcb_tx_extralen(skb) = (num_pdu *
4269730ffcbSVarun Prakash 				cxgbit_digest_len[cxgbit_skcb_submode(skb)]) +
4279730ffcbSVarun Prakash 						((num_pdu - 1) * ISCSI_HDR_LEN);
4289730ffcbSVarun Prakash 
4299730ffcbSVarun Prakash 		memset(&datain, 0, sizeof(struct iscsi_datain));
4309730ffcbSVarun Prakash 		memset(&iso_info, 0, sizeof(iso_info));
4319730ffcbSVarun Prakash 
4329730ffcbSVarun Prakash 		if (!tx_data)
4339730ffcbSVarun Prakash 			iso_info.flags |= CXGBIT_ISO_FSLICE;
4349730ffcbSVarun Prakash 
4359730ffcbSVarun Prakash 		if (!(data_length - plen)) {
4369730ffcbSVarun Prakash 			iso_info.flags |= CXGBIT_ISO_LSLICE;
4379730ffcbSVarun Prakash 			if (!task_sense) {
4389730ffcbSVarun Prakash 				datain.flags = ISCSI_FLAG_DATA_STATUS;
4399730ffcbSVarun Prakash 				iscsit_increment_maxcmdsn(cmd, conn->sess);
4409730ffcbSVarun Prakash 				cmd->stat_sn = conn->stat_sn++;
4419730ffcbSVarun Prakash 				set_statsn = true;
4429730ffcbSVarun Prakash 			}
4439730ffcbSVarun Prakash 		}
4449730ffcbSVarun Prakash 
4459730ffcbSVarun Prakash 		iso_info.burst_len = num_pdu * mrdsl;
4469730ffcbSVarun Prakash 		iso_info.mpdu = mrdsl;
4479730ffcbSVarun Prakash 		iso_info.len = ISCSI_HDR_LEN + plen;
4489730ffcbSVarun Prakash 
4499730ffcbSVarun Prakash 		cxgbit_cpl_tx_data_iso(skb, &iso_info);
4509730ffcbSVarun Prakash 
4519730ffcbSVarun Prakash 		datain.offset = tx_data;
4529730ffcbSVarun Prakash 		datain.data_sn = cmd->data_sn - 1;
4539730ffcbSVarun Prakash 
4549730ffcbSVarun Prakash 		iscsit_build_datain_pdu(cmd, conn, &datain,
4559730ffcbSVarun Prakash 					(struct iscsi_data_rsp *)skb->data,
4569730ffcbSVarun Prakash 					set_statsn);
4579730ffcbSVarun Prakash 
4589730ffcbSVarun Prakash 		ret = cxgbit_map_skb(cmd, skb, tx_data, plen);
4599730ffcbSVarun Prakash 		if (unlikely(ret)) {
4609730ffcbSVarun Prakash 			__kfree_skb(skb);
4619730ffcbSVarun Prakash 			goto out;
4629730ffcbSVarun Prakash 		}
4639730ffcbSVarun Prakash 
4649730ffcbSVarun Prakash 		ret = cxgbit_queue_skb(csk, skb);
4659730ffcbSVarun Prakash 		if (unlikely(ret))
4669730ffcbSVarun Prakash 			goto out;
4679730ffcbSVarun Prakash 
4689730ffcbSVarun Prakash 		tx_data += plen;
4699730ffcbSVarun Prakash 		data_length -= plen;
4709730ffcbSVarun Prakash 
4719730ffcbSVarun Prakash 		cmd->read_data_done += plen;
4729730ffcbSVarun Prakash 		cmd->data_sn += num_pdu;
4739730ffcbSVarun Prakash 	}
4749730ffcbSVarun Prakash 
4759730ffcbSVarun Prakash 	dr->dr_complete = DATAIN_COMPLETE_NORMAL;
4769730ffcbSVarun Prakash 
4779730ffcbSVarun Prakash 	return 0;
4789730ffcbSVarun Prakash 
4799730ffcbSVarun Prakash out:
4809730ffcbSVarun Prakash 	return ret;
4819730ffcbSVarun Prakash }
4829730ffcbSVarun Prakash 
4839730ffcbSVarun Prakash static int
cxgbit_tx_datain(struct cxgbit_sock * csk,struct iscsit_cmd * cmd,const struct iscsi_datain * datain)48466cd9d4eSMax Gurtovoy cxgbit_tx_datain(struct cxgbit_sock *csk, struct iscsit_cmd *cmd,
4859730ffcbSVarun Prakash 		 const struct iscsi_datain *datain)
4869730ffcbSVarun Prakash {
4879730ffcbSVarun Prakash 	struct sk_buff *skb;
4889730ffcbSVarun Prakash 	int ret = 0;
4899730ffcbSVarun Prakash 
4909730ffcbSVarun Prakash 	skb = cxgbit_alloc_skb(csk, 0);
4919730ffcbSVarun Prakash 	if (unlikely(!skb))
4929730ffcbSVarun Prakash 		return -ENOMEM;
4939730ffcbSVarun Prakash 
4949730ffcbSVarun Prakash 	memcpy(skb->data, cmd->pdu, ISCSI_HDR_LEN);
4959730ffcbSVarun Prakash 
4969730ffcbSVarun Prakash 	if (datain->length) {
4979730ffcbSVarun Prakash 		cxgbit_skcb_submode(skb) |= (csk->submode &
4989730ffcbSVarun Prakash 				CXGBIT_SUBMODE_DCRC);
4999730ffcbSVarun Prakash 		cxgbit_skcb_tx_extralen(skb) =
5009730ffcbSVarun Prakash 				cxgbit_digest_len[cxgbit_skcb_submode(skb)];
5019730ffcbSVarun Prakash 	}
5029730ffcbSVarun Prakash 
5039730ffcbSVarun Prakash 	ret = cxgbit_map_skb(cmd, skb, datain->offset, datain->length);
5049730ffcbSVarun Prakash 	if (ret < 0) {
5059730ffcbSVarun Prakash 		__kfree_skb(skb);
5069730ffcbSVarun Prakash 		return ret;
5079730ffcbSVarun Prakash 	}
5089730ffcbSVarun Prakash 
5099730ffcbSVarun Prakash 	return cxgbit_queue_skb(csk, skb);
5109730ffcbSVarun Prakash }
5119730ffcbSVarun Prakash 
5129730ffcbSVarun Prakash static int
cxgbit_xmit_datain_pdu(struct iscsit_conn * conn,struct iscsit_cmd * cmd,struct iscsi_datain_req * dr,const struct iscsi_datain * datain)513*be36d683SMax Gurtovoy cxgbit_xmit_datain_pdu(struct iscsit_conn *conn, struct iscsit_cmd *cmd,
5149730ffcbSVarun Prakash 		       struct iscsi_datain_req *dr,
5159730ffcbSVarun Prakash 		       const struct iscsi_datain *datain)
5169730ffcbSVarun Prakash {
5179730ffcbSVarun Prakash 	struct cxgbit_sock *csk = conn->context;
5189730ffcbSVarun Prakash 	u32 data_length = cmd->se_cmd.data_length;
5199730ffcbSVarun Prakash 	u32 padding = ((-data_length) & 3);
5209730ffcbSVarun Prakash 	u32 mrdsl = conn->conn_ops->MaxRecvDataSegmentLength;
5219730ffcbSVarun Prakash 
5229730ffcbSVarun Prakash 	if ((data_length > mrdsl) && (!dr->recovery) &&
5239730ffcbSVarun Prakash 	    (!padding) && (!datain->offset) && csk->max_iso_npdu) {
5249730ffcbSVarun Prakash 		atomic_long_add(data_length - datain->length,
5259730ffcbSVarun Prakash 				&conn->sess->tx_data_octets);
5269730ffcbSVarun Prakash 		return cxgbit_tx_datain_iso(csk, cmd, dr);
5279730ffcbSVarun Prakash 	}
5289730ffcbSVarun Prakash 
5299730ffcbSVarun Prakash 	return cxgbit_tx_datain(csk, cmd, datain);
5309730ffcbSVarun Prakash }
5319730ffcbSVarun Prakash 
5329730ffcbSVarun Prakash static int
cxgbit_xmit_nondatain_pdu(struct iscsit_conn * conn,struct iscsit_cmd * cmd,const void * data_buf,u32 data_buf_len)533*be36d683SMax Gurtovoy cxgbit_xmit_nondatain_pdu(struct iscsit_conn *conn, struct iscsit_cmd *cmd,
5349730ffcbSVarun Prakash 			  const void *data_buf, u32 data_buf_len)
5359730ffcbSVarun Prakash {
5369730ffcbSVarun Prakash 	struct cxgbit_sock *csk = conn->context;
5379730ffcbSVarun Prakash 	struct sk_buff *skb;
5389730ffcbSVarun Prakash 	u32 padding = ((-data_buf_len) & 3);
5399730ffcbSVarun Prakash 
5409730ffcbSVarun Prakash 	skb = cxgbit_alloc_skb(csk, data_buf_len + padding);
5419730ffcbSVarun Prakash 	if (unlikely(!skb))
5429730ffcbSVarun Prakash 		return -ENOMEM;
5439730ffcbSVarun Prakash 
5449730ffcbSVarun Prakash 	memcpy(skb->data, cmd->pdu, ISCSI_HDR_LEN);
5459730ffcbSVarun Prakash 
5469730ffcbSVarun Prakash 	if (data_buf_len) {
5479730ffcbSVarun Prakash 		u32 pad_bytes = 0;
5489730ffcbSVarun Prakash 
5499730ffcbSVarun Prakash 		skb_store_bits(skb, ISCSI_HDR_LEN, data_buf, data_buf_len);
5509730ffcbSVarun Prakash 
5519730ffcbSVarun Prakash 		if (padding)
5529730ffcbSVarun Prakash 			skb_store_bits(skb, ISCSI_HDR_LEN + data_buf_len,
5539730ffcbSVarun Prakash 				       &pad_bytes, padding);
5549730ffcbSVarun Prakash 	}
5559730ffcbSVarun Prakash 
5569730ffcbSVarun Prakash 	cxgbit_skcb_tx_extralen(skb) = cxgbit_digest_len[
5579730ffcbSVarun Prakash 				       cxgbit_skcb_submode(skb)];
5589730ffcbSVarun Prakash 
5599730ffcbSVarun Prakash 	return cxgbit_queue_skb(csk, skb);
5609730ffcbSVarun Prakash }
5619730ffcbSVarun Prakash 
5629730ffcbSVarun Prakash int
cxgbit_xmit_pdu(struct iscsit_conn * conn,struct iscsit_cmd * cmd,struct iscsi_datain_req * dr,const void * buf,u32 buf_len)563*be36d683SMax Gurtovoy cxgbit_xmit_pdu(struct iscsit_conn *conn, struct iscsit_cmd *cmd,
5649730ffcbSVarun Prakash 		struct iscsi_datain_req *dr, const void *buf, u32 buf_len)
5659730ffcbSVarun Prakash {
5669730ffcbSVarun Prakash 	if (dr)
5679730ffcbSVarun Prakash 		return cxgbit_xmit_datain_pdu(conn, cmd, dr, buf);
5689730ffcbSVarun Prakash 	else
5699730ffcbSVarun Prakash 		return cxgbit_xmit_nondatain_pdu(conn, cmd, buf, buf_len);
5709730ffcbSVarun Prakash }
5719730ffcbSVarun Prakash 
cxgbit_validate_params(struct iscsit_conn * conn)572*be36d683SMax Gurtovoy int cxgbit_validate_params(struct iscsit_conn *conn)
5739730ffcbSVarun Prakash {
5749730ffcbSVarun Prakash 	struct cxgbit_sock *csk = conn->context;
5759730ffcbSVarun Prakash 	struct cxgbit_device *cdev = csk->com.cdev;
5769730ffcbSVarun Prakash 	struct iscsi_param *param;
5779730ffcbSVarun Prakash 	u32 max_xmitdsl;
5789730ffcbSVarun Prakash 
5799730ffcbSVarun Prakash 	param = iscsi_find_param_from_key(MAXXMITDATASEGMENTLENGTH,
5809730ffcbSVarun Prakash 					  conn->param_list);
5819730ffcbSVarun Prakash 	if (!param)
5829730ffcbSVarun Prakash 		return -1;
5839730ffcbSVarun Prakash 
5849730ffcbSVarun Prakash 	if (kstrtou32(param->value, 0, &max_xmitdsl) < 0)
5859730ffcbSVarun Prakash 		return -1;
5869730ffcbSVarun Prakash 
5879730ffcbSVarun Prakash 	if (max_xmitdsl > cdev->mdsl) {
5889730ffcbSVarun Prakash 		if (iscsi_change_param_sprintf(
5899730ffcbSVarun Prakash 			conn, "MaxXmitDataSegmentLength=%u", cdev->mdsl))
5909730ffcbSVarun Prakash 			return -1;
5919730ffcbSVarun Prakash 	}
5929730ffcbSVarun Prakash 
5939730ffcbSVarun Prakash 	return 0;
5949730ffcbSVarun Prakash }
5959730ffcbSVarun Prakash 
cxgbit_set_digest(struct cxgbit_sock * csk)5969730ffcbSVarun Prakash static int cxgbit_set_digest(struct cxgbit_sock *csk)
5979730ffcbSVarun Prakash {
598*be36d683SMax Gurtovoy 	struct iscsit_conn *conn = csk->conn;
5999730ffcbSVarun Prakash 	struct iscsi_param *param;
6009730ffcbSVarun Prakash 
6019730ffcbSVarun Prakash 	param = iscsi_find_param_from_key(HEADERDIGEST, conn->param_list);
6029730ffcbSVarun Prakash 	if (!param) {
6039730ffcbSVarun Prakash 		pr_err("param not found key %s\n", HEADERDIGEST);
6049730ffcbSVarun Prakash 		return -1;
6059730ffcbSVarun Prakash 	}
6069730ffcbSVarun Prakash 
6079730ffcbSVarun Prakash 	if (!strcmp(param->value, CRC32C))
6089730ffcbSVarun Prakash 		csk->submode |= CXGBIT_SUBMODE_HCRC;
6099730ffcbSVarun Prakash 
6109730ffcbSVarun Prakash 	param = iscsi_find_param_from_key(DATADIGEST, conn->param_list);
6119730ffcbSVarun Prakash 	if (!param) {
6129730ffcbSVarun Prakash 		csk->submode = 0;
6139730ffcbSVarun Prakash 		pr_err("param not found key %s\n", DATADIGEST);
6149730ffcbSVarun Prakash 		return -1;
6159730ffcbSVarun Prakash 	}
6169730ffcbSVarun Prakash 
6179730ffcbSVarun Prakash 	if (!strcmp(param->value, CRC32C))
6189730ffcbSVarun Prakash 		csk->submode |= CXGBIT_SUBMODE_DCRC;
6199730ffcbSVarun Prakash 
6209730ffcbSVarun Prakash 	if (cxgbit_setup_conn_digest(csk)) {
6219730ffcbSVarun Prakash 		csk->submode = 0;
6229730ffcbSVarun Prakash 		return -1;
6239730ffcbSVarun Prakash 	}
6249730ffcbSVarun Prakash 
6259730ffcbSVarun Prakash 	return 0;
6269730ffcbSVarun Prakash }
6279730ffcbSVarun Prakash 
cxgbit_set_iso_npdu(struct cxgbit_sock * csk)6289730ffcbSVarun Prakash static int cxgbit_set_iso_npdu(struct cxgbit_sock *csk)
6299730ffcbSVarun Prakash {
630*be36d683SMax Gurtovoy 	struct iscsit_conn *conn = csk->conn;
6319730ffcbSVarun Prakash 	struct iscsi_conn_ops *conn_ops = conn->conn_ops;
6329730ffcbSVarun Prakash 	struct iscsi_param *param;
6339730ffcbSVarun Prakash 	u32 mrdsl, mbl;
6349730ffcbSVarun Prakash 	u32 max_npdu, max_iso_npdu;
6351b350ea0SVarun Prakash 	u32 max_iso_payload;
6369730ffcbSVarun Prakash 
6379730ffcbSVarun Prakash 	if (conn->login->leading_connection) {
6389730ffcbSVarun Prakash 		param = iscsi_find_param_from_key(MAXBURSTLENGTH,
6399730ffcbSVarun Prakash 						  conn->param_list);
6409730ffcbSVarun Prakash 		if (!param) {
6419730ffcbSVarun Prakash 			pr_err("param not found key %s\n", MAXBURSTLENGTH);
6429730ffcbSVarun Prakash 			return -1;
6439730ffcbSVarun Prakash 		}
6449730ffcbSVarun Prakash 
6459730ffcbSVarun Prakash 		if (kstrtou32(param->value, 0, &mbl) < 0)
6469730ffcbSVarun Prakash 			return -1;
6479730ffcbSVarun Prakash 	} else {
6489730ffcbSVarun Prakash 		mbl = conn->sess->sess_ops->MaxBurstLength;
6499730ffcbSVarun Prakash 	}
6509730ffcbSVarun Prakash 
6519730ffcbSVarun Prakash 	mrdsl = conn_ops->MaxRecvDataSegmentLength;
6529730ffcbSVarun Prakash 	max_npdu = mbl / mrdsl;
6539730ffcbSVarun Prakash 
6541b350ea0SVarun Prakash 	max_iso_payload = rounddown(CXGBIT_MAX_ISO_PAYLOAD, csk->emss);
6551b350ea0SVarun Prakash 
6561b350ea0SVarun Prakash 	max_iso_npdu = max_iso_payload /
6579730ffcbSVarun Prakash 		       (ISCSI_HDR_LEN + mrdsl +
6589730ffcbSVarun Prakash 			cxgbit_digest_len[csk->submode]);
6599730ffcbSVarun Prakash 
6609730ffcbSVarun Prakash 	csk->max_iso_npdu = min(max_npdu, max_iso_npdu);
6619730ffcbSVarun Prakash 
6629730ffcbSVarun Prakash 	if (csk->max_iso_npdu <= 1)
6639730ffcbSVarun Prakash 		csk->max_iso_npdu = 0;
6649730ffcbSVarun Prakash 
6659730ffcbSVarun Prakash 	return 0;
6669730ffcbSVarun Prakash }
6679730ffcbSVarun Prakash 
6685248788eSVarun Prakash /*
6695248788eSVarun Prakash  * cxgbit_seq_pdu_inorder()
6705248788eSVarun Prakash  * @csk: pointer to cxgbit socket structure
6715248788eSVarun Prakash  *
6725248788eSVarun Prakash  * This function checks whether data sequence and data
6735248788eSVarun Prakash  * pdu are in order.
6745248788eSVarun Prakash  *
6755248788eSVarun Prakash  * Return: returns -1 on error, 0 if data sequence and
6765248788eSVarun Prakash  * data pdu are in order, 1 if data sequence or data pdu
6775248788eSVarun Prakash  * is not in order.
6785248788eSVarun Prakash  */
cxgbit_seq_pdu_inorder(struct cxgbit_sock * csk)6795248788eSVarun Prakash static int cxgbit_seq_pdu_inorder(struct cxgbit_sock *csk)
6805248788eSVarun Prakash {
681*be36d683SMax Gurtovoy 	struct iscsit_conn *conn = csk->conn;
6825248788eSVarun Prakash 	struct iscsi_param *param;
6835248788eSVarun Prakash 
6845248788eSVarun Prakash 	if (conn->login->leading_connection) {
6855248788eSVarun Prakash 		param = iscsi_find_param_from_key(DATASEQUENCEINORDER,
6865248788eSVarun Prakash 						  conn->param_list);
6875248788eSVarun Prakash 		if (!param) {
6885248788eSVarun Prakash 			pr_err("param not found key %s\n", DATASEQUENCEINORDER);
6895248788eSVarun Prakash 			return -1;
6905248788eSVarun Prakash 		}
6915248788eSVarun Prakash 
6925248788eSVarun Prakash 		if (strcmp(param->value, YES))
6935248788eSVarun Prakash 			return 1;
6945248788eSVarun Prakash 
6955248788eSVarun Prakash 		param = iscsi_find_param_from_key(DATAPDUINORDER,
6965248788eSVarun Prakash 						  conn->param_list);
6975248788eSVarun Prakash 		if (!param) {
6985248788eSVarun Prakash 			pr_err("param not found key %s\n", DATAPDUINORDER);
6995248788eSVarun Prakash 			return -1;
7005248788eSVarun Prakash 		}
7015248788eSVarun Prakash 
7025248788eSVarun Prakash 		if (strcmp(param->value, YES))
7035248788eSVarun Prakash 			return 1;
7045248788eSVarun Prakash 
7055248788eSVarun Prakash 	} else {
7065248788eSVarun Prakash 		if (!conn->sess->sess_ops->DataSequenceInOrder)
7075248788eSVarun Prakash 			return 1;
7085248788eSVarun Prakash 		if (!conn->sess->sess_ops->DataPDUInOrder)
7095248788eSVarun Prakash 			return 1;
7105248788eSVarun Prakash 	}
7115248788eSVarun Prakash 
7125248788eSVarun Prakash 	return 0;
7135248788eSVarun Prakash }
7145248788eSVarun Prakash 
cxgbit_set_params(struct iscsit_conn * conn)715*be36d683SMax Gurtovoy static int cxgbit_set_params(struct iscsit_conn *conn)
7169730ffcbSVarun Prakash {
7179730ffcbSVarun Prakash 	struct cxgbit_sock *csk = conn->context;
7189730ffcbSVarun Prakash 	struct cxgbit_device *cdev = csk->com.cdev;
7199730ffcbSVarun Prakash 	struct cxgbi_ppm *ppm = *csk->com.cdev->lldi.iscsi_ppm;
7209730ffcbSVarun Prakash 	struct iscsi_conn_ops *conn_ops = conn->conn_ops;
7219730ffcbSVarun Prakash 	struct iscsi_param *param;
7229730ffcbSVarun Prakash 	u8 erl;
7239730ffcbSVarun Prakash 
7249730ffcbSVarun Prakash 	if (conn_ops->MaxRecvDataSegmentLength > cdev->mdsl)
7259730ffcbSVarun Prakash 		conn_ops->MaxRecvDataSegmentLength = cdev->mdsl;
7269730ffcbSVarun Prakash 
7271b350ea0SVarun Prakash 	if (cxgbit_set_digest(csk))
7281b350ea0SVarun Prakash 		return -1;
7291b350ea0SVarun Prakash 
7309730ffcbSVarun Prakash 	if (conn->login->leading_connection) {
7319730ffcbSVarun Prakash 		param = iscsi_find_param_from_key(ERRORRECOVERYLEVEL,
7329730ffcbSVarun Prakash 						  conn->param_list);
7339730ffcbSVarun Prakash 		if (!param) {
7349730ffcbSVarun Prakash 			pr_err("param not found key %s\n", ERRORRECOVERYLEVEL);
7359730ffcbSVarun Prakash 			return -1;
7369730ffcbSVarun Prakash 		}
7379730ffcbSVarun Prakash 		if (kstrtou8(param->value, 0, &erl) < 0)
7389730ffcbSVarun Prakash 			return -1;
7399730ffcbSVarun Prakash 	} else {
7409730ffcbSVarun Prakash 		erl = conn->sess->sess_ops->ErrorRecoveryLevel;
7419730ffcbSVarun Prakash 	}
7429730ffcbSVarun Prakash 
7439730ffcbSVarun Prakash 	if (!erl) {
7445248788eSVarun Prakash 		int ret;
7455248788eSVarun Prakash 
7465248788eSVarun Prakash 		ret = cxgbit_seq_pdu_inorder(csk);
7475248788eSVarun Prakash 		if (ret < 0) {
7485248788eSVarun Prakash 			return -1;
7495248788eSVarun Prakash 		} else if (ret > 0) {
7505248788eSVarun Prakash 			if (is_t5(cdev->lldi.adapter_type))
7515248788eSVarun Prakash 				goto enable_ddp;
7525248788eSVarun Prakash 			else
7531b350ea0SVarun Prakash 				return 0;
7545248788eSVarun Prakash 		}
7555248788eSVarun Prakash 
7569730ffcbSVarun Prakash 		if (test_bit(CDEV_ISO_ENABLE, &cdev->flags)) {
7579730ffcbSVarun Prakash 			if (cxgbit_set_iso_npdu(csk))
7589730ffcbSVarun Prakash 				return -1;
7599730ffcbSVarun Prakash 		}
7609730ffcbSVarun Prakash 
7615248788eSVarun Prakash enable_ddp:
7629730ffcbSVarun Prakash 		if (test_bit(CDEV_DDP_ENABLE, &cdev->flags)) {
7639730ffcbSVarun Prakash 			if (cxgbit_setup_conn_pgidx(csk,
7649730ffcbSVarun Prakash 						    ppm->tformat.pgsz_idx_dflt))
7659730ffcbSVarun Prakash 				return -1;
7669730ffcbSVarun Prakash 			set_bit(CSK_DDP_ENABLE, &csk->com.flags);
7679730ffcbSVarun Prakash 		}
7689730ffcbSVarun Prakash 	}
7699730ffcbSVarun Prakash 
7709730ffcbSVarun Prakash 	return 0;
7719730ffcbSVarun Prakash }
7729730ffcbSVarun Prakash 
7739730ffcbSVarun Prakash int
cxgbit_put_login_tx(struct iscsit_conn * conn,struct iscsi_login * login,u32 length)774*be36d683SMax Gurtovoy cxgbit_put_login_tx(struct iscsit_conn *conn, struct iscsi_login *login,
7759730ffcbSVarun Prakash 		    u32 length)
7769730ffcbSVarun Prakash {
7779730ffcbSVarun Prakash 	struct cxgbit_sock *csk = conn->context;
7789730ffcbSVarun Prakash 	struct sk_buff *skb;
7799730ffcbSVarun Prakash 	u32 padding_buf = 0;
7809730ffcbSVarun Prakash 	u8 padding = ((-length) & 3);
7819730ffcbSVarun Prakash 
7829730ffcbSVarun Prakash 	skb = cxgbit_alloc_skb(csk, length + padding);
7839730ffcbSVarun Prakash 	if (!skb)
7849730ffcbSVarun Prakash 		return -ENOMEM;
7859730ffcbSVarun Prakash 	skb_store_bits(skb, 0, login->rsp, ISCSI_HDR_LEN);
7869730ffcbSVarun Prakash 	skb_store_bits(skb, ISCSI_HDR_LEN, login->rsp_buf, length);
7879730ffcbSVarun Prakash 
7889730ffcbSVarun Prakash 	if (padding)
7899730ffcbSVarun Prakash 		skb_store_bits(skb, ISCSI_HDR_LEN + length,
7909730ffcbSVarun Prakash 			       &padding_buf, padding);
7919730ffcbSVarun Prakash 
7929730ffcbSVarun Prakash 	if (login->login_complete) {
7939730ffcbSVarun Prakash 		if (cxgbit_set_params(conn)) {
7949730ffcbSVarun Prakash 			kfree_skb(skb);
7959730ffcbSVarun Prakash 			return -1;
7969730ffcbSVarun Prakash 		}
7979730ffcbSVarun Prakash 
7989730ffcbSVarun Prakash 		set_bit(CSK_LOGIN_DONE, &csk->com.flags);
7999730ffcbSVarun Prakash 	}
8009730ffcbSVarun Prakash 
8019730ffcbSVarun Prakash 	if (cxgbit_queue_skb(csk, skb))
8029730ffcbSVarun Prakash 		return -1;
8039730ffcbSVarun Prakash 
8049730ffcbSVarun Prakash 	if ((!login->login_complete) && (!login->login_failed))
8059730ffcbSVarun Prakash 		schedule_delayed_work(&conn->login_work, 0);
8069730ffcbSVarun Prakash 
8079730ffcbSVarun Prakash 	return 0;
8089730ffcbSVarun Prakash }
8099730ffcbSVarun Prakash 
8109730ffcbSVarun Prakash static void
cxgbit_skb_copy_to_sg(struct sk_buff * skb,struct scatterlist * sg,unsigned int nents,u32 skip)8119730ffcbSVarun Prakash cxgbit_skb_copy_to_sg(struct sk_buff *skb, struct scatterlist *sg,
812d96adb9bSVarun Prakash 		      unsigned int nents, u32 skip)
8139730ffcbSVarun Prakash {
8149730ffcbSVarun Prakash 	struct skb_seq_state st;
8159730ffcbSVarun Prakash 	const u8 *buf;
8169730ffcbSVarun Prakash 	unsigned int consumed = 0, buf_len;
8179730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(skb);
8189730ffcbSVarun Prakash 
8199730ffcbSVarun Prakash 	skb_prepare_seq_read(skb, pdu_cb->doffset,
8209730ffcbSVarun Prakash 			     pdu_cb->doffset + pdu_cb->dlen,
8219730ffcbSVarun Prakash 			     &st);
8229730ffcbSVarun Prakash 
8239730ffcbSVarun Prakash 	while (true) {
8249730ffcbSVarun Prakash 		buf_len = skb_seq_read(consumed, &buf, &st);
8259730ffcbSVarun Prakash 		if (!buf_len) {
8269730ffcbSVarun Prakash 			skb_abort_seq_read(&st);
8279730ffcbSVarun Prakash 			break;
8289730ffcbSVarun Prakash 		}
8299730ffcbSVarun Prakash 
8309730ffcbSVarun Prakash 		consumed += sg_pcopy_from_buffer(sg, nents, (void *)buf,
831d96adb9bSVarun Prakash 						 buf_len, skip + consumed);
8329730ffcbSVarun Prakash 	}
8339730ffcbSVarun Prakash }
8349730ffcbSVarun Prakash 
cxgbit_allocate_cmd(struct cxgbit_sock * csk)83566cd9d4eSMax Gurtovoy static struct iscsit_cmd *cxgbit_allocate_cmd(struct cxgbit_sock *csk)
8369730ffcbSVarun Prakash {
837*be36d683SMax Gurtovoy 	struct iscsit_conn *conn = csk->conn;
8389730ffcbSVarun Prakash 	struct cxgbi_ppm *ppm = cdev2ppm(csk->com.cdev);
8399730ffcbSVarun Prakash 	struct cxgbit_cmd *ccmd;
84066cd9d4eSMax Gurtovoy 	struct iscsit_cmd *cmd;
8419730ffcbSVarun Prakash 
8429730ffcbSVarun Prakash 	cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
8439730ffcbSVarun Prakash 	if (!cmd) {
84466cd9d4eSMax Gurtovoy 		pr_err("Unable to allocate iscsit_cmd + cxgbit_cmd\n");
8459730ffcbSVarun Prakash 		return NULL;
8469730ffcbSVarun Prakash 	}
8479730ffcbSVarun Prakash 
8489730ffcbSVarun Prakash 	ccmd = iscsit_priv_cmd(cmd);
8499730ffcbSVarun Prakash 	ccmd->ttinfo.tag = ppm->tformat.no_ddp_mask;
8509730ffcbSVarun Prakash 	ccmd->setup_ddp = true;
8519730ffcbSVarun Prakash 
8529730ffcbSVarun Prakash 	return cmd;
8539730ffcbSVarun Prakash }
8549730ffcbSVarun Prakash 
8559730ffcbSVarun Prakash static int
cxgbit_handle_immediate_data(struct iscsit_cmd * cmd,struct iscsi_scsi_req * hdr,u32 length)85666cd9d4eSMax Gurtovoy cxgbit_handle_immediate_data(struct iscsit_cmd *cmd, struct iscsi_scsi_req *hdr,
8579730ffcbSVarun Prakash 			     u32 length)
8589730ffcbSVarun Prakash {
859*be36d683SMax Gurtovoy 	struct iscsit_conn *conn = cmd->conn;
8609730ffcbSVarun Prakash 	struct cxgbit_sock *csk = conn->context;
8619730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
8629730ffcbSVarun Prakash 
8639730ffcbSVarun Prakash 	if (pdu_cb->flags & PDUCBF_RX_DCRC_ERR) {
8649730ffcbSVarun Prakash 		pr_err("ImmediateData CRC32C DataDigest error\n");
8659730ffcbSVarun Prakash 		if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
8669730ffcbSVarun Prakash 			pr_err("Unable to recover from"
8679730ffcbSVarun Prakash 			       " Immediate Data digest failure while"
8689730ffcbSVarun Prakash 			       " in ERL=0.\n");
8699730ffcbSVarun Prakash 			iscsit_reject_cmd(cmd, ISCSI_REASON_DATA_DIGEST_ERROR,
8709730ffcbSVarun Prakash 					  (unsigned char *)hdr);
8719730ffcbSVarun Prakash 			return IMMEDIATE_DATA_CANNOT_RECOVER;
8729730ffcbSVarun Prakash 		}
8739730ffcbSVarun Prakash 
8749730ffcbSVarun Prakash 		iscsit_reject_cmd(cmd, ISCSI_REASON_DATA_DIGEST_ERROR,
8759730ffcbSVarun Prakash 				  (unsigned char *)hdr);
8769730ffcbSVarun Prakash 		return IMMEDIATE_DATA_ERL1_CRC_FAILURE;
8779730ffcbSVarun Prakash 	}
8789730ffcbSVarun Prakash 
8799730ffcbSVarun Prakash 	if (cmd->se_cmd.se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) {
8809730ffcbSVarun Prakash 		struct cxgbit_cmd *ccmd = iscsit_priv_cmd(cmd);
8819730ffcbSVarun Prakash 		struct skb_shared_info *ssi = skb_shinfo(csk->skb);
8829730ffcbSVarun Prakash 		skb_frag_t *dfrag = &ssi->frags[pdu_cb->dfrag_idx];
8839730ffcbSVarun Prakash 
8849730ffcbSVarun Prakash 		sg_init_table(&ccmd->sg, 1);
885d7840976SMatthew Wilcox (Oracle) 		sg_set_page(&ccmd->sg, skb_frag_page(dfrag),
886b54c9d5bSJonathan Lemon 				skb_frag_size(dfrag), skb_frag_off(dfrag));
887d7840976SMatthew Wilcox (Oracle) 		get_page(skb_frag_page(dfrag));
8889730ffcbSVarun Prakash 
8899730ffcbSVarun Prakash 		cmd->se_cmd.t_data_sg = &ccmd->sg;
8909730ffcbSVarun Prakash 		cmd->se_cmd.t_data_nents = 1;
8919730ffcbSVarun Prakash 
8929730ffcbSVarun Prakash 		ccmd->release = true;
8939730ffcbSVarun Prakash 	} else {
8949730ffcbSVarun Prakash 		struct scatterlist *sg = &cmd->se_cmd.t_data_sg[0];
8959730ffcbSVarun Prakash 		u32 sg_nents = max(1UL, DIV_ROUND_UP(pdu_cb->dlen, PAGE_SIZE));
8969730ffcbSVarun Prakash 
897d96adb9bSVarun Prakash 		cxgbit_skb_copy_to_sg(csk->skb, sg, sg_nents, 0);
8989730ffcbSVarun Prakash 	}
8999730ffcbSVarun Prakash 
9009730ffcbSVarun Prakash 	cmd->write_data_done += pdu_cb->dlen;
9019730ffcbSVarun Prakash 
9029730ffcbSVarun Prakash 	if (cmd->write_data_done == cmd->se_cmd.data_length) {
9039730ffcbSVarun Prakash 		spin_lock_bh(&cmd->istate_lock);
9049730ffcbSVarun Prakash 		cmd->cmd_flags |= ICF_GOT_LAST_DATAOUT;
9059730ffcbSVarun Prakash 		cmd->i_state = ISTATE_RECEIVED_LAST_DATAOUT;
9069730ffcbSVarun Prakash 		spin_unlock_bh(&cmd->istate_lock);
9079730ffcbSVarun Prakash 	}
9089730ffcbSVarun Prakash 
9099730ffcbSVarun Prakash 	return IMMEDIATE_DATA_NORMAL_OPERATION;
9109730ffcbSVarun Prakash }
9119730ffcbSVarun Prakash 
9129730ffcbSVarun Prakash static int
cxgbit_get_immediate_data(struct iscsit_cmd * cmd,struct iscsi_scsi_req * hdr,bool dump_payload)91366cd9d4eSMax Gurtovoy cxgbit_get_immediate_data(struct iscsit_cmd *cmd, struct iscsi_scsi_req *hdr,
9149730ffcbSVarun Prakash 			  bool dump_payload)
9159730ffcbSVarun Prakash {
916*be36d683SMax Gurtovoy 	struct iscsit_conn *conn = cmd->conn;
9179730ffcbSVarun Prakash 	int cmdsn_ret = 0, immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION;
9189730ffcbSVarun Prakash 	/*
9199730ffcbSVarun Prakash 	 * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes.
9209730ffcbSVarun Prakash 	 */
9219730ffcbSVarun Prakash 	if (dump_payload)
9229730ffcbSVarun Prakash 		goto after_immediate_data;
9239730ffcbSVarun Prakash 
9249730ffcbSVarun Prakash 	immed_ret = cxgbit_handle_immediate_data(cmd, hdr,
9259730ffcbSVarun Prakash 						 cmd->first_burst_len);
9269730ffcbSVarun Prakash after_immediate_data:
9279730ffcbSVarun Prakash 	if (immed_ret == IMMEDIATE_DATA_NORMAL_OPERATION) {
9289730ffcbSVarun Prakash 		/*
9299730ffcbSVarun Prakash 		 * A PDU/CmdSN carrying Immediate Data passed
9309730ffcbSVarun Prakash 		 * DataCRC, check against ExpCmdSN/MaxCmdSN if
9319730ffcbSVarun Prakash 		 * Immediate Bit is not set.
9329730ffcbSVarun Prakash 		 */
9339730ffcbSVarun Prakash 		cmdsn_ret = iscsit_sequence_cmd(conn, cmd,
9349730ffcbSVarun Prakash 						(unsigned char *)hdr,
9359730ffcbSVarun Prakash 						hdr->cmdsn);
9369730ffcbSVarun Prakash 		if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
9379730ffcbSVarun Prakash 			return -1;
9389730ffcbSVarun Prakash 
9399730ffcbSVarun Prakash 		if (cmd->sense_reason || cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
9409730ffcbSVarun Prakash 			target_put_sess_cmd(&cmd->se_cmd);
9419730ffcbSVarun Prakash 			return 0;
9429730ffcbSVarun Prakash 		} else if (cmd->unsolicited_data) {
9430300b114SBart Van Assche 			iscsit_set_unsolicited_dataout(cmd);
9449730ffcbSVarun Prakash 		}
9459730ffcbSVarun Prakash 
9469730ffcbSVarun Prakash 	} else if (immed_ret == IMMEDIATE_DATA_ERL1_CRC_FAILURE) {
9479730ffcbSVarun Prakash 		/*
9489730ffcbSVarun Prakash 		 * Immediate Data failed DataCRC and ERL>=1,
9499730ffcbSVarun Prakash 		 * silently drop this PDU and let the initiator
9509730ffcbSVarun Prakash 		 * plug the CmdSN gap.
9519730ffcbSVarun Prakash 		 *
9529730ffcbSVarun Prakash 		 * FIXME: Send Unsolicited NOPIN with reserved
9539730ffcbSVarun Prakash 		 * TTT here to help the initiator figure out
9549730ffcbSVarun Prakash 		 * the missing CmdSN, although they should be
9559730ffcbSVarun Prakash 		 * intelligent enough to determine the missing
9569730ffcbSVarun Prakash 		 * CmdSN and issue a retry to plug the sequence.
9579730ffcbSVarun Prakash 		 */
9589730ffcbSVarun Prakash 		cmd->i_state = ISTATE_REMOVE;
9599730ffcbSVarun Prakash 		iscsit_add_cmd_to_immediate_queue(cmd, conn, cmd->i_state);
9609730ffcbSVarun Prakash 	} else /* immed_ret == IMMEDIATE_DATA_CANNOT_RECOVER */
9619730ffcbSVarun Prakash 		return -1;
9629730ffcbSVarun Prakash 
9639730ffcbSVarun Prakash 	return 0;
9649730ffcbSVarun Prakash }
9659730ffcbSVarun Prakash 
9669730ffcbSVarun Prakash static int
cxgbit_handle_scsi_cmd(struct cxgbit_sock * csk,struct iscsit_cmd * cmd)96766cd9d4eSMax Gurtovoy cxgbit_handle_scsi_cmd(struct cxgbit_sock *csk, struct iscsit_cmd *cmd)
9689730ffcbSVarun Prakash {
969*be36d683SMax Gurtovoy 	struct iscsit_conn *conn = csk->conn;
9709730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
9719730ffcbSVarun Prakash 	struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)pdu_cb->hdr;
9729730ffcbSVarun Prakash 	int rc;
9739730ffcbSVarun Prakash 	bool dump_payload = false;
9749730ffcbSVarun Prakash 
9759730ffcbSVarun Prakash 	rc = iscsit_setup_scsi_cmd(conn, cmd, (unsigned char *)hdr);
9769730ffcbSVarun Prakash 	if (rc < 0)
9779730ffcbSVarun Prakash 		return rc;
9789730ffcbSVarun Prakash 
9799730ffcbSVarun Prakash 	if (pdu_cb->dlen && (pdu_cb->dlen == cmd->se_cmd.data_length) &&
9809730ffcbSVarun Prakash 	    (pdu_cb->nr_dfrags == 1))
9819730ffcbSVarun Prakash 		cmd->se_cmd.se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
9829730ffcbSVarun Prakash 
9839730ffcbSVarun Prakash 	rc = iscsit_process_scsi_cmd(conn, cmd, hdr);
9849730ffcbSVarun Prakash 	if (rc < 0)
9859730ffcbSVarun Prakash 		return 0;
9869730ffcbSVarun Prakash 	else if (rc > 0)
9879730ffcbSVarun Prakash 		dump_payload = true;
9889730ffcbSVarun Prakash 
9899730ffcbSVarun Prakash 	if (!pdu_cb->dlen)
9909730ffcbSVarun Prakash 		return 0;
9919730ffcbSVarun Prakash 
9929730ffcbSVarun Prakash 	return cxgbit_get_immediate_data(cmd, hdr, dump_payload);
9939730ffcbSVarun Prakash }
9949730ffcbSVarun Prakash 
cxgbit_handle_iscsi_dataout(struct cxgbit_sock * csk)9959730ffcbSVarun Prakash static int cxgbit_handle_iscsi_dataout(struct cxgbit_sock *csk)
9969730ffcbSVarun Prakash {
9979730ffcbSVarun Prakash 	struct scatterlist *sg_start;
998*be36d683SMax Gurtovoy 	struct iscsit_conn *conn = csk->conn;
99966cd9d4eSMax Gurtovoy 	struct iscsit_cmd *cmd = NULL;
10006ecdafaeSVarun Prakash 	struct cxgbit_cmd *ccmd;
10016ecdafaeSVarun Prakash 	struct cxgbi_task_tag_info *ttinfo;
10029730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
10039730ffcbSVarun Prakash 	struct iscsi_data *hdr = (struct iscsi_data *)pdu_cb->hdr;
10049730ffcbSVarun Prakash 	u32 data_offset = be32_to_cpu(hdr->offset);
10056ecdafaeSVarun Prakash 	u32 data_len = ntoh24(hdr->dlength);
10069730ffcbSVarun Prakash 	int rc, sg_nents, sg_off;
10079730ffcbSVarun Prakash 	bool dcrc_err = false;
10089730ffcbSVarun Prakash 
100979e57cfeSVarun Prakash 	if (pdu_cb->flags & PDUCBF_RX_DDP_CMP) {
101079e57cfeSVarun Prakash 		u32 offset = be32_to_cpu(hdr->offset);
101179e57cfeSVarun Prakash 		u32 ddp_data_len;
101279e57cfeSVarun Prakash 		bool success = false;
101379e57cfeSVarun Prakash 
101479e57cfeSVarun Prakash 		cmd = iscsit_find_cmd_from_itt_or_dump(conn, hdr->itt, 0);
101579e57cfeSVarun Prakash 		if (!cmd)
101679e57cfeSVarun Prakash 			return 0;
101779e57cfeSVarun Prakash 
101879e57cfeSVarun Prakash 		ddp_data_len = offset - cmd->write_data_done;
101979e57cfeSVarun Prakash 		atomic_long_add(ddp_data_len, &conn->sess->rx_data_octets);
102079e57cfeSVarun Prakash 
102179e57cfeSVarun Prakash 		cmd->write_data_done = offset;
102279e57cfeSVarun Prakash 		cmd->next_burst_len = ddp_data_len;
102379e57cfeSVarun Prakash 		cmd->data_sn = be32_to_cpu(hdr->datasn);
102479e57cfeSVarun Prakash 
102579e57cfeSVarun Prakash 		rc = __iscsit_check_dataout_hdr(conn, (unsigned char *)hdr,
10266ecdafaeSVarun Prakash 						cmd, data_len, &success);
102779e57cfeSVarun Prakash 		if (rc < 0)
102879e57cfeSVarun Prakash 			return rc;
102979e57cfeSVarun Prakash 		else if (!success)
103079e57cfeSVarun Prakash 			return 0;
103179e57cfeSVarun Prakash 	} else {
10329730ffcbSVarun Prakash 		rc = iscsit_check_dataout_hdr(conn, (unsigned char *)hdr, &cmd);
10339730ffcbSVarun Prakash 		if (rc < 0)
10349730ffcbSVarun Prakash 			return rc;
10359730ffcbSVarun Prakash 		else if (!cmd)
10369730ffcbSVarun Prakash 			return 0;
103779e57cfeSVarun Prakash 	}
10389730ffcbSVarun Prakash 
10399730ffcbSVarun Prakash 	if (pdu_cb->flags & PDUCBF_RX_DCRC_ERR) {
10409730ffcbSVarun Prakash 		pr_err("ITT: 0x%08x, Offset: %u, Length: %u,"
10419730ffcbSVarun Prakash 		       " DataSN: 0x%08x\n",
10429730ffcbSVarun Prakash 		       hdr->itt, hdr->offset, data_len,
10439730ffcbSVarun Prakash 		       hdr->datasn);
10449730ffcbSVarun Prakash 
10459730ffcbSVarun Prakash 		dcrc_err = true;
10469730ffcbSVarun Prakash 		goto check_payload;
10479730ffcbSVarun Prakash 	}
10489730ffcbSVarun Prakash 
10499730ffcbSVarun Prakash 	pr_debug("DataOut data_len: %u, "
10509730ffcbSVarun Prakash 		"write_data_done: %u, data_length: %u\n",
10519730ffcbSVarun Prakash 		  data_len,  cmd->write_data_done,
10529730ffcbSVarun Prakash 		  cmd->se_cmd.data_length);
10539730ffcbSVarun Prakash 
10549730ffcbSVarun Prakash 	if (!(pdu_cb->flags & PDUCBF_RX_DATA_DDPD)) {
1055d96adb9bSVarun Prakash 		u32 skip = data_offset % PAGE_SIZE;
1056d96adb9bSVarun Prakash 
10579730ffcbSVarun Prakash 		sg_off = data_offset / PAGE_SIZE;
10589730ffcbSVarun Prakash 		sg_start = &cmd->se_cmd.t_data_sg[sg_off];
1059d96adb9bSVarun Prakash 		sg_nents = max(1UL, DIV_ROUND_UP(skip + data_len, PAGE_SIZE));
10609730ffcbSVarun Prakash 
1061d96adb9bSVarun Prakash 		cxgbit_skb_copy_to_sg(csk->skb, sg_start, sg_nents, skip);
10629730ffcbSVarun Prakash 	}
10639730ffcbSVarun Prakash 
10646ecdafaeSVarun Prakash 	ccmd = iscsit_priv_cmd(cmd);
10656ecdafaeSVarun Prakash 	ttinfo = &ccmd->ttinfo;
10666ecdafaeSVarun Prakash 
10676ecdafaeSVarun Prakash 	if (ccmd->release && ttinfo->sgl &&
10686ecdafaeSVarun Prakash 	    (cmd->se_cmd.data_length ==	(cmd->write_data_done + data_len))) {
10696ecdafaeSVarun Prakash 		struct cxgbit_device *cdev = csk->com.cdev;
10706ecdafaeSVarun Prakash 		struct cxgbi_ppm *ppm = cdev2ppm(cdev);
10716ecdafaeSVarun Prakash 
10726ecdafaeSVarun Prakash 		dma_unmap_sg(&ppm->pdev->dev, ttinfo->sgl, ttinfo->nents,
10736ecdafaeSVarun Prakash 			     DMA_FROM_DEVICE);
10746ecdafaeSVarun Prakash 		ttinfo->nents = 0;
10756ecdafaeSVarun Prakash 		ttinfo->sgl = NULL;
10766ecdafaeSVarun Prakash 	}
10776ecdafaeSVarun Prakash 
10789730ffcbSVarun Prakash check_payload:
10799730ffcbSVarun Prakash 
10809730ffcbSVarun Prakash 	rc = iscsit_check_dataout_payload(cmd, hdr, dcrc_err);
10819730ffcbSVarun Prakash 	if (rc < 0)
10829730ffcbSVarun Prakash 		return rc;
10839730ffcbSVarun Prakash 
10849730ffcbSVarun Prakash 	return 0;
10859730ffcbSVarun Prakash }
10869730ffcbSVarun Prakash 
cxgbit_handle_nop_out(struct cxgbit_sock * csk,struct iscsit_cmd * cmd)108766cd9d4eSMax Gurtovoy static int cxgbit_handle_nop_out(struct cxgbit_sock *csk, struct iscsit_cmd *cmd)
10889730ffcbSVarun Prakash {
1089*be36d683SMax Gurtovoy 	struct iscsit_conn *conn = csk->conn;
10909730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
10919730ffcbSVarun Prakash 	struct iscsi_nopout *hdr = (struct iscsi_nopout *)pdu_cb->hdr;
10929730ffcbSVarun Prakash 	unsigned char *ping_data = NULL;
10939730ffcbSVarun Prakash 	u32 payload_length = pdu_cb->dlen;
10949730ffcbSVarun Prakash 	int ret;
10959730ffcbSVarun Prakash 
10969730ffcbSVarun Prakash 	ret = iscsit_setup_nop_out(conn, cmd, hdr);
10979730ffcbSVarun Prakash 	if (ret < 0)
10989730ffcbSVarun Prakash 		return 0;
10999730ffcbSVarun Prakash 
11009730ffcbSVarun Prakash 	if (pdu_cb->flags & PDUCBF_RX_DCRC_ERR) {
11019730ffcbSVarun Prakash 		if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
11029730ffcbSVarun Prakash 			pr_err("Unable to recover from"
11039730ffcbSVarun Prakash 			       " NOPOUT Ping DataCRC failure while in"
11049730ffcbSVarun Prakash 			       " ERL=0.\n");
11059730ffcbSVarun Prakash 			ret = -1;
11069730ffcbSVarun Prakash 			goto out;
11079730ffcbSVarun Prakash 		} else {
11089730ffcbSVarun Prakash 			/*
11099730ffcbSVarun Prakash 			 * drop this PDU and let the
11109730ffcbSVarun Prakash 			 * initiator plug the CmdSN gap.
11119730ffcbSVarun Prakash 			 */
11129730ffcbSVarun Prakash 			pr_info("Dropping NOPOUT"
11139730ffcbSVarun Prakash 				" Command CmdSN: 0x%08x due to"
11149730ffcbSVarun Prakash 				" DataCRC error.\n", hdr->cmdsn);
11159730ffcbSVarun Prakash 			ret = 0;
11169730ffcbSVarun Prakash 			goto out;
11179730ffcbSVarun Prakash 		}
11189730ffcbSVarun Prakash 	}
11199730ffcbSVarun Prakash 
11209730ffcbSVarun Prakash 	/*
11219730ffcbSVarun Prakash 	 * Handle NOP-OUT payload for traditional iSCSI sockets
11229730ffcbSVarun Prakash 	 */
11239730ffcbSVarun Prakash 	if (payload_length && hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
11249730ffcbSVarun Prakash 		ping_data = kzalloc(payload_length + 1, GFP_KERNEL);
11259730ffcbSVarun Prakash 		if (!ping_data) {
11269730ffcbSVarun Prakash 			pr_err("Unable to allocate memory for"
11279730ffcbSVarun Prakash 				" NOPOUT ping data.\n");
11289730ffcbSVarun Prakash 			ret = -1;
11299730ffcbSVarun Prakash 			goto out;
11309730ffcbSVarun Prakash 		}
11319730ffcbSVarun Prakash 
11329730ffcbSVarun Prakash 		skb_copy_bits(csk->skb, pdu_cb->doffset,
11339730ffcbSVarun Prakash 			      ping_data, payload_length);
11349730ffcbSVarun Prakash 
11359730ffcbSVarun Prakash 		ping_data[payload_length] = '\0';
11369730ffcbSVarun Prakash 		/*
113766cd9d4eSMax Gurtovoy 		 * Attach ping data to struct iscsit_cmd->buf_ptr.
11389730ffcbSVarun Prakash 		 */
11399730ffcbSVarun Prakash 		cmd->buf_ptr = ping_data;
11409730ffcbSVarun Prakash 		cmd->buf_ptr_size = payload_length;
11419730ffcbSVarun Prakash 
11429730ffcbSVarun Prakash 		pr_debug("Got %u bytes of NOPOUT ping"
11439730ffcbSVarun Prakash 			" data.\n", payload_length);
11449730ffcbSVarun Prakash 		pr_debug("Ping Data: \"%s\"\n", ping_data);
11459730ffcbSVarun Prakash 	}
11469730ffcbSVarun Prakash 
11479730ffcbSVarun Prakash 	return iscsit_process_nop_out(conn, cmd, hdr);
11489730ffcbSVarun Prakash out:
11499730ffcbSVarun Prakash 	if (cmd)
11509730ffcbSVarun Prakash 		iscsit_free_cmd(cmd, false);
11519730ffcbSVarun Prakash 	return ret;
11529730ffcbSVarun Prakash }
11539730ffcbSVarun Prakash 
11549730ffcbSVarun Prakash static int
cxgbit_handle_text_cmd(struct cxgbit_sock * csk,struct iscsit_cmd * cmd)115566cd9d4eSMax Gurtovoy cxgbit_handle_text_cmd(struct cxgbit_sock *csk, struct iscsit_cmd *cmd)
11569730ffcbSVarun Prakash {
1157*be36d683SMax Gurtovoy 	struct iscsit_conn *conn = csk->conn;
11589730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
11599730ffcbSVarun Prakash 	struct iscsi_text *hdr = (struct iscsi_text *)pdu_cb->hdr;
11609730ffcbSVarun Prakash 	u32 payload_length = pdu_cb->dlen;
11619730ffcbSVarun Prakash 	int rc;
11629730ffcbSVarun Prakash 	unsigned char *text_in = NULL;
11639730ffcbSVarun Prakash 
11649730ffcbSVarun Prakash 	rc = iscsit_setup_text_cmd(conn, cmd, hdr);
11659730ffcbSVarun Prakash 	if (rc < 0)
11669730ffcbSVarun Prakash 		return rc;
11679730ffcbSVarun Prakash 
11689730ffcbSVarun Prakash 	if (pdu_cb->flags & PDUCBF_RX_DCRC_ERR) {
11699730ffcbSVarun Prakash 		if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
11709730ffcbSVarun Prakash 			pr_err("Unable to recover from"
11719730ffcbSVarun Prakash 			       " Text Data digest failure while in"
11729730ffcbSVarun Prakash 			       " ERL=0.\n");
11739730ffcbSVarun Prakash 			goto reject;
11749730ffcbSVarun Prakash 		} else {
11759730ffcbSVarun Prakash 			/*
11769730ffcbSVarun Prakash 			 * drop this PDU and let the
11779730ffcbSVarun Prakash 			 * initiator plug the CmdSN gap.
11789730ffcbSVarun Prakash 			 */
11799730ffcbSVarun Prakash 			pr_info("Dropping Text"
11809730ffcbSVarun Prakash 				" Command CmdSN: 0x%08x due to"
11819730ffcbSVarun Prakash 				" DataCRC error.\n", hdr->cmdsn);
11829730ffcbSVarun Prakash 			return 0;
11839730ffcbSVarun Prakash 		}
11849730ffcbSVarun Prakash 	}
11859730ffcbSVarun Prakash 
11869730ffcbSVarun Prakash 	if (payload_length) {
11879730ffcbSVarun Prakash 		text_in = kzalloc(payload_length, GFP_KERNEL);
11889730ffcbSVarun Prakash 		if (!text_in) {
11899730ffcbSVarun Prakash 			pr_err("Unable to allocate text_in of payload_length: %u\n",
11909730ffcbSVarun Prakash 			       payload_length);
11919730ffcbSVarun Prakash 			return -ENOMEM;
11929730ffcbSVarun Prakash 		}
11939730ffcbSVarun Prakash 		skb_copy_bits(csk->skb, pdu_cb->doffset,
11949730ffcbSVarun Prakash 			      text_in, payload_length);
11959730ffcbSVarun Prakash 
11969730ffcbSVarun Prakash 		text_in[payload_length - 1] = '\0';
11979730ffcbSVarun Prakash 
11989730ffcbSVarun Prakash 		cmd->text_in_ptr = text_in;
11999730ffcbSVarun Prakash 	}
12009730ffcbSVarun Prakash 
12019730ffcbSVarun Prakash 	return iscsit_process_text_cmd(conn, cmd, hdr);
12029730ffcbSVarun Prakash 
12039730ffcbSVarun Prakash reject:
12049730ffcbSVarun Prakash 	return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
12059730ffcbSVarun Prakash 				 pdu_cb->hdr);
12069730ffcbSVarun Prakash }
12079730ffcbSVarun Prakash 
cxgbit_target_rx_opcode(struct cxgbit_sock * csk)12089730ffcbSVarun Prakash static int cxgbit_target_rx_opcode(struct cxgbit_sock *csk)
12099730ffcbSVarun Prakash {
12109730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
12119730ffcbSVarun Prakash 	struct iscsi_hdr *hdr = (struct iscsi_hdr *)pdu_cb->hdr;
1212*be36d683SMax Gurtovoy 	struct iscsit_conn *conn = csk->conn;
121366cd9d4eSMax Gurtovoy 	struct iscsit_cmd *cmd = NULL;
12149730ffcbSVarun Prakash 	u8 opcode = (hdr->opcode & ISCSI_OPCODE_MASK);
12159730ffcbSVarun Prakash 	int ret = -EINVAL;
12169730ffcbSVarun Prakash 
12179730ffcbSVarun Prakash 	switch (opcode) {
12189730ffcbSVarun Prakash 	case ISCSI_OP_SCSI_CMD:
12199730ffcbSVarun Prakash 		cmd = cxgbit_allocate_cmd(csk);
12209730ffcbSVarun Prakash 		if (!cmd)
12219730ffcbSVarun Prakash 			goto reject;
12229730ffcbSVarun Prakash 
12239730ffcbSVarun Prakash 		ret = cxgbit_handle_scsi_cmd(csk, cmd);
12249730ffcbSVarun Prakash 		break;
12259730ffcbSVarun Prakash 	case ISCSI_OP_SCSI_DATA_OUT:
12269730ffcbSVarun Prakash 		ret = cxgbit_handle_iscsi_dataout(csk);
12279730ffcbSVarun Prakash 		break;
12289730ffcbSVarun Prakash 	case ISCSI_OP_NOOP_OUT:
12299730ffcbSVarun Prakash 		if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
12309730ffcbSVarun Prakash 			cmd = cxgbit_allocate_cmd(csk);
12319730ffcbSVarun Prakash 			if (!cmd)
12329730ffcbSVarun Prakash 				goto reject;
12339730ffcbSVarun Prakash 		}
12349730ffcbSVarun Prakash 
12359730ffcbSVarun Prakash 		ret = cxgbit_handle_nop_out(csk, cmd);
12369730ffcbSVarun Prakash 		break;
12379730ffcbSVarun Prakash 	case ISCSI_OP_SCSI_TMFUNC:
12389730ffcbSVarun Prakash 		cmd = cxgbit_allocate_cmd(csk);
12399730ffcbSVarun Prakash 		if (!cmd)
12409730ffcbSVarun Prakash 			goto reject;
12419730ffcbSVarun Prakash 
12429730ffcbSVarun Prakash 		ret = iscsit_handle_task_mgt_cmd(conn, cmd,
12439730ffcbSVarun Prakash 						 (unsigned char *)hdr);
12449730ffcbSVarun Prakash 		break;
12459730ffcbSVarun Prakash 	case ISCSI_OP_TEXT:
12469730ffcbSVarun Prakash 		if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) {
12479730ffcbSVarun Prakash 			cmd = iscsit_find_cmd_from_itt(conn, hdr->itt);
12489730ffcbSVarun Prakash 			if (!cmd)
12499730ffcbSVarun Prakash 				goto reject;
12509730ffcbSVarun Prakash 		} else {
12519730ffcbSVarun Prakash 			cmd = cxgbit_allocate_cmd(csk);
12529730ffcbSVarun Prakash 			if (!cmd)
12539730ffcbSVarun Prakash 				goto reject;
12549730ffcbSVarun Prakash 		}
12559730ffcbSVarun Prakash 
12569730ffcbSVarun Prakash 		ret = cxgbit_handle_text_cmd(csk, cmd);
12579730ffcbSVarun Prakash 		break;
12589730ffcbSVarun Prakash 	case ISCSI_OP_LOGOUT:
12599730ffcbSVarun Prakash 		cmd = cxgbit_allocate_cmd(csk);
12609730ffcbSVarun Prakash 		if (!cmd)
12619730ffcbSVarun Prakash 			goto reject;
12629730ffcbSVarun Prakash 
12639730ffcbSVarun Prakash 		ret = iscsit_handle_logout_cmd(conn, cmd, (unsigned char *)hdr);
12649730ffcbSVarun Prakash 		if (ret > 0)
12659730ffcbSVarun Prakash 			wait_for_completion_timeout(&conn->conn_logout_comp,
12669730ffcbSVarun Prakash 						    SECONDS_FOR_LOGOUT_COMP
12679730ffcbSVarun Prakash 						    * HZ);
12689730ffcbSVarun Prakash 		break;
12699730ffcbSVarun Prakash 	case ISCSI_OP_SNACK:
12709730ffcbSVarun Prakash 		ret = iscsit_handle_snack(conn, (unsigned char *)hdr);
12719730ffcbSVarun Prakash 		break;
12729730ffcbSVarun Prakash 	default:
12739730ffcbSVarun Prakash 		pr_err("Got unknown iSCSI OpCode: 0x%02x\n", opcode);
12749730ffcbSVarun Prakash 		dump_stack();
12759730ffcbSVarun Prakash 		break;
12769730ffcbSVarun Prakash 	}
12779730ffcbSVarun Prakash 
12789730ffcbSVarun Prakash 	return ret;
12799730ffcbSVarun Prakash 
12809730ffcbSVarun Prakash reject:
12819730ffcbSVarun Prakash 	return iscsit_add_reject(conn, ISCSI_REASON_BOOKMARK_NO_RESOURCES,
12829730ffcbSVarun Prakash 				 (unsigned char *)hdr);
12839730ffcbSVarun Prakash 	return ret;
12849730ffcbSVarun Prakash }
12859730ffcbSVarun Prakash 
cxgbit_rx_opcode(struct cxgbit_sock * csk)12869730ffcbSVarun Prakash static int cxgbit_rx_opcode(struct cxgbit_sock *csk)
12879730ffcbSVarun Prakash {
12889730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
1289*be36d683SMax Gurtovoy 	struct iscsit_conn *conn = csk->conn;
12909730ffcbSVarun Prakash 	struct iscsi_hdr *hdr = pdu_cb->hdr;
12919730ffcbSVarun Prakash 	u8 opcode;
12929730ffcbSVarun Prakash 
12939730ffcbSVarun Prakash 	if (pdu_cb->flags & PDUCBF_RX_HCRC_ERR) {
12949730ffcbSVarun Prakash 		atomic_long_inc(&conn->sess->conn_digest_errors);
12959730ffcbSVarun Prakash 		goto transport_err;
12969730ffcbSVarun Prakash 	}
12979730ffcbSVarun Prakash 
12989730ffcbSVarun Prakash 	if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT)
12999730ffcbSVarun Prakash 		goto transport_err;
13009730ffcbSVarun Prakash 
13019730ffcbSVarun Prakash 	opcode = hdr->opcode & ISCSI_OPCODE_MASK;
13029730ffcbSVarun Prakash 
13039730ffcbSVarun Prakash 	if (conn->sess->sess_ops->SessionType &&
13049730ffcbSVarun Prakash 	    ((!(opcode & ISCSI_OP_TEXT)) ||
13059730ffcbSVarun Prakash 	     (!(opcode & ISCSI_OP_LOGOUT)))) {
13069730ffcbSVarun Prakash 		pr_err("Received illegal iSCSI Opcode: 0x%02x"
13079730ffcbSVarun Prakash 			" while in Discovery Session, rejecting.\n", opcode);
13089730ffcbSVarun Prakash 		iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
13099730ffcbSVarun Prakash 				  (unsigned char *)hdr);
13109730ffcbSVarun Prakash 		goto transport_err;
13119730ffcbSVarun Prakash 	}
13129730ffcbSVarun Prakash 
13139730ffcbSVarun Prakash 	if (cxgbit_target_rx_opcode(csk) < 0)
13149730ffcbSVarun Prakash 		goto transport_err;
13159730ffcbSVarun Prakash 
13169730ffcbSVarun Prakash 	return 0;
13179730ffcbSVarun Prakash 
13189730ffcbSVarun Prakash transport_err:
13199730ffcbSVarun Prakash 	return -1;
13209730ffcbSVarun Prakash }
13219730ffcbSVarun Prakash 
cxgbit_rx_login_pdu(struct cxgbit_sock * csk)13229730ffcbSVarun Prakash static int cxgbit_rx_login_pdu(struct cxgbit_sock *csk)
13239730ffcbSVarun Prakash {
1324*be36d683SMax Gurtovoy 	struct iscsit_conn *conn = csk->conn;
13259730ffcbSVarun Prakash 	struct iscsi_login *login = conn->login;
13269730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
13279730ffcbSVarun Prakash 	struct iscsi_login_req *login_req;
13289730ffcbSVarun Prakash 
13299730ffcbSVarun Prakash 	login_req = (struct iscsi_login_req *)login->req;
13309730ffcbSVarun Prakash 	memcpy(login_req, pdu_cb->hdr, sizeof(*login_req));
13319730ffcbSVarun Prakash 
13329730ffcbSVarun Prakash 	pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x,"
13339730ffcbSVarun Prakash 		" CmdSN: 0x%08x, ExpStatSN: 0x%08x, CID: %hu, Length: %u\n",
13349730ffcbSVarun Prakash 		login_req->flags, login_req->itt, login_req->cmdsn,
13359730ffcbSVarun Prakash 		login_req->exp_statsn, login_req->cid, pdu_cb->dlen);
13369730ffcbSVarun Prakash 	/*
13379730ffcbSVarun Prakash 	 * Setup the initial iscsi_login values from the leading
13389730ffcbSVarun Prakash 	 * login request PDU.
13399730ffcbSVarun Prakash 	 */
13409730ffcbSVarun Prakash 	if (login->first_request) {
13419730ffcbSVarun Prakash 		login_req = (struct iscsi_login_req *)login->req;
13429730ffcbSVarun Prakash 		login->leading_connection = (!login_req->tsih) ? 1 : 0;
13439730ffcbSVarun Prakash 		login->current_stage	= ISCSI_LOGIN_CURRENT_STAGE(
13449730ffcbSVarun Prakash 				login_req->flags);
13459730ffcbSVarun Prakash 		login->version_min	= login_req->min_version;
13469730ffcbSVarun Prakash 		login->version_max	= login_req->max_version;
13479730ffcbSVarun Prakash 		memcpy(login->isid, login_req->isid, 6);
13489730ffcbSVarun Prakash 		login->cmd_sn		= be32_to_cpu(login_req->cmdsn);
13499730ffcbSVarun Prakash 		login->init_task_tag	= login_req->itt;
13509730ffcbSVarun Prakash 		login->initial_exp_statsn = be32_to_cpu(login_req->exp_statsn);
13519730ffcbSVarun Prakash 		login->cid		= be16_to_cpu(login_req->cid);
13529730ffcbSVarun Prakash 		login->tsih		= be16_to_cpu(login_req->tsih);
13539730ffcbSVarun Prakash 	}
13549730ffcbSVarun Prakash 
13559730ffcbSVarun Prakash 	if (iscsi_target_check_login_request(conn, login) < 0)
13569730ffcbSVarun Prakash 		return -1;
13579730ffcbSVarun Prakash 
13589730ffcbSVarun Prakash 	memset(login->req_buf, 0, MAX_KEY_VALUE_PAIRS);
13599730ffcbSVarun Prakash 	skb_copy_bits(csk->skb, pdu_cb->doffset, login->req_buf, pdu_cb->dlen);
13609730ffcbSVarun Prakash 
13619730ffcbSVarun Prakash 	return 0;
13629730ffcbSVarun Prakash }
13639730ffcbSVarun Prakash 
13649730ffcbSVarun Prakash static int
cxgbit_process_iscsi_pdu(struct cxgbit_sock * csk,struct sk_buff * skb,int idx)13659730ffcbSVarun Prakash cxgbit_process_iscsi_pdu(struct cxgbit_sock *csk, struct sk_buff *skb, int idx)
13669730ffcbSVarun Prakash {
13679730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, idx);
13689730ffcbSVarun Prakash 	int ret;
13699730ffcbSVarun Prakash 
13709730ffcbSVarun Prakash 	cxgbit_rx_pdu_cb(skb) = pdu_cb;
13719730ffcbSVarun Prakash 
13729730ffcbSVarun Prakash 	csk->skb = skb;
13739730ffcbSVarun Prakash 
13749730ffcbSVarun Prakash 	if (!test_bit(CSK_LOGIN_DONE, &csk->com.flags)) {
13759730ffcbSVarun Prakash 		ret = cxgbit_rx_login_pdu(csk);
13769730ffcbSVarun Prakash 		set_bit(CSK_LOGIN_PDU_DONE, &csk->com.flags);
13779730ffcbSVarun Prakash 	} else {
13789730ffcbSVarun Prakash 		ret = cxgbit_rx_opcode(csk);
13799730ffcbSVarun Prakash 	}
13809730ffcbSVarun Prakash 
13819730ffcbSVarun Prakash 	return ret;
13829730ffcbSVarun Prakash }
13839730ffcbSVarun Prakash 
cxgbit_lro_skb_dump(struct sk_buff * skb)13849730ffcbSVarun Prakash static void cxgbit_lro_skb_dump(struct sk_buff *skb)
13859730ffcbSVarun Prakash {
13869730ffcbSVarun Prakash 	struct skb_shared_info *ssi = skb_shinfo(skb);
13879730ffcbSVarun Prakash 	struct cxgbit_lro_cb *lro_cb = cxgbit_skb_lro_cb(skb);
13889730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, 0);
13899730ffcbSVarun Prakash 	u8 i;
13909730ffcbSVarun Prakash 
13919730ffcbSVarun Prakash 	pr_info("skb 0x%p, head 0x%p, 0x%p, len %u,%u, frags %u.\n",
13929730ffcbSVarun Prakash 		skb, skb->head, skb->data, skb->len, skb->data_len,
13939730ffcbSVarun Prakash 		ssi->nr_frags);
13949730ffcbSVarun Prakash 	pr_info("skb 0x%p, lro_cb, csk 0x%p, pdu %u, %u.\n",
13959730ffcbSVarun Prakash 		skb, lro_cb->csk, lro_cb->pdu_idx, lro_cb->pdu_totallen);
13969730ffcbSVarun Prakash 
13979730ffcbSVarun Prakash 	for (i = 0; i < lro_cb->pdu_idx; i++, pdu_cb++)
13989730ffcbSVarun Prakash 		pr_info("skb 0x%p, pdu %d, %u, f 0x%x, seq 0x%x, dcrc 0x%x, "
13999730ffcbSVarun Prakash 			"frags %u.\n",
14009730ffcbSVarun Prakash 			skb, i, pdu_cb->pdulen, pdu_cb->flags, pdu_cb->seq,
14019730ffcbSVarun Prakash 			pdu_cb->ddigest, pdu_cb->frags);
14029730ffcbSVarun Prakash 	for (i = 0; i < ssi->nr_frags; i++)
14039730ffcbSVarun Prakash 		pr_info("skb 0x%p, frag %d, off %u, sz %u.\n",
1404b54c9d5bSJonathan Lemon 			skb, i, skb_frag_off(&ssi->frags[i]),
1405d7840976SMatthew Wilcox (Oracle) 			skb_frag_size(&ssi->frags[i]));
14069730ffcbSVarun Prakash }
14079730ffcbSVarun Prakash 
cxgbit_lro_hskb_reset(struct cxgbit_sock * csk)14089730ffcbSVarun Prakash static void cxgbit_lro_hskb_reset(struct cxgbit_sock *csk)
14099730ffcbSVarun Prakash {
14109730ffcbSVarun Prakash 	struct sk_buff *skb = csk->lro_hskb;
14119730ffcbSVarun Prakash 	struct skb_shared_info *ssi = skb_shinfo(skb);
14129730ffcbSVarun Prakash 	u8 i;
14139730ffcbSVarun Prakash 
14149730ffcbSVarun Prakash 	memset(skb->data, 0, LRO_SKB_MIN_HEADROOM);
14159730ffcbSVarun Prakash 	for (i = 0; i < ssi->nr_frags; i++)
14169730ffcbSVarun Prakash 		put_page(skb_frag_page(&ssi->frags[i]));
14179730ffcbSVarun Prakash 	ssi->nr_frags = 0;
141879e57cfeSVarun Prakash 	skb->data_len = 0;
141979e57cfeSVarun Prakash 	skb->truesize -= skb->len;
142079e57cfeSVarun Prakash 	skb->len = 0;
14219730ffcbSVarun Prakash }
14229730ffcbSVarun Prakash 
14239730ffcbSVarun Prakash static void
cxgbit_lro_skb_merge(struct cxgbit_sock * csk,struct sk_buff * skb,u8 pdu_idx)14249730ffcbSVarun Prakash cxgbit_lro_skb_merge(struct cxgbit_sock *csk, struct sk_buff *skb, u8 pdu_idx)
14259730ffcbSVarun Prakash {
14269730ffcbSVarun Prakash 	struct sk_buff *hskb = csk->lro_hskb;
14279730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *hpdu_cb = cxgbit_skb_lro_pdu_cb(hskb, 0);
14289730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, pdu_idx);
14299730ffcbSVarun Prakash 	struct skb_shared_info *hssi = skb_shinfo(hskb);
14309730ffcbSVarun Prakash 	struct skb_shared_info *ssi = skb_shinfo(skb);
14319730ffcbSVarun Prakash 	unsigned int len = 0;
14329730ffcbSVarun Prakash 
14339730ffcbSVarun Prakash 	if (pdu_cb->flags & PDUCBF_RX_HDR) {
143479e57cfeSVarun Prakash 		u8 hfrag_idx = hssi->nr_frags;
143579e57cfeSVarun Prakash 
143679e57cfeSVarun Prakash 		hpdu_cb->flags |= pdu_cb->flags;
14379730ffcbSVarun Prakash 		hpdu_cb->seq = pdu_cb->seq;
14389730ffcbSVarun Prakash 		hpdu_cb->hdr = pdu_cb->hdr;
14399730ffcbSVarun Prakash 		hpdu_cb->hlen = pdu_cb->hlen;
14409730ffcbSVarun Prakash 
144179e57cfeSVarun Prakash 		memcpy(&hssi->frags[hfrag_idx], &ssi->frags[pdu_cb->hfrag_idx],
14429730ffcbSVarun Prakash 		       sizeof(skb_frag_t));
14439730ffcbSVarun Prakash 
14449730ffcbSVarun Prakash 		get_page(skb_frag_page(&hssi->frags[hfrag_idx]));
144579e57cfeSVarun Prakash 		hssi->nr_frags++;
144679e57cfeSVarun Prakash 		hpdu_cb->frags++;
144779e57cfeSVarun Prakash 		hpdu_cb->hfrag_idx = hfrag_idx;
14489730ffcbSVarun Prakash 
144992493a2fSMatthew Wilcox (Oracle) 		len = skb_frag_size(&hssi->frags[hfrag_idx]);
145079e57cfeSVarun Prakash 		hskb->len += len;
145179e57cfeSVarun Prakash 		hskb->data_len += len;
145279e57cfeSVarun Prakash 		hskb->truesize += len;
145379e57cfeSVarun Prakash 	}
145479e57cfeSVarun Prakash 
145579e57cfeSVarun Prakash 	if (pdu_cb->flags & PDUCBF_RX_DATA) {
145679e57cfeSVarun Prakash 		u8 dfrag_idx = hssi->nr_frags, i;
145779e57cfeSVarun Prakash 
145879e57cfeSVarun Prakash 		hpdu_cb->flags |= pdu_cb->flags;
145979e57cfeSVarun Prakash 		hpdu_cb->dfrag_idx = dfrag_idx;
146079e57cfeSVarun Prakash 
146179e57cfeSVarun Prakash 		len = 0;
146279e57cfeSVarun Prakash 		for (i = 0; i < pdu_cb->nr_dfrags; dfrag_idx++, i++) {
146379e57cfeSVarun Prakash 			memcpy(&hssi->frags[dfrag_idx],
146479e57cfeSVarun Prakash 			       &ssi->frags[pdu_cb->dfrag_idx + i],
146579e57cfeSVarun Prakash 			       sizeof(skb_frag_t));
146679e57cfeSVarun Prakash 
146779e57cfeSVarun Prakash 			get_page(skb_frag_page(&hssi->frags[dfrag_idx]));
146879e57cfeSVarun Prakash 
1469d7840976SMatthew Wilcox (Oracle) 			len += skb_frag_size(&hssi->frags[dfrag_idx]);
14709730ffcbSVarun Prakash 
14719730ffcbSVarun Prakash 			hssi->nr_frags++;
14729730ffcbSVarun Prakash 			hpdu_cb->frags++;
14739730ffcbSVarun Prakash 		}
14749730ffcbSVarun Prakash 
14759730ffcbSVarun Prakash 		hpdu_cb->dlen = pdu_cb->dlen;
14769730ffcbSVarun Prakash 		hpdu_cb->doffset = hpdu_cb->hlen;
14779730ffcbSVarun Prakash 		hpdu_cb->nr_dfrags = pdu_cb->nr_dfrags;
14789730ffcbSVarun Prakash 		hskb->len += len;
14799730ffcbSVarun Prakash 		hskb->data_len += len;
14809730ffcbSVarun Prakash 		hskb->truesize += len;
14819730ffcbSVarun Prakash 	}
14829730ffcbSVarun Prakash 
14839730ffcbSVarun Prakash 	if (pdu_cb->flags & PDUCBF_RX_STATUS) {
14849730ffcbSVarun Prakash 		hpdu_cb->flags |= pdu_cb->flags;
14859730ffcbSVarun Prakash 
14869730ffcbSVarun Prakash 		if (hpdu_cb->flags & PDUCBF_RX_DATA)
14879730ffcbSVarun Prakash 			hpdu_cb->flags &= ~PDUCBF_RX_DATA_DDPD;
14889730ffcbSVarun Prakash 
14899730ffcbSVarun Prakash 		hpdu_cb->ddigest = pdu_cb->ddigest;
14909730ffcbSVarun Prakash 		hpdu_cb->pdulen = pdu_cb->pdulen;
14919730ffcbSVarun Prakash 	}
14929730ffcbSVarun Prakash }
14939730ffcbSVarun Prakash 
cxgbit_process_lro_skb(struct cxgbit_sock * csk,struct sk_buff * skb)14949730ffcbSVarun Prakash static int cxgbit_process_lro_skb(struct cxgbit_sock *csk, struct sk_buff *skb)
14959730ffcbSVarun Prakash {
14969730ffcbSVarun Prakash 	struct cxgbit_lro_cb *lro_cb = cxgbit_skb_lro_cb(skb);
14979730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, 0);
14989730ffcbSVarun Prakash 	u8 pdu_idx = 0, last_idx = 0;
14999730ffcbSVarun Prakash 	int ret = 0;
15009730ffcbSVarun Prakash 
15019730ffcbSVarun Prakash 	if (!pdu_cb->complete) {
15029730ffcbSVarun Prakash 		cxgbit_lro_skb_merge(csk, skb, 0);
15039730ffcbSVarun Prakash 
15049730ffcbSVarun Prakash 		if (pdu_cb->flags & PDUCBF_RX_STATUS) {
15059730ffcbSVarun Prakash 			struct sk_buff *hskb = csk->lro_hskb;
15069730ffcbSVarun Prakash 
15079730ffcbSVarun Prakash 			ret = cxgbit_process_iscsi_pdu(csk, hskb, 0);
15089730ffcbSVarun Prakash 
15099730ffcbSVarun Prakash 			cxgbit_lro_hskb_reset(csk);
15109730ffcbSVarun Prakash 
15119730ffcbSVarun Prakash 			if (ret < 0)
15129730ffcbSVarun Prakash 				goto out;
15139730ffcbSVarun Prakash 		}
15149730ffcbSVarun Prakash 
15159730ffcbSVarun Prakash 		pdu_idx = 1;
15169730ffcbSVarun Prakash 	}
15179730ffcbSVarun Prakash 
15189730ffcbSVarun Prakash 	if (lro_cb->pdu_idx)
15199730ffcbSVarun Prakash 		last_idx = lro_cb->pdu_idx - 1;
15209730ffcbSVarun Prakash 
15219730ffcbSVarun Prakash 	for (; pdu_idx <= last_idx; pdu_idx++) {
15229730ffcbSVarun Prakash 		ret = cxgbit_process_iscsi_pdu(csk, skb, pdu_idx);
15239730ffcbSVarun Prakash 		if (ret < 0)
15249730ffcbSVarun Prakash 			goto out;
15259730ffcbSVarun Prakash 	}
15269730ffcbSVarun Prakash 
15279730ffcbSVarun Prakash 	if ((!lro_cb->complete) && lro_cb->pdu_idx)
15289730ffcbSVarun Prakash 		cxgbit_lro_skb_merge(csk, skb, lro_cb->pdu_idx);
15299730ffcbSVarun Prakash 
15309730ffcbSVarun Prakash out:
15319730ffcbSVarun Prakash 	return ret;
15329730ffcbSVarun Prakash }
15339730ffcbSVarun Prakash 
cxgbit_t5_rx_lro_skb(struct cxgbit_sock * csk,struct sk_buff * skb)1534d1e51ea6SVarun Prakash static int cxgbit_t5_rx_lro_skb(struct cxgbit_sock *csk, struct sk_buff *skb)
15359730ffcbSVarun Prakash {
15369730ffcbSVarun Prakash 	struct cxgbit_lro_cb *lro_cb = cxgbit_skb_lro_cb(skb);
15379730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, 0);
15389730ffcbSVarun Prakash 	int ret = -1;
15399730ffcbSVarun Prakash 
15409730ffcbSVarun Prakash 	if ((pdu_cb->flags & PDUCBF_RX_HDR) &&
15419730ffcbSVarun Prakash 	    (pdu_cb->seq != csk->rcv_nxt)) {
15429730ffcbSVarun Prakash 		pr_info("csk 0x%p, tid 0x%x, seq 0x%x != 0x%x.\n",
15439730ffcbSVarun Prakash 			csk, csk->tid, pdu_cb->seq, csk->rcv_nxt);
15449730ffcbSVarun Prakash 		cxgbit_lro_skb_dump(skb);
15459730ffcbSVarun Prakash 		return ret;
15469730ffcbSVarun Prakash 	}
15479730ffcbSVarun Prakash 
15489730ffcbSVarun Prakash 	csk->rcv_nxt += lro_cb->pdu_totallen;
15499730ffcbSVarun Prakash 
15509730ffcbSVarun Prakash 	ret = cxgbit_process_lro_skb(csk, skb);
15519730ffcbSVarun Prakash 
15529730ffcbSVarun Prakash 	csk->rx_credits += lro_cb->pdu_totallen;
15539730ffcbSVarun Prakash 
15549730ffcbSVarun Prakash 	if (csk->rx_credits >= (csk->rcv_win / 4))
15559730ffcbSVarun Prakash 		cxgbit_rx_data_ack(csk);
15569730ffcbSVarun Prakash 
15579730ffcbSVarun Prakash 	return ret;
15589730ffcbSVarun Prakash }
15599730ffcbSVarun Prakash 
cxgbit_rx_lro_skb(struct cxgbit_sock * csk,struct sk_buff * skb)1560d1e51ea6SVarun Prakash static int cxgbit_rx_lro_skb(struct cxgbit_sock *csk, struct sk_buff *skb)
1561d1e51ea6SVarun Prakash {
1562d1e51ea6SVarun Prakash 	struct cxgbit_lro_cb *lro_cb = cxgbit_skb_lro_cb(skb);
1563d1e51ea6SVarun Prakash 	int ret;
1564d1e51ea6SVarun Prakash 
1565d1e51ea6SVarun Prakash 	ret = cxgbit_process_lro_skb(csk, skb);
1566d1e51ea6SVarun Prakash 	if (ret)
1567d1e51ea6SVarun Prakash 		return ret;
1568d1e51ea6SVarun Prakash 
1569d1e51ea6SVarun Prakash 	csk->rx_credits += lro_cb->pdu_totallen;
1570d1e51ea6SVarun Prakash 	if (csk->rx_credits >= csk->rcv_win) {
1571d1e51ea6SVarun Prakash 		csk->rx_credits = 0;
1572d1e51ea6SVarun Prakash 		cxgbit_rx_data_ack(csk);
1573d1e51ea6SVarun Prakash 	}
1574d1e51ea6SVarun Prakash 
1575d1e51ea6SVarun Prakash 	return 0;
1576d1e51ea6SVarun Prakash }
1577d1e51ea6SVarun Prakash 
cxgbit_rx_skb(struct cxgbit_sock * csk,struct sk_buff * skb)15789730ffcbSVarun Prakash static int cxgbit_rx_skb(struct cxgbit_sock *csk, struct sk_buff *skb)
15799730ffcbSVarun Prakash {
158079e57cfeSVarun Prakash 	struct cxgb4_lld_info *lldi = &csk->com.cdev->lldi;
15819730ffcbSVarun Prakash 	int ret = -1;
15829730ffcbSVarun Prakash 
158379e57cfeSVarun Prakash 	if (likely(cxgbit_skcb_flags(skb) & SKCBF_RX_LRO)) {
158479e57cfeSVarun Prakash 		if (is_t5(lldi->adapter_type))
1585d1e51ea6SVarun Prakash 			ret = cxgbit_t5_rx_lro_skb(csk, skb);
158679e57cfeSVarun Prakash 		else
1587d1e51ea6SVarun Prakash 			ret = cxgbit_rx_lro_skb(csk, skb);
158879e57cfeSVarun Prakash 	}
15899730ffcbSVarun Prakash 
15909730ffcbSVarun Prakash 	__kfree_skb(skb);
15919730ffcbSVarun Prakash 	return ret;
15929730ffcbSVarun Prakash }
15939730ffcbSVarun Prakash 
cxgbit_rxq_len(struct cxgbit_sock * csk,struct sk_buff_head * rxq)15949730ffcbSVarun Prakash static bool cxgbit_rxq_len(struct cxgbit_sock *csk, struct sk_buff_head *rxq)
15959730ffcbSVarun Prakash {
15969730ffcbSVarun Prakash 	spin_lock_bh(&csk->rxq.lock);
15979730ffcbSVarun Prakash 	if (skb_queue_len(&csk->rxq)) {
15989730ffcbSVarun Prakash 		skb_queue_splice_init(&csk->rxq, rxq);
15999730ffcbSVarun Prakash 		spin_unlock_bh(&csk->rxq.lock);
16009730ffcbSVarun Prakash 		return true;
16019730ffcbSVarun Prakash 	}
16029730ffcbSVarun Prakash 	spin_unlock_bh(&csk->rxq.lock);
16039730ffcbSVarun Prakash 	return false;
16049730ffcbSVarun Prakash }
16059730ffcbSVarun Prakash 
cxgbit_wait_rxq(struct cxgbit_sock * csk)16069730ffcbSVarun Prakash static int cxgbit_wait_rxq(struct cxgbit_sock *csk)
16079730ffcbSVarun Prakash {
16089730ffcbSVarun Prakash 	struct sk_buff *skb;
16099730ffcbSVarun Prakash 	struct sk_buff_head rxq;
16109730ffcbSVarun Prakash 
16119730ffcbSVarun Prakash 	skb_queue_head_init(&rxq);
16129730ffcbSVarun Prakash 
16139730ffcbSVarun Prakash 	wait_event_interruptible(csk->waitq, cxgbit_rxq_len(csk, &rxq));
16149730ffcbSVarun Prakash 
16159730ffcbSVarun Prakash 	if (signal_pending(current))
16169730ffcbSVarun Prakash 		goto out;
16179730ffcbSVarun Prakash 
16189730ffcbSVarun Prakash 	while ((skb = __skb_dequeue(&rxq))) {
16199730ffcbSVarun Prakash 		if (cxgbit_rx_skb(csk, skb))
16209730ffcbSVarun Prakash 			goto out;
16219730ffcbSVarun Prakash 	}
16229730ffcbSVarun Prakash 
16239730ffcbSVarun Prakash 	return 0;
16249730ffcbSVarun Prakash out:
16259730ffcbSVarun Prakash 	__skb_queue_purge(&rxq);
16269730ffcbSVarun Prakash 	return -1;
16279730ffcbSVarun Prakash }
16289730ffcbSVarun Prakash 
cxgbit_get_login_rx(struct iscsit_conn * conn,struct iscsi_login * login)1629*be36d683SMax Gurtovoy int cxgbit_get_login_rx(struct iscsit_conn *conn, struct iscsi_login *login)
16309730ffcbSVarun Prakash {
16319730ffcbSVarun Prakash 	struct cxgbit_sock *csk = conn->context;
16329730ffcbSVarun Prakash 	int ret = -1;
16339730ffcbSVarun Prakash 
16349730ffcbSVarun Prakash 	while (!test_and_clear_bit(CSK_LOGIN_PDU_DONE, &csk->com.flags)) {
16359730ffcbSVarun Prakash 		ret = cxgbit_wait_rxq(csk);
16369730ffcbSVarun Prakash 		if (ret) {
16379730ffcbSVarun Prakash 			clear_bit(CSK_LOGIN_PDU_DONE, &csk->com.flags);
16389730ffcbSVarun Prakash 			break;
16399730ffcbSVarun Prakash 		}
16409730ffcbSVarun Prakash 	}
16419730ffcbSVarun Prakash 
16429730ffcbSVarun Prakash 	return ret;
16439730ffcbSVarun Prakash }
16449730ffcbSVarun Prakash 
cxgbit_get_rx_pdu(struct iscsit_conn * conn)1645*be36d683SMax Gurtovoy void cxgbit_get_rx_pdu(struct iscsit_conn *conn)
16469730ffcbSVarun Prakash {
16479730ffcbSVarun Prakash 	struct cxgbit_sock *csk = conn->context;
16489730ffcbSVarun Prakash 
16499730ffcbSVarun Prakash 	while (!kthread_should_stop()) {
16509730ffcbSVarun Prakash 		iscsit_thread_check_cpumask(conn, current, 0);
16519730ffcbSVarun Prakash 		if (cxgbit_wait_rxq(csk))
16529730ffcbSVarun Prakash 			return;
16539730ffcbSVarun Prakash 	}
16549730ffcbSVarun Prakash }
1655