xref: /linux/drivers/target/iscsi/cxgbit/cxgbit_target.c (revision d2912cb15bdda8ba4a5dd73396ad62641af2f520)
1*d2912cb1SThomas 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 *
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 
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  */
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 
899730ffcbSVarun Prakash #define MAX_IMM_TX_PKT_LEN	256
909730ffcbSVarun Prakash 	return length <= MAX_IMM_TX_PKT_LEN;
919730ffcbSVarun Prakash }
929730ffcbSVarun Prakash 
939730ffcbSVarun Prakash /*
949730ffcbSVarun Prakash  * cxgbit_sgl_len - calculates the size of an SGL of the given capacity
959730ffcbSVarun Prakash  * @n: the number of SGL entries
969730ffcbSVarun Prakash  * Calculates the number of flits needed for a scatter/gather list that
979730ffcbSVarun Prakash  * can hold the given number of entries.
989730ffcbSVarun Prakash  */
999730ffcbSVarun Prakash static inline unsigned int cxgbit_sgl_len(unsigned int n)
1009730ffcbSVarun Prakash {
1019730ffcbSVarun Prakash 	n--;
1029730ffcbSVarun Prakash 	return (3 * n) / 2 + (n & 1) + 2;
1039730ffcbSVarun Prakash }
1049730ffcbSVarun Prakash 
1059730ffcbSVarun Prakash /*
1069730ffcbSVarun Prakash  * cxgbit_calc_tx_flits_ofld - calculate # of flits for an offload packet
1079730ffcbSVarun Prakash  * @skb: the packet
1089730ffcbSVarun Prakash  *
1099730ffcbSVarun Prakash  * Returns the number of flits needed for the given offload packet.
1109730ffcbSVarun Prakash  * These packets are already fully constructed and no additional headers
1119730ffcbSVarun Prakash  * will be added.
1129730ffcbSVarun Prakash  */
1139730ffcbSVarun Prakash static unsigned int cxgbit_calc_tx_flits_ofld(const struct sk_buff *skb)
1149730ffcbSVarun Prakash {
1159730ffcbSVarun Prakash 	unsigned int flits, cnt;
1169730ffcbSVarun Prakash 
1179730ffcbSVarun Prakash 	if (cxgbit_is_ofld_imm(skb))
1189730ffcbSVarun Prakash 		return DIV_ROUND_UP(skb->len, 8);
1199730ffcbSVarun Prakash 	flits = skb_transport_offset(skb) / 8;
1209730ffcbSVarun Prakash 	cnt = skb_shinfo(skb)->nr_frags;
1219730ffcbSVarun Prakash 	if (skb_tail_pointer(skb) != skb_transport_header(skb))
1229730ffcbSVarun Prakash 		cnt++;
1239730ffcbSVarun Prakash 	return flits + cxgbit_sgl_len(cnt);
1249730ffcbSVarun Prakash }
1259730ffcbSVarun Prakash 
1269730ffcbSVarun Prakash #define CXGBIT_ISO_FSLICE 0x1
1279730ffcbSVarun Prakash #define CXGBIT_ISO_LSLICE 0x2
1289730ffcbSVarun Prakash static void
1299730ffcbSVarun Prakash cxgbit_cpl_tx_data_iso(struct sk_buff *skb, struct cxgbit_iso_info *iso_info)
1309730ffcbSVarun Prakash {
1319730ffcbSVarun Prakash 	struct cpl_tx_data_iso *cpl;
1329730ffcbSVarun Prakash 	unsigned int submode = cxgbit_skcb_submode(skb);
1339730ffcbSVarun Prakash 	unsigned int fslice = !!(iso_info->flags & CXGBIT_ISO_FSLICE);
1349730ffcbSVarun Prakash 	unsigned int lslice = !!(iso_info->flags & CXGBIT_ISO_LSLICE);
1359730ffcbSVarun Prakash 
136d58ff351SJohannes Berg 	cpl = __skb_push(skb, sizeof(*cpl));
1379730ffcbSVarun Prakash 
1389730ffcbSVarun Prakash 	cpl->op_to_scsi = htonl(CPL_TX_DATA_ISO_OP_V(CPL_TX_DATA_ISO) |
1399730ffcbSVarun Prakash 			CPL_TX_DATA_ISO_FIRST_V(fslice) |
1409730ffcbSVarun Prakash 			CPL_TX_DATA_ISO_LAST_V(lslice) |
1419730ffcbSVarun Prakash 			CPL_TX_DATA_ISO_CPLHDRLEN_V(0) |
1429730ffcbSVarun Prakash 			CPL_TX_DATA_ISO_HDRCRC_V(submode & 1) |
1439730ffcbSVarun Prakash 			CPL_TX_DATA_ISO_PLDCRC_V(((submode >> 1) & 1)) |
1449730ffcbSVarun Prakash 			CPL_TX_DATA_ISO_IMMEDIATE_V(0) |
1459730ffcbSVarun Prakash 			CPL_TX_DATA_ISO_SCSI_V(2));
1469730ffcbSVarun Prakash 
1479730ffcbSVarun Prakash 	cpl->ahs_len = 0;
1489730ffcbSVarun Prakash 	cpl->mpdu = htons(DIV_ROUND_UP(iso_info->mpdu, 4));
1499730ffcbSVarun Prakash 	cpl->burst_size = htonl(DIV_ROUND_UP(iso_info->burst_len, 4));
1509730ffcbSVarun Prakash 	cpl->len = htonl(iso_info->len);
1519730ffcbSVarun Prakash 	cpl->reserved2_seglen_offset = htonl(0);
1529730ffcbSVarun Prakash 	cpl->datasn_offset = htonl(0);
1539730ffcbSVarun Prakash 	cpl->buffer_offset = htonl(0);
1549730ffcbSVarun Prakash 	cpl->reserved3 = 0;
1559730ffcbSVarun Prakash 
1569730ffcbSVarun Prakash 	__skb_pull(skb, sizeof(*cpl));
1579730ffcbSVarun Prakash }
1589730ffcbSVarun Prakash 
1599730ffcbSVarun Prakash static void
1609730ffcbSVarun Prakash cxgbit_tx_data_wr(struct cxgbit_sock *csk, struct sk_buff *skb, u32 dlen,
1619730ffcbSVarun Prakash 		  u32 len, u32 credits, u32 compl)
1629730ffcbSVarun Prakash {
1639730ffcbSVarun Prakash 	struct fw_ofld_tx_data_wr *req;
164bdec5188SVarun Prakash 	const struct cxgb4_lld_info *lldi = &csk->com.cdev->lldi;
1659730ffcbSVarun Prakash 	u32 submode = cxgbit_skcb_submode(skb);
1669730ffcbSVarun Prakash 	u32 wr_ulp_mode = 0;
1679730ffcbSVarun Prakash 	u32 hdr_size = sizeof(*req);
1689730ffcbSVarun Prakash 	u32 opcode = FW_OFLD_TX_DATA_WR;
1699730ffcbSVarun Prakash 	u32 immlen = 0;
170bdec5188SVarun Prakash 	u32 force = is_t5(lldi->adapter_type) ? TX_FORCE_V(!submode) :
171bdec5188SVarun Prakash 		    T6_TX_FORCE_F;
1729730ffcbSVarun Prakash 
1739730ffcbSVarun Prakash 	if (cxgbit_skcb_flags(skb) & SKCBF_TX_ISO) {
1749730ffcbSVarun Prakash 		opcode = FW_ISCSI_TX_DATA_WR;
1759730ffcbSVarun Prakash 		immlen += sizeof(struct cpl_tx_data_iso);
1769730ffcbSVarun Prakash 		hdr_size += sizeof(struct cpl_tx_data_iso);
1779730ffcbSVarun Prakash 		submode |= 8;
1789730ffcbSVarun Prakash 	}
1799730ffcbSVarun Prakash 
1809730ffcbSVarun Prakash 	if (cxgbit_is_ofld_imm(skb))
1819730ffcbSVarun Prakash 		immlen += dlen;
1829730ffcbSVarun Prakash 
183d58ff351SJohannes Berg 	req = __skb_push(skb, hdr_size);
1849730ffcbSVarun Prakash 	req->op_to_immdlen = cpu_to_be32(FW_WR_OP_V(opcode) |
1859730ffcbSVarun Prakash 					FW_WR_COMPL_V(compl) |
1869730ffcbSVarun Prakash 					FW_WR_IMMDLEN_V(immlen));
1879730ffcbSVarun Prakash 	req->flowid_len16 = cpu_to_be32(FW_WR_FLOWID_V(csk->tid) |
1889730ffcbSVarun Prakash 					FW_WR_LEN16_V(credits));
1899730ffcbSVarun Prakash 	req->plen = htonl(len);
1909730ffcbSVarun Prakash 	wr_ulp_mode = FW_OFLD_TX_DATA_WR_ULPMODE_V(ULP_MODE_ISCSI) |
1919730ffcbSVarun Prakash 				FW_OFLD_TX_DATA_WR_ULPSUBMODE_V(submode);
1929730ffcbSVarun Prakash 
1939730ffcbSVarun Prakash 	req->tunnel_to_proxy = htonl((wr_ulp_mode) | force |
1949730ffcbSVarun Prakash 		 FW_OFLD_TX_DATA_WR_SHOVE_V(skb_peek(&csk->txq) ? 0 : 1));
1959730ffcbSVarun Prakash }
1969730ffcbSVarun Prakash 
1979730ffcbSVarun Prakash static void cxgbit_arp_failure_skb_discard(void *handle, struct sk_buff *skb)
1989730ffcbSVarun Prakash {
1999730ffcbSVarun Prakash 	kfree_skb(skb);
2009730ffcbSVarun Prakash }
2019730ffcbSVarun Prakash 
2029730ffcbSVarun Prakash void cxgbit_push_tx_frames(struct cxgbit_sock *csk)
2039730ffcbSVarun Prakash {
2049730ffcbSVarun Prakash 	struct sk_buff *skb;
2059730ffcbSVarun Prakash 
2069730ffcbSVarun Prakash 	while (csk->wr_cred && ((skb = skb_peek(&csk->txq)) != NULL)) {
2079730ffcbSVarun Prakash 		u32 dlen = skb->len;
2089730ffcbSVarun Prakash 		u32 len = skb->len;
2099730ffcbSVarun Prakash 		u32 credits_needed;
2109730ffcbSVarun Prakash 		u32 compl = 0;
2119730ffcbSVarun Prakash 		u32 flowclen16 = 0;
2129730ffcbSVarun Prakash 		u32 iso_cpl_len = 0;
2139730ffcbSVarun Prakash 
2149730ffcbSVarun Prakash 		if (cxgbit_skcb_flags(skb) & SKCBF_TX_ISO)
2159730ffcbSVarun Prakash 			iso_cpl_len = sizeof(struct cpl_tx_data_iso);
2169730ffcbSVarun Prakash 
2179730ffcbSVarun Prakash 		if (cxgbit_is_ofld_imm(skb))
2189730ffcbSVarun Prakash 			credits_needed = DIV_ROUND_UP(dlen + iso_cpl_len, 16);
2199730ffcbSVarun Prakash 		else
2209730ffcbSVarun Prakash 			credits_needed = DIV_ROUND_UP((8 *
2219730ffcbSVarun Prakash 					cxgbit_calc_tx_flits_ofld(skb)) +
2229730ffcbSVarun Prakash 					iso_cpl_len, 16);
2239730ffcbSVarun Prakash 
2249730ffcbSVarun Prakash 		if (likely(cxgbit_skcb_flags(skb) & SKCBF_TX_NEED_HDR))
2259730ffcbSVarun Prakash 			credits_needed += DIV_ROUND_UP(
2269730ffcbSVarun Prakash 				sizeof(struct fw_ofld_tx_data_wr), 16);
2279730ffcbSVarun Prakash 		/*
2289730ffcbSVarun Prakash 		 * Assumes the initial credits is large enough to support
2299730ffcbSVarun Prakash 		 * fw_flowc_wr plus largest possible first payload
2309730ffcbSVarun Prakash 		 */
2319730ffcbSVarun Prakash 
2329730ffcbSVarun Prakash 		if (!test_and_set_bit(CSK_TX_DATA_SENT, &csk->com.flags)) {
2339730ffcbSVarun Prakash 			flowclen16 = cxgbit_send_tx_flowc_wr(csk);
2349730ffcbSVarun Prakash 			csk->wr_cred -= flowclen16;
2359730ffcbSVarun Prakash 			csk->wr_una_cred += flowclen16;
2369730ffcbSVarun Prakash 		}
2379730ffcbSVarun Prakash 
2389730ffcbSVarun Prakash 		if (csk->wr_cred < credits_needed) {
2399730ffcbSVarun Prakash 			pr_debug("csk 0x%p, skb %u/%u, wr %d < %u.\n",
2409730ffcbSVarun Prakash 				 csk, skb->len, skb->data_len,
2419730ffcbSVarun Prakash 				 credits_needed, csk->wr_cred);
2429730ffcbSVarun Prakash 			break;
2439730ffcbSVarun Prakash 		}
2449730ffcbSVarun Prakash 		__skb_unlink(skb, &csk->txq);
2459730ffcbSVarun Prakash 		set_wr_txq(skb, CPL_PRIORITY_DATA, csk->txq_idx);
2465cadafb2SBart Van Assche 		skb->csum = (__force __wsum)(credits_needed + flowclen16);
2479730ffcbSVarun Prakash 		csk->wr_cred -= credits_needed;
2489730ffcbSVarun Prakash 		csk->wr_una_cred += credits_needed;
2499730ffcbSVarun Prakash 
2509730ffcbSVarun Prakash 		pr_debug("csk 0x%p, skb %u/%u, wr %d, left %u, unack %u.\n",
2519730ffcbSVarun Prakash 			 csk, skb->len, skb->data_len, credits_needed,
2529730ffcbSVarun Prakash 			 csk->wr_cred, csk->wr_una_cred);
2539730ffcbSVarun Prakash 
2549730ffcbSVarun Prakash 		if (likely(cxgbit_skcb_flags(skb) & SKCBF_TX_NEED_HDR)) {
2559730ffcbSVarun Prakash 			len += cxgbit_skcb_tx_extralen(skb);
2569730ffcbSVarun Prakash 
2579730ffcbSVarun Prakash 			if ((csk->wr_una_cred >= (csk->wr_max_cred / 2)) ||
2589730ffcbSVarun Prakash 			    (!before(csk->write_seq,
2599730ffcbSVarun Prakash 				     csk->snd_una + csk->snd_win))) {
2609730ffcbSVarun Prakash 				compl = 1;
2619730ffcbSVarun Prakash 				csk->wr_una_cred = 0;
2629730ffcbSVarun Prakash 			}
2639730ffcbSVarun Prakash 
2649730ffcbSVarun Prakash 			cxgbit_tx_data_wr(csk, skb, dlen, len, credits_needed,
2659730ffcbSVarun Prakash 					  compl);
2669730ffcbSVarun Prakash 			csk->snd_nxt += len;
2679730ffcbSVarun Prakash 
2689730ffcbSVarun Prakash 		} else if ((cxgbit_skcb_flags(skb) & SKCBF_TX_FLAG_COMPL) ||
2699730ffcbSVarun Prakash 			   (csk->wr_una_cred >= (csk->wr_max_cred / 2))) {
2709730ffcbSVarun Prakash 			struct cpl_close_con_req *req =
2719730ffcbSVarun Prakash 				(struct cpl_close_con_req *)skb->data;
2729730ffcbSVarun Prakash 			req->wr.wr_hi |= htonl(FW_WR_COMPL_F);
2739730ffcbSVarun Prakash 			csk->wr_una_cred = 0;
2749730ffcbSVarun Prakash 		}
2759730ffcbSVarun Prakash 
2769730ffcbSVarun Prakash 		cxgbit_sock_enqueue_wr(csk, skb);
2779730ffcbSVarun Prakash 		t4_set_arp_err_handler(skb, csk,
2789730ffcbSVarun Prakash 				       cxgbit_arp_failure_skb_discard);
2799730ffcbSVarun Prakash 
2809730ffcbSVarun Prakash 		pr_debug("csk 0x%p,%u, skb 0x%p, %u.\n",
2819730ffcbSVarun Prakash 			 csk, csk->tid, skb, len);
2829730ffcbSVarun Prakash 
2839730ffcbSVarun Prakash 		cxgbit_l2t_send(csk->com.cdev, skb, csk->l2t);
2849730ffcbSVarun Prakash 	}
2859730ffcbSVarun Prakash }
2869730ffcbSVarun Prakash 
2879730ffcbSVarun Prakash static bool cxgbit_lock_sock(struct cxgbit_sock *csk)
2889730ffcbSVarun Prakash {
2899730ffcbSVarun Prakash 	spin_lock_bh(&csk->lock);
2909730ffcbSVarun Prakash 
2919730ffcbSVarun Prakash 	if (before(csk->write_seq, csk->snd_una + csk->snd_win))
2929730ffcbSVarun Prakash 		csk->lock_owner = true;
2939730ffcbSVarun Prakash 
2949730ffcbSVarun Prakash 	spin_unlock_bh(&csk->lock);
2959730ffcbSVarun Prakash 
2969730ffcbSVarun Prakash 	return csk->lock_owner;
2979730ffcbSVarun Prakash }
2989730ffcbSVarun Prakash 
2999730ffcbSVarun Prakash static void cxgbit_unlock_sock(struct cxgbit_sock *csk)
3009730ffcbSVarun Prakash {
3019730ffcbSVarun Prakash 	struct sk_buff_head backlogq;
3029730ffcbSVarun Prakash 	struct sk_buff *skb;
3039730ffcbSVarun Prakash 	void (*fn)(struct cxgbit_sock *, struct sk_buff *);
3049730ffcbSVarun Prakash 
3059730ffcbSVarun Prakash 	skb_queue_head_init(&backlogq);
3069730ffcbSVarun Prakash 
3079730ffcbSVarun Prakash 	spin_lock_bh(&csk->lock);
3089730ffcbSVarun Prakash 	while (skb_queue_len(&csk->backlogq)) {
3099730ffcbSVarun Prakash 		skb_queue_splice_init(&csk->backlogq, &backlogq);
3109730ffcbSVarun Prakash 		spin_unlock_bh(&csk->lock);
3119730ffcbSVarun Prakash 
3129730ffcbSVarun Prakash 		while ((skb = __skb_dequeue(&backlogq))) {
3139730ffcbSVarun Prakash 			fn = cxgbit_skcb_rx_backlog_fn(skb);
3149730ffcbSVarun Prakash 			fn(csk, skb);
3159730ffcbSVarun Prakash 		}
3169730ffcbSVarun Prakash 
3179730ffcbSVarun Prakash 		spin_lock_bh(&csk->lock);
3189730ffcbSVarun Prakash 	}
3199730ffcbSVarun Prakash 
3209730ffcbSVarun Prakash 	csk->lock_owner = false;
3219730ffcbSVarun Prakash 	spin_unlock_bh(&csk->lock);
3229730ffcbSVarun Prakash }
3239730ffcbSVarun Prakash 
3249730ffcbSVarun Prakash static int cxgbit_queue_skb(struct cxgbit_sock *csk, struct sk_buff *skb)
3259730ffcbSVarun Prakash {
3269730ffcbSVarun Prakash 	int ret = 0;
3279730ffcbSVarun Prakash 
3289730ffcbSVarun Prakash 	wait_event_interruptible(csk->ack_waitq, cxgbit_lock_sock(csk));
3299730ffcbSVarun Prakash 
3309730ffcbSVarun Prakash 	if (unlikely((csk->com.state != CSK_STATE_ESTABLISHED) ||
3319730ffcbSVarun Prakash 		     signal_pending(current))) {
3329730ffcbSVarun Prakash 		__kfree_skb(skb);
3339730ffcbSVarun Prakash 		__skb_queue_purge(&csk->ppodq);
3349730ffcbSVarun Prakash 		ret = -1;
3359730ffcbSVarun Prakash 		spin_lock_bh(&csk->lock);
3369730ffcbSVarun Prakash 		if (csk->lock_owner) {
3379730ffcbSVarun Prakash 			spin_unlock_bh(&csk->lock);
3389730ffcbSVarun Prakash 			goto unlock;
3399730ffcbSVarun Prakash 		}
3409730ffcbSVarun Prakash 		spin_unlock_bh(&csk->lock);
3419730ffcbSVarun Prakash 		return ret;
3429730ffcbSVarun Prakash 	}
3439730ffcbSVarun Prakash 
3449730ffcbSVarun Prakash 	csk->write_seq += skb->len +
3459730ffcbSVarun Prakash 			  cxgbit_skcb_tx_extralen(skb);
3469730ffcbSVarun Prakash 
3479730ffcbSVarun Prakash 	skb_queue_splice_tail_init(&csk->ppodq, &csk->txq);
3489730ffcbSVarun Prakash 	__skb_queue_tail(&csk->txq, skb);
3499730ffcbSVarun Prakash 	cxgbit_push_tx_frames(csk);
3509730ffcbSVarun Prakash 
3519730ffcbSVarun Prakash unlock:
3529730ffcbSVarun Prakash 	cxgbit_unlock_sock(csk);
3539730ffcbSVarun Prakash 	return ret;
3549730ffcbSVarun Prakash }
3559730ffcbSVarun Prakash 
3569730ffcbSVarun Prakash static int
3579730ffcbSVarun Prakash cxgbit_map_skb(struct iscsi_cmd *cmd, struct sk_buff *skb, u32 data_offset,
3589730ffcbSVarun Prakash 	       u32 data_length)
3599730ffcbSVarun Prakash {
3609730ffcbSVarun Prakash 	u32 i = 0, nr_frags = MAX_SKB_FRAGS;
3619730ffcbSVarun Prakash 	u32 padding = ((-data_length) & 3);
3629730ffcbSVarun Prakash 	struct scatterlist *sg;
3639730ffcbSVarun Prakash 	struct page *page;
3649730ffcbSVarun Prakash 	unsigned int page_off;
3659730ffcbSVarun Prakash 
3669730ffcbSVarun Prakash 	if (padding)
3679730ffcbSVarun Prakash 		nr_frags--;
3689730ffcbSVarun Prakash 
3699730ffcbSVarun Prakash 	/*
3709730ffcbSVarun Prakash 	 * We know each entry in t_data_sg contains a page.
3719730ffcbSVarun Prakash 	 */
3729730ffcbSVarun Prakash 	sg = &cmd->se_cmd.t_data_sg[data_offset / PAGE_SIZE];
3739730ffcbSVarun Prakash 	page_off = (data_offset % PAGE_SIZE);
3749730ffcbSVarun Prakash 
3759730ffcbSVarun Prakash 	while (data_length && (i < nr_frags)) {
3769730ffcbSVarun Prakash 		u32 cur_len = min_t(u32, data_length, sg->length - page_off);
3779730ffcbSVarun Prakash 
3789730ffcbSVarun Prakash 		page = sg_page(sg);
3799730ffcbSVarun Prakash 
3809730ffcbSVarun Prakash 		get_page(page);
3819730ffcbSVarun Prakash 		skb_fill_page_desc(skb, i, page, sg->offset + page_off,
3829730ffcbSVarun Prakash 				   cur_len);
3839730ffcbSVarun Prakash 		skb->data_len += cur_len;
3849730ffcbSVarun Prakash 		skb->len += cur_len;
3859730ffcbSVarun Prakash 		skb->truesize += cur_len;
3869730ffcbSVarun Prakash 
3879730ffcbSVarun Prakash 		data_length -= cur_len;
3889730ffcbSVarun Prakash 		page_off = 0;
3899730ffcbSVarun Prakash 		sg = sg_next(sg);
3909730ffcbSVarun Prakash 		i++;
3919730ffcbSVarun Prakash 	}
3929730ffcbSVarun Prakash 
3939730ffcbSVarun Prakash 	if (data_length)
3949730ffcbSVarun Prakash 		return -1;
3959730ffcbSVarun Prakash 
3969730ffcbSVarun Prakash 	if (padding) {
3979730ffcbSVarun Prakash 		page = alloc_page(GFP_KERNEL | __GFP_ZERO);
3989730ffcbSVarun Prakash 		if (!page)
3999730ffcbSVarun Prakash 			return -1;
4009730ffcbSVarun Prakash 		skb_fill_page_desc(skb, i, page, 0, padding);
4019730ffcbSVarun Prakash 		skb->data_len += padding;
4029730ffcbSVarun Prakash 		skb->len += padding;
4039730ffcbSVarun Prakash 		skb->truesize += padding;
4049730ffcbSVarun Prakash 	}
4059730ffcbSVarun Prakash 
4069730ffcbSVarun Prakash 	return 0;
4079730ffcbSVarun Prakash }
4089730ffcbSVarun Prakash 
4099730ffcbSVarun Prakash static int
4109730ffcbSVarun Prakash cxgbit_tx_datain_iso(struct cxgbit_sock *csk, struct iscsi_cmd *cmd,
4119730ffcbSVarun Prakash 		     struct iscsi_datain_req *dr)
4129730ffcbSVarun Prakash {
4139730ffcbSVarun Prakash 	struct iscsi_conn *conn = csk->conn;
4149730ffcbSVarun Prakash 	struct sk_buff *skb;
4159730ffcbSVarun Prakash 	struct iscsi_datain datain;
4169730ffcbSVarun Prakash 	struct cxgbit_iso_info iso_info;
4179730ffcbSVarun Prakash 	u32 data_length = cmd->se_cmd.data_length;
4189730ffcbSVarun Prakash 	u32 mrdsl = conn->conn_ops->MaxRecvDataSegmentLength;
4199730ffcbSVarun Prakash 	u32 num_pdu, plen, tx_data = 0;
4209730ffcbSVarun Prakash 	bool task_sense = !!(cmd->se_cmd.se_cmd_flags &
4219730ffcbSVarun Prakash 		SCF_TRANSPORT_TASK_SENSE);
4229730ffcbSVarun Prakash 	bool set_statsn = false;
4239730ffcbSVarun Prakash 	int ret = -1;
4249730ffcbSVarun Prakash 
4259730ffcbSVarun Prakash 	while (data_length) {
4269730ffcbSVarun Prakash 		num_pdu = (data_length + mrdsl - 1) / mrdsl;
4279730ffcbSVarun Prakash 		if (num_pdu > csk->max_iso_npdu)
4289730ffcbSVarun Prakash 			num_pdu = csk->max_iso_npdu;
4299730ffcbSVarun Prakash 
4309730ffcbSVarun Prakash 		plen = num_pdu * mrdsl;
4319730ffcbSVarun Prakash 		if (plen > data_length)
4329730ffcbSVarun Prakash 			plen = data_length;
4339730ffcbSVarun Prakash 
4349730ffcbSVarun Prakash 		skb = __cxgbit_alloc_skb(csk, 0, true);
4359730ffcbSVarun Prakash 		if (unlikely(!skb))
4369730ffcbSVarun Prakash 			return -ENOMEM;
4379730ffcbSVarun Prakash 
4389730ffcbSVarun Prakash 		memset(skb->data, 0, ISCSI_HDR_LEN);
4399730ffcbSVarun Prakash 		cxgbit_skcb_flags(skb) |= SKCBF_TX_ISO;
4409730ffcbSVarun Prakash 		cxgbit_skcb_submode(skb) |= (csk->submode &
4419730ffcbSVarun Prakash 				CXGBIT_SUBMODE_DCRC);
4429730ffcbSVarun Prakash 		cxgbit_skcb_tx_extralen(skb) = (num_pdu *
4439730ffcbSVarun Prakash 				cxgbit_digest_len[cxgbit_skcb_submode(skb)]) +
4449730ffcbSVarun Prakash 						((num_pdu - 1) * ISCSI_HDR_LEN);
4459730ffcbSVarun Prakash 
4469730ffcbSVarun Prakash 		memset(&datain, 0, sizeof(struct iscsi_datain));
4479730ffcbSVarun Prakash 		memset(&iso_info, 0, sizeof(iso_info));
4489730ffcbSVarun Prakash 
4499730ffcbSVarun Prakash 		if (!tx_data)
4509730ffcbSVarun Prakash 			iso_info.flags |= CXGBIT_ISO_FSLICE;
4519730ffcbSVarun Prakash 
4529730ffcbSVarun Prakash 		if (!(data_length - plen)) {
4539730ffcbSVarun Prakash 			iso_info.flags |= CXGBIT_ISO_LSLICE;
4549730ffcbSVarun Prakash 			if (!task_sense) {
4559730ffcbSVarun Prakash 				datain.flags = ISCSI_FLAG_DATA_STATUS;
4569730ffcbSVarun Prakash 				iscsit_increment_maxcmdsn(cmd, conn->sess);
4579730ffcbSVarun Prakash 				cmd->stat_sn = conn->stat_sn++;
4589730ffcbSVarun Prakash 				set_statsn = true;
4599730ffcbSVarun Prakash 			}
4609730ffcbSVarun Prakash 		}
4619730ffcbSVarun Prakash 
4629730ffcbSVarun Prakash 		iso_info.burst_len = num_pdu * mrdsl;
4639730ffcbSVarun Prakash 		iso_info.mpdu = mrdsl;
4649730ffcbSVarun Prakash 		iso_info.len = ISCSI_HDR_LEN + plen;
4659730ffcbSVarun Prakash 
4669730ffcbSVarun Prakash 		cxgbit_cpl_tx_data_iso(skb, &iso_info);
4679730ffcbSVarun Prakash 
4689730ffcbSVarun Prakash 		datain.offset = tx_data;
4699730ffcbSVarun Prakash 		datain.data_sn = cmd->data_sn - 1;
4709730ffcbSVarun Prakash 
4719730ffcbSVarun Prakash 		iscsit_build_datain_pdu(cmd, conn, &datain,
4729730ffcbSVarun Prakash 					(struct iscsi_data_rsp *)skb->data,
4739730ffcbSVarun Prakash 					set_statsn);
4749730ffcbSVarun Prakash 
4759730ffcbSVarun Prakash 		ret = cxgbit_map_skb(cmd, skb, tx_data, plen);
4769730ffcbSVarun Prakash 		if (unlikely(ret)) {
4779730ffcbSVarun Prakash 			__kfree_skb(skb);
4789730ffcbSVarun Prakash 			goto out;
4799730ffcbSVarun Prakash 		}
4809730ffcbSVarun Prakash 
4819730ffcbSVarun Prakash 		ret = cxgbit_queue_skb(csk, skb);
4829730ffcbSVarun Prakash 		if (unlikely(ret))
4839730ffcbSVarun Prakash 			goto out;
4849730ffcbSVarun Prakash 
4859730ffcbSVarun Prakash 		tx_data += plen;
4869730ffcbSVarun Prakash 		data_length -= plen;
4879730ffcbSVarun Prakash 
4889730ffcbSVarun Prakash 		cmd->read_data_done += plen;
4899730ffcbSVarun Prakash 		cmd->data_sn += num_pdu;
4909730ffcbSVarun Prakash 	}
4919730ffcbSVarun Prakash 
4929730ffcbSVarun Prakash 	dr->dr_complete = DATAIN_COMPLETE_NORMAL;
4939730ffcbSVarun Prakash 
4949730ffcbSVarun Prakash 	return 0;
4959730ffcbSVarun Prakash 
4969730ffcbSVarun Prakash out:
4979730ffcbSVarun Prakash 	return ret;
4989730ffcbSVarun Prakash }
4999730ffcbSVarun Prakash 
5009730ffcbSVarun Prakash static int
5019730ffcbSVarun Prakash cxgbit_tx_datain(struct cxgbit_sock *csk, struct iscsi_cmd *cmd,
5029730ffcbSVarun Prakash 		 const struct iscsi_datain *datain)
5039730ffcbSVarun Prakash {
5049730ffcbSVarun Prakash 	struct sk_buff *skb;
5059730ffcbSVarun Prakash 	int ret = 0;
5069730ffcbSVarun Prakash 
5079730ffcbSVarun Prakash 	skb = cxgbit_alloc_skb(csk, 0);
5089730ffcbSVarun Prakash 	if (unlikely(!skb))
5099730ffcbSVarun Prakash 		return -ENOMEM;
5109730ffcbSVarun Prakash 
5119730ffcbSVarun Prakash 	memcpy(skb->data, cmd->pdu, ISCSI_HDR_LEN);
5129730ffcbSVarun Prakash 
5139730ffcbSVarun Prakash 	if (datain->length) {
5149730ffcbSVarun Prakash 		cxgbit_skcb_submode(skb) |= (csk->submode &
5159730ffcbSVarun Prakash 				CXGBIT_SUBMODE_DCRC);
5169730ffcbSVarun Prakash 		cxgbit_skcb_tx_extralen(skb) =
5179730ffcbSVarun Prakash 				cxgbit_digest_len[cxgbit_skcb_submode(skb)];
5189730ffcbSVarun Prakash 	}
5199730ffcbSVarun Prakash 
5209730ffcbSVarun Prakash 	ret = cxgbit_map_skb(cmd, skb, datain->offset, datain->length);
5219730ffcbSVarun Prakash 	if (ret < 0) {
5229730ffcbSVarun Prakash 		__kfree_skb(skb);
5239730ffcbSVarun Prakash 		return ret;
5249730ffcbSVarun Prakash 	}
5259730ffcbSVarun Prakash 
5269730ffcbSVarun Prakash 	return cxgbit_queue_skb(csk, skb);
5279730ffcbSVarun Prakash }
5289730ffcbSVarun Prakash 
5299730ffcbSVarun Prakash static int
5309730ffcbSVarun Prakash cxgbit_xmit_datain_pdu(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
5319730ffcbSVarun Prakash 		       struct iscsi_datain_req *dr,
5329730ffcbSVarun Prakash 		       const struct iscsi_datain *datain)
5339730ffcbSVarun Prakash {
5349730ffcbSVarun Prakash 	struct cxgbit_sock *csk = conn->context;
5359730ffcbSVarun Prakash 	u32 data_length = cmd->se_cmd.data_length;
5369730ffcbSVarun Prakash 	u32 padding = ((-data_length) & 3);
5379730ffcbSVarun Prakash 	u32 mrdsl = conn->conn_ops->MaxRecvDataSegmentLength;
5389730ffcbSVarun Prakash 
5399730ffcbSVarun Prakash 	if ((data_length > mrdsl) && (!dr->recovery) &&
5409730ffcbSVarun Prakash 	    (!padding) && (!datain->offset) && csk->max_iso_npdu) {
5419730ffcbSVarun Prakash 		atomic_long_add(data_length - datain->length,
5429730ffcbSVarun Prakash 				&conn->sess->tx_data_octets);
5439730ffcbSVarun Prakash 		return cxgbit_tx_datain_iso(csk, cmd, dr);
5449730ffcbSVarun Prakash 	}
5459730ffcbSVarun Prakash 
5469730ffcbSVarun Prakash 	return cxgbit_tx_datain(csk, cmd, datain);
5479730ffcbSVarun Prakash }
5489730ffcbSVarun Prakash 
5499730ffcbSVarun Prakash static int
5509730ffcbSVarun Prakash cxgbit_xmit_nondatain_pdu(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
5519730ffcbSVarun Prakash 			  const void *data_buf, u32 data_buf_len)
5529730ffcbSVarun Prakash {
5539730ffcbSVarun Prakash 	struct cxgbit_sock *csk = conn->context;
5549730ffcbSVarun Prakash 	struct sk_buff *skb;
5559730ffcbSVarun Prakash 	u32 padding = ((-data_buf_len) & 3);
5569730ffcbSVarun Prakash 
5579730ffcbSVarun Prakash 	skb = cxgbit_alloc_skb(csk, data_buf_len + padding);
5589730ffcbSVarun Prakash 	if (unlikely(!skb))
5599730ffcbSVarun Prakash 		return -ENOMEM;
5609730ffcbSVarun Prakash 
5619730ffcbSVarun Prakash 	memcpy(skb->data, cmd->pdu, ISCSI_HDR_LEN);
5629730ffcbSVarun Prakash 
5639730ffcbSVarun Prakash 	if (data_buf_len) {
5649730ffcbSVarun Prakash 		u32 pad_bytes = 0;
5659730ffcbSVarun Prakash 
5669730ffcbSVarun Prakash 		skb_store_bits(skb, ISCSI_HDR_LEN, data_buf, data_buf_len);
5679730ffcbSVarun Prakash 
5689730ffcbSVarun Prakash 		if (padding)
5699730ffcbSVarun Prakash 			skb_store_bits(skb, ISCSI_HDR_LEN + data_buf_len,
5709730ffcbSVarun Prakash 				       &pad_bytes, padding);
5719730ffcbSVarun Prakash 	}
5729730ffcbSVarun Prakash 
5739730ffcbSVarun Prakash 	cxgbit_skcb_tx_extralen(skb) = cxgbit_digest_len[
5749730ffcbSVarun Prakash 				       cxgbit_skcb_submode(skb)];
5759730ffcbSVarun Prakash 
5769730ffcbSVarun Prakash 	return cxgbit_queue_skb(csk, skb);
5779730ffcbSVarun Prakash }
5789730ffcbSVarun Prakash 
5799730ffcbSVarun Prakash int
5809730ffcbSVarun Prakash cxgbit_xmit_pdu(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
5819730ffcbSVarun Prakash 		struct iscsi_datain_req *dr, const void *buf, u32 buf_len)
5829730ffcbSVarun Prakash {
5839730ffcbSVarun Prakash 	if (dr)
5849730ffcbSVarun Prakash 		return cxgbit_xmit_datain_pdu(conn, cmd, dr, buf);
5859730ffcbSVarun Prakash 	else
5869730ffcbSVarun Prakash 		return cxgbit_xmit_nondatain_pdu(conn, cmd, buf, buf_len);
5879730ffcbSVarun Prakash }
5889730ffcbSVarun Prakash 
5899730ffcbSVarun Prakash int cxgbit_validate_params(struct iscsi_conn *conn)
5909730ffcbSVarun Prakash {
5919730ffcbSVarun Prakash 	struct cxgbit_sock *csk = conn->context;
5929730ffcbSVarun Prakash 	struct cxgbit_device *cdev = csk->com.cdev;
5939730ffcbSVarun Prakash 	struct iscsi_param *param;
5949730ffcbSVarun Prakash 	u32 max_xmitdsl;
5959730ffcbSVarun Prakash 
5969730ffcbSVarun Prakash 	param = iscsi_find_param_from_key(MAXXMITDATASEGMENTLENGTH,
5979730ffcbSVarun Prakash 					  conn->param_list);
5989730ffcbSVarun Prakash 	if (!param)
5999730ffcbSVarun Prakash 		return -1;
6009730ffcbSVarun Prakash 
6019730ffcbSVarun Prakash 	if (kstrtou32(param->value, 0, &max_xmitdsl) < 0)
6029730ffcbSVarun Prakash 		return -1;
6039730ffcbSVarun Prakash 
6049730ffcbSVarun Prakash 	if (max_xmitdsl > cdev->mdsl) {
6059730ffcbSVarun Prakash 		if (iscsi_change_param_sprintf(
6069730ffcbSVarun Prakash 			conn, "MaxXmitDataSegmentLength=%u", cdev->mdsl))
6079730ffcbSVarun Prakash 			return -1;
6089730ffcbSVarun Prakash 	}
6099730ffcbSVarun Prakash 
6109730ffcbSVarun Prakash 	return 0;
6119730ffcbSVarun Prakash }
6129730ffcbSVarun Prakash 
6139730ffcbSVarun Prakash static int cxgbit_set_digest(struct cxgbit_sock *csk)
6149730ffcbSVarun Prakash {
6159730ffcbSVarun Prakash 	struct iscsi_conn *conn = csk->conn;
6169730ffcbSVarun Prakash 	struct iscsi_param *param;
6179730ffcbSVarun Prakash 
6189730ffcbSVarun Prakash 	param = iscsi_find_param_from_key(HEADERDIGEST, conn->param_list);
6199730ffcbSVarun Prakash 	if (!param) {
6209730ffcbSVarun Prakash 		pr_err("param not found key %s\n", HEADERDIGEST);
6219730ffcbSVarun Prakash 		return -1;
6229730ffcbSVarun Prakash 	}
6239730ffcbSVarun Prakash 
6249730ffcbSVarun Prakash 	if (!strcmp(param->value, CRC32C))
6259730ffcbSVarun Prakash 		csk->submode |= CXGBIT_SUBMODE_HCRC;
6269730ffcbSVarun Prakash 
6279730ffcbSVarun Prakash 	param = iscsi_find_param_from_key(DATADIGEST, conn->param_list);
6289730ffcbSVarun Prakash 	if (!param) {
6299730ffcbSVarun Prakash 		csk->submode = 0;
6309730ffcbSVarun Prakash 		pr_err("param not found key %s\n", DATADIGEST);
6319730ffcbSVarun Prakash 		return -1;
6329730ffcbSVarun Prakash 	}
6339730ffcbSVarun Prakash 
6349730ffcbSVarun Prakash 	if (!strcmp(param->value, CRC32C))
6359730ffcbSVarun Prakash 		csk->submode |= CXGBIT_SUBMODE_DCRC;
6369730ffcbSVarun Prakash 
6379730ffcbSVarun Prakash 	if (cxgbit_setup_conn_digest(csk)) {
6389730ffcbSVarun Prakash 		csk->submode = 0;
6399730ffcbSVarun Prakash 		return -1;
6409730ffcbSVarun Prakash 	}
6419730ffcbSVarun Prakash 
6429730ffcbSVarun Prakash 	return 0;
6439730ffcbSVarun Prakash }
6449730ffcbSVarun Prakash 
6459730ffcbSVarun Prakash static int cxgbit_set_iso_npdu(struct cxgbit_sock *csk)
6469730ffcbSVarun Prakash {
6479730ffcbSVarun Prakash 	struct iscsi_conn *conn = csk->conn;
6489730ffcbSVarun Prakash 	struct iscsi_conn_ops *conn_ops = conn->conn_ops;
6499730ffcbSVarun Prakash 	struct iscsi_param *param;
6509730ffcbSVarun Prakash 	u32 mrdsl, mbl;
6519730ffcbSVarun Prakash 	u32 max_npdu, max_iso_npdu;
6521b350ea0SVarun Prakash 	u32 max_iso_payload;
6539730ffcbSVarun Prakash 
6549730ffcbSVarun Prakash 	if (conn->login->leading_connection) {
6559730ffcbSVarun Prakash 		param = iscsi_find_param_from_key(MAXBURSTLENGTH,
6569730ffcbSVarun Prakash 						  conn->param_list);
6579730ffcbSVarun Prakash 		if (!param) {
6589730ffcbSVarun Prakash 			pr_err("param not found key %s\n", MAXBURSTLENGTH);
6599730ffcbSVarun Prakash 			return -1;
6609730ffcbSVarun Prakash 		}
6619730ffcbSVarun Prakash 
6629730ffcbSVarun Prakash 		if (kstrtou32(param->value, 0, &mbl) < 0)
6639730ffcbSVarun Prakash 			return -1;
6649730ffcbSVarun Prakash 	} else {
6659730ffcbSVarun Prakash 		mbl = conn->sess->sess_ops->MaxBurstLength;
6669730ffcbSVarun Prakash 	}
6679730ffcbSVarun Prakash 
6689730ffcbSVarun Prakash 	mrdsl = conn_ops->MaxRecvDataSegmentLength;
6699730ffcbSVarun Prakash 	max_npdu = mbl / mrdsl;
6709730ffcbSVarun Prakash 
6711b350ea0SVarun Prakash 	max_iso_payload = rounddown(CXGBIT_MAX_ISO_PAYLOAD, csk->emss);
6721b350ea0SVarun Prakash 
6731b350ea0SVarun Prakash 	max_iso_npdu = max_iso_payload /
6749730ffcbSVarun Prakash 		       (ISCSI_HDR_LEN + mrdsl +
6759730ffcbSVarun Prakash 			cxgbit_digest_len[csk->submode]);
6769730ffcbSVarun Prakash 
6779730ffcbSVarun Prakash 	csk->max_iso_npdu = min(max_npdu, max_iso_npdu);
6789730ffcbSVarun Prakash 
6799730ffcbSVarun Prakash 	if (csk->max_iso_npdu <= 1)
6809730ffcbSVarun Prakash 		csk->max_iso_npdu = 0;
6819730ffcbSVarun Prakash 
6829730ffcbSVarun Prakash 	return 0;
6839730ffcbSVarun Prakash }
6849730ffcbSVarun Prakash 
6855248788eSVarun Prakash /*
6865248788eSVarun Prakash  * cxgbit_seq_pdu_inorder()
6875248788eSVarun Prakash  * @csk: pointer to cxgbit socket structure
6885248788eSVarun Prakash  *
6895248788eSVarun Prakash  * This function checks whether data sequence and data
6905248788eSVarun Prakash  * pdu are in order.
6915248788eSVarun Prakash  *
6925248788eSVarun Prakash  * Return: returns -1 on error, 0 if data sequence and
6935248788eSVarun Prakash  * data pdu are in order, 1 if data sequence or data pdu
6945248788eSVarun Prakash  * is not in order.
6955248788eSVarun Prakash  */
6965248788eSVarun Prakash static int cxgbit_seq_pdu_inorder(struct cxgbit_sock *csk)
6975248788eSVarun Prakash {
6985248788eSVarun Prakash 	struct iscsi_conn *conn = csk->conn;
6995248788eSVarun Prakash 	struct iscsi_param *param;
7005248788eSVarun Prakash 
7015248788eSVarun Prakash 	if (conn->login->leading_connection) {
7025248788eSVarun Prakash 		param = iscsi_find_param_from_key(DATASEQUENCEINORDER,
7035248788eSVarun Prakash 						  conn->param_list);
7045248788eSVarun Prakash 		if (!param) {
7055248788eSVarun Prakash 			pr_err("param not found key %s\n", DATASEQUENCEINORDER);
7065248788eSVarun Prakash 			return -1;
7075248788eSVarun Prakash 		}
7085248788eSVarun Prakash 
7095248788eSVarun Prakash 		if (strcmp(param->value, YES))
7105248788eSVarun Prakash 			return 1;
7115248788eSVarun Prakash 
7125248788eSVarun Prakash 		param = iscsi_find_param_from_key(DATAPDUINORDER,
7135248788eSVarun Prakash 						  conn->param_list);
7145248788eSVarun Prakash 		if (!param) {
7155248788eSVarun Prakash 			pr_err("param not found key %s\n", DATAPDUINORDER);
7165248788eSVarun Prakash 			return -1;
7175248788eSVarun Prakash 		}
7185248788eSVarun Prakash 
7195248788eSVarun Prakash 		if (strcmp(param->value, YES))
7205248788eSVarun Prakash 			return 1;
7215248788eSVarun Prakash 
7225248788eSVarun Prakash 	} else {
7235248788eSVarun Prakash 		if (!conn->sess->sess_ops->DataSequenceInOrder)
7245248788eSVarun Prakash 			return 1;
7255248788eSVarun Prakash 		if (!conn->sess->sess_ops->DataPDUInOrder)
7265248788eSVarun Prakash 			return 1;
7275248788eSVarun Prakash 	}
7285248788eSVarun Prakash 
7295248788eSVarun Prakash 	return 0;
7305248788eSVarun Prakash }
7315248788eSVarun Prakash 
7329730ffcbSVarun Prakash static int cxgbit_set_params(struct iscsi_conn *conn)
7339730ffcbSVarun Prakash {
7349730ffcbSVarun Prakash 	struct cxgbit_sock *csk = conn->context;
7359730ffcbSVarun Prakash 	struct cxgbit_device *cdev = csk->com.cdev;
7369730ffcbSVarun Prakash 	struct cxgbi_ppm *ppm = *csk->com.cdev->lldi.iscsi_ppm;
7379730ffcbSVarun Prakash 	struct iscsi_conn_ops *conn_ops = conn->conn_ops;
7389730ffcbSVarun Prakash 	struct iscsi_param *param;
7399730ffcbSVarun Prakash 	u8 erl;
7409730ffcbSVarun Prakash 
7419730ffcbSVarun Prakash 	if (conn_ops->MaxRecvDataSegmentLength > cdev->mdsl)
7429730ffcbSVarun Prakash 		conn_ops->MaxRecvDataSegmentLength = cdev->mdsl;
7439730ffcbSVarun Prakash 
7441b350ea0SVarun Prakash 	if (cxgbit_set_digest(csk))
7451b350ea0SVarun Prakash 		return -1;
7461b350ea0SVarun Prakash 
7479730ffcbSVarun Prakash 	if (conn->login->leading_connection) {
7489730ffcbSVarun Prakash 		param = iscsi_find_param_from_key(ERRORRECOVERYLEVEL,
7499730ffcbSVarun Prakash 						  conn->param_list);
7509730ffcbSVarun Prakash 		if (!param) {
7519730ffcbSVarun Prakash 			pr_err("param not found key %s\n", ERRORRECOVERYLEVEL);
7529730ffcbSVarun Prakash 			return -1;
7539730ffcbSVarun Prakash 		}
7549730ffcbSVarun Prakash 		if (kstrtou8(param->value, 0, &erl) < 0)
7559730ffcbSVarun Prakash 			return -1;
7569730ffcbSVarun Prakash 	} else {
7579730ffcbSVarun Prakash 		erl = conn->sess->sess_ops->ErrorRecoveryLevel;
7589730ffcbSVarun Prakash 	}
7599730ffcbSVarun Prakash 
7609730ffcbSVarun Prakash 	if (!erl) {
7615248788eSVarun Prakash 		int ret;
7625248788eSVarun Prakash 
7635248788eSVarun Prakash 		ret = cxgbit_seq_pdu_inorder(csk);
7645248788eSVarun Prakash 		if (ret < 0) {
7655248788eSVarun Prakash 			return -1;
7665248788eSVarun Prakash 		} else if (ret > 0) {
7675248788eSVarun Prakash 			if (is_t5(cdev->lldi.adapter_type))
7685248788eSVarun Prakash 				goto enable_ddp;
7695248788eSVarun Prakash 			else
7701b350ea0SVarun Prakash 				return 0;
7715248788eSVarun Prakash 		}
7725248788eSVarun Prakash 
7739730ffcbSVarun Prakash 		if (test_bit(CDEV_ISO_ENABLE, &cdev->flags)) {
7749730ffcbSVarun Prakash 			if (cxgbit_set_iso_npdu(csk))
7759730ffcbSVarun Prakash 				return -1;
7769730ffcbSVarun Prakash 		}
7779730ffcbSVarun Prakash 
7785248788eSVarun Prakash enable_ddp:
7799730ffcbSVarun Prakash 		if (test_bit(CDEV_DDP_ENABLE, &cdev->flags)) {
7809730ffcbSVarun Prakash 			if (cxgbit_setup_conn_pgidx(csk,
7819730ffcbSVarun Prakash 						    ppm->tformat.pgsz_idx_dflt))
7829730ffcbSVarun Prakash 				return -1;
7839730ffcbSVarun Prakash 			set_bit(CSK_DDP_ENABLE, &csk->com.flags);
7849730ffcbSVarun Prakash 		}
7859730ffcbSVarun Prakash 	}
7869730ffcbSVarun Prakash 
7879730ffcbSVarun Prakash 	return 0;
7889730ffcbSVarun Prakash }
7899730ffcbSVarun Prakash 
7909730ffcbSVarun Prakash int
7919730ffcbSVarun Prakash cxgbit_put_login_tx(struct iscsi_conn *conn, struct iscsi_login *login,
7929730ffcbSVarun Prakash 		    u32 length)
7939730ffcbSVarun Prakash {
7949730ffcbSVarun Prakash 	struct cxgbit_sock *csk = conn->context;
7959730ffcbSVarun Prakash 	struct sk_buff *skb;
7969730ffcbSVarun Prakash 	u32 padding_buf = 0;
7979730ffcbSVarun Prakash 	u8 padding = ((-length) & 3);
7989730ffcbSVarun Prakash 
7999730ffcbSVarun Prakash 	skb = cxgbit_alloc_skb(csk, length + padding);
8009730ffcbSVarun Prakash 	if (!skb)
8019730ffcbSVarun Prakash 		return -ENOMEM;
8029730ffcbSVarun Prakash 	skb_store_bits(skb, 0, login->rsp, ISCSI_HDR_LEN);
8039730ffcbSVarun Prakash 	skb_store_bits(skb, ISCSI_HDR_LEN, login->rsp_buf, length);
8049730ffcbSVarun Prakash 
8059730ffcbSVarun Prakash 	if (padding)
8069730ffcbSVarun Prakash 		skb_store_bits(skb, ISCSI_HDR_LEN + length,
8079730ffcbSVarun Prakash 			       &padding_buf, padding);
8089730ffcbSVarun Prakash 
8099730ffcbSVarun Prakash 	if (login->login_complete) {
8109730ffcbSVarun Prakash 		if (cxgbit_set_params(conn)) {
8119730ffcbSVarun Prakash 			kfree_skb(skb);
8129730ffcbSVarun Prakash 			return -1;
8139730ffcbSVarun Prakash 		}
8149730ffcbSVarun Prakash 
8159730ffcbSVarun Prakash 		set_bit(CSK_LOGIN_DONE, &csk->com.flags);
8169730ffcbSVarun Prakash 	}
8179730ffcbSVarun Prakash 
8189730ffcbSVarun Prakash 	if (cxgbit_queue_skb(csk, skb))
8199730ffcbSVarun Prakash 		return -1;
8209730ffcbSVarun Prakash 
8219730ffcbSVarun Prakash 	if ((!login->login_complete) && (!login->login_failed))
8229730ffcbSVarun Prakash 		schedule_delayed_work(&conn->login_work, 0);
8239730ffcbSVarun Prakash 
8249730ffcbSVarun Prakash 	return 0;
8259730ffcbSVarun Prakash }
8269730ffcbSVarun Prakash 
8279730ffcbSVarun Prakash static void
8289730ffcbSVarun Prakash cxgbit_skb_copy_to_sg(struct sk_buff *skb, struct scatterlist *sg,
829d96adb9bSVarun Prakash 		      unsigned int nents, u32 skip)
8309730ffcbSVarun Prakash {
8319730ffcbSVarun Prakash 	struct skb_seq_state st;
8329730ffcbSVarun Prakash 	const u8 *buf;
8339730ffcbSVarun Prakash 	unsigned int consumed = 0, buf_len;
8349730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(skb);
8359730ffcbSVarun Prakash 
8369730ffcbSVarun Prakash 	skb_prepare_seq_read(skb, pdu_cb->doffset,
8379730ffcbSVarun Prakash 			     pdu_cb->doffset + pdu_cb->dlen,
8389730ffcbSVarun Prakash 			     &st);
8399730ffcbSVarun Prakash 
8409730ffcbSVarun Prakash 	while (true) {
8419730ffcbSVarun Prakash 		buf_len = skb_seq_read(consumed, &buf, &st);
8429730ffcbSVarun Prakash 		if (!buf_len) {
8439730ffcbSVarun Prakash 			skb_abort_seq_read(&st);
8449730ffcbSVarun Prakash 			break;
8459730ffcbSVarun Prakash 		}
8469730ffcbSVarun Prakash 
8479730ffcbSVarun Prakash 		consumed += sg_pcopy_from_buffer(sg, nents, (void *)buf,
848d96adb9bSVarun Prakash 						 buf_len, skip + consumed);
8499730ffcbSVarun Prakash 	}
8509730ffcbSVarun Prakash }
8519730ffcbSVarun Prakash 
8529730ffcbSVarun Prakash static struct iscsi_cmd *cxgbit_allocate_cmd(struct cxgbit_sock *csk)
8539730ffcbSVarun Prakash {
8549730ffcbSVarun Prakash 	struct iscsi_conn *conn = csk->conn;
8559730ffcbSVarun Prakash 	struct cxgbi_ppm *ppm = cdev2ppm(csk->com.cdev);
8569730ffcbSVarun Prakash 	struct cxgbit_cmd *ccmd;
8579730ffcbSVarun Prakash 	struct iscsi_cmd *cmd;
8589730ffcbSVarun Prakash 
8599730ffcbSVarun Prakash 	cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
8609730ffcbSVarun Prakash 	if (!cmd) {
8619730ffcbSVarun Prakash 		pr_err("Unable to allocate iscsi_cmd + cxgbit_cmd\n");
8629730ffcbSVarun Prakash 		return NULL;
8639730ffcbSVarun Prakash 	}
8649730ffcbSVarun Prakash 
8659730ffcbSVarun Prakash 	ccmd = iscsit_priv_cmd(cmd);
8669730ffcbSVarun Prakash 	ccmd->ttinfo.tag = ppm->tformat.no_ddp_mask;
8679730ffcbSVarun Prakash 	ccmd->setup_ddp = true;
8689730ffcbSVarun Prakash 
8699730ffcbSVarun Prakash 	return cmd;
8709730ffcbSVarun Prakash }
8719730ffcbSVarun Prakash 
8729730ffcbSVarun Prakash static int
8739730ffcbSVarun Prakash cxgbit_handle_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr,
8749730ffcbSVarun Prakash 			     u32 length)
8759730ffcbSVarun Prakash {
8769730ffcbSVarun Prakash 	struct iscsi_conn *conn = cmd->conn;
8779730ffcbSVarun Prakash 	struct cxgbit_sock *csk = conn->context;
8789730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
8799730ffcbSVarun Prakash 
8809730ffcbSVarun Prakash 	if (pdu_cb->flags & PDUCBF_RX_DCRC_ERR) {
8819730ffcbSVarun Prakash 		pr_err("ImmediateData CRC32C DataDigest error\n");
8829730ffcbSVarun Prakash 		if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
8839730ffcbSVarun Prakash 			pr_err("Unable to recover from"
8849730ffcbSVarun Prakash 			       " Immediate Data digest failure while"
8859730ffcbSVarun Prakash 			       " in ERL=0.\n");
8869730ffcbSVarun Prakash 			iscsit_reject_cmd(cmd, ISCSI_REASON_DATA_DIGEST_ERROR,
8879730ffcbSVarun Prakash 					  (unsigned char *)hdr);
8889730ffcbSVarun Prakash 			return IMMEDIATE_DATA_CANNOT_RECOVER;
8899730ffcbSVarun Prakash 		}
8909730ffcbSVarun Prakash 
8919730ffcbSVarun Prakash 		iscsit_reject_cmd(cmd, ISCSI_REASON_DATA_DIGEST_ERROR,
8929730ffcbSVarun Prakash 				  (unsigned char *)hdr);
8939730ffcbSVarun Prakash 		return IMMEDIATE_DATA_ERL1_CRC_FAILURE;
8949730ffcbSVarun Prakash 	}
8959730ffcbSVarun Prakash 
8969730ffcbSVarun Prakash 	if (cmd->se_cmd.se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) {
8979730ffcbSVarun Prakash 		struct cxgbit_cmd *ccmd = iscsit_priv_cmd(cmd);
8989730ffcbSVarun Prakash 		struct skb_shared_info *ssi = skb_shinfo(csk->skb);
8999730ffcbSVarun Prakash 		skb_frag_t *dfrag = &ssi->frags[pdu_cb->dfrag_idx];
9009730ffcbSVarun Prakash 
9019730ffcbSVarun Prakash 		sg_init_table(&ccmd->sg, 1);
9029730ffcbSVarun Prakash 		sg_set_page(&ccmd->sg, dfrag->page.p, skb_frag_size(dfrag),
9039730ffcbSVarun Prakash 			    dfrag->page_offset);
9049730ffcbSVarun Prakash 		get_page(dfrag->page.p);
9059730ffcbSVarun Prakash 
9069730ffcbSVarun Prakash 		cmd->se_cmd.t_data_sg = &ccmd->sg;
9079730ffcbSVarun Prakash 		cmd->se_cmd.t_data_nents = 1;
9089730ffcbSVarun Prakash 
9099730ffcbSVarun Prakash 		ccmd->release = true;
9109730ffcbSVarun Prakash 	} else {
9119730ffcbSVarun Prakash 		struct scatterlist *sg = &cmd->se_cmd.t_data_sg[0];
9129730ffcbSVarun Prakash 		u32 sg_nents = max(1UL, DIV_ROUND_UP(pdu_cb->dlen, PAGE_SIZE));
9139730ffcbSVarun Prakash 
914d96adb9bSVarun Prakash 		cxgbit_skb_copy_to_sg(csk->skb, sg, sg_nents, 0);
9159730ffcbSVarun Prakash 	}
9169730ffcbSVarun Prakash 
9179730ffcbSVarun Prakash 	cmd->write_data_done += pdu_cb->dlen;
9189730ffcbSVarun Prakash 
9199730ffcbSVarun Prakash 	if (cmd->write_data_done == cmd->se_cmd.data_length) {
9209730ffcbSVarun Prakash 		spin_lock_bh(&cmd->istate_lock);
9219730ffcbSVarun Prakash 		cmd->cmd_flags |= ICF_GOT_LAST_DATAOUT;
9229730ffcbSVarun Prakash 		cmd->i_state = ISTATE_RECEIVED_LAST_DATAOUT;
9239730ffcbSVarun Prakash 		spin_unlock_bh(&cmd->istate_lock);
9249730ffcbSVarun Prakash 	}
9259730ffcbSVarun Prakash 
9269730ffcbSVarun Prakash 	return IMMEDIATE_DATA_NORMAL_OPERATION;
9279730ffcbSVarun Prakash }
9289730ffcbSVarun Prakash 
9299730ffcbSVarun Prakash static int
9309730ffcbSVarun Prakash cxgbit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr,
9319730ffcbSVarun Prakash 			  bool dump_payload)
9329730ffcbSVarun Prakash {
9339730ffcbSVarun Prakash 	struct iscsi_conn *conn = cmd->conn;
9349730ffcbSVarun Prakash 	int cmdsn_ret = 0, immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION;
9359730ffcbSVarun Prakash 	/*
9369730ffcbSVarun Prakash 	 * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes.
9379730ffcbSVarun Prakash 	 */
9389730ffcbSVarun Prakash 	if (dump_payload)
9399730ffcbSVarun Prakash 		goto after_immediate_data;
9409730ffcbSVarun Prakash 
9419730ffcbSVarun Prakash 	immed_ret = cxgbit_handle_immediate_data(cmd, hdr,
9429730ffcbSVarun Prakash 						 cmd->first_burst_len);
9439730ffcbSVarun Prakash after_immediate_data:
9449730ffcbSVarun Prakash 	if (immed_ret == IMMEDIATE_DATA_NORMAL_OPERATION) {
9459730ffcbSVarun Prakash 		/*
9469730ffcbSVarun Prakash 		 * A PDU/CmdSN carrying Immediate Data passed
9479730ffcbSVarun Prakash 		 * DataCRC, check against ExpCmdSN/MaxCmdSN if
9489730ffcbSVarun Prakash 		 * Immediate Bit is not set.
9499730ffcbSVarun Prakash 		 */
9509730ffcbSVarun Prakash 		cmdsn_ret = iscsit_sequence_cmd(conn, cmd,
9519730ffcbSVarun Prakash 						(unsigned char *)hdr,
9529730ffcbSVarun Prakash 						hdr->cmdsn);
9539730ffcbSVarun Prakash 		if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
9549730ffcbSVarun Prakash 			return -1;
9559730ffcbSVarun Prakash 
9569730ffcbSVarun Prakash 		if (cmd->sense_reason || cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
9579730ffcbSVarun Prakash 			target_put_sess_cmd(&cmd->se_cmd);
9589730ffcbSVarun Prakash 			return 0;
9599730ffcbSVarun Prakash 		} else if (cmd->unsolicited_data) {
9600300b114SBart Van Assche 			iscsit_set_unsolicited_dataout(cmd);
9619730ffcbSVarun Prakash 		}
9629730ffcbSVarun Prakash 
9639730ffcbSVarun Prakash 	} else if (immed_ret == IMMEDIATE_DATA_ERL1_CRC_FAILURE) {
9649730ffcbSVarun Prakash 		/*
9659730ffcbSVarun Prakash 		 * Immediate Data failed DataCRC and ERL>=1,
9669730ffcbSVarun Prakash 		 * silently drop this PDU and let the initiator
9679730ffcbSVarun Prakash 		 * plug the CmdSN gap.
9689730ffcbSVarun Prakash 		 *
9699730ffcbSVarun Prakash 		 * FIXME: Send Unsolicited NOPIN with reserved
9709730ffcbSVarun Prakash 		 * TTT here to help the initiator figure out
9719730ffcbSVarun Prakash 		 * the missing CmdSN, although they should be
9729730ffcbSVarun Prakash 		 * intelligent enough to determine the missing
9739730ffcbSVarun Prakash 		 * CmdSN and issue a retry to plug the sequence.
9749730ffcbSVarun Prakash 		 */
9759730ffcbSVarun Prakash 		cmd->i_state = ISTATE_REMOVE;
9769730ffcbSVarun Prakash 		iscsit_add_cmd_to_immediate_queue(cmd, conn, cmd->i_state);
9779730ffcbSVarun Prakash 	} else /* immed_ret == IMMEDIATE_DATA_CANNOT_RECOVER */
9789730ffcbSVarun Prakash 		return -1;
9799730ffcbSVarun Prakash 
9809730ffcbSVarun Prakash 	return 0;
9819730ffcbSVarun Prakash }
9829730ffcbSVarun Prakash 
9839730ffcbSVarun Prakash static int
9849730ffcbSVarun Prakash cxgbit_handle_scsi_cmd(struct cxgbit_sock *csk, struct iscsi_cmd *cmd)
9859730ffcbSVarun Prakash {
9869730ffcbSVarun Prakash 	struct iscsi_conn *conn = csk->conn;
9879730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
9889730ffcbSVarun Prakash 	struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)pdu_cb->hdr;
9899730ffcbSVarun Prakash 	int rc;
9909730ffcbSVarun Prakash 	bool dump_payload = false;
9919730ffcbSVarun Prakash 
9929730ffcbSVarun Prakash 	rc = iscsit_setup_scsi_cmd(conn, cmd, (unsigned char *)hdr);
9939730ffcbSVarun Prakash 	if (rc < 0)
9949730ffcbSVarun Prakash 		return rc;
9959730ffcbSVarun Prakash 
9969730ffcbSVarun Prakash 	if (pdu_cb->dlen && (pdu_cb->dlen == cmd->se_cmd.data_length) &&
9979730ffcbSVarun Prakash 	    (pdu_cb->nr_dfrags == 1))
9989730ffcbSVarun Prakash 		cmd->se_cmd.se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
9999730ffcbSVarun Prakash 
10009730ffcbSVarun Prakash 	rc = iscsit_process_scsi_cmd(conn, cmd, hdr);
10019730ffcbSVarun Prakash 	if (rc < 0)
10029730ffcbSVarun Prakash 		return 0;
10039730ffcbSVarun Prakash 	else if (rc > 0)
10049730ffcbSVarun Prakash 		dump_payload = true;
10059730ffcbSVarun Prakash 
10069730ffcbSVarun Prakash 	if (!pdu_cb->dlen)
10079730ffcbSVarun Prakash 		return 0;
10089730ffcbSVarun Prakash 
10099730ffcbSVarun Prakash 	return cxgbit_get_immediate_data(cmd, hdr, dump_payload);
10109730ffcbSVarun Prakash }
10119730ffcbSVarun Prakash 
10129730ffcbSVarun Prakash static int cxgbit_handle_iscsi_dataout(struct cxgbit_sock *csk)
10139730ffcbSVarun Prakash {
10149730ffcbSVarun Prakash 	struct scatterlist *sg_start;
10159730ffcbSVarun Prakash 	struct iscsi_conn *conn = csk->conn;
10169730ffcbSVarun Prakash 	struct iscsi_cmd *cmd = NULL;
10179730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
10189730ffcbSVarun Prakash 	struct iscsi_data *hdr = (struct iscsi_data *)pdu_cb->hdr;
10199730ffcbSVarun Prakash 	u32 data_offset = be32_to_cpu(hdr->offset);
10209730ffcbSVarun Prakash 	u32 data_len = pdu_cb->dlen;
10219730ffcbSVarun Prakash 	int rc, sg_nents, sg_off;
10229730ffcbSVarun Prakash 	bool dcrc_err = false;
10239730ffcbSVarun Prakash 
102479e57cfeSVarun Prakash 	if (pdu_cb->flags & PDUCBF_RX_DDP_CMP) {
102579e57cfeSVarun Prakash 		u32 offset = be32_to_cpu(hdr->offset);
102679e57cfeSVarun Prakash 		u32 ddp_data_len;
102779e57cfeSVarun Prakash 		u32 payload_length = ntoh24(hdr->dlength);
102879e57cfeSVarun Prakash 		bool success = false;
102979e57cfeSVarun Prakash 
103079e57cfeSVarun Prakash 		cmd = iscsit_find_cmd_from_itt_or_dump(conn, hdr->itt, 0);
103179e57cfeSVarun Prakash 		if (!cmd)
103279e57cfeSVarun Prakash 			return 0;
103379e57cfeSVarun Prakash 
103479e57cfeSVarun Prakash 		ddp_data_len = offset - cmd->write_data_done;
103579e57cfeSVarun Prakash 		atomic_long_add(ddp_data_len, &conn->sess->rx_data_octets);
103679e57cfeSVarun Prakash 
103779e57cfeSVarun Prakash 		cmd->write_data_done = offset;
103879e57cfeSVarun Prakash 		cmd->next_burst_len = ddp_data_len;
103979e57cfeSVarun Prakash 		cmd->data_sn = be32_to_cpu(hdr->datasn);
104079e57cfeSVarun Prakash 
104179e57cfeSVarun Prakash 		rc = __iscsit_check_dataout_hdr(conn, (unsigned char *)hdr,
104279e57cfeSVarun Prakash 						cmd, payload_length, &success);
104379e57cfeSVarun Prakash 		if (rc < 0)
104479e57cfeSVarun Prakash 			return rc;
104579e57cfeSVarun Prakash 		else if (!success)
104679e57cfeSVarun Prakash 			return 0;
104779e57cfeSVarun Prakash 	} else {
10489730ffcbSVarun Prakash 		rc = iscsit_check_dataout_hdr(conn, (unsigned char *)hdr, &cmd);
10499730ffcbSVarun Prakash 		if (rc < 0)
10509730ffcbSVarun Prakash 			return rc;
10519730ffcbSVarun Prakash 		else if (!cmd)
10529730ffcbSVarun Prakash 			return 0;
105379e57cfeSVarun Prakash 	}
10549730ffcbSVarun Prakash 
10559730ffcbSVarun Prakash 	if (pdu_cb->flags & PDUCBF_RX_DCRC_ERR) {
10569730ffcbSVarun Prakash 		pr_err("ITT: 0x%08x, Offset: %u, Length: %u,"
10579730ffcbSVarun Prakash 		       " DataSN: 0x%08x\n",
10589730ffcbSVarun Prakash 		       hdr->itt, hdr->offset, data_len,
10599730ffcbSVarun Prakash 		       hdr->datasn);
10609730ffcbSVarun Prakash 
10619730ffcbSVarun Prakash 		dcrc_err = true;
10629730ffcbSVarun Prakash 		goto check_payload;
10639730ffcbSVarun Prakash 	}
10649730ffcbSVarun Prakash 
10659730ffcbSVarun Prakash 	pr_debug("DataOut data_len: %u, "
10669730ffcbSVarun Prakash 		"write_data_done: %u, data_length: %u\n",
10679730ffcbSVarun Prakash 		  data_len,  cmd->write_data_done,
10689730ffcbSVarun Prakash 		  cmd->se_cmd.data_length);
10699730ffcbSVarun Prakash 
10709730ffcbSVarun Prakash 	if (!(pdu_cb->flags & PDUCBF_RX_DATA_DDPD)) {
1071d96adb9bSVarun Prakash 		u32 skip = data_offset % PAGE_SIZE;
1072d96adb9bSVarun Prakash 
10739730ffcbSVarun Prakash 		sg_off = data_offset / PAGE_SIZE;
10749730ffcbSVarun Prakash 		sg_start = &cmd->se_cmd.t_data_sg[sg_off];
1075d96adb9bSVarun Prakash 		sg_nents = max(1UL, DIV_ROUND_UP(skip + data_len, PAGE_SIZE));
10769730ffcbSVarun Prakash 
1077d96adb9bSVarun Prakash 		cxgbit_skb_copy_to_sg(csk->skb, sg_start, sg_nents, skip);
10789730ffcbSVarun Prakash 	}
10799730ffcbSVarun Prakash 
10809730ffcbSVarun Prakash check_payload:
10819730ffcbSVarun Prakash 
10829730ffcbSVarun Prakash 	rc = iscsit_check_dataout_payload(cmd, hdr, dcrc_err);
10839730ffcbSVarun Prakash 	if (rc < 0)
10849730ffcbSVarun Prakash 		return rc;
10859730ffcbSVarun Prakash 
10869730ffcbSVarun Prakash 	return 0;
10879730ffcbSVarun Prakash }
10889730ffcbSVarun Prakash 
10899730ffcbSVarun Prakash static int cxgbit_handle_nop_out(struct cxgbit_sock *csk, struct iscsi_cmd *cmd)
10909730ffcbSVarun Prakash {
10919730ffcbSVarun Prakash 	struct iscsi_conn *conn = csk->conn;
10929730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
10939730ffcbSVarun Prakash 	struct iscsi_nopout *hdr = (struct iscsi_nopout *)pdu_cb->hdr;
10949730ffcbSVarun Prakash 	unsigned char *ping_data = NULL;
10959730ffcbSVarun Prakash 	u32 payload_length = pdu_cb->dlen;
10969730ffcbSVarun Prakash 	int ret;
10979730ffcbSVarun Prakash 
10989730ffcbSVarun Prakash 	ret = iscsit_setup_nop_out(conn, cmd, hdr);
10999730ffcbSVarun Prakash 	if (ret < 0)
11009730ffcbSVarun Prakash 		return 0;
11019730ffcbSVarun Prakash 
11029730ffcbSVarun Prakash 	if (pdu_cb->flags & PDUCBF_RX_DCRC_ERR) {
11039730ffcbSVarun Prakash 		if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
11049730ffcbSVarun Prakash 			pr_err("Unable to recover from"
11059730ffcbSVarun Prakash 			       " NOPOUT Ping DataCRC failure while in"
11069730ffcbSVarun Prakash 			       " ERL=0.\n");
11079730ffcbSVarun Prakash 			ret = -1;
11089730ffcbSVarun Prakash 			goto out;
11099730ffcbSVarun Prakash 		} else {
11109730ffcbSVarun Prakash 			/*
11119730ffcbSVarun Prakash 			 * drop this PDU and let the
11129730ffcbSVarun Prakash 			 * initiator plug the CmdSN gap.
11139730ffcbSVarun Prakash 			 */
11149730ffcbSVarun Prakash 			pr_info("Dropping NOPOUT"
11159730ffcbSVarun Prakash 				" Command CmdSN: 0x%08x due to"
11169730ffcbSVarun Prakash 				" DataCRC error.\n", hdr->cmdsn);
11179730ffcbSVarun Prakash 			ret = 0;
11189730ffcbSVarun Prakash 			goto out;
11199730ffcbSVarun Prakash 		}
11209730ffcbSVarun Prakash 	}
11219730ffcbSVarun Prakash 
11229730ffcbSVarun Prakash 	/*
11239730ffcbSVarun Prakash 	 * Handle NOP-OUT payload for traditional iSCSI sockets
11249730ffcbSVarun Prakash 	 */
11259730ffcbSVarun Prakash 	if (payload_length && hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
11269730ffcbSVarun Prakash 		ping_data = kzalloc(payload_length + 1, GFP_KERNEL);
11279730ffcbSVarun Prakash 		if (!ping_data) {
11289730ffcbSVarun Prakash 			pr_err("Unable to allocate memory for"
11299730ffcbSVarun Prakash 				" NOPOUT ping data.\n");
11309730ffcbSVarun Prakash 			ret = -1;
11319730ffcbSVarun Prakash 			goto out;
11329730ffcbSVarun Prakash 		}
11339730ffcbSVarun Prakash 
11349730ffcbSVarun Prakash 		skb_copy_bits(csk->skb, pdu_cb->doffset,
11359730ffcbSVarun Prakash 			      ping_data, payload_length);
11369730ffcbSVarun Prakash 
11379730ffcbSVarun Prakash 		ping_data[payload_length] = '\0';
11389730ffcbSVarun Prakash 		/*
11399730ffcbSVarun Prakash 		 * Attach ping data to struct iscsi_cmd->buf_ptr.
11409730ffcbSVarun Prakash 		 */
11419730ffcbSVarun Prakash 		cmd->buf_ptr = ping_data;
11429730ffcbSVarun Prakash 		cmd->buf_ptr_size = payload_length;
11439730ffcbSVarun Prakash 
11449730ffcbSVarun Prakash 		pr_debug("Got %u bytes of NOPOUT ping"
11459730ffcbSVarun Prakash 			" data.\n", payload_length);
11469730ffcbSVarun Prakash 		pr_debug("Ping Data: \"%s\"\n", ping_data);
11479730ffcbSVarun Prakash 	}
11489730ffcbSVarun Prakash 
11499730ffcbSVarun Prakash 	return iscsit_process_nop_out(conn, cmd, hdr);
11509730ffcbSVarun Prakash out:
11519730ffcbSVarun Prakash 	if (cmd)
11529730ffcbSVarun Prakash 		iscsit_free_cmd(cmd, false);
11539730ffcbSVarun Prakash 	return ret;
11549730ffcbSVarun Prakash }
11559730ffcbSVarun Prakash 
11569730ffcbSVarun Prakash static int
11579730ffcbSVarun Prakash cxgbit_handle_text_cmd(struct cxgbit_sock *csk, struct iscsi_cmd *cmd)
11589730ffcbSVarun Prakash {
11599730ffcbSVarun Prakash 	struct iscsi_conn *conn = csk->conn;
11609730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
11619730ffcbSVarun Prakash 	struct iscsi_text *hdr = (struct iscsi_text *)pdu_cb->hdr;
11629730ffcbSVarun Prakash 	u32 payload_length = pdu_cb->dlen;
11639730ffcbSVarun Prakash 	int rc;
11649730ffcbSVarun Prakash 	unsigned char *text_in = NULL;
11659730ffcbSVarun Prakash 
11669730ffcbSVarun Prakash 	rc = iscsit_setup_text_cmd(conn, cmd, hdr);
11679730ffcbSVarun Prakash 	if (rc < 0)
11689730ffcbSVarun Prakash 		return rc;
11699730ffcbSVarun Prakash 
11709730ffcbSVarun Prakash 	if (pdu_cb->flags & PDUCBF_RX_DCRC_ERR) {
11719730ffcbSVarun Prakash 		if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
11729730ffcbSVarun Prakash 			pr_err("Unable to recover from"
11739730ffcbSVarun Prakash 			       " Text Data digest failure while in"
11749730ffcbSVarun Prakash 			       " ERL=0.\n");
11759730ffcbSVarun Prakash 			goto reject;
11769730ffcbSVarun Prakash 		} else {
11779730ffcbSVarun Prakash 			/*
11789730ffcbSVarun Prakash 			 * drop this PDU and let the
11799730ffcbSVarun Prakash 			 * initiator plug the CmdSN gap.
11809730ffcbSVarun Prakash 			 */
11819730ffcbSVarun Prakash 			pr_info("Dropping Text"
11829730ffcbSVarun Prakash 				" Command CmdSN: 0x%08x due to"
11839730ffcbSVarun Prakash 				" DataCRC error.\n", hdr->cmdsn);
11849730ffcbSVarun Prakash 			return 0;
11859730ffcbSVarun Prakash 		}
11869730ffcbSVarun Prakash 	}
11879730ffcbSVarun Prakash 
11889730ffcbSVarun Prakash 	if (payload_length) {
11899730ffcbSVarun Prakash 		text_in = kzalloc(payload_length, GFP_KERNEL);
11909730ffcbSVarun Prakash 		if (!text_in) {
11919730ffcbSVarun Prakash 			pr_err("Unable to allocate text_in of payload_length: %u\n",
11929730ffcbSVarun Prakash 			       payload_length);
11939730ffcbSVarun Prakash 			return -ENOMEM;
11949730ffcbSVarun Prakash 		}
11959730ffcbSVarun Prakash 		skb_copy_bits(csk->skb, pdu_cb->doffset,
11969730ffcbSVarun Prakash 			      text_in, payload_length);
11979730ffcbSVarun Prakash 
11989730ffcbSVarun Prakash 		text_in[payload_length - 1] = '\0';
11999730ffcbSVarun Prakash 
12009730ffcbSVarun Prakash 		cmd->text_in_ptr = text_in;
12019730ffcbSVarun Prakash 	}
12029730ffcbSVarun Prakash 
12039730ffcbSVarun Prakash 	return iscsit_process_text_cmd(conn, cmd, hdr);
12049730ffcbSVarun Prakash 
12059730ffcbSVarun Prakash reject:
12069730ffcbSVarun Prakash 	return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
12079730ffcbSVarun Prakash 				 pdu_cb->hdr);
12089730ffcbSVarun Prakash }
12099730ffcbSVarun Prakash 
12109730ffcbSVarun Prakash static int cxgbit_target_rx_opcode(struct cxgbit_sock *csk)
12119730ffcbSVarun Prakash {
12129730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
12139730ffcbSVarun Prakash 	struct iscsi_hdr *hdr = (struct iscsi_hdr *)pdu_cb->hdr;
12149730ffcbSVarun Prakash 	struct iscsi_conn *conn = csk->conn;
12159730ffcbSVarun Prakash 	struct iscsi_cmd *cmd = NULL;
12169730ffcbSVarun Prakash 	u8 opcode = (hdr->opcode & ISCSI_OPCODE_MASK);
12179730ffcbSVarun Prakash 	int ret = -EINVAL;
12189730ffcbSVarun Prakash 
12199730ffcbSVarun Prakash 	switch (opcode) {
12209730ffcbSVarun Prakash 	case ISCSI_OP_SCSI_CMD:
12219730ffcbSVarun Prakash 		cmd = cxgbit_allocate_cmd(csk);
12229730ffcbSVarun Prakash 		if (!cmd)
12239730ffcbSVarun Prakash 			goto reject;
12249730ffcbSVarun Prakash 
12259730ffcbSVarun Prakash 		ret = cxgbit_handle_scsi_cmd(csk, cmd);
12269730ffcbSVarun Prakash 		break;
12279730ffcbSVarun Prakash 	case ISCSI_OP_SCSI_DATA_OUT:
12289730ffcbSVarun Prakash 		ret = cxgbit_handle_iscsi_dataout(csk);
12299730ffcbSVarun Prakash 		break;
12309730ffcbSVarun Prakash 	case ISCSI_OP_NOOP_OUT:
12319730ffcbSVarun Prakash 		if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
12329730ffcbSVarun Prakash 			cmd = cxgbit_allocate_cmd(csk);
12339730ffcbSVarun Prakash 			if (!cmd)
12349730ffcbSVarun Prakash 				goto reject;
12359730ffcbSVarun Prakash 		}
12369730ffcbSVarun Prakash 
12379730ffcbSVarun Prakash 		ret = cxgbit_handle_nop_out(csk, cmd);
12389730ffcbSVarun Prakash 		break;
12399730ffcbSVarun Prakash 	case ISCSI_OP_SCSI_TMFUNC:
12409730ffcbSVarun Prakash 		cmd = cxgbit_allocate_cmd(csk);
12419730ffcbSVarun Prakash 		if (!cmd)
12429730ffcbSVarun Prakash 			goto reject;
12439730ffcbSVarun Prakash 
12449730ffcbSVarun Prakash 		ret = iscsit_handle_task_mgt_cmd(conn, cmd,
12459730ffcbSVarun Prakash 						 (unsigned char *)hdr);
12469730ffcbSVarun Prakash 		break;
12479730ffcbSVarun Prakash 	case ISCSI_OP_TEXT:
12489730ffcbSVarun Prakash 		if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) {
12499730ffcbSVarun Prakash 			cmd = iscsit_find_cmd_from_itt(conn, hdr->itt);
12509730ffcbSVarun Prakash 			if (!cmd)
12519730ffcbSVarun Prakash 				goto reject;
12529730ffcbSVarun Prakash 		} else {
12539730ffcbSVarun Prakash 			cmd = cxgbit_allocate_cmd(csk);
12549730ffcbSVarun Prakash 			if (!cmd)
12559730ffcbSVarun Prakash 				goto reject;
12569730ffcbSVarun Prakash 		}
12579730ffcbSVarun Prakash 
12589730ffcbSVarun Prakash 		ret = cxgbit_handle_text_cmd(csk, cmd);
12599730ffcbSVarun Prakash 		break;
12609730ffcbSVarun Prakash 	case ISCSI_OP_LOGOUT:
12619730ffcbSVarun Prakash 		cmd = cxgbit_allocate_cmd(csk);
12629730ffcbSVarun Prakash 		if (!cmd)
12639730ffcbSVarun Prakash 			goto reject;
12649730ffcbSVarun Prakash 
12659730ffcbSVarun Prakash 		ret = iscsit_handle_logout_cmd(conn, cmd, (unsigned char *)hdr);
12669730ffcbSVarun Prakash 		if (ret > 0)
12679730ffcbSVarun Prakash 			wait_for_completion_timeout(&conn->conn_logout_comp,
12689730ffcbSVarun Prakash 						    SECONDS_FOR_LOGOUT_COMP
12699730ffcbSVarun Prakash 						    * HZ);
12709730ffcbSVarun Prakash 		break;
12719730ffcbSVarun Prakash 	case ISCSI_OP_SNACK:
12729730ffcbSVarun Prakash 		ret = iscsit_handle_snack(conn, (unsigned char *)hdr);
12739730ffcbSVarun Prakash 		break;
12749730ffcbSVarun Prakash 	default:
12759730ffcbSVarun Prakash 		pr_err("Got unknown iSCSI OpCode: 0x%02x\n", opcode);
12769730ffcbSVarun Prakash 		dump_stack();
12779730ffcbSVarun Prakash 		break;
12789730ffcbSVarun Prakash 	}
12799730ffcbSVarun Prakash 
12809730ffcbSVarun Prakash 	return ret;
12819730ffcbSVarun Prakash 
12829730ffcbSVarun Prakash reject:
12839730ffcbSVarun Prakash 	return iscsit_add_reject(conn, ISCSI_REASON_BOOKMARK_NO_RESOURCES,
12849730ffcbSVarun Prakash 				 (unsigned char *)hdr);
12859730ffcbSVarun Prakash 	return ret;
12869730ffcbSVarun Prakash }
12879730ffcbSVarun Prakash 
12889730ffcbSVarun Prakash static int cxgbit_rx_opcode(struct cxgbit_sock *csk)
12899730ffcbSVarun Prakash {
12909730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
12919730ffcbSVarun Prakash 	struct iscsi_conn *conn = csk->conn;
12929730ffcbSVarun Prakash 	struct iscsi_hdr *hdr = pdu_cb->hdr;
12939730ffcbSVarun Prakash 	u8 opcode;
12949730ffcbSVarun Prakash 
12959730ffcbSVarun Prakash 	if (pdu_cb->flags & PDUCBF_RX_HCRC_ERR) {
12969730ffcbSVarun Prakash 		atomic_long_inc(&conn->sess->conn_digest_errors);
12979730ffcbSVarun Prakash 		goto transport_err;
12989730ffcbSVarun Prakash 	}
12999730ffcbSVarun Prakash 
13009730ffcbSVarun Prakash 	if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT)
13019730ffcbSVarun Prakash 		goto transport_err;
13029730ffcbSVarun Prakash 
13039730ffcbSVarun Prakash 	opcode = hdr->opcode & ISCSI_OPCODE_MASK;
13049730ffcbSVarun Prakash 
13059730ffcbSVarun Prakash 	if (conn->sess->sess_ops->SessionType &&
13069730ffcbSVarun Prakash 	    ((!(opcode & ISCSI_OP_TEXT)) ||
13079730ffcbSVarun Prakash 	     (!(opcode & ISCSI_OP_LOGOUT)))) {
13089730ffcbSVarun Prakash 		pr_err("Received illegal iSCSI Opcode: 0x%02x"
13099730ffcbSVarun Prakash 			" while in Discovery Session, rejecting.\n", opcode);
13109730ffcbSVarun Prakash 		iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
13119730ffcbSVarun Prakash 				  (unsigned char *)hdr);
13129730ffcbSVarun Prakash 		goto transport_err;
13139730ffcbSVarun Prakash 	}
13149730ffcbSVarun Prakash 
13159730ffcbSVarun Prakash 	if (cxgbit_target_rx_opcode(csk) < 0)
13169730ffcbSVarun Prakash 		goto transport_err;
13179730ffcbSVarun Prakash 
13189730ffcbSVarun Prakash 	return 0;
13199730ffcbSVarun Prakash 
13209730ffcbSVarun Prakash transport_err:
13219730ffcbSVarun Prakash 	return -1;
13229730ffcbSVarun Prakash }
13239730ffcbSVarun Prakash 
13249730ffcbSVarun Prakash static int cxgbit_rx_login_pdu(struct cxgbit_sock *csk)
13259730ffcbSVarun Prakash {
13269730ffcbSVarun Prakash 	struct iscsi_conn *conn = csk->conn;
13279730ffcbSVarun Prakash 	struct iscsi_login *login = conn->login;
13289730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
13299730ffcbSVarun Prakash 	struct iscsi_login_req *login_req;
13309730ffcbSVarun Prakash 
13319730ffcbSVarun Prakash 	login_req = (struct iscsi_login_req *)login->req;
13329730ffcbSVarun Prakash 	memcpy(login_req, pdu_cb->hdr, sizeof(*login_req));
13339730ffcbSVarun Prakash 
13349730ffcbSVarun Prakash 	pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x,"
13359730ffcbSVarun Prakash 		" CmdSN: 0x%08x, ExpStatSN: 0x%08x, CID: %hu, Length: %u\n",
13369730ffcbSVarun Prakash 		login_req->flags, login_req->itt, login_req->cmdsn,
13379730ffcbSVarun Prakash 		login_req->exp_statsn, login_req->cid, pdu_cb->dlen);
13389730ffcbSVarun Prakash 	/*
13399730ffcbSVarun Prakash 	 * Setup the initial iscsi_login values from the leading
13409730ffcbSVarun Prakash 	 * login request PDU.
13419730ffcbSVarun Prakash 	 */
13429730ffcbSVarun Prakash 	if (login->first_request) {
13439730ffcbSVarun Prakash 		login_req = (struct iscsi_login_req *)login->req;
13449730ffcbSVarun Prakash 		login->leading_connection = (!login_req->tsih) ? 1 : 0;
13459730ffcbSVarun Prakash 		login->current_stage	= ISCSI_LOGIN_CURRENT_STAGE(
13469730ffcbSVarun Prakash 				login_req->flags);
13479730ffcbSVarun Prakash 		login->version_min	= login_req->min_version;
13489730ffcbSVarun Prakash 		login->version_max	= login_req->max_version;
13499730ffcbSVarun Prakash 		memcpy(login->isid, login_req->isid, 6);
13509730ffcbSVarun Prakash 		login->cmd_sn		= be32_to_cpu(login_req->cmdsn);
13519730ffcbSVarun Prakash 		login->init_task_tag	= login_req->itt;
13529730ffcbSVarun Prakash 		login->initial_exp_statsn = be32_to_cpu(login_req->exp_statsn);
13539730ffcbSVarun Prakash 		login->cid		= be16_to_cpu(login_req->cid);
13549730ffcbSVarun Prakash 		login->tsih		= be16_to_cpu(login_req->tsih);
13559730ffcbSVarun Prakash 	}
13569730ffcbSVarun Prakash 
13579730ffcbSVarun Prakash 	if (iscsi_target_check_login_request(conn, login) < 0)
13589730ffcbSVarun Prakash 		return -1;
13599730ffcbSVarun Prakash 
13609730ffcbSVarun Prakash 	memset(login->req_buf, 0, MAX_KEY_VALUE_PAIRS);
13619730ffcbSVarun Prakash 	skb_copy_bits(csk->skb, pdu_cb->doffset, login->req_buf, pdu_cb->dlen);
13629730ffcbSVarun Prakash 
13639730ffcbSVarun Prakash 	return 0;
13649730ffcbSVarun Prakash }
13659730ffcbSVarun Prakash 
13669730ffcbSVarun Prakash static int
13679730ffcbSVarun Prakash cxgbit_process_iscsi_pdu(struct cxgbit_sock *csk, struct sk_buff *skb, int idx)
13689730ffcbSVarun Prakash {
13699730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, idx);
13709730ffcbSVarun Prakash 	int ret;
13719730ffcbSVarun Prakash 
13729730ffcbSVarun Prakash 	cxgbit_rx_pdu_cb(skb) = pdu_cb;
13739730ffcbSVarun Prakash 
13749730ffcbSVarun Prakash 	csk->skb = skb;
13759730ffcbSVarun Prakash 
13769730ffcbSVarun Prakash 	if (!test_bit(CSK_LOGIN_DONE, &csk->com.flags)) {
13779730ffcbSVarun Prakash 		ret = cxgbit_rx_login_pdu(csk);
13789730ffcbSVarun Prakash 		set_bit(CSK_LOGIN_PDU_DONE, &csk->com.flags);
13799730ffcbSVarun Prakash 	} else {
13809730ffcbSVarun Prakash 		ret = cxgbit_rx_opcode(csk);
13819730ffcbSVarun Prakash 	}
13829730ffcbSVarun Prakash 
13839730ffcbSVarun Prakash 	return ret;
13849730ffcbSVarun Prakash }
13859730ffcbSVarun Prakash 
13869730ffcbSVarun Prakash static void cxgbit_lro_skb_dump(struct sk_buff *skb)
13879730ffcbSVarun Prakash {
13889730ffcbSVarun Prakash 	struct skb_shared_info *ssi = skb_shinfo(skb);
13899730ffcbSVarun Prakash 	struct cxgbit_lro_cb *lro_cb = cxgbit_skb_lro_cb(skb);
13909730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, 0);
13919730ffcbSVarun Prakash 	u8 i;
13929730ffcbSVarun Prakash 
13939730ffcbSVarun Prakash 	pr_info("skb 0x%p, head 0x%p, 0x%p, len %u,%u, frags %u.\n",
13949730ffcbSVarun Prakash 		skb, skb->head, skb->data, skb->len, skb->data_len,
13959730ffcbSVarun Prakash 		ssi->nr_frags);
13969730ffcbSVarun Prakash 	pr_info("skb 0x%p, lro_cb, csk 0x%p, pdu %u, %u.\n",
13979730ffcbSVarun Prakash 		skb, lro_cb->csk, lro_cb->pdu_idx, lro_cb->pdu_totallen);
13989730ffcbSVarun Prakash 
13999730ffcbSVarun Prakash 	for (i = 0; i < lro_cb->pdu_idx; i++, pdu_cb++)
14009730ffcbSVarun Prakash 		pr_info("skb 0x%p, pdu %d, %u, f 0x%x, seq 0x%x, dcrc 0x%x, "
14019730ffcbSVarun Prakash 			"frags %u.\n",
14029730ffcbSVarun Prakash 			skb, i, pdu_cb->pdulen, pdu_cb->flags, pdu_cb->seq,
14039730ffcbSVarun Prakash 			pdu_cb->ddigest, pdu_cb->frags);
14049730ffcbSVarun Prakash 	for (i = 0; i < ssi->nr_frags; i++)
14059730ffcbSVarun Prakash 		pr_info("skb 0x%p, frag %d, off %u, sz %u.\n",
14069730ffcbSVarun Prakash 			skb, i, ssi->frags[i].page_offset, ssi->frags[i].size);
14079730ffcbSVarun Prakash }
14089730ffcbSVarun Prakash 
14099730ffcbSVarun Prakash static void cxgbit_lro_hskb_reset(struct cxgbit_sock *csk)
14109730ffcbSVarun Prakash {
14119730ffcbSVarun Prakash 	struct sk_buff *skb = csk->lro_hskb;
14129730ffcbSVarun Prakash 	struct skb_shared_info *ssi = skb_shinfo(skb);
14139730ffcbSVarun Prakash 	u8 i;
14149730ffcbSVarun Prakash 
14159730ffcbSVarun Prakash 	memset(skb->data, 0, LRO_SKB_MIN_HEADROOM);
14169730ffcbSVarun Prakash 	for (i = 0; i < ssi->nr_frags; i++)
14179730ffcbSVarun Prakash 		put_page(skb_frag_page(&ssi->frags[i]));
14189730ffcbSVarun Prakash 	ssi->nr_frags = 0;
141979e57cfeSVarun Prakash 	skb->data_len = 0;
142079e57cfeSVarun Prakash 	skb->truesize -= skb->len;
142179e57cfeSVarun Prakash 	skb->len = 0;
14229730ffcbSVarun Prakash }
14239730ffcbSVarun Prakash 
14249730ffcbSVarun Prakash static void
14259730ffcbSVarun Prakash cxgbit_lro_skb_merge(struct cxgbit_sock *csk, struct sk_buff *skb, u8 pdu_idx)
14269730ffcbSVarun Prakash {
14279730ffcbSVarun Prakash 	struct sk_buff *hskb = csk->lro_hskb;
14289730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *hpdu_cb = cxgbit_skb_lro_pdu_cb(hskb, 0);
14299730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, pdu_idx);
14309730ffcbSVarun Prakash 	struct skb_shared_info *hssi = skb_shinfo(hskb);
14319730ffcbSVarun Prakash 	struct skb_shared_info *ssi = skb_shinfo(skb);
14329730ffcbSVarun Prakash 	unsigned int len = 0;
14339730ffcbSVarun Prakash 
14349730ffcbSVarun Prakash 	if (pdu_cb->flags & PDUCBF_RX_HDR) {
143579e57cfeSVarun Prakash 		u8 hfrag_idx = hssi->nr_frags;
143679e57cfeSVarun Prakash 
143779e57cfeSVarun Prakash 		hpdu_cb->flags |= pdu_cb->flags;
14389730ffcbSVarun Prakash 		hpdu_cb->seq = pdu_cb->seq;
14399730ffcbSVarun Prakash 		hpdu_cb->hdr = pdu_cb->hdr;
14409730ffcbSVarun Prakash 		hpdu_cb->hlen = pdu_cb->hlen;
14419730ffcbSVarun Prakash 
144279e57cfeSVarun Prakash 		memcpy(&hssi->frags[hfrag_idx], &ssi->frags[pdu_cb->hfrag_idx],
14439730ffcbSVarun Prakash 		       sizeof(skb_frag_t));
14449730ffcbSVarun Prakash 
14459730ffcbSVarun Prakash 		get_page(skb_frag_page(&hssi->frags[hfrag_idx]));
144679e57cfeSVarun Prakash 		hssi->nr_frags++;
144779e57cfeSVarun Prakash 		hpdu_cb->frags++;
144879e57cfeSVarun Prakash 		hpdu_cb->hfrag_idx = hfrag_idx;
14499730ffcbSVarun Prakash 
145079e57cfeSVarun Prakash 		len = hssi->frags[hfrag_idx].size;
145179e57cfeSVarun Prakash 		hskb->len += len;
145279e57cfeSVarun Prakash 		hskb->data_len += len;
145379e57cfeSVarun Prakash 		hskb->truesize += len;
145479e57cfeSVarun Prakash 	}
145579e57cfeSVarun Prakash 
145679e57cfeSVarun Prakash 	if (pdu_cb->flags & PDUCBF_RX_DATA) {
145779e57cfeSVarun Prakash 		u8 dfrag_idx = hssi->nr_frags, i;
145879e57cfeSVarun Prakash 
145979e57cfeSVarun Prakash 		hpdu_cb->flags |= pdu_cb->flags;
146079e57cfeSVarun Prakash 		hpdu_cb->dfrag_idx = dfrag_idx;
146179e57cfeSVarun Prakash 
146279e57cfeSVarun Prakash 		len = 0;
146379e57cfeSVarun Prakash 		for (i = 0; i < pdu_cb->nr_dfrags; dfrag_idx++, i++) {
146479e57cfeSVarun Prakash 			memcpy(&hssi->frags[dfrag_idx],
146579e57cfeSVarun Prakash 			       &ssi->frags[pdu_cb->dfrag_idx + i],
146679e57cfeSVarun Prakash 			       sizeof(skb_frag_t));
146779e57cfeSVarun Prakash 
146879e57cfeSVarun Prakash 			get_page(skb_frag_page(&hssi->frags[dfrag_idx]));
146979e57cfeSVarun Prakash 
147079e57cfeSVarun Prakash 			len += hssi->frags[dfrag_idx].size;
14719730ffcbSVarun Prakash 
14729730ffcbSVarun Prakash 			hssi->nr_frags++;
14739730ffcbSVarun Prakash 			hpdu_cb->frags++;
14749730ffcbSVarun Prakash 		}
14759730ffcbSVarun Prakash 
14769730ffcbSVarun Prakash 		hpdu_cb->dlen = pdu_cb->dlen;
14779730ffcbSVarun Prakash 		hpdu_cb->doffset = hpdu_cb->hlen;
14789730ffcbSVarun Prakash 		hpdu_cb->nr_dfrags = pdu_cb->nr_dfrags;
14799730ffcbSVarun Prakash 		hskb->len += len;
14809730ffcbSVarun Prakash 		hskb->data_len += len;
14819730ffcbSVarun Prakash 		hskb->truesize += len;
14829730ffcbSVarun Prakash 	}
14839730ffcbSVarun Prakash 
14849730ffcbSVarun Prakash 	if (pdu_cb->flags & PDUCBF_RX_STATUS) {
14859730ffcbSVarun Prakash 		hpdu_cb->flags |= pdu_cb->flags;
14869730ffcbSVarun Prakash 
14879730ffcbSVarun Prakash 		if (hpdu_cb->flags & PDUCBF_RX_DATA)
14889730ffcbSVarun Prakash 			hpdu_cb->flags &= ~PDUCBF_RX_DATA_DDPD;
14899730ffcbSVarun Prakash 
14909730ffcbSVarun Prakash 		hpdu_cb->ddigest = pdu_cb->ddigest;
14919730ffcbSVarun Prakash 		hpdu_cb->pdulen = pdu_cb->pdulen;
14929730ffcbSVarun Prakash 	}
14939730ffcbSVarun Prakash }
14949730ffcbSVarun Prakash 
14959730ffcbSVarun Prakash static int cxgbit_process_lro_skb(struct cxgbit_sock *csk, struct sk_buff *skb)
14969730ffcbSVarun Prakash {
14979730ffcbSVarun Prakash 	struct cxgbit_lro_cb *lro_cb = cxgbit_skb_lro_cb(skb);
14989730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, 0);
14999730ffcbSVarun Prakash 	u8 pdu_idx = 0, last_idx = 0;
15009730ffcbSVarun Prakash 	int ret = 0;
15019730ffcbSVarun Prakash 
15029730ffcbSVarun Prakash 	if (!pdu_cb->complete) {
15039730ffcbSVarun Prakash 		cxgbit_lro_skb_merge(csk, skb, 0);
15049730ffcbSVarun Prakash 
15059730ffcbSVarun Prakash 		if (pdu_cb->flags & PDUCBF_RX_STATUS) {
15069730ffcbSVarun Prakash 			struct sk_buff *hskb = csk->lro_hskb;
15079730ffcbSVarun Prakash 
15089730ffcbSVarun Prakash 			ret = cxgbit_process_iscsi_pdu(csk, hskb, 0);
15099730ffcbSVarun Prakash 
15109730ffcbSVarun Prakash 			cxgbit_lro_hskb_reset(csk);
15119730ffcbSVarun Prakash 
15129730ffcbSVarun Prakash 			if (ret < 0)
15139730ffcbSVarun Prakash 				goto out;
15149730ffcbSVarun Prakash 		}
15159730ffcbSVarun Prakash 
15169730ffcbSVarun Prakash 		pdu_idx = 1;
15179730ffcbSVarun Prakash 	}
15189730ffcbSVarun Prakash 
15199730ffcbSVarun Prakash 	if (lro_cb->pdu_idx)
15209730ffcbSVarun Prakash 		last_idx = lro_cb->pdu_idx - 1;
15219730ffcbSVarun Prakash 
15229730ffcbSVarun Prakash 	for (; pdu_idx <= last_idx; pdu_idx++) {
15239730ffcbSVarun Prakash 		ret = cxgbit_process_iscsi_pdu(csk, skb, pdu_idx);
15249730ffcbSVarun Prakash 		if (ret < 0)
15259730ffcbSVarun Prakash 			goto out;
15269730ffcbSVarun Prakash 	}
15279730ffcbSVarun Prakash 
15289730ffcbSVarun Prakash 	if ((!lro_cb->complete) && lro_cb->pdu_idx)
15299730ffcbSVarun Prakash 		cxgbit_lro_skb_merge(csk, skb, lro_cb->pdu_idx);
15309730ffcbSVarun Prakash 
15319730ffcbSVarun Prakash out:
15329730ffcbSVarun Prakash 	return ret;
15339730ffcbSVarun Prakash }
15349730ffcbSVarun Prakash 
15359730ffcbSVarun Prakash static int cxgbit_rx_lro_skb(struct cxgbit_sock *csk, struct sk_buff *skb)
15369730ffcbSVarun Prakash {
15379730ffcbSVarun Prakash 	struct cxgbit_lro_cb *lro_cb = cxgbit_skb_lro_cb(skb);
15389730ffcbSVarun Prakash 	struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, 0);
15399730ffcbSVarun Prakash 	int ret = -1;
15409730ffcbSVarun Prakash 
15419730ffcbSVarun Prakash 	if ((pdu_cb->flags & PDUCBF_RX_HDR) &&
15429730ffcbSVarun Prakash 	    (pdu_cb->seq != csk->rcv_nxt)) {
15439730ffcbSVarun Prakash 		pr_info("csk 0x%p, tid 0x%x, seq 0x%x != 0x%x.\n",
15449730ffcbSVarun Prakash 			csk, csk->tid, pdu_cb->seq, csk->rcv_nxt);
15459730ffcbSVarun Prakash 		cxgbit_lro_skb_dump(skb);
15469730ffcbSVarun Prakash 		return ret;
15479730ffcbSVarun Prakash 	}
15489730ffcbSVarun Prakash 
15499730ffcbSVarun Prakash 	csk->rcv_nxt += lro_cb->pdu_totallen;
15509730ffcbSVarun Prakash 
15519730ffcbSVarun Prakash 	ret = cxgbit_process_lro_skb(csk, skb);
15529730ffcbSVarun Prakash 
15539730ffcbSVarun Prakash 	csk->rx_credits += lro_cb->pdu_totallen;
15549730ffcbSVarun Prakash 
15559730ffcbSVarun Prakash 	if (csk->rx_credits >= (csk->rcv_win / 4))
15569730ffcbSVarun Prakash 		cxgbit_rx_data_ack(csk);
15579730ffcbSVarun Prakash 
15589730ffcbSVarun Prakash 	return ret;
15599730ffcbSVarun Prakash }
15609730ffcbSVarun Prakash 
15619730ffcbSVarun Prakash static int cxgbit_rx_skb(struct cxgbit_sock *csk, struct sk_buff *skb)
15629730ffcbSVarun Prakash {
156379e57cfeSVarun Prakash 	struct cxgb4_lld_info *lldi = &csk->com.cdev->lldi;
15649730ffcbSVarun Prakash 	int ret = -1;
15659730ffcbSVarun Prakash 
156679e57cfeSVarun Prakash 	if (likely(cxgbit_skcb_flags(skb) & SKCBF_RX_LRO)) {
156779e57cfeSVarun Prakash 		if (is_t5(lldi->adapter_type))
15689730ffcbSVarun Prakash 			ret = cxgbit_rx_lro_skb(csk, skb);
156979e57cfeSVarun Prakash 		else
157079e57cfeSVarun Prakash 			ret = cxgbit_process_lro_skb(csk, skb);
157179e57cfeSVarun Prakash 	}
15729730ffcbSVarun Prakash 
15739730ffcbSVarun Prakash 	__kfree_skb(skb);
15749730ffcbSVarun Prakash 	return ret;
15759730ffcbSVarun Prakash }
15769730ffcbSVarun Prakash 
15779730ffcbSVarun Prakash static bool cxgbit_rxq_len(struct cxgbit_sock *csk, struct sk_buff_head *rxq)
15789730ffcbSVarun Prakash {
15799730ffcbSVarun Prakash 	spin_lock_bh(&csk->rxq.lock);
15809730ffcbSVarun Prakash 	if (skb_queue_len(&csk->rxq)) {
15819730ffcbSVarun Prakash 		skb_queue_splice_init(&csk->rxq, rxq);
15829730ffcbSVarun Prakash 		spin_unlock_bh(&csk->rxq.lock);
15839730ffcbSVarun Prakash 		return true;
15849730ffcbSVarun Prakash 	}
15859730ffcbSVarun Prakash 	spin_unlock_bh(&csk->rxq.lock);
15869730ffcbSVarun Prakash 	return false;
15879730ffcbSVarun Prakash }
15889730ffcbSVarun Prakash 
15899730ffcbSVarun Prakash static int cxgbit_wait_rxq(struct cxgbit_sock *csk)
15909730ffcbSVarun Prakash {
15919730ffcbSVarun Prakash 	struct sk_buff *skb;
15929730ffcbSVarun Prakash 	struct sk_buff_head rxq;
15939730ffcbSVarun Prakash 
15949730ffcbSVarun Prakash 	skb_queue_head_init(&rxq);
15959730ffcbSVarun Prakash 
15969730ffcbSVarun Prakash 	wait_event_interruptible(csk->waitq, cxgbit_rxq_len(csk, &rxq));
15979730ffcbSVarun Prakash 
15989730ffcbSVarun Prakash 	if (signal_pending(current))
15999730ffcbSVarun Prakash 		goto out;
16009730ffcbSVarun Prakash 
16019730ffcbSVarun Prakash 	while ((skb = __skb_dequeue(&rxq))) {
16029730ffcbSVarun Prakash 		if (cxgbit_rx_skb(csk, skb))
16039730ffcbSVarun Prakash 			goto out;
16049730ffcbSVarun Prakash 	}
16059730ffcbSVarun Prakash 
16069730ffcbSVarun Prakash 	return 0;
16079730ffcbSVarun Prakash out:
16089730ffcbSVarun Prakash 	__skb_queue_purge(&rxq);
16099730ffcbSVarun Prakash 	return -1;
16109730ffcbSVarun Prakash }
16119730ffcbSVarun Prakash 
16129730ffcbSVarun Prakash int cxgbit_get_login_rx(struct iscsi_conn *conn, struct iscsi_login *login)
16139730ffcbSVarun Prakash {
16149730ffcbSVarun Prakash 	struct cxgbit_sock *csk = conn->context;
16159730ffcbSVarun Prakash 	int ret = -1;
16169730ffcbSVarun Prakash 
16179730ffcbSVarun Prakash 	while (!test_and_clear_bit(CSK_LOGIN_PDU_DONE, &csk->com.flags)) {
16189730ffcbSVarun Prakash 		ret = cxgbit_wait_rxq(csk);
16199730ffcbSVarun Prakash 		if (ret) {
16209730ffcbSVarun Prakash 			clear_bit(CSK_LOGIN_PDU_DONE, &csk->com.flags);
16219730ffcbSVarun Prakash 			break;
16229730ffcbSVarun Prakash 		}
16239730ffcbSVarun Prakash 	}
16249730ffcbSVarun Prakash 
16259730ffcbSVarun Prakash 	return ret;
16269730ffcbSVarun Prakash }
16279730ffcbSVarun Prakash 
16289730ffcbSVarun Prakash void cxgbit_get_rx_pdu(struct iscsi_conn *conn)
16299730ffcbSVarun Prakash {
16309730ffcbSVarun Prakash 	struct cxgbit_sock *csk = conn->context;
16319730ffcbSVarun Prakash 
16329730ffcbSVarun Prakash 	while (!kthread_should_stop()) {
16339730ffcbSVarun Prakash 		iscsit_thread_check_cpumask(conn, current, 0);
16349730ffcbSVarun Prakash 		if (cxgbit_wait_rxq(csk))
16359730ffcbSVarun Prakash 			return;
16369730ffcbSVarun Prakash 	}
16379730ffcbSVarun Prakash }
1638