xref: /linux/drivers/infiniband/sw/siw/siw_qp_rx.c (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce)
13ec648c6SKrzysztof Kozlowski // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
28b6a361bSBernard Metzler 
38b6a361bSBernard Metzler /* Authors: Bernard Metzler <bmt@zurich.ibm.com> */
48b6a361bSBernard Metzler /* Copyright (c) 2008-2019, IBM Corporation */
58b6a361bSBernard Metzler 
68b6a361bSBernard Metzler #include <linux/errno.h>
78b6a361bSBernard Metzler #include <linux/types.h>
88b6a361bSBernard Metzler #include <linux/net.h>
98b6a361bSBernard Metzler #include <linux/scatterlist.h>
108b6a361bSBernard Metzler #include <linux/highmem.h>
118b6a361bSBernard Metzler 
128b6a361bSBernard Metzler #include <rdma/iw_cm.h>
138b6a361bSBernard Metzler #include <rdma/ib_verbs.h>
148b6a361bSBernard Metzler 
158b6a361bSBernard Metzler #include "siw.h"
168b6a361bSBernard Metzler #include "siw_verbs.h"
178b6a361bSBernard Metzler #include "siw_mem.h"
188b6a361bSBernard Metzler 
198b6a361bSBernard Metzler /*
208b6a361bSBernard Metzler  * siw_rx_umem()
218b6a361bSBernard Metzler  *
228b6a361bSBernard Metzler  * Receive data of @len into target referenced by @dest_addr.
238b6a361bSBernard Metzler  *
248b6a361bSBernard Metzler  * @srx:	Receive Context
258b6a361bSBernard Metzler  * @umem:	siw representation of target memory
268b6a361bSBernard Metzler  * @dest_addr:	user virtual address
278b6a361bSBernard Metzler  * @len:	number of bytes to place
288b6a361bSBernard Metzler  */
siw_rx_umem(struct siw_rx_stream * srx,struct siw_umem * umem,u64 dest_addr,int len)298b6a361bSBernard Metzler static int siw_rx_umem(struct siw_rx_stream *srx, struct siw_umem *umem,
308b6a361bSBernard Metzler 		       u64 dest_addr, int len)
318b6a361bSBernard Metzler {
328b6a361bSBernard Metzler 	int copied = 0;
338b6a361bSBernard Metzler 
348b6a361bSBernard Metzler 	while (len) {
358b6a361bSBernard Metzler 		struct page *p;
368b6a361bSBernard Metzler 		int pg_off, bytes, rv;
378b6a361bSBernard Metzler 		void *dest;
388b6a361bSBernard Metzler 
398b6a361bSBernard Metzler 		p = siw_get_upage(umem, dest_addr);
408b6a361bSBernard Metzler 		if (unlikely(!p)) {
41*9334003dSThomas Weißschuh 			pr_warn("siw: %s: [QP %u]: bogus addr: %p, %p\n",
428b6a361bSBernard Metzler 				__func__, qp_id(rx_qp(srx)),
43c536277eSBernard Metzler 				(void *)(uintptr_t)dest_addr,
44c536277eSBernard Metzler 				(void *)(uintptr_t)umem->fp_addr);
458b6a361bSBernard Metzler 			/* siw internal error */
468b6a361bSBernard Metzler 			srx->skb_copied += copied;
478b6a361bSBernard Metzler 			srx->skb_new -= copied;
488b6a361bSBernard Metzler 
498b6a361bSBernard Metzler 			return -EFAULT;
508b6a361bSBernard Metzler 		}
518b6a361bSBernard Metzler 		pg_off = dest_addr & ~PAGE_MASK;
528b6a361bSBernard Metzler 		bytes = min(len, (int)PAGE_SIZE - pg_off);
538b6a361bSBernard Metzler 
54*9334003dSThomas Weißschuh 		siw_dbg_qp(rx_qp(srx), "page %p, bytes=%u\n", p, bytes);
558b6a361bSBernard Metzler 
568b6a361bSBernard Metzler 		dest = kmap_atomic(p);
578b6a361bSBernard Metzler 		rv = skb_copy_bits(srx->skb, srx->skb_offset, dest + pg_off,
588b6a361bSBernard Metzler 				   bytes);
598b6a361bSBernard Metzler 
608b6a361bSBernard Metzler 		if (unlikely(rv)) {
618b6a361bSBernard Metzler 			kunmap_atomic(dest);
628b6a361bSBernard Metzler 			srx->skb_copied += copied;
638b6a361bSBernard Metzler 			srx->skb_new -= copied;
648b6a361bSBernard Metzler 
658b6a361bSBernard Metzler 			pr_warn("siw: [QP %u]: %s, len %d, page %p, rv %d\n",
668b6a361bSBernard Metzler 				qp_id(rx_qp(srx)), __func__, len, p, rv);
678b6a361bSBernard Metzler 
688b6a361bSBernard Metzler 			return -EFAULT;
698b6a361bSBernard Metzler 		}
70426370c8SEric Biggers 		if (srx->mpa_crc_enabled) {
7158fb0b56SBernard Metzler 			if (rdma_is_kernel_res(&rx_qp(srx)->base_qp.res)) {
72426370c8SEric Biggers 				siw_crc_update(&srx->mpa_crc, dest + pg_off,
73426370c8SEric Biggers 					       bytes);
748b6a361bSBernard Metzler 				kunmap_atomic(dest);
758b6a361bSBernard Metzler 			} else {
768b6a361bSBernard Metzler 				kunmap_atomic(dest);
778b6a361bSBernard Metzler 				/*
788b6a361bSBernard Metzler 				 * Do CRC on original, not target buffer.
798b6a361bSBernard Metzler 				 * Some user land applications may
808b6a361bSBernard Metzler 				 * concurrently write the target buffer,
818b6a361bSBernard Metzler 				 * which would yield a broken CRC.
828b6a361bSBernard Metzler 				 * Walking the skb twice is very ineffcient.
838b6a361bSBernard Metzler 				 * Folding the CRC into skb_copy_bits()
848b6a361bSBernard Metzler 				 * would be much better, but is currently
858b6a361bSBernard Metzler 				 * not supported.
868b6a361bSBernard Metzler 				 */
878b6a361bSBernard Metzler 				siw_crc_skb(srx, bytes);
888b6a361bSBernard Metzler 			}
898b6a361bSBernard Metzler 		} else {
908b6a361bSBernard Metzler 			kunmap_atomic(dest);
918b6a361bSBernard Metzler 		}
928b6a361bSBernard Metzler 		srx->skb_offset += bytes;
938b6a361bSBernard Metzler 		copied += bytes;
948b6a361bSBernard Metzler 		len -= bytes;
958b6a361bSBernard Metzler 		dest_addr += bytes;
968b6a361bSBernard Metzler 		pg_off = 0;
978b6a361bSBernard Metzler 	}
988b6a361bSBernard Metzler 	srx->skb_copied += copied;
998b6a361bSBernard Metzler 	srx->skb_new -= copied;
1008b6a361bSBernard Metzler 
1018b6a361bSBernard Metzler 	return copied;
1028b6a361bSBernard Metzler }
1038b6a361bSBernard Metzler 
siw_rx_kva(struct siw_rx_stream * srx,void * kva,int len)1048b6a361bSBernard Metzler static int siw_rx_kva(struct siw_rx_stream *srx, void *kva, int len)
1058b6a361bSBernard Metzler {
1068b6a361bSBernard Metzler 	int rv;
1078b6a361bSBernard Metzler 
108*9334003dSThomas Weißschuh 	siw_dbg_qp(rx_qp(srx), "kva: 0x%p, len: %u\n", kva, len);
1098b6a361bSBernard Metzler 
1108b6a361bSBernard Metzler 	rv = skb_copy_bits(srx->skb, srx->skb_offset, kva, len);
1118b6a361bSBernard Metzler 	if (unlikely(rv)) {
112*9334003dSThomas Weißschuh 		pr_warn("siw: [QP %u]: %s, len %d, kva 0x%p, rv %d\n",
1138b6a361bSBernard Metzler 			qp_id(rx_qp(srx)), __func__, len, kva, rv);
1148b6a361bSBernard Metzler 
1158b6a361bSBernard Metzler 		return rv;
1168b6a361bSBernard Metzler 	}
117426370c8SEric Biggers 	if (srx->mpa_crc_enabled)
118426370c8SEric Biggers 		siw_crc_update(&srx->mpa_crc, kva, len);
1198b6a361bSBernard Metzler 
1208b6a361bSBernard Metzler 	srx->skb_offset += len;
1218b6a361bSBernard Metzler 	srx->skb_copied += len;
1228b6a361bSBernard Metzler 	srx->skb_new -= len;
1238b6a361bSBernard Metzler 
1248b6a361bSBernard Metzler 	return len;
1258b6a361bSBernard Metzler }
1268b6a361bSBernard Metzler 
siw_rx_pbl(struct siw_rx_stream * srx,int * pbl_idx,struct siw_mem * mem,u64 addr,int len)1278b6a361bSBernard Metzler static int siw_rx_pbl(struct siw_rx_stream *srx, int *pbl_idx,
1288b6a361bSBernard Metzler 		      struct siw_mem *mem, u64 addr, int len)
1298b6a361bSBernard Metzler {
1308b6a361bSBernard Metzler 	struct siw_pbl *pbl = mem->pbl;
1318b6a361bSBernard Metzler 	u64 offset = addr - mem->va;
1328b6a361bSBernard Metzler 	int copied = 0;
1338b6a361bSBernard Metzler 
1348b6a361bSBernard Metzler 	while (len) {
1358b6a361bSBernard Metzler 		int bytes;
136c536277eSBernard Metzler 		dma_addr_t buf_addr =
1378b6a361bSBernard Metzler 			siw_pbl_get_buffer(pbl, offset, &bytes, pbl_idx);
1388b6a361bSBernard Metzler 		if (!buf_addr)
1398b6a361bSBernard Metzler 			break;
1408b6a361bSBernard Metzler 
1418b6a361bSBernard Metzler 		bytes = min(bytes, len);
1428d7c7c0eSJason Gunthorpe 		if (siw_rx_kva(srx, ib_virt_dma_to_ptr(buf_addr), bytes) ==
1436769b275STom Seewald 		    bytes) {
1448b6a361bSBernard Metzler 			copied += bytes;
1458b6a361bSBernard Metzler 			offset += bytes;
1468b6a361bSBernard Metzler 			len -= bytes;
1478b6a361bSBernard Metzler 		} else {
1488b6a361bSBernard Metzler 			break;
1498b6a361bSBernard Metzler 		}
1508b6a361bSBernard Metzler 	}
1518b6a361bSBernard Metzler 	return copied;
1528b6a361bSBernard Metzler }
1538b6a361bSBernard Metzler 
1548b6a361bSBernard Metzler /*
1558b6a361bSBernard Metzler  * siw_rresp_check_ntoh()
1568b6a361bSBernard Metzler  *
1578b6a361bSBernard Metzler  * Check incoming RRESP fragment header against expected
1588b6a361bSBernard Metzler  * header values and update expected values for potential next
1598b6a361bSBernard Metzler  * fragment.
1608b6a361bSBernard Metzler  *
1618b6a361bSBernard Metzler  * NOTE: This function must be called only if a RRESP DDP segment
1628b6a361bSBernard Metzler  *       starts but not for fragmented consecutive pieces of an
1638b6a361bSBernard Metzler  *       already started DDP segment.
1648b6a361bSBernard Metzler  */
siw_rresp_check_ntoh(struct siw_rx_stream * srx,struct siw_rx_fpdu * frx)1658b6a361bSBernard Metzler static int siw_rresp_check_ntoh(struct siw_rx_stream *srx,
1668b6a361bSBernard Metzler 				struct siw_rx_fpdu *frx)
1678b6a361bSBernard Metzler {
1688b6a361bSBernard Metzler 	struct iwarp_rdma_rresp *rresp = &srx->hdr.rresp;
1698b6a361bSBernard Metzler 	struct siw_wqe *wqe = &frx->wqe_active;
1708b6a361bSBernard Metzler 	enum ddp_ecode ecode;
1718b6a361bSBernard Metzler 
1728b6a361bSBernard Metzler 	u32 sink_stag = be32_to_cpu(rresp->sink_stag);
1738b6a361bSBernard Metzler 	u64 sink_to = be64_to_cpu(rresp->sink_to);
1748b6a361bSBernard Metzler 
1758b6a361bSBernard Metzler 	if (frx->first_ddp_seg) {
1768b6a361bSBernard Metzler 		srx->ddp_stag = wqe->sqe.sge[0].lkey;
1778b6a361bSBernard Metzler 		srx->ddp_to = wqe->sqe.sge[0].laddr;
1788b6a361bSBernard Metzler 		frx->pbl_idx = 0;
1798b6a361bSBernard Metzler 	}
1808b6a361bSBernard Metzler 	/* Below checks extend beyond the semantics of DDP, and
1818b6a361bSBernard Metzler 	 * into RDMAP:
1828b6a361bSBernard Metzler 	 * We check if the read response matches exactly the
1838b6a361bSBernard Metzler 	 * read request which was send to the remote peer to
1848b6a361bSBernard Metzler 	 * trigger this read response. RFC5040/5041 do not
1858b6a361bSBernard Metzler 	 * always have a proper error code for the detected
1868b6a361bSBernard Metzler 	 * error cases. We choose 'base or bounds error' for
1878b6a361bSBernard Metzler 	 * cases where the inbound STag is valid, but offset
1888b6a361bSBernard Metzler 	 * or length do not match our response receive state.
1898b6a361bSBernard Metzler 	 */
1908b6a361bSBernard Metzler 	if (unlikely(srx->ddp_stag != sink_stag)) {
1918b6a361bSBernard Metzler 		pr_warn("siw: [QP %u]: rresp stag: %08x != %08x\n",
1928b6a361bSBernard Metzler 			qp_id(rx_qp(srx)), sink_stag, srx->ddp_stag);
1938b6a361bSBernard Metzler 		ecode = DDP_ECODE_T_INVALID_STAG;
1948b6a361bSBernard Metzler 		goto error;
1958b6a361bSBernard Metzler 	}
1968b6a361bSBernard Metzler 	if (unlikely(srx->ddp_to != sink_to)) {
1978b6a361bSBernard Metzler 		pr_warn("siw: [QP %u]: rresp off: %016llx != %016llx\n",
1988b6a361bSBernard Metzler 			qp_id(rx_qp(srx)), (unsigned long long)sink_to,
1998b6a361bSBernard Metzler 			(unsigned long long)srx->ddp_to);
2008b6a361bSBernard Metzler 		ecode = DDP_ECODE_T_BASE_BOUNDS;
2018b6a361bSBernard Metzler 		goto error;
2028b6a361bSBernard Metzler 	}
2038b6a361bSBernard Metzler 	if (unlikely(!frx->more_ddp_segs &&
2048b6a361bSBernard Metzler 		     (wqe->processed + srx->fpdu_part_rem != wqe->bytes))) {
2058b6a361bSBernard Metzler 		pr_warn("siw: [QP %u]: rresp len: %d != %d\n",
2068b6a361bSBernard Metzler 			qp_id(rx_qp(srx)),
2078b6a361bSBernard Metzler 			wqe->processed + srx->fpdu_part_rem, wqe->bytes);
2088b6a361bSBernard Metzler 		ecode = DDP_ECODE_T_BASE_BOUNDS;
2098b6a361bSBernard Metzler 		goto error;
2108b6a361bSBernard Metzler 	}
2118b6a361bSBernard Metzler 	return 0;
2128b6a361bSBernard Metzler error:
2138b6a361bSBernard Metzler 	siw_init_terminate(rx_qp(srx), TERM_ERROR_LAYER_DDP,
2148b6a361bSBernard Metzler 			   DDP_ETYPE_TAGGED_BUF, ecode, 0);
2158b6a361bSBernard Metzler 	return -EINVAL;
2168b6a361bSBernard Metzler }
2178b6a361bSBernard Metzler 
2188b6a361bSBernard Metzler /*
2198b6a361bSBernard Metzler  * siw_write_check_ntoh()
2208b6a361bSBernard Metzler  *
2218b6a361bSBernard Metzler  * Check incoming WRITE fragment header against expected
2228b6a361bSBernard Metzler  * header values and update expected values for potential next
2238b6a361bSBernard Metzler  * fragment
2248b6a361bSBernard Metzler  *
2258b6a361bSBernard Metzler  * NOTE: This function must be called only if a WRITE DDP segment
2268b6a361bSBernard Metzler  *       starts but not for fragmented consecutive pieces of an
2278b6a361bSBernard Metzler  *       already started DDP segment.
2288b6a361bSBernard Metzler  */
siw_write_check_ntoh(struct siw_rx_stream * srx,struct siw_rx_fpdu * frx)2298b6a361bSBernard Metzler static int siw_write_check_ntoh(struct siw_rx_stream *srx,
2308b6a361bSBernard Metzler 				struct siw_rx_fpdu *frx)
2318b6a361bSBernard Metzler {
2328b6a361bSBernard Metzler 	struct iwarp_rdma_write *write = &srx->hdr.rwrite;
2338b6a361bSBernard Metzler 	enum ddp_ecode ecode;
2348b6a361bSBernard Metzler 
2358b6a361bSBernard Metzler 	u32 sink_stag = be32_to_cpu(write->sink_stag);
2368b6a361bSBernard Metzler 	u64 sink_to = be64_to_cpu(write->sink_to);
2378b6a361bSBernard Metzler 
2388b6a361bSBernard Metzler 	if (frx->first_ddp_seg) {
2398b6a361bSBernard Metzler 		srx->ddp_stag = sink_stag;
2408b6a361bSBernard Metzler 		srx->ddp_to = sink_to;
2418b6a361bSBernard Metzler 		frx->pbl_idx = 0;
2428b6a361bSBernard Metzler 	} else {
2438b6a361bSBernard Metzler 		if (unlikely(srx->ddp_stag != sink_stag)) {
2448b6a361bSBernard Metzler 			pr_warn("siw: [QP %u]: write stag: %08x != %08x\n",
2458b6a361bSBernard Metzler 				qp_id(rx_qp(srx)), sink_stag,
2468b6a361bSBernard Metzler 				srx->ddp_stag);
2478b6a361bSBernard Metzler 			ecode = DDP_ECODE_T_INVALID_STAG;
2488b6a361bSBernard Metzler 			goto error;
2498b6a361bSBernard Metzler 		}
2508b6a361bSBernard Metzler 		if (unlikely(srx->ddp_to != sink_to)) {
2518b6a361bSBernard Metzler 			pr_warn("siw: [QP %u]: write off: %016llx != %016llx\n",
2528b6a361bSBernard Metzler 				qp_id(rx_qp(srx)),
2538b6a361bSBernard Metzler 				(unsigned long long)sink_to,
2548b6a361bSBernard Metzler 				(unsigned long long)srx->ddp_to);
2558b6a361bSBernard Metzler 			ecode = DDP_ECODE_T_BASE_BOUNDS;
2568b6a361bSBernard Metzler 			goto error;
2578b6a361bSBernard Metzler 		}
2588b6a361bSBernard Metzler 	}
2598b6a361bSBernard Metzler 	return 0;
2608b6a361bSBernard Metzler error:
2618b6a361bSBernard Metzler 	siw_init_terminate(rx_qp(srx), TERM_ERROR_LAYER_DDP,
2628b6a361bSBernard Metzler 			   DDP_ETYPE_TAGGED_BUF, ecode, 0);
2638b6a361bSBernard Metzler 	return -EINVAL;
2648b6a361bSBernard Metzler }
2658b6a361bSBernard Metzler 
2668b6a361bSBernard Metzler /*
2678b6a361bSBernard Metzler  * siw_send_check_ntoh()
2688b6a361bSBernard Metzler  *
2698b6a361bSBernard Metzler  * Check incoming SEND fragment header against expected
2708b6a361bSBernard Metzler  * header values and update expected MSN if no next
2718b6a361bSBernard Metzler  * fragment expected
2728b6a361bSBernard Metzler  *
2738b6a361bSBernard Metzler  * NOTE: This function must be called only if a SEND DDP segment
2748b6a361bSBernard Metzler  *       starts but not for fragmented consecutive pieces of an
2758b6a361bSBernard Metzler  *       already started DDP segment.
2768b6a361bSBernard Metzler  */
siw_send_check_ntoh(struct siw_rx_stream * srx,struct siw_rx_fpdu * frx)2778b6a361bSBernard Metzler static int siw_send_check_ntoh(struct siw_rx_stream *srx,
2788b6a361bSBernard Metzler 			       struct siw_rx_fpdu *frx)
2798b6a361bSBernard Metzler {
2808b6a361bSBernard Metzler 	struct iwarp_send_inv *send = &srx->hdr.send_inv;
2818b6a361bSBernard Metzler 	struct siw_wqe *wqe = &frx->wqe_active;
2828b6a361bSBernard Metzler 	enum ddp_ecode ecode;
2838b6a361bSBernard Metzler 
2848b6a361bSBernard Metzler 	u32 ddp_msn = be32_to_cpu(send->ddp_msn);
2858b6a361bSBernard Metzler 	u32 ddp_mo = be32_to_cpu(send->ddp_mo);
2868b6a361bSBernard Metzler 	u32 ddp_qn = be32_to_cpu(send->ddp_qn);
2878b6a361bSBernard Metzler 
2888b6a361bSBernard Metzler 	if (unlikely(ddp_qn != RDMAP_UNTAGGED_QN_SEND)) {
2898b6a361bSBernard Metzler 		pr_warn("siw: [QP %u]: invalid ddp qn %d for send\n",
2908b6a361bSBernard Metzler 			qp_id(rx_qp(srx)), ddp_qn);
2918b6a361bSBernard Metzler 		ecode = DDP_ECODE_UT_INVALID_QN;
2928b6a361bSBernard Metzler 		goto error;
2938b6a361bSBernard Metzler 	}
2948b6a361bSBernard Metzler 	if (unlikely(ddp_msn != srx->ddp_msn[RDMAP_UNTAGGED_QN_SEND])) {
2958b6a361bSBernard Metzler 		pr_warn("siw: [QP %u]: send msn: %u != %u\n",
2968b6a361bSBernard Metzler 			qp_id(rx_qp(srx)), ddp_msn,
2978b6a361bSBernard Metzler 			srx->ddp_msn[RDMAP_UNTAGGED_QN_SEND]);
2988b6a361bSBernard Metzler 		ecode = DDP_ECODE_UT_INVALID_MSN_RANGE;
2998b6a361bSBernard Metzler 		goto error;
3008b6a361bSBernard Metzler 	}
3018b6a361bSBernard Metzler 	if (unlikely(ddp_mo != wqe->processed)) {
3028b6a361bSBernard Metzler 		pr_warn("siw: [QP %u], send mo: %u != %u\n",
3038b6a361bSBernard Metzler 			qp_id(rx_qp(srx)), ddp_mo, wqe->processed);
3048b6a361bSBernard Metzler 		ecode = DDP_ECODE_UT_INVALID_MO;
3058b6a361bSBernard Metzler 		goto error;
3068b6a361bSBernard Metzler 	}
3078b6a361bSBernard Metzler 	if (frx->first_ddp_seg) {
3088b6a361bSBernard Metzler 		/* initialize user memory write position */
3098b6a361bSBernard Metzler 		frx->sge_idx = 0;
3108b6a361bSBernard Metzler 		frx->sge_off = 0;
3118b6a361bSBernard Metzler 		frx->pbl_idx = 0;
3128b6a361bSBernard Metzler 
3138b6a361bSBernard Metzler 		/* only valid for SEND_INV and SEND_SE_INV operations */
3148b6a361bSBernard Metzler 		srx->inval_stag = be32_to_cpu(send->inval_stag);
3158b6a361bSBernard Metzler 	}
3168b6a361bSBernard Metzler 	if (unlikely(wqe->bytes < wqe->processed + srx->fpdu_part_rem)) {
3178b6a361bSBernard Metzler 		siw_dbg_qp(rx_qp(srx), "receive space short: %d - %d < %d\n",
3188b6a361bSBernard Metzler 			   wqe->bytes, wqe->processed, srx->fpdu_part_rem);
3198b6a361bSBernard Metzler 		wqe->wc_status = SIW_WC_LOC_LEN_ERR;
3208b6a361bSBernard Metzler 		ecode = DDP_ECODE_UT_INVALID_MSN_NOBUF;
3218b6a361bSBernard Metzler 		goto error;
3228b6a361bSBernard Metzler 	}
3238b6a361bSBernard Metzler 	return 0;
3248b6a361bSBernard Metzler error:
3258b6a361bSBernard Metzler 	siw_init_terminate(rx_qp(srx), TERM_ERROR_LAYER_DDP,
3268b6a361bSBernard Metzler 			   DDP_ETYPE_UNTAGGED_BUF, ecode, 0);
3278b6a361bSBernard Metzler 	return -EINVAL;
3288b6a361bSBernard Metzler }
3298b6a361bSBernard Metzler 
siw_rqe_get(struct siw_qp * qp)3308b6a361bSBernard Metzler static struct siw_wqe *siw_rqe_get(struct siw_qp *qp)
3318b6a361bSBernard Metzler {
3328b6a361bSBernard Metzler 	struct siw_rqe *rqe;
3338b6a361bSBernard Metzler 	struct siw_srq *srq;
3348b6a361bSBernard Metzler 	struct siw_wqe *wqe = NULL;
3358b6a361bSBernard Metzler 	bool srq_event = false;
3363f649ab7SKees Cook 	unsigned long flags;
3378b6a361bSBernard Metzler 
3388b6a361bSBernard Metzler 	srq = qp->srq;
3398b6a361bSBernard Metzler 	if (srq) {
3408b6a361bSBernard Metzler 		spin_lock_irqsave(&srq->lock, flags);
3418b6a361bSBernard Metzler 		if (unlikely(!srq->num_rqe))
3428b6a361bSBernard Metzler 			goto out;
3438b6a361bSBernard Metzler 
3448b6a361bSBernard Metzler 		rqe = &srq->recvq[srq->rq_get % srq->num_rqe];
3458b6a361bSBernard Metzler 	} else {
3468b6a361bSBernard Metzler 		if (unlikely(!qp->recvq))
3478b6a361bSBernard Metzler 			goto out;
3488b6a361bSBernard Metzler 
3498b6a361bSBernard Metzler 		rqe = &qp->recvq[qp->rq_get % qp->attrs.rq_size];
3508b6a361bSBernard Metzler 	}
3518b6a361bSBernard Metzler 	if (likely(rqe->flags == SIW_WQE_VALID)) {
3528b6a361bSBernard Metzler 		int num_sge = rqe->num_sge;
3538b6a361bSBernard Metzler 
3548b6a361bSBernard Metzler 		if (likely(num_sge <= SIW_MAX_SGE)) {
3558b6a361bSBernard Metzler 			int i = 0;
3568b6a361bSBernard Metzler 
3578b6a361bSBernard Metzler 			wqe = rx_wqe(&qp->rx_untagged);
3588b6a361bSBernard Metzler 			rx_type(wqe) = SIW_OP_RECEIVE;
3598b6a361bSBernard Metzler 			wqe->wr_status = SIW_WR_INPROGRESS;
3608b6a361bSBernard Metzler 			wqe->bytes = 0;
3618b6a361bSBernard Metzler 			wqe->processed = 0;
3628b6a361bSBernard Metzler 
3638b6a361bSBernard Metzler 			wqe->rqe.id = rqe->id;
3648b6a361bSBernard Metzler 			wqe->rqe.num_sge = num_sge;
3658b6a361bSBernard Metzler 
3668b6a361bSBernard Metzler 			while (i < num_sge) {
3678b6a361bSBernard Metzler 				wqe->rqe.sge[i].laddr = rqe->sge[i].laddr;
3688b6a361bSBernard Metzler 				wqe->rqe.sge[i].lkey = rqe->sge[i].lkey;
3698b6a361bSBernard Metzler 				wqe->rqe.sge[i].length = rqe->sge[i].length;
3708b6a361bSBernard Metzler 				wqe->bytes += wqe->rqe.sge[i].length;
3718b6a361bSBernard Metzler 				wqe->mem[i] = NULL;
3728b6a361bSBernard Metzler 				i++;
3738b6a361bSBernard Metzler 			}
3748b6a361bSBernard Metzler 			/* can be re-used by appl */
3758b6a361bSBernard Metzler 			smp_store_mb(rqe->flags, 0);
3768b6a361bSBernard Metzler 		} else {
3778b6a361bSBernard Metzler 			siw_dbg_qp(qp, "too many sge's: %d\n", rqe->num_sge);
3788b6a361bSBernard Metzler 			if (srq)
3798b6a361bSBernard Metzler 				spin_unlock_irqrestore(&srq->lock, flags);
3808b6a361bSBernard Metzler 			return NULL;
3818b6a361bSBernard Metzler 		}
3828b6a361bSBernard Metzler 		if (!srq) {
3838b6a361bSBernard Metzler 			qp->rq_get++;
3848b6a361bSBernard Metzler 		} else {
3858b6a361bSBernard Metzler 			if (srq->armed) {
3868b6a361bSBernard Metzler 				/* Test SRQ limit */
3878b6a361bSBernard Metzler 				u32 off = (srq->rq_get + srq->limit) %
3888b6a361bSBernard Metzler 					  srq->num_rqe;
3898b6a361bSBernard Metzler 				struct siw_rqe *rqe2 = &srq->recvq[off];
3908b6a361bSBernard Metzler 
3918b6a361bSBernard Metzler 				if (!(rqe2->flags & SIW_WQE_VALID)) {
39258fb0b56SBernard Metzler 					srq->armed = false;
3938b6a361bSBernard Metzler 					srq_event = true;
3948b6a361bSBernard Metzler 				}
3958b6a361bSBernard Metzler 			}
3968b6a361bSBernard Metzler 			srq->rq_get++;
3978b6a361bSBernard Metzler 		}
3988b6a361bSBernard Metzler 	}
3998b6a361bSBernard Metzler out:
4008b6a361bSBernard Metzler 	if (srq) {
4018b6a361bSBernard Metzler 		spin_unlock_irqrestore(&srq->lock, flags);
4028b6a361bSBernard Metzler 		if (srq_event)
4038b6a361bSBernard Metzler 			siw_srq_event(srq, IB_EVENT_SRQ_LIMIT_REACHED);
4048b6a361bSBernard Metzler 	}
4058b6a361bSBernard Metzler 	return wqe;
4068b6a361bSBernard Metzler }
4078b6a361bSBernard Metzler 
siw_rx_data(struct siw_mem * mem_p,struct siw_rx_stream * srx,unsigned int * pbl_idx,u64 addr,int bytes)40860d2136dSGuoqing Jiang static int siw_rx_data(struct siw_mem *mem_p, struct siw_rx_stream *srx,
40960d2136dSGuoqing Jiang 		       unsigned int *pbl_idx, u64 addr, int bytes)
41060d2136dSGuoqing Jiang {
41160d2136dSGuoqing Jiang 	int rv;
41260d2136dSGuoqing Jiang 
41360d2136dSGuoqing Jiang 	if (mem_p->mem_obj == NULL)
41460d2136dSGuoqing Jiang 		rv = siw_rx_kva(srx, ib_virt_dma_to_ptr(addr), bytes);
41560d2136dSGuoqing Jiang 	else if (!mem_p->is_pbl)
41660d2136dSGuoqing Jiang 		rv = siw_rx_umem(srx, mem_p->umem, addr, bytes);
41760d2136dSGuoqing Jiang 	else
41860d2136dSGuoqing Jiang 		rv = siw_rx_pbl(srx, pbl_idx, mem_p, addr, bytes);
41960d2136dSGuoqing Jiang 	return rv;
42060d2136dSGuoqing Jiang }
42160d2136dSGuoqing Jiang 
4228b6a361bSBernard Metzler /*
4238b6a361bSBernard Metzler  * siw_proc_send:
4248b6a361bSBernard Metzler  *
4258b6a361bSBernard Metzler  * Process one incoming SEND and place data into memory referenced by
4268b6a361bSBernard Metzler  * receive wqe.
4278b6a361bSBernard Metzler  *
4288b6a361bSBernard Metzler  * Function supports partially received sends (suspending/resuming
4298b6a361bSBernard Metzler  * current receive wqe processing)
4308b6a361bSBernard Metzler  *
4318b6a361bSBernard Metzler  * return value:
4328b6a361bSBernard Metzler  *	0:       reached the end of a DDP segment
4338b6a361bSBernard Metzler  *	-EAGAIN: to be called again to finish the DDP segment
4348b6a361bSBernard Metzler  */
siw_proc_send(struct siw_qp * qp)4358b6a361bSBernard Metzler int siw_proc_send(struct siw_qp *qp)
4368b6a361bSBernard Metzler {
4378b6a361bSBernard Metzler 	struct siw_rx_stream *srx = &qp->rx_stream;
4388b6a361bSBernard Metzler 	struct siw_rx_fpdu *frx = &qp->rx_untagged;
4398b6a361bSBernard Metzler 	struct siw_wqe *wqe;
4408b6a361bSBernard Metzler 	u32 data_bytes; /* all data bytes available */
4418b6a361bSBernard Metzler 	u32 rcvd_bytes; /* sum of data bytes rcvd */
4428b6a361bSBernard Metzler 	int rv = 0;
4438b6a361bSBernard Metzler 
4448b6a361bSBernard Metzler 	if (frx->first_ddp_seg) {
4458b6a361bSBernard Metzler 		wqe = siw_rqe_get(qp);
4468b6a361bSBernard Metzler 		if (unlikely(!wqe)) {
4478b6a361bSBernard Metzler 			siw_init_terminate(qp, TERM_ERROR_LAYER_DDP,
4488b6a361bSBernard Metzler 					   DDP_ETYPE_UNTAGGED_BUF,
4498b6a361bSBernard Metzler 					   DDP_ECODE_UT_INVALID_MSN_NOBUF, 0);
4508b6a361bSBernard Metzler 			return -ENOENT;
4518b6a361bSBernard Metzler 		}
4528b6a361bSBernard Metzler 	} else {
4538b6a361bSBernard Metzler 		wqe = rx_wqe(frx);
4548b6a361bSBernard Metzler 	}
4558b6a361bSBernard Metzler 	if (srx->state == SIW_GET_DATA_START) {
4568b6a361bSBernard Metzler 		rv = siw_send_check_ntoh(srx, frx);
4578b6a361bSBernard Metzler 		if (unlikely(rv)) {
4588b6a361bSBernard Metzler 			siw_qp_event(qp, IB_EVENT_QP_FATAL);
4598b6a361bSBernard Metzler 			return rv;
4608b6a361bSBernard Metzler 		}
4618b6a361bSBernard Metzler 		if (!srx->fpdu_part_rem) /* zero length SEND */
4628b6a361bSBernard Metzler 			return 0;
4638b6a361bSBernard Metzler 	}
4648b6a361bSBernard Metzler 	data_bytes = min(srx->fpdu_part_rem, srx->skb_new);
4658b6a361bSBernard Metzler 	rcvd_bytes = 0;
4668b6a361bSBernard Metzler 
4678b6a361bSBernard Metzler 	/* A zero length SEND will skip below loop */
4688b6a361bSBernard Metzler 	while (data_bytes) {
4698b6a361bSBernard Metzler 		struct ib_pd *pd;
4708b6a361bSBernard Metzler 		struct siw_mem **mem, *mem_p;
4718b6a361bSBernard Metzler 		struct siw_sge *sge;
4728b6a361bSBernard Metzler 		u32 sge_bytes; /* data bytes avail for SGE */
4738b6a361bSBernard Metzler 
4748b6a361bSBernard Metzler 		sge = &wqe->rqe.sge[frx->sge_idx];
4758b6a361bSBernard Metzler 
4768b6a361bSBernard Metzler 		if (!sge->length) {
4778b6a361bSBernard Metzler 			/* just skip empty sge's */
4788b6a361bSBernard Metzler 			frx->sge_idx++;
4798b6a361bSBernard Metzler 			frx->sge_off = 0;
4808b6a361bSBernard Metzler 			frx->pbl_idx = 0;
4818b6a361bSBernard Metzler 			continue;
4828b6a361bSBernard Metzler 		}
4838b6a361bSBernard Metzler 		sge_bytes = min(data_bytes, sge->length - frx->sge_off);
4848b6a361bSBernard Metzler 		mem = &wqe->mem[frx->sge_idx];
4858b6a361bSBernard Metzler 
4868b6a361bSBernard Metzler 		/*
4878b6a361bSBernard Metzler 		 * check with QP's PD if no SRQ present, SRQ's PD otherwise
4888b6a361bSBernard Metzler 		 */
4898b6a361bSBernard Metzler 		pd = qp->srq == NULL ? qp->pd : qp->srq->base_srq.pd;
4908b6a361bSBernard Metzler 
4918b6a361bSBernard Metzler 		rv = siw_check_sge(pd, sge, mem, IB_ACCESS_LOCAL_WRITE,
4928b6a361bSBernard Metzler 				   frx->sge_off, sge_bytes);
4938b6a361bSBernard Metzler 		if (unlikely(rv)) {
4948b6a361bSBernard Metzler 			siw_init_terminate(qp, TERM_ERROR_LAYER_DDP,
4958b6a361bSBernard Metzler 					   DDP_ETYPE_CATASTROPHIC,
4968b6a361bSBernard Metzler 					   DDP_ECODE_CATASTROPHIC, 0);
4978b6a361bSBernard Metzler 
4988b6a361bSBernard Metzler 			siw_qp_event(qp, IB_EVENT_QP_ACCESS_ERR);
4998b6a361bSBernard Metzler 			break;
5008b6a361bSBernard Metzler 		}
5018b6a361bSBernard Metzler 		mem_p = *mem;
50260d2136dSGuoqing Jiang 		rv = siw_rx_data(mem_p, srx, &frx->pbl_idx,
5038b6a361bSBernard Metzler 				 sge->laddr + frx->sge_off, sge_bytes);
5048b6a361bSBernard Metzler 		if (unlikely(rv != sge_bytes)) {
5058b6a361bSBernard Metzler 			wqe->processed += rcvd_bytes;
5068b6a361bSBernard Metzler 
5078b6a361bSBernard Metzler 			siw_init_terminate(qp, TERM_ERROR_LAYER_DDP,
5088b6a361bSBernard Metzler 					   DDP_ETYPE_CATASTROPHIC,
5098b6a361bSBernard Metzler 					   DDP_ECODE_CATASTROPHIC, 0);
5108b6a361bSBernard Metzler 			return -EINVAL;
5118b6a361bSBernard Metzler 		}
5128b6a361bSBernard Metzler 		frx->sge_off += rv;
5138b6a361bSBernard Metzler 
5148b6a361bSBernard Metzler 		if (frx->sge_off == sge->length) {
5158b6a361bSBernard Metzler 			frx->sge_idx++;
5168b6a361bSBernard Metzler 			frx->sge_off = 0;
5178b6a361bSBernard Metzler 			frx->pbl_idx = 0;
5188b6a361bSBernard Metzler 		}
5198b6a361bSBernard Metzler 		data_bytes -= rv;
5208b6a361bSBernard Metzler 		rcvd_bytes += rv;
5218b6a361bSBernard Metzler 
5228b6a361bSBernard Metzler 		srx->fpdu_part_rem -= rv;
5238b6a361bSBernard Metzler 		srx->fpdu_part_rcvd += rv;
5248b6a361bSBernard Metzler 	}
5258b6a361bSBernard Metzler 	wqe->processed += rcvd_bytes;
5268b6a361bSBernard Metzler 
5278b6a361bSBernard Metzler 	if (!srx->fpdu_part_rem)
5288b6a361bSBernard Metzler 		return 0;
5298b6a361bSBernard Metzler 
5308b6a361bSBernard Metzler 	return (rv < 0) ? rv : -EAGAIN;
5318b6a361bSBernard Metzler }
5328b6a361bSBernard Metzler 
5338b6a361bSBernard Metzler /*
5348b6a361bSBernard Metzler  * siw_proc_write:
5358b6a361bSBernard Metzler  *
5368b6a361bSBernard Metzler  * Place incoming WRITE after referencing and checking target buffer
5378b6a361bSBernard Metzler 
5388b6a361bSBernard Metzler  * Function supports partially received WRITEs (suspending/resuming
5398b6a361bSBernard Metzler  * current receive processing)
5408b6a361bSBernard Metzler  *
5418b6a361bSBernard Metzler  * return value:
5428b6a361bSBernard Metzler  *	0:       reached the end of a DDP segment
5438b6a361bSBernard Metzler  *	-EAGAIN: to be called again to finish the DDP segment
5448b6a361bSBernard Metzler  */
siw_proc_write(struct siw_qp * qp)5458b6a361bSBernard Metzler int siw_proc_write(struct siw_qp *qp)
5468b6a361bSBernard Metzler {
5478b6a361bSBernard Metzler 	struct siw_rx_stream *srx = &qp->rx_stream;
5488b6a361bSBernard Metzler 	struct siw_rx_fpdu *frx = &qp->rx_tagged;
5498b6a361bSBernard Metzler 	struct siw_mem *mem;
5508b6a361bSBernard Metzler 	int bytes, rv;
5518b6a361bSBernard Metzler 
5528b6a361bSBernard Metzler 	if (srx->state == SIW_GET_DATA_START) {
5538b6a361bSBernard Metzler 		if (!srx->fpdu_part_rem) /* zero length WRITE */
5548b6a361bSBernard Metzler 			return 0;
5558b6a361bSBernard Metzler 
5568b6a361bSBernard Metzler 		rv = siw_write_check_ntoh(srx, frx);
5578b6a361bSBernard Metzler 		if (unlikely(rv)) {
5588b6a361bSBernard Metzler 			siw_qp_event(qp, IB_EVENT_QP_FATAL);
5598b6a361bSBernard Metzler 			return rv;
5608b6a361bSBernard Metzler 		}
5618b6a361bSBernard Metzler 	}
5628b6a361bSBernard Metzler 	bytes = min(srx->fpdu_part_rem, srx->skb_new);
5638b6a361bSBernard Metzler 
5648b6a361bSBernard Metzler 	if (frx->first_ddp_seg) {
5658b6a361bSBernard Metzler 		struct siw_wqe *wqe = rx_wqe(frx);
5668b6a361bSBernard Metzler 
5678b6a361bSBernard Metzler 		rx_mem(frx) = siw_mem_id2obj(qp->sdev, srx->ddp_stag >> 8);
5688b6a361bSBernard Metzler 		if (unlikely(!rx_mem(frx))) {
5698b6a361bSBernard Metzler 			siw_dbg_qp(qp,
5708b6a361bSBernard Metzler 				   "sink stag not found/invalid, stag 0x%08x\n",
5718b6a361bSBernard Metzler 				   srx->ddp_stag);
5728b6a361bSBernard Metzler 
5738b6a361bSBernard Metzler 			siw_init_terminate(qp, TERM_ERROR_LAYER_DDP,
5748b6a361bSBernard Metzler 					   DDP_ETYPE_TAGGED_BUF,
5758b6a361bSBernard Metzler 					   DDP_ECODE_T_INVALID_STAG, 0);
5768b6a361bSBernard Metzler 			return -EINVAL;
5778b6a361bSBernard Metzler 		}
5788b6a361bSBernard Metzler 		wqe->rqe.num_sge = 1;
5798b6a361bSBernard Metzler 		rx_type(wqe) = SIW_OP_WRITE;
5808b6a361bSBernard Metzler 		wqe->wr_status = SIW_WR_INPROGRESS;
5818b6a361bSBernard Metzler 	}
5828b6a361bSBernard Metzler 	mem = rx_mem(frx);
5838b6a361bSBernard Metzler 
5848b6a361bSBernard Metzler 	/*
5858b6a361bSBernard Metzler 	 * Check if application re-registered memory with different
5868b6a361bSBernard Metzler 	 * key field of STag.
5878b6a361bSBernard Metzler 	 */
5888b6a361bSBernard Metzler 	if (unlikely(mem->stag != srx->ddp_stag)) {
5898b6a361bSBernard Metzler 		siw_init_terminate(qp, TERM_ERROR_LAYER_DDP,
5908b6a361bSBernard Metzler 				   DDP_ETYPE_TAGGED_BUF,
5918b6a361bSBernard Metzler 				   DDP_ECODE_T_INVALID_STAG, 0);
5928b6a361bSBernard Metzler 		return -EINVAL;
5938b6a361bSBernard Metzler 	}
5948b6a361bSBernard Metzler 	rv = siw_check_mem(qp->pd, mem, srx->ddp_to + srx->fpdu_part_rcvd,
5958b6a361bSBernard Metzler 			   IB_ACCESS_REMOTE_WRITE, bytes);
5968b6a361bSBernard Metzler 	if (unlikely(rv)) {
5978b6a361bSBernard Metzler 		siw_init_terminate(qp, TERM_ERROR_LAYER_DDP,
5988b6a361bSBernard Metzler 				   DDP_ETYPE_TAGGED_BUF, siw_tagged_error(-rv),
5998b6a361bSBernard Metzler 				   0);
6008b6a361bSBernard Metzler 
6018b6a361bSBernard Metzler 		siw_qp_event(qp, IB_EVENT_QP_ACCESS_ERR);
6028b6a361bSBernard Metzler 
6038b6a361bSBernard Metzler 		return -EINVAL;
6048b6a361bSBernard Metzler 	}
6058b6a361bSBernard Metzler 
60660d2136dSGuoqing Jiang 	rv = siw_rx_data(mem, srx, &frx->pbl_idx,
6078b6a361bSBernard Metzler 			 srx->ddp_to + srx->fpdu_part_rcvd, bytes);
6088b6a361bSBernard Metzler 	if (unlikely(rv != bytes)) {
6098b6a361bSBernard Metzler 		siw_init_terminate(qp, TERM_ERROR_LAYER_DDP,
6108b6a361bSBernard Metzler 				   DDP_ETYPE_CATASTROPHIC,
6118b6a361bSBernard Metzler 				   DDP_ECODE_CATASTROPHIC, 0);
6128b6a361bSBernard Metzler 		return -EINVAL;
6138b6a361bSBernard Metzler 	}
6148b6a361bSBernard Metzler 	srx->fpdu_part_rem -= rv;
6158b6a361bSBernard Metzler 	srx->fpdu_part_rcvd += rv;
6168b6a361bSBernard Metzler 
6178b6a361bSBernard Metzler 	if (!srx->fpdu_part_rem) {
6188b6a361bSBernard Metzler 		srx->ddp_to += srx->fpdu_part_rcvd;
6198b6a361bSBernard Metzler 		return 0;
6208b6a361bSBernard Metzler 	}
6218b6a361bSBernard Metzler 	return -EAGAIN;
6228b6a361bSBernard Metzler }
6238b6a361bSBernard Metzler 
6248b6a361bSBernard Metzler /*
6258b6a361bSBernard Metzler  * Inbound RREQ's cannot carry user data.
6268b6a361bSBernard Metzler  */
siw_proc_rreq(struct siw_qp * qp)6278b6a361bSBernard Metzler int siw_proc_rreq(struct siw_qp *qp)
6288b6a361bSBernard Metzler {
6298b6a361bSBernard Metzler 	struct siw_rx_stream *srx = &qp->rx_stream;
6308b6a361bSBernard Metzler 
6318b6a361bSBernard Metzler 	if (!srx->fpdu_part_rem)
6328b6a361bSBernard Metzler 		return 0;
6338b6a361bSBernard Metzler 
6348b6a361bSBernard Metzler 	pr_warn("siw: [QP %u]: rreq with mpa len %d\n", qp_id(qp),
6358b6a361bSBernard Metzler 		be16_to_cpu(srx->hdr.ctrl.mpa_len));
6368b6a361bSBernard Metzler 
6378b6a361bSBernard Metzler 	return -EPROTO;
6388b6a361bSBernard Metzler }
6398b6a361bSBernard Metzler 
6408b6a361bSBernard Metzler /*
6418b6a361bSBernard Metzler  * siw_init_rresp:
6428b6a361bSBernard Metzler  *
6438b6a361bSBernard Metzler  * Process inbound RDMA READ REQ. Produce a pseudo READ RESPONSE WQE.
6448b6a361bSBernard Metzler  * Put it at the tail of the IRQ, if there is another WQE currently in
6458b6a361bSBernard Metzler  * transmit processing. If not, make it the current WQE to be processed
6468b6a361bSBernard Metzler  * and schedule transmit processing.
6478b6a361bSBernard Metzler  *
6488b6a361bSBernard Metzler  * Can be called from softirq context and from process
6498b6a361bSBernard Metzler  * context (RREAD socket loopback case!)
6508b6a361bSBernard Metzler  *
6518b6a361bSBernard Metzler  * return value:
6528b6a361bSBernard Metzler  *	0:      success,
6538b6a361bSBernard Metzler  *		failure code otherwise
6548b6a361bSBernard Metzler  */
6558b6a361bSBernard Metzler 
siw_init_rresp(struct siw_qp * qp,struct siw_rx_stream * srx)6568b6a361bSBernard Metzler static int siw_init_rresp(struct siw_qp *qp, struct siw_rx_stream *srx)
6578b6a361bSBernard Metzler {
6588b6a361bSBernard Metzler 	struct siw_wqe *tx_work = tx_wqe(qp);
6598b6a361bSBernard Metzler 	struct siw_sqe *resp;
6608b6a361bSBernard Metzler 
6618b6a361bSBernard Metzler 	uint64_t raddr = be64_to_cpu(srx->hdr.rreq.sink_to),
6628b6a361bSBernard Metzler 		 laddr = be64_to_cpu(srx->hdr.rreq.source_to);
6638b6a361bSBernard Metzler 	uint32_t length = be32_to_cpu(srx->hdr.rreq.read_size),
6648b6a361bSBernard Metzler 		 lkey = be32_to_cpu(srx->hdr.rreq.source_stag),
6658b6a361bSBernard Metzler 		 rkey = be32_to_cpu(srx->hdr.rreq.sink_stag),
6668b6a361bSBernard Metzler 		 msn = be32_to_cpu(srx->hdr.rreq.ddp_msn);
6678b6a361bSBernard Metzler 
6688b6a361bSBernard Metzler 	int run_sq = 1, rv = 0;
6698b6a361bSBernard Metzler 	unsigned long flags;
6708b6a361bSBernard Metzler 
6718b6a361bSBernard Metzler 	if (unlikely(msn != srx->ddp_msn[RDMAP_UNTAGGED_QN_RDMA_READ])) {
6728b6a361bSBernard Metzler 		siw_init_terminate(qp, TERM_ERROR_LAYER_DDP,
6738b6a361bSBernard Metzler 				   DDP_ETYPE_UNTAGGED_BUF,
6748b6a361bSBernard Metzler 				   DDP_ECODE_UT_INVALID_MSN_RANGE, 0);
6758b6a361bSBernard Metzler 		return -EPROTO;
6768b6a361bSBernard Metzler 	}
6778b6a361bSBernard Metzler 	spin_lock_irqsave(&qp->sq_lock, flags);
6788b6a361bSBernard Metzler 
679661f3859SBernard Metzler 	if (unlikely(!qp->attrs.irq_size)) {
680661f3859SBernard Metzler 		run_sq = 0;
681661f3859SBernard Metzler 		goto error_irq;
682661f3859SBernard Metzler 	}
6838b6a361bSBernard Metzler 	if (tx_work->wr_status == SIW_WR_IDLE) {
6848b6a361bSBernard Metzler 		/*
6858b6a361bSBernard Metzler 		 * immediately schedule READ response w/o
6868b6a361bSBernard Metzler 		 * consuming IRQ entry: IRQ must be empty.
6878b6a361bSBernard Metzler 		 */
6888b6a361bSBernard Metzler 		tx_work->processed = 0;
6898b6a361bSBernard Metzler 		tx_work->mem[0] = NULL;
6908b6a361bSBernard Metzler 		tx_work->wr_status = SIW_WR_QUEUED;
6918b6a361bSBernard Metzler 		resp = &tx_work->sqe;
6928b6a361bSBernard Metzler 	} else {
6938b6a361bSBernard Metzler 		resp = irq_alloc_free(qp);
6948b6a361bSBernard Metzler 		run_sq = 0;
6958b6a361bSBernard Metzler 	}
6968b6a361bSBernard Metzler 	if (likely(resp)) {
6978b6a361bSBernard Metzler 		resp->opcode = SIW_OP_READ_RESPONSE;
6988b6a361bSBernard Metzler 
6998b6a361bSBernard Metzler 		resp->sge[0].length = length;
7008b6a361bSBernard Metzler 		resp->sge[0].laddr = laddr;
7018b6a361bSBernard Metzler 		resp->sge[0].lkey = lkey;
7028b6a361bSBernard Metzler 
7038b6a361bSBernard Metzler 		/* Keep aside message sequence number for potential
7048b6a361bSBernard Metzler 		 * error reporting during Read Response generation.
7058b6a361bSBernard Metzler 		 */
7068b6a361bSBernard Metzler 		resp->sge[1].length = msn;
7078b6a361bSBernard Metzler 
7088b6a361bSBernard Metzler 		resp->raddr = raddr;
7098b6a361bSBernard Metzler 		resp->rkey = rkey;
7108b6a361bSBernard Metzler 		resp->num_sge = length ? 1 : 0;
7118b6a361bSBernard Metzler 
7128b6a361bSBernard Metzler 		/* RRESP now valid as current TX wqe or placed into IRQ */
7138b6a361bSBernard Metzler 		smp_store_mb(resp->flags, SIW_WQE_VALID);
7148b6a361bSBernard Metzler 	} else {
715661f3859SBernard Metzler error_irq:
716661f3859SBernard Metzler 		pr_warn("siw: [QP %u]: IRQ exceeded or null, size %d\n",
717661f3859SBernard Metzler 			qp_id(qp), qp->attrs.irq_size);
7188b6a361bSBernard Metzler 
7198b6a361bSBernard Metzler 		siw_init_terminate(qp, TERM_ERROR_LAYER_RDMAP,
7208b6a361bSBernard Metzler 				   RDMAP_ETYPE_REMOTE_OPERATION,
7218b6a361bSBernard Metzler 				   RDMAP_ECODE_CATASTROPHIC_STREAM, 0);
7228b6a361bSBernard Metzler 		rv = -EPROTO;
7238b6a361bSBernard Metzler 	}
7248b6a361bSBernard Metzler 
7258b6a361bSBernard Metzler 	spin_unlock_irqrestore(&qp->sq_lock, flags);
7268b6a361bSBernard Metzler 
7278b6a361bSBernard Metzler 	if (run_sq)
7288b6a361bSBernard Metzler 		rv = siw_sq_start(qp);
7298b6a361bSBernard Metzler 
7308b6a361bSBernard Metzler 	return rv;
7318b6a361bSBernard Metzler }
7328b6a361bSBernard Metzler 
7338b6a361bSBernard Metzler /*
7348b6a361bSBernard Metzler  * Only called at start of Read.Resonse processing.
7358b6a361bSBernard Metzler  * Transfer pending Read from tip of ORQ into currrent rx wqe,
7368b6a361bSBernard Metzler  * but keep ORQ entry valid until Read.Response processing done.
7378b6a361bSBernard Metzler  * No Queue locking needed.
7388b6a361bSBernard Metzler  */
siw_orqe_start_rx(struct siw_qp * qp)7398b6a361bSBernard Metzler static int siw_orqe_start_rx(struct siw_qp *qp)
7408b6a361bSBernard Metzler {
7418b6a361bSBernard Metzler 	struct siw_sqe *orqe;
7428b6a361bSBernard Metzler 	struct siw_wqe *wqe = NULL;
7438b6a361bSBernard Metzler 
744661f3859SBernard Metzler 	if (unlikely(!qp->attrs.orq_size))
745661f3859SBernard Metzler 		return -EPROTO;
746661f3859SBernard Metzler 
7478b6a361bSBernard Metzler 	/* make sure ORQ indices are current */
7488b6a361bSBernard Metzler 	smp_mb();
7498b6a361bSBernard Metzler 
7508b6a361bSBernard Metzler 	orqe = orq_get_current(qp);
7518b6a361bSBernard Metzler 	if (READ_ONCE(orqe->flags) & SIW_WQE_VALID) {
7528b6a361bSBernard Metzler 		/* RRESP is a TAGGED RDMAP operation */
7538b6a361bSBernard Metzler 		wqe = rx_wqe(&qp->rx_tagged);
7548b6a361bSBernard Metzler 		wqe->sqe.id = orqe->id;
7558b6a361bSBernard Metzler 		wqe->sqe.opcode = orqe->opcode;
7568b6a361bSBernard Metzler 		wqe->sqe.sge[0].laddr = orqe->sge[0].laddr;
7578b6a361bSBernard Metzler 		wqe->sqe.sge[0].lkey = orqe->sge[0].lkey;
7588b6a361bSBernard Metzler 		wqe->sqe.sge[0].length = orqe->sge[0].length;
7598b6a361bSBernard Metzler 		wqe->sqe.flags = orqe->flags;
7608b6a361bSBernard Metzler 		wqe->sqe.num_sge = 1;
7618b6a361bSBernard Metzler 		wqe->bytes = orqe->sge[0].length;
7628b6a361bSBernard Metzler 		wqe->processed = 0;
7638b6a361bSBernard Metzler 		wqe->mem[0] = NULL;
7648b6a361bSBernard Metzler 		/* make sure WQE is completely written before valid */
7658b6a361bSBernard Metzler 		smp_wmb();
7668b6a361bSBernard Metzler 		wqe->wr_status = SIW_WR_INPROGRESS;
7678b6a361bSBernard Metzler 
7688b6a361bSBernard Metzler 		return 0;
7698b6a361bSBernard Metzler 	}
7708b6a361bSBernard Metzler 	return -EPROTO;
7718b6a361bSBernard Metzler }
7728b6a361bSBernard Metzler 
7738b6a361bSBernard Metzler /*
7748b6a361bSBernard Metzler  * siw_proc_rresp:
7758b6a361bSBernard Metzler  *
7768b6a361bSBernard Metzler  * Place incoming RRESP data into memory referenced by RREQ WQE
7778b6a361bSBernard Metzler  * which is at the tip of the ORQ
7788b6a361bSBernard Metzler  *
7798b6a361bSBernard Metzler  * Function supports partially received RRESP's (suspending/resuming
7808b6a361bSBernard Metzler  * current receive processing)
7818b6a361bSBernard Metzler  */
siw_proc_rresp(struct siw_qp * qp)7828b6a361bSBernard Metzler int siw_proc_rresp(struct siw_qp *qp)
7838b6a361bSBernard Metzler {
7848b6a361bSBernard Metzler 	struct siw_rx_stream *srx = &qp->rx_stream;
7858b6a361bSBernard Metzler 	struct siw_rx_fpdu *frx = &qp->rx_tagged;
7868b6a361bSBernard Metzler 	struct siw_wqe *wqe = rx_wqe(frx);
7878b6a361bSBernard Metzler 	struct siw_mem **mem, *mem_p;
7888b6a361bSBernard Metzler 	struct siw_sge *sge;
7898b6a361bSBernard Metzler 	int bytes, rv;
7908b6a361bSBernard Metzler 
7918b6a361bSBernard Metzler 	if (frx->first_ddp_seg) {
7928b6a361bSBernard Metzler 		if (unlikely(wqe->wr_status != SIW_WR_IDLE)) {
7938b6a361bSBernard Metzler 			pr_warn("siw: [QP %u]: proc RRESP: status %d, op %d\n",
7948b6a361bSBernard Metzler 				qp_id(qp), wqe->wr_status, wqe->sqe.opcode);
7958b6a361bSBernard Metzler 			rv = -EPROTO;
7968b6a361bSBernard Metzler 			goto error_term;
7978b6a361bSBernard Metzler 		}
7988b6a361bSBernard Metzler 		/*
7998b6a361bSBernard Metzler 		 * fetch pending RREQ from orq
8008b6a361bSBernard Metzler 		 */
8018b6a361bSBernard Metzler 		rv = siw_orqe_start_rx(qp);
8028b6a361bSBernard Metzler 		if (rv) {
803661f3859SBernard Metzler 			pr_warn("siw: [QP %u]: ORQ empty, size %d\n",
804661f3859SBernard Metzler 				qp_id(qp), qp->attrs.orq_size);
8058b6a361bSBernard Metzler 			goto error_term;
8068b6a361bSBernard Metzler 		}
8078b6a361bSBernard Metzler 		rv = siw_rresp_check_ntoh(srx, frx);
8088b6a361bSBernard Metzler 		if (unlikely(rv)) {
8098b6a361bSBernard Metzler 			siw_qp_event(qp, IB_EVENT_QP_FATAL);
8108b6a361bSBernard Metzler 			return rv;
8118b6a361bSBernard Metzler 		}
8128b6a361bSBernard Metzler 	} else {
8138b6a361bSBernard Metzler 		if (unlikely(wqe->wr_status != SIW_WR_INPROGRESS)) {
8148b6a361bSBernard Metzler 			pr_warn("siw: [QP %u]: resume RRESP: status %d\n",
8158b6a361bSBernard Metzler 				qp_id(qp), wqe->wr_status);
8168b6a361bSBernard Metzler 			rv = -EPROTO;
8178b6a361bSBernard Metzler 			goto error_term;
8188b6a361bSBernard Metzler 		}
8198b6a361bSBernard Metzler 	}
8208b6a361bSBernard Metzler 	if (!srx->fpdu_part_rem) /* zero length RRESPONSE */
8218b6a361bSBernard Metzler 		return 0;
8228b6a361bSBernard Metzler 
8238b6a361bSBernard Metzler 	sge = wqe->sqe.sge; /* there is only one */
8248b6a361bSBernard Metzler 	mem = &wqe->mem[0];
8258b6a361bSBernard Metzler 
8268b6a361bSBernard Metzler 	if (!(*mem)) {
8278b6a361bSBernard Metzler 		/*
8288b6a361bSBernard Metzler 		 * check target memory which resolves memory on first fragment
8298b6a361bSBernard Metzler 		 */
8308b6a361bSBernard Metzler 		rv = siw_check_sge(qp->pd, sge, mem, IB_ACCESS_LOCAL_WRITE, 0,
8318b6a361bSBernard Metzler 				   wqe->bytes);
8328b6a361bSBernard Metzler 		if (unlikely(rv)) {
8338b6a361bSBernard Metzler 			siw_dbg_qp(qp, "target mem check: %d\n", rv);
8348b6a361bSBernard Metzler 			wqe->wc_status = SIW_WC_LOC_PROT_ERR;
8358b6a361bSBernard Metzler 
8368b6a361bSBernard Metzler 			siw_init_terminate(qp, TERM_ERROR_LAYER_DDP,
8378b6a361bSBernard Metzler 					   DDP_ETYPE_TAGGED_BUF,
8388b6a361bSBernard Metzler 					   siw_tagged_error(-rv), 0);
8398b6a361bSBernard Metzler 
8408b6a361bSBernard Metzler 			siw_qp_event(qp, IB_EVENT_QP_ACCESS_ERR);
8418b6a361bSBernard Metzler 
8428b6a361bSBernard Metzler 			return -EINVAL;
8438b6a361bSBernard Metzler 		}
8448b6a361bSBernard Metzler 	}
8458b6a361bSBernard Metzler 	mem_p = *mem;
8468b6a361bSBernard Metzler 
8478b6a361bSBernard Metzler 	bytes = min(srx->fpdu_part_rem, srx->skb_new);
84860d2136dSGuoqing Jiang 	rv = siw_rx_data(mem_p, srx, &frx->pbl_idx,
8498b6a361bSBernard Metzler 			 sge->laddr + wqe->processed, bytes);
8508b6a361bSBernard Metzler 	if (rv != bytes) {
8518b6a361bSBernard Metzler 		wqe->wc_status = SIW_WC_GENERAL_ERR;
8528b6a361bSBernard Metzler 		rv = -EINVAL;
8538b6a361bSBernard Metzler 		goto error_term;
8548b6a361bSBernard Metzler 	}
8558b6a361bSBernard Metzler 	srx->fpdu_part_rem -= rv;
8568b6a361bSBernard Metzler 	srx->fpdu_part_rcvd += rv;
8578b6a361bSBernard Metzler 	wqe->processed += rv;
8588b6a361bSBernard Metzler 
8598b6a361bSBernard Metzler 	if (!srx->fpdu_part_rem) {
8608b6a361bSBernard Metzler 		srx->ddp_to += srx->fpdu_part_rcvd;
8618b6a361bSBernard Metzler 		return 0;
8628b6a361bSBernard Metzler 	}
8638b6a361bSBernard Metzler 	return -EAGAIN;
8648b6a361bSBernard Metzler 
8658b6a361bSBernard Metzler error_term:
8668b6a361bSBernard Metzler 	siw_init_terminate(qp, TERM_ERROR_LAYER_DDP, DDP_ETYPE_CATASTROPHIC,
8678b6a361bSBernard Metzler 			   DDP_ECODE_CATASTROPHIC, 0);
8688b6a361bSBernard Metzler 	return rv;
8698b6a361bSBernard Metzler }
8708b6a361bSBernard Metzler 
siw_update_skb_rcvd(struct siw_rx_stream * srx,u16 length)871a2b64565SGuoqing Jiang static void siw_update_skb_rcvd(struct siw_rx_stream *srx, u16 length)
872a2b64565SGuoqing Jiang {
873a2b64565SGuoqing Jiang 	srx->skb_offset += length;
874a2b64565SGuoqing Jiang 	srx->skb_new -= length;
875a2b64565SGuoqing Jiang 	srx->skb_copied += length;
876a2b64565SGuoqing Jiang }
877a2b64565SGuoqing Jiang 
siw_proc_terminate(struct siw_qp * qp)8788b6a361bSBernard Metzler int siw_proc_terminate(struct siw_qp *qp)
8798b6a361bSBernard Metzler {
8808b6a361bSBernard Metzler 	struct siw_rx_stream *srx = &qp->rx_stream;
8818b6a361bSBernard Metzler 	struct sk_buff *skb = srx->skb;
8828b6a361bSBernard Metzler 	struct iwarp_terminate *term = &srx->hdr.terminate;
8838b6a361bSBernard Metzler 	union iwarp_hdr term_info;
8848b6a361bSBernard Metzler 	u8 *infop = (u8 *)&term_info;
8858b6a361bSBernard Metzler 	enum rdma_opcode op;
8868b6a361bSBernard Metzler 	u16 to_copy = sizeof(struct iwarp_ctrl);
8878b6a361bSBernard Metzler 
8888b6a361bSBernard Metzler 	pr_warn("siw: got TERMINATE. layer %d, type %d, code %d\n",
8898b6a361bSBernard Metzler 		__rdmap_term_layer(term), __rdmap_term_etype(term),
8908b6a361bSBernard Metzler 		__rdmap_term_ecode(term));
8918b6a361bSBernard Metzler 
8928b6a361bSBernard Metzler 	if (be32_to_cpu(term->ddp_qn) != RDMAP_UNTAGGED_QN_TERMINATE ||
8938b6a361bSBernard Metzler 	    be32_to_cpu(term->ddp_msn) !=
8948b6a361bSBernard Metzler 		    qp->rx_stream.ddp_msn[RDMAP_UNTAGGED_QN_TERMINATE] ||
8958b6a361bSBernard Metzler 	    be32_to_cpu(term->ddp_mo) != 0) {
8968b6a361bSBernard Metzler 		pr_warn("siw: rx bogus TERM [QN x%08x, MSN x%08x, MO x%08x]\n",
8978b6a361bSBernard Metzler 			be32_to_cpu(term->ddp_qn), be32_to_cpu(term->ddp_msn),
8988b6a361bSBernard Metzler 			be32_to_cpu(term->ddp_mo));
8998b6a361bSBernard Metzler 		return -ECONNRESET;
9008b6a361bSBernard Metzler 	}
9018b6a361bSBernard Metzler 	/*
9028b6a361bSBernard Metzler 	 * Receive remaining pieces of TERM if indicated
9038b6a361bSBernard Metzler 	 */
9048b6a361bSBernard Metzler 	if (!term->flag_m)
9058b6a361bSBernard Metzler 		return -ECONNRESET;
9068b6a361bSBernard Metzler 
9078b6a361bSBernard Metzler 	/* Do not take the effort to reassemble a network fragmented
9088b6a361bSBernard Metzler 	 * TERM message
9098b6a361bSBernard Metzler 	 */
9108b6a361bSBernard Metzler 	if (srx->skb_new < sizeof(struct iwarp_ctrl_tagged))
9118b6a361bSBernard Metzler 		return -ECONNRESET;
9128b6a361bSBernard Metzler 
9138b6a361bSBernard Metzler 	memset(infop, 0, sizeof(term_info));
9148b6a361bSBernard Metzler 
9158b6a361bSBernard Metzler 	skb_copy_bits(skb, srx->skb_offset, infop, to_copy);
9168b6a361bSBernard Metzler 
9178b6a361bSBernard Metzler 	op = __rdmap_get_opcode(&term_info.ctrl);
9188b6a361bSBernard Metzler 	if (op >= RDMAP_TERMINATE)
9198b6a361bSBernard Metzler 		goto out;
9208b6a361bSBernard Metzler 
9218b6a361bSBernard Metzler 	infop += to_copy;
922a2b64565SGuoqing Jiang 	siw_update_skb_rcvd(srx, to_copy);
9238b6a361bSBernard Metzler 	srx->fpdu_part_rcvd += to_copy;
9248b6a361bSBernard Metzler 	srx->fpdu_part_rem -= to_copy;
9258b6a361bSBernard Metzler 
9268b6a361bSBernard Metzler 	to_copy = iwarp_pktinfo[op].hdr_len - to_copy;
9278b6a361bSBernard Metzler 
9288b6a361bSBernard Metzler 	/* Again, no network fragmented TERM's */
9298b6a361bSBernard Metzler 	if (to_copy + MPA_CRC_SIZE > srx->skb_new)
9308b6a361bSBernard Metzler 		return -ECONNRESET;
9318b6a361bSBernard Metzler 
9328b6a361bSBernard Metzler 	skb_copy_bits(skb, srx->skb_offset, infop, to_copy);
9338b6a361bSBernard Metzler 
9348b6a361bSBernard Metzler 	if (term->flag_r) {
9358b6a361bSBernard Metzler 		siw_dbg_qp(qp, "TERM reports RDMAP hdr type %u, len %u (%s)\n",
9368b6a361bSBernard Metzler 			   op, be16_to_cpu(term_info.ctrl.mpa_len),
9378b6a361bSBernard Metzler 			   term->flag_m ? "valid" : "invalid");
9388b6a361bSBernard Metzler 	} else if (term->flag_d) {
9398b6a361bSBernard Metzler 		siw_dbg_qp(qp, "TERM reports DDP hdr type %u, len %u (%s)\n",
9408b6a361bSBernard Metzler 			   op, be16_to_cpu(term_info.ctrl.mpa_len),
9418b6a361bSBernard Metzler 			   term->flag_m ? "valid" : "invalid");
9428b6a361bSBernard Metzler 	}
9438b6a361bSBernard Metzler out:
944a2b64565SGuoqing Jiang 	siw_update_skb_rcvd(srx, to_copy);
9458b6a361bSBernard Metzler 	srx->fpdu_part_rcvd += to_copy;
9468b6a361bSBernard Metzler 	srx->fpdu_part_rem -= to_copy;
9478b6a361bSBernard Metzler 
9488b6a361bSBernard Metzler 	return -ECONNRESET;
9498b6a361bSBernard Metzler }
9508b6a361bSBernard Metzler 
siw_get_trailer(struct siw_qp * qp,struct siw_rx_stream * srx)9518b6a361bSBernard Metzler static int siw_get_trailer(struct siw_qp *qp, struct siw_rx_stream *srx)
9528b6a361bSBernard Metzler {
9538b6a361bSBernard Metzler 	struct sk_buff *skb = srx->skb;
95475420985SBernard Metzler 	int avail = min(srx->skb_new, srx->fpdu_part_rem);
9558b6a361bSBernard Metzler 	u8 *tbuf = (u8 *)&srx->trailer.crc - srx->pad;
9568b6a361bSBernard Metzler 	__wsum crc_in, crc_own = 0;
9578b6a361bSBernard Metzler 
9588b6a361bSBernard Metzler 	siw_dbg_qp(qp, "expected %d, available %d, pad %u\n",
9598b6a361bSBernard Metzler 		   srx->fpdu_part_rem, srx->skb_new, srx->pad);
9608b6a361bSBernard Metzler 
96175420985SBernard Metzler 	skb_copy_bits(skb, srx->skb_offset, tbuf, avail);
96275420985SBernard Metzler 
963a2b64565SGuoqing Jiang 	siw_update_skb_rcvd(srx, avail);
96475420985SBernard Metzler 	srx->fpdu_part_rem -= avail;
96575420985SBernard Metzler 
96675420985SBernard Metzler 	if (srx->fpdu_part_rem)
9678b6a361bSBernard Metzler 		return -EAGAIN;
9688b6a361bSBernard Metzler 
969426370c8SEric Biggers 	if (!srx->mpa_crc_enabled)
9708b6a361bSBernard Metzler 		return 0;
9718b6a361bSBernard Metzler 
97275420985SBernard Metzler 	if (srx->pad)
973426370c8SEric Biggers 		siw_crc_update(&srx->mpa_crc, tbuf, srx->pad);
9748b6a361bSBernard Metzler 	/*
9758b6a361bSBernard Metzler 	 * CRC32 is computed, transmitted and received directly in NBO,
9768b6a361bSBernard Metzler 	 * so there's never a reason to convert byte order.
9778b6a361bSBernard Metzler 	 */
978426370c8SEric Biggers 	siw_crc_final(&srx->mpa_crc, (u8 *)&crc_own);
9798b6a361bSBernard Metzler 	crc_in = (__force __wsum)srx->trailer.crc;
9808b6a361bSBernard Metzler 
9818b6a361bSBernard Metzler 	if (unlikely(crc_in != crc_own)) {
9828b6a361bSBernard Metzler 		pr_warn("siw: crc error. in: %08x, own %08x, op %u\n",
9838b6a361bSBernard Metzler 			crc_in, crc_own, qp->rx_stream.rdmap_op);
9848b6a361bSBernard Metzler 
9858b6a361bSBernard Metzler 		siw_init_terminate(qp, TERM_ERROR_LAYER_LLP,
9868b6a361bSBernard Metzler 				   LLP_ETYPE_MPA,
9878b6a361bSBernard Metzler 				   LLP_ECODE_RECEIVED_CRC, 0);
9888b6a361bSBernard Metzler 		return -EINVAL;
9898b6a361bSBernard Metzler 	}
9908b6a361bSBernard Metzler 	return 0;
9918b6a361bSBernard Metzler }
9928b6a361bSBernard Metzler 
9938b6a361bSBernard Metzler #define MIN_DDP_HDR sizeof(struct iwarp_ctrl_tagged)
9948b6a361bSBernard Metzler 
siw_get_hdr(struct siw_rx_stream * srx)9958b6a361bSBernard Metzler static int siw_get_hdr(struct siw_rx_stream *srx)
9968b6a361bSBernard Metzler {
9978b6a361bSBernard Metzler 	struct sk_buff *skb = srx->skb;
9988b6a361bSBernard Metzler 	struct siw_qp *qp = rx_qp(srx);
9998b6a361bSBernard Metzler 	struct iwarp_ctrl *c_hdr = &srx->hdr.ctrl;
10008b6a361bSBernard Metzler 	struct siw_rx_fpdu *frx;
10018b6a361bSBernard Metzler 	u8 opcode;
10028b6a361bSBernard Metzler 	int bytes;
10038b6a361bSBernard Metzler 
10048b6a361bSBernard Metzler 	if (srx->fpdu_part_rcvd < MIN_DDP_HDR) {
10058b6a361bSBernard Metzler 		/*
10068b6a361bSBernard Metzler 		 * copy a mimimum sized (tagged) DDP frame control part
10078b6a361bSBernard Metzler 		 */
10088b6a361bSBernard Metzler 		bytes = min_t(int, srx->skb_new,
10098b6a361bSBernard Metzler 			      MIN_DDP_HDR - srx->fpdu_part_rcvd);
10108b6a361bSBernard Metzler 
10118b6a361bSBernard Metzler 		skb_copy_bits(skb, srx->skb_offset,
10128b6a361bSBernard Metzler 			      (char *)c_hdr + srx->fpdu_part_rcvd, bytes);
10138b6a361bSBernard Metzler 
1014a2b64565SGuoqing Jiang 		siw_update_skb_rcvd(srx, bytes);
10158b6a361bSBernard Metzler 		srx->fpdu_part_rcvd += bytes;
10168b6a361bSBernard Metzler 		if (srx->fpdu_part_rcvd < MIN_DDP_HDR)
10178b6a361bSBernard Metzler 			return -EAGAIN;
10188b6a361bSBernard Metzler 
10198b6a361bSBernard Metzler 		if (unlikely(__ddp_get_version(c_hdr) != DDP_VERSION)) {
10208b6a361bSBernard Metzler 			enum ddp_etype etype;
10218b6a361bSBernard Metzler 			enum ddp_ecode ecode;
10228b6a361bSBernard Metzler 
10238b6a361bSBernard Metzler 			pr_warn("siw: received ddp version unsupported %d\n",
10248b6a361bSBernard Metzler 				__ddp_get_version(c_hdr));
10258b6a361bSBernard Metzler 
10268b6a361bSBernard Metzler 			if (c_hdr->ddp_rdmap_ctrl & DDP_FLAG_TAGGED) {
10278b6a361bSBernard Metzler 				etype = DDP_ETYPE_TAGGED_BUF;
10288b6a361bSBernard Metzler 				ecode = DDP_ECODE_T_VERSION;
10298b6a361bSBernard Metzler 			} else {
10308b6a361bSBernard Metzler 				etype = DDP_ETYPE_UNTAGGED_BUF;
10318b6a361bSBernard Metzler 				ecode = DDP_ECODE_UT_VERSION;
10328b6a361bSBernard Metzler 			}
10338b6a361bSBernard Metzler 			siw_init_terminate(rx_qp(srx), TERM_ERROR_LAYER_DDP,
10348b6a361bSBernard Metzler 					   etype, ecode, 0);
10358b6a361bSBernard Metzler 			return -EINVAL;
10368b6a361bSBernard Metzler 		}
10378b6a361bSBernard Metzler 		if (unlikely(__rdmap_get_version(c_hdr) != RDMAP_VERSION)) {
10388b6a361bSBernard Metzler 			pr_warn("siw: received rdmap version unsupported %d\n",
10398b6a361bSBernard Metzler 				__rdmap_get_version(c_hdr));
10408b6a361bSBernard Metzler 
10418b6a361bSBernard Metzler 			siw_init_terminate(rx_qp(srx), TERM_ERROR_LAYER_RDMAP,
10428b6a361bSBernard Metzler 					   RDMAP_ETYPE_REMOTE_OPERATION,
10438b6a361bSBernard Metzler 					   RDMAP_ECODE_VERSION, 0);
10448b6a361bSBernard Metzler 			return -EINVAL;
10458b6a361bSBernard Metzler 		}
10468b6a361bSBernard Metzler 		opcode = __rdmap_get_opcode(c_hdr);
10478b6a361bSBernard Metzler 
10488b6a361bSBernard Metzler 		if (opcode > RDMAP_TERMINATE) {
10498b6a361bSBernard Metzler 			pr_warn("siw: received unknown packet type %u\n",
10508b6a361bSBernard Metzler 				opcode);
10518b6a361bSBernard Metzler 
10528b6a361bSBernard Metzler 			siw_init_terminate(rx_qp(srx), TERM_ERROR_LAYER_RDMAP,
10538b6a361bSBernard Metzler 					   RDMAP_ETYPE_REMOTE_OPERATION,
10548b6a361bSBernard Metzler 					   RDMAP_ECODE_OPCODE, 0);
10558b6a361bSBernard Metzler 			return -EINVAL;
10568b6a361bSBernard Metzler 		}
10578b6a361bSBernard Metzler 		siw_dbg_qp(rx_qp(srx), "new header, opcode %u\n", opcode);
10588b6a361bSBernard Metzler 	} else {
10598b6a361bSBernard Metzler 		opcode = __rdmap_get_opcode(c_hdr);
10608b6a361bSBernard Metzler 	}
10618b6a361bSBernard Metzler 	set_rx_fpdu_context(qp, opcode);
10628b6a361bSBernard Metzler 	frx = qp->rx_fpdu;
10638b6a361bSBernard Metzler 
10648b6a361bSBernard Metzler 	/*
10658b6a361bSBernard Metzler 	 * Figure out len of current hdr: variable length of
10668b6a361bSBernard Metzler 	 * iwarp hdr may force us to copy hdr information in
10678b6a361bSBernard Metzler 	 * two steps. Only tagged DDP messages are already
10688b6a361bSBernard Metzler 	 * completely received.
10698b6a361bSBernard Metzler 	 */
10708b6a361bSBernard Metzler 	if (iwarp_pktinfo[opcode].hdr_len > sizeof(struct iwarp_ctrl_tagged)) {
107175420985SBernard Metzler 		int hdrlen = iwarp_pktinfo[opcode].hdr_len;
10728b6a361bSBernard Metzler 
107375420985SBernard Metzler 		bytes = min_t(int, hdrlen - MIN_DDP_HDR, srx->skb_new);
10748b6a361bSBernard Metzler 
10758b6a361bSBernard Metzler 		skb_copy_bits(skb, srx->skb_offset,
10768b6a361bSBernard Metzler 			      (char *)c_hdr + srx->fpdu_part_rcvd, bytes);
10778b6a361bSBernard Metzler 
1078a2b64565SGuoqing Jiang 		siw_update_skb_rcvd(srx, bytes);
10798b6a361bSBernard Metzler 		srx->fpdu_part_rcvd += bytes;
108075420985SBernard Metzler 		if (srx->fpdu_part_rcvd < hdrlen)
108175420985SBernard Metzler 			return -EAGAIN;
10828b6a361bSBernard Metzler 	}
10838b6a361bSBernard Metzler 
10848b6a361bSBernard Metzler 	/*
10858b6a361bSBernard Metzler 	 * DDP/RDMAP header receive completed. Check if the current
10868b6a361bSBernard Metzler 	 * DDP segment starts a new RDMAP message or continues a previously
10878b6a361bSBernard Metzler 	 * started RDMAP message.
10888b6a361bSBernard Metzler 	 *
10898b6a361bSBernard Metzler 	 * Alternating reception of DDP segments (or FPDUs) from incomplete
10908b6a361bSBernard Metzler 	 * tagged and untagged RDMAP messages is supported, as long as
10918b6a361bSBernard Metzler 	 * the current tagged or untagged message gets eventually completed
10928b6a361bSBernard Metzler 	 * w/o intersection from another message of the same type
10938b6a361bSBernard Metzler 	 * (tagged/untagged). E.g., a WRITE can get intersected by a SEND,
10948b6a361bSBernard Metzler 	 * but not by a READ RESPONSE etc.
10958b6a361bSBernard Metzler 	 */
1096426370c8SEric Biggers 	if (srx->mpa_crc_enabled) {
10978b6a361bSBernard Metzler 		/*
10988b6a361bSBernard Metzler 		 * Restart CRC computation
10998b6a361bSBernard Metzler 		 */
1100426370c8SEric Biggers 		siw_crc_init(&srx->mpa_crc);
1101426370c8SEric Biggers 		siw_crc_update(&srx->mpa_crc, c_hdr, srx->fpdu_part_rcvd);
11028b6a361bSBernard Metzler 	}
11038b6a361bSBernard Metzler 	if (frx->more_ddp_segs) {
11048b6a361bSBernard Metzler 		frx->first_ddp_seg = 0;
11058b6a361bSBernard Metzler 		if (frx->prev_rdmap_op != opcode) {
11068b6a361bSBernard Metzler 			pr_warn("siw: packet intersection: %u : %u\n",
11078b6a361bSBernard Metzler 				frx->prev_rdmap_op, opcode);
11088b6a361bSBernard Metzler 			/*
11098b6a361bSBernard Metzler 			 * The last inbound RDMA operation of same type
11108b6a361bSBernard Metzler 			 * (tagged or untagged) is left unfinished.
11118b6a361bSBernard Metzler 			 * To complete it in error, make it the current
11128b6a361bSBernard Metzler 			 * operation again, even with the header already
11138b6a361bSBernard Metzler 			 * overwritten. For error handling, only the opcode
11148b6a361bSBernard Metzler 			 * and current rx context are relevant.
11158b6a361bSBernard Metzler 			 */
11168b6a361bSBernard Metzler 			set_rx_fpdu_context(qp, frx->prev_rdmap_op);
11178b6a361bSBernard Metzler 			__rdmap_set_opcode(c_hdr, frx->prev_rdmap_op);
11188b6a361bSBernard Metzler 			return -EPROTO;
11198b6a361bSBernard Metzler 		}
11208b6a361bSBernard Metzler 	} else {
11218b6a361bSBernard Metzler 		frx->prev_rdmap_op = opcode;
11228b6a361bSBernard Metzler 		frx->first_ddp_seg = 1;
11238b6a361bSBernard Metzler 	}
11248b6a361bSBernard Metzler 	frx->more_ddp_segs = c_hdr->ddp_rdmap_ctrl & DDP_FLAG_LAST ? 0 : 1;
11258b6a361bSBernard Metzler 
11268b6a361bSBernard Metzler 	return 0;
11278b6a361bSBernard Metzler }
11288b6a361bSBernard Metzler 
siw_check_tx_fence(struct siw_qp * qp)11298b6a361bSBernard Metzler static int siw_check_tx_fence(struct siw_qp *qp)
11308b6a361bSBernard Metzler {
11318b6a361bSBernard Metzler 	struct siw_wqe *tx_waiting = tx_wqe(qp);
11328b6a361bSBernard Metzler 	struct siw_sqe *rreq;
11338b6a361bSBernard Metzler 	int resume_tx = 0, rv = 0;
11348b6a361bSBernard Metzler 	unsigned long flags;
11358b6a361bSBernard Metzler 
11368b6a361bSBernard Metzler 	spin_lock_irqsave(&qp->orq_lock, flags);
11378b6a361bSBernard Metzler 
11388b6a361bSBernard Metzler 	/* free current orq entry */
1139b43a76f4SBernard Metzler 	rreq = orq_get_current(qp);
11408b6a361bSBernard Metzler 	WRITE_ONCE(rreq->flags, 0);
11418b6a361bSBernard Metzler 
1142b43a76f4SBernard Metzler 	qp->orq_get++;
1143b43a76f4SBernard Metzler 
11448b6a361bSBernard Metzler 	if (qp->tx_ctx.orq_fence) {
11458b6a361bSBernard Metzler 		if (unlikely(tx_waiting->wr_status != SIW_WR_QUEUED)) {
11468b6a361bSBernard Metzler 			pr_warn("siw: [QP %u]: fence resume: bad status %d\n",
11478b6a361bSBernard Metzler 				qp_id(qp), tx_waiting->wr_status);
11488b6a361bSBernard Metzler 			rv = -EPROTO;
11498b6a361bSBernard Metzler 			goto out;
11508b6a361bSBernard Metzler 		}
1151b43a76f4SBernard Metzler 		/* resume SQ processing, if possible */
11528b6a361bSBernard Metzler 		if (tx_waiting->sqe.opcode == SIW_OP_READ ||
11538b6a361bSBernard Metzler 		    tx_waiting->sqe.opcode == SIW_OP_READ_LOCAL_INV) {
1154b43a76f4SBernard Metzler 
1155b43a76f4SBernard Metzler 			/* SQ processing was stopped because of a full ORQ */
1156b43a76f4SBernard Metzler 			rreq = orq_get_free(qp);
11578b6a361bSBernard Metzler 			if (unlikely(!rreq)) {
11588b6a361bSBernard Metzler 				pr_warn("siw: [QP %u]: no ORQE\n", qp_id(qp));
11598b6a361bSBernard Metzler 				rv = -EPROTO;
11608b6a361bSBernard Metzler 				goto out;
11618b6a361bSBernard Metzler 			}
11628b6a361bSBernard Metzler 			siw_read_to_orq(rreq, &tx_waiting->sqe);
11638b6a361bSBernard Metzler 
11648b6a361bSBernard Metzler 			qp->orq_put++;
11658b6a361bSBernard Metzler 			qp->tx_ctx.orq_fence = 0;
11668b6a361bSBernard Metzler 			resume_tx = 1;
11678b6a361bSBernard Metzler 
11688b6a361bSBernard Metzler 		} else if (siw_orq_empty(qp)) {
1169b43a76f4SBernard Metzler 			/*
1170b43a76f4SBernard Metzler 			 * SQ processing was stopped by fenced work request.
1171b43a76f4SBernard Metzler 			 * Resume since all previous Read's are now completed.
1172b43a76f4SBernard Metzler 			 */
11738b6a361bSBernard Metzler 			qp->tx_ctx.orq_fence = 0;
11748b6a361bSBernard Metzler 			resume_tx = 1;
11758b6a361bSBernard Metzler 		}
11768b6a361bSBernard Metzler 	}
11778b6a361bSBernard Metzler out:
11788b6a361bSBernard Metzler 	spin_unlock_irqrestore(&qp->orq_lock, flags);
11798b6a361bSBernard Metzler 
11808b6a361bSBernard Metzler 	if (resume_tx)
11818b6a361bSBernard Metzler 		rv = siw_sq_start(qp);
11828b6a361bSBernard Metzler 
11838b6a361bSBernard Metzler 	return rv;
11848b6a361bSBernard Metzler }
11858b6a361bSBernard Metzler 
11868b6a361bSBernard Metzler /*
11878b6a361bSBernard Metzler  * siw_rdmap_complete()
11888b6a361bSBernard Metzler  *
11898b6a361bSBernard Metzler  * Complete processing of an RDMA message after receiving all
11908b6a361bSBernard Metzler  * DDP segmens or ABort processing after encountering error case.
11918b6a361bSBernard Metzler  *
11928b6a361bSBernard Metzler  *   o SENDs + RRESPs will need for completion,
11938b6a361bSBernard Metzler  *   o RREQs need for  READ RESPONSE initialization
11948b6a361bSBernard Metzler  *   o WRITEs need memory dereferencing
11958b6a361bSBernard Metzler  *
11968b6a361bSBernard Metzler  * TODO: Failed WRITEs need local error to be surfaced.
11978b6a361bSBernard Metzler  */
siw_rdmap_complete(struct siw_qp * qp,int error)11988b6a361bSBernard Metzler static int siw_rdmap_complete(struct siw_qp *qp, int error)
11998b6a361bSBernard Metzler {
12008b6a361bSBernard Metzler 	struct siw_rx_stream *srx = &qp->rx_stream;
12018b6a361bSBernard Metzler 	struct siw_wqe *wqe = rx_wqe(qp->rx_fpdu);
12028b6a361bSBernard Metzler 	enum siw_wc_status wc_status = wqe->wc_status;
12038b6a361bSBernard Metzler 	u8 opcode = __rdmap_get_opcode(&srx->hdr.ctrl);
12048b6a361bSBernard Metzler 	int rv = 0;
12058b6a361bSBernard Metzler 
12068b6a361bSBernard Metzler 	switch (opcode) {
12078b6a361bSBernard Metzler 	case RDMAP_SEND_SE:
12088b6a361bSBernard Metzler 	case RDMAP_SEND_SE_INVAL:
12098b6a361bSBernard Metzler 		wqe->rqe.flags |= SIW_WQE_SOLICITED;
1210df561f66SGustavo A. R. Silva 		fallthrough;
1211cea743f2SGustavo A. R. Silva 
12128b6a361bSBernard Metzler 	case RDMAP_SEND:
12138b6a361bSBernard Metzler 	case RDMAP_SEND_INVAL:
12148b6a361bSBernard Metzler 		if (wqe->wr_status == SIW_WR_IDLE)
12158b6a361bSBernard Metzler 			break;
12168b6a361bSBernard Metzler 
12178b6a361bSBernard Metzler 		srx->ddp_msn[RDMAP_UNTAGGED_QN_SEND]++;
12188b6a361bSBernard Metzler 
12198b6a361bSBernard Metzler 		if (error != 0 && wc_status == SIW_WC_SUCCESS)
12208b6a361bSBernard Metzler 			wc_status = SIW_WC_GENERAL_ERR;
12218b6a361bSBernard Metzler 		/*
12228b6a361bSBernard Metzler 		 * Handle STag invalidation request
12238b6a361bSBernard Metzler 		 */
12248b6a361bSBernard Metzler 		if (wc_status == SIW_WC_SUCCESS &&
12258b6a361bSBernard Metzler 		    (opcode == RDMAP_SEND_INVAL ||
12268b6a361bSBernard Metzler 		     opcode == RDMAP_SEND_SE_INVAL)) {
12278b6a361bSBernard Metzler 			rv = siw_invalidate_stag(qp->pd, srx->inval_stag);
12288b6a361bSBernard Metzler 			if (rv) {
12298b6a361bSBernard Metzler 				siw_init_terminate(
12308b6a361bSBernard Metzler 					qp, TERM_ERROR_LAYER_RDMAP,
12318b6a361bSBernard Metzler 					rv == -EACCES ?
12328b6a361bSBernard Metzler 						RDMAP_ETYPE_REMOTE_PROTECTION :
12338b6a361bSBernard Metzler 						RDMAP_ETYPE_REMOTE_OPERATION,
12348b6a361bSBernard Metzler 					RDMAP_ECODE_CANNOT_INVALIDATE, 0);
12358b6a361bSBernard Metzler 
12368b6a361bSBernard Metzler 				wc_status = SIW_WC_REM_INV_REQ_ERR;
12378b6a361bSBernard Metzler 			}
12388b6a361bSBernard Metzler 			rv = siw_rqe_complete(qp, &wqe->rqe, wqe->processed,
12398b6a361bSBernard Metzler 					      rv ? 0 : srx->inval_stag,
12408b6a361bSBernard Metzler 					      wc_status);
12418b6a361bSBernard Metzler 		} else {
12428b6a361bSBernard Metzler 			rv = siw_rqe_complete(qp, &wqe->rqe, wqe->processed,
12438b6a361bSBernard Metzler 					      0, wc_status);
12448b6a361bSBernard Metzler 		}
12458b6a361bSBernard Metzler 		siw_wqe_put_mem(wqe, SIW_OP_RECEIVE);
12468b6a361bSBernard Metzler 		break;
12478b6a361bSBernard Metzler 
12488b6a361bSBernard Metzler 	case RDMAP_RDMA_READ_RESP:
12498b6a361bSBernard Metzler 		if (wqe->wr_status == SIW_WR_IDLE)
12508b6a361bSBernard Metzler 			break;
12518b6a361bSBernard Metzler 
12528b6a361bSBernard Metzler 		if (error != 0) {
12538b6a361bSBernard Metzler 			if ((srx->state == SIW_GET_HDR &&
12548b6a361bSBernard Metzler 			     qp->rx_fpdu->first_ddp_seg) || error == -ENODATA)
12558b6a361bSBernard Metzler 				/* possible RREQ in ORQ left untouched */
12568b6a361bSBernard Metzler 				break;
12578b6a361bSBernard Metzler 
12588b6a361bSBernard Metzler 			if (wc_status == SIW_WC_SUCCESS)
12598b6a361bSBernard Metzler 				wc_status = SIW_WC_GENERAL_ERR;
126058fb0b56SBernard Metzler 		} else if (rdma_is_kernel_res(&qp->base_qp.res) &&
12618b6a361bSBernard Metzler 			   rx_type(wqe) == SIW_OP_READ_LOCAL_INV) {
12628b6a361bSBernard Metzler 			/*
12638b6a361bSBernard Metzler 			 * Handle any STag invalidation request
12648b6a361bSBernard Metzler 			 */
12658b6a361bSBernard Metzler 			rv = siw_invalidate_stag(qp->pd, wqe->sqe.sge[0].lkey);
12668b6a361bSBernard Metzler 			if (rv) {
12678b6a361bSBernard Metzler 				siw_init_terminate(qp, TERM_ERROR_LAYER_RDMAP,
12688b6a361bSBernard Metzler 						   RDMAP_ETYPE_CATASTROPHIC,
12698b6a361bSBernard Metzler 						   RDMAP_ECODE_UNSPECIFIED, 0);
12708b6a361bSBernard Metzler 
12718b6a361bSBernard Metzler 				if (wc_status == SIW_WC_SUCCESS) {
12728b6a361bSBernard Metzler 					wc_status = SIW_WC_GENERAL_ERR;
12738b6a361bSBernard Metzler 					error = rv;
12748b6a361bSBernard Metzler 				}
12758b6a361bSBernard Metzler 			}
12768b6a361bSBernard Metzler 		}
12778b6a361bSBernard Metzler 		/*
12788b6a361bSBernard Metzler 		 * All errors turn the wqe into signalled.
12798b6a361bSBernard Metzler 		 */
12808b6a361bSBernard Metzler 		if ((wqe->sqe.flags & SIW_WQE_SIGNALLED) || error != 0)
12818b6a361bSBernard Metzler 			rv = siw_sqe_complete(qp, &wqe->sqe, wqe->processed,
12828b6a361bSBernard Metzler 					      wc_status);
12838b6a361bSBernard Metzler 		siw_wqe_put_mem(wqe, SIW_OP_READ);
12848b6a361bSBernard Metzler 
1285661f3859SBernard Metzler 		if (!error) {
12868b6a361bSBernard Metzler 			rv = siw_check_tx_fence(qp);
1287661f3859SBernard Metzler 		} else {
1288661f3859SBernard Metzler 			/* Disable current ORQ element */
1289661f3859SBernard Metzler 			if (qp->attrs.orq_size)
12908b6a361bSBernard Metzler 				WRITE_ONCE(orq_get_current(qp)->flags, 0);
1291661f3859SBernard Metzler 		}
12928b6a361bSBernard Metzler 		break;
12938b6a361bSBernard Metzler 
12948b6a361bSBernard Metzler 	case RDMAP_RDMA_READ_REQ:
12958b6a361bSBernard Metzler 		if (!error) {
12968b6a361bSBernard Metzler 			rv = siw_init_rresp(qp, srx);
12978b6a361bSBernard Metzler 			srx->ddp_msn[RDMAP_UNTAGGED_QN_RDMA_READ]++;
12988b6a361bSBernard Metzler 		}
12998b6a361bSBernard Metzler 		break;
13008b6a361bSBernard Metzler 
13018b6a361bSBernard Metzler 	case RDMAP_RDMA_WRITE:
13028b6a361bSBernard Metzler 		if (wqe->wr_status == SIW_WR_IDLE)
13038b6a361bSBernard Metzler 			break;
13048b6a361bSBernard Metzler 
13058b6a361bSBernard Metzler 		/*
13068b6a361bSBernard Metzler 		 * Free References from memory object if
13078b6a361bSBernard Metzler 		 * attached to receive context (inbound WRITE).
13088b6a361bSBernard Metzler 		 * While a zero-length WRITE is allowed,
13098b6a361bSBernard Metzler 		 * no memory reference got created.
13108b6a361bSBernard Metzler 		 */
13118b6a361bSBernard Metzler 		if (rx_mem(&qp->rx_tagged)) {
13128b6a361bSBernard Metzler 			siw_mem_put(rx_mem(&qp->rx_tagged));
13138b6a361bSBernard Metzler 			rx_mem(&qp->rx_tagged) = NULL;
13148b6a361bSBernard Metzler 		}
13158b6a361bSBernard Metzler 		break;
13168b6a361bSBernard Metzler 
13178b6a361bSBernard Metzler 	default:
13188b6a361bSBernard Metzler 		break;
13198b6a361bSBernard Metzler 	}
13208b6a361bSBernard Metzler 	wqe->wr_status = SIW_WR_IDLE;
13218b6a361bSBernard Metzler 
13228b6a361bSBernard Metzler 	return rv;
13238b6a361bSBernard Metzler }
13248b6a361bSBernard Metzler 
13258b6a361bSBernard Metzler /*
13268b6a361bSBernard Metzler  * siw_tcp_rx_data()
13278b6a361bSBernard Metzler  *
13288b6a361bSBernard Metzler  * Main routine to consume inbound TCP payload
13298b6a361bSBernard Metzler  *
13308b6a361bSBernard Metzler  * @rd_desc:	read descriptor
13318b6a361bSBernard Metzler  * @skb:	socket buffer
13328b6a361bSBernard Metzler  * @off:	offset in skb
13338b6a361bSBernard Metzler  * @len:	skb->len - offset : payload in skb
13348b6a361bSBernard Metzler  */
siw_tcp_rx_data(read_descriptor_t * rd_desc,struct sk_buff * skb,unsigned int off,size_t len)13358b6a361bSBernard Metzler int siw_tcp_rx_data(read_descriptor_t *rd_desc, struct sk_buff *skb,
13368b6a361bSBernard Metzler 		    unsigned int off, size_t len)
13378b6a361bSBernard Metzler {
13388b6a361bSBernard Metzler 	struct siw_qp *qp = rd_desc->arg.data;
13398b6a361bSBernard Metzler 	struct siw_rx_stream *srx = &qp->rx_stream;
13408b6a361bSBernard Metzler 	int rv;
13418b6a361bSBernard Metzler 
13428b6a361bSBernard Metzler 	srx->skb = skb;
13438b6a361bSBernard Metzler 	srx->skb_new = skb->len - off;
13448b6a361bSBernard Metzler 	srx->skb_offset = off;
13458b6a361bSBernard Metzler 	srx->skb_copied = 0;
13468b6a361bSBernard Metzler 
13478b6a361bSBernard Metzler 	siw_dbg_qp(qp, "new data, len %d\n", srx->skb_new);
13488b6a361bSBernard Metzler 
13498b6a361bSBernard Metzler 	while (srx->skb_new) {
13508b6a361bSBernard Metzler 		int run_completion = 1;
13518b6a361bSBernard Metzler 
13528b6a361bSBernard Metzler 		if (unlikely(srx->rx_suspend)) {
13538b6a361bSBernard Metzler 			/* Do not process any more data */
13548b6a361bSBernard Metzler 			srx->skb_copied += srx->skb_new;
13558b6a361bSBernard Metzler 			break;
13568b6a361bSBernard Metzler 		}
13578b6a361bSBernard Metzler 		switch (srx->state) {
13588b6a361bSBernard Metzler 		case SIW_GET_HDR:
13598b6a361bSBernard Metzler 			rv = siw_get_hdr(srx);
13608b6a361bSBernard Metzler 			if (!rv) {
13618b6a361bSBernard Metzler 				srx->fpdu_part_rem =
13628b6a361bSBernard Metzler 					be16_to_cpu(srx->hdr.ctrl.mpa_len) -
13638b6a361bSBernard Metzler 					srx->fpdu_part_rcvd + MPA_HDR_SIZE;
13648b6a361bSBernard Metzler 
13658b6a361bSBernard Metzler 				if (srx->fpdu_part_rem)
13668b6a361bSBernard Metzler 					srx->pad = -srx->fpdu_part_rem & 0x3;
13678b6a361bSBernard Metzler 				else
13688b6a361bSBernard Metzler 					srx->pad = 0;
13698b6a361bSBernard Metzler 
13708b6a361bSBernard Metzler 				srx->state = SIW_GET_DATA_START;
13718b6a361bSBernard Metzler 				srx->fpdu_part_rcvd = 0;
13728b6a361bSBernard Metzler 			}
13738b6a361bSBernard Metzler 			break;
13748b6a361bSBernard Metzler 
13758b6a361bSBernard Metzler 		case SIW_GET_DATA_MORE:
13768b6a361bSBernard Metzler 			/*
13778b6a361bSBernard Metzler 			 * Another data fragment of the same DDP segment.
13788b6a361bSBernard Metzler 			 * Setting first_ddp_seg = 0 avoids repeating
13798b6a361bSBernard Metzler 			 * initializations that shall occur only once per
13808b6a361bSBernard Metzler 			 * DDP segment.
13818b6a361bSBernard Metzler 			 */
13828b6a361bSBernard Metzler 			qp->rx_fpdu->first_ddp_seg = 0;
1383df561f66SGustavo A. R. Silva 			fallthrough;
13848b6a361bSBernard Metzler 
13858b6a361bSBernard Metzler 		case SIW_GET_DATA_START:
13868b6a361bSBernard Metzler 			/*
13878b6a361bSBernard Metzler 			 * Headers will be checked by the opcode-specific
13888b6a361bSBernard Metzler 			 * data receive function below.
13898b6a361bSBernard Metzler 			 */
13908b6a361bSBernard Metzler 			rv = iwarp_pktinfo[qp->rx_stream.rdmap_op].rx_data(qp);
13918b6a361bSBernard Metzler 			if (!rv) {
13928b6a361bSBernard Metzler 				int mpa_len =
13938b6a361bSBernard Metzler 					be16_to_cpu(srx->hdr.ctrl.mpa_len)
13948b6a361bSBernard Metzler 					+ MPA_HDR_SIZE;
13958b6a361bSBernard Metzler 
13968b6a361bSBernard Metzler 				srx->fpdu_part_rem = (-mpa_len & 0x3)
13978b6a361bSBernard Metzler 						      + MPA_CRC_SIZE;
13988b6a361bSBernard Metzler 				srx->fpdu_part_rcvd = 0;
13998b6a361bSBernard Metzler 				srx->state = SIW_GET_TRAILER;
14008b6a361bSBernard Metzler 			} else {
14018b6a361bSBernard Metzler 				if (unlikely(rv == -ECONNRESET))
14028b6a361bSBernard Metzler 					run_completion = 0;
14038b6a361bSBernard Metzler 				else
14048b6a361bSBernard Metzler 					srx->state = SIW_GET_DATA_MORE;
14058b6a361bSBernard Metzler 			}
14068b6a361bSBernard Metzler 			break;
14078b6a361bSBernard Metzler 
14088b6a361bSBernard Metzler 		case SIW_GET_TRAILER:
14098b6a361bSBernard Metzler 			/*
14108b6a361bSBernard Metzler 			 * read CRC + any padding
14118b6a361bSBernard Metzler 			 */
14128b6a361bSBernard Metzler 			rv = siw_get_trailer(qp, srx);
14138b6a361bSBernard Metzler 			if (likely(!rv)) {
14148b6a361bSBernard Metzler 				/*
14158b6a361bSBernard Metzler 				 * FPDU completed.
14168b6a361bSBernard Metzler 				 * complete RDMAP message if last fragment
14178b6a361bSBernard Metzler 				 */
14188b6a361bSBernard Metzler 				srx->state = SIW_GET_HDR;
14198b6a361bSBernard Metzler 				srx->fpdu_part_rcvd = 0;
14208b6a361bSBernard Metzler 
14218b6a361bSBernard Metzler 				if (!(srx->hdr.ctrl.ddp_rdmap_ctrl &
14228b6a361bSBernard Metzler 				      DDP_FLAG_LAST))
14238b6a361bSBernard Metzler 					/* more frags */
14248b6a361bSBernard Metzler 					break;
14258b6a361bSBernard Metzler 
14268b6a361bSBernard Metzler 				rv = siw_rdmap_complete(qp, 0);
14278b6a361bSBernard Metzler 				run_completion = 0;
14288b6a361bSBernard Metzler 			}
14298b6a361bSBernard Metzler 			break;
14308b6a361bSBernard Metzler 
14318b6a361bSBernard Metzler 		default:
14328b6a361bSBernard Metzler 			pr_warn("QP[%u]: RX out of state\n", qp_id(qp));
14338b6a361bSBernard Metzler 			rv = -EPROTO;
14348b6a361bSBernard Metzler 			run_completion = 0;
14358b6a361bSBernard Metzler 		}
14368b6a361bSBernard Metzler 		if (unlikely(rv != 0 && rv != -EAGAIN)) {
14378b6a361bSBernard Metzler 			if ((srx->state > SIW_GET_HDR ||
14388b6a361bSBernard Metzler 			     qp->rx_fpdu->more_ddp_segs) && run_completion)
14398b6a361bSBernard Metzler 				siw_rdmap_complete(qp, rv);
14408b6a361bSBernard Metzler 
14418b6a361bSBernard Metzler 			siw_dbg_qp(qp, "rx error %d, rx state %d\n", rv,
14428b6a361bSBernard Metzler 				   srx->state);
14438b6a361bSBernard Metzler 
14448b6a361bSBernard Metzler 			siw_qp_cm_drop(qp, 1);
14458b6a361bSBernard Metzler 
14468b6a361bSBernard Metzler 			break;
14478b6a361bSBernard Metzler 		}
14488b6a361bSBernard Metzler 		if (rv) {
14498b6a361bSBernard Metzler 			siw_dbg_qp(qp, "fpdu fragment, state %d, missing %d\n",
14508b6a361bSBernard Metzler 				   srx->state, srx->fpdu_part_rem);
14518b6a361bSBernard Metzler 			break;
14528b6a361bSBernard Metzler 		}
14538b6a361bSBernard Metzler 	}
14548b6a361bSBernard Metzler 	return srx->skb_copied;
14558b6a361bSBernard Metzler }
1456