162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci/* Authors: Bernard Metzler <bmt@zurich.ibm.com> */ 462306a36Sopenharmony_ci/* Copyright (c) 2008-2019, IBM Corporation */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/errno.h> 762306a36Sopenharmony_ci#include <linux/types.h> 862306a36Sopenharmony_ci#include <linux/net.h> 962306a36Sopenharmony_ci#include <linux/scatterlist.h> 1062306a36Sopenharmony_ci#include <linux/highmem.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <rdma/iw_cm.h> 1362306a36Sopenharmony_ci#include <rdma/ib_verbs.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "siw.h" 1662306a36Sopenharmony_ci#include "siw_verbs.h" 1762306a36Sopenharmony_ci#include "siw_mem.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* 2062306a36Sopenharmony_ci * siw_rx_umem() 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * Receive data of @len into target referenced by @dest_addr. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * @srx: Receive Context 2562306a36Sopenharmony_ci * @umem: siw representation of target memory 2662306a36Sopenharmony_ci * @dest_addr: user virtual address 2762306a36Sopenharmony_ci * @len: number of bytes to place 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_cistatic int siw_rx_umem(struct siw_rx_stream *srx, struct siw_umem *umem, 3062306a36Sopenharmony_ci u64 dest_addr, int len) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci int copied = 0; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci while (len) { 3562306a36Sopenharmony_ci struct page *p; 3662306a36Sopenharmony_ci int pg_off, bytes, rv; 3762306a36Sopenharmony_ci void *dest; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci p = siw_get_upage(umem, dest_addr); 4062306a36Sopenharmony_ci if (unlikely(!p)) { 4162306a36Sopenharmony_ci pr_warn("siw: %s: [QP %u]: bogus addr: %pK, %pK\n", 4262306a36Sopenharmony_ci __func__, qp_id(rx_qp(srx)), 4362306a36Sopenharmony_ci (void *)(uintptr_t)dest_addr, 4462306a36Sopenharmony_ci (void *)(uintptr_t)umem->fp_addr); 4562306a36Sopenharmony_ci /* siw internal error */ 4662306a36Sopenharmony_ci srx->skb_copied += copied; 4762306a36Sopenharmony_ci srx->skb_new -= copied; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci return -EFAULT; 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci pg_off = dest_addr & ~PAGE_MASK; 5262306a36Sopenharmony_ci bytes = min(len, (int)PAGE_SIZE - pg_off); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci siw_dbg_qp(rx_qp(srx), "page %pK, bytes=%u\n", p, bytes); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci dest = kmap_atomic(p); 5762306a36Sopenharmony_ci rv = skb_copy_bits(srx->skb, srx->skb_offset, dest + pg_off, 5862306a36Sopenharmony_ci bytes); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci if (unlikely(rv)) { 6162306a36Sopenharmony_ci kunmap_atomic(dest); 6262306a36Sopenharmony_ci srx->skb_copied += copied; 6362306a36Sopenharmony_ci srx->skb_new -= copied; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci pr_warn("siw: [QP %u]: %s, len %d, page %p, rv %d\n", 6662306a36Sopenharmony_ci qp_id(rx_qp(srx)), __func__, len, p, rv); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci return -EFAULT; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci if (srx->mpa_crc_hd) { 7162306a36Sopenharmony_ci if (rdma_is_kernel_res(&rx_qp(srx)->base_qp.res)) { 7262306a36Sopenharmony_ci crypto_shash_update(srx->mpa_crc_hd, 7362306a36Sopenharmony_ci (u8 *)(dest + pg_off), bytes); 7462306a36Sopenharmony_ci kunmap_atomic(dest); 7562306a36Sopenharmony_ci } else { 7662306a36Sopenharmony_ci kunmap_atomic(dest); 7762306a36Sopenharmony_ci /* 7862306a36Sopenharmony_ci * Do CRC on original, not target buffer. 7962306a36Sopenharmony_ci * Some user land applications may 8062306a36Sopenharmony_ci * concurrently write the target buffer, 8162306a36Sopenharmony_ci * which would yield a broken CRC. 8262306a36Sopenharmony_ci * Walking the skb twice is very ineffcient. 8362306a36Sopenharmony_ci * Folding the CRC into skb_copy_bits() 8462306a36Sopenharmony_ci * would be much better, but is currently 8562306a36Sopenharmony_ci * not supported. 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_ci siw_crc_skb(srx, bytes); 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci } else { 9062306a36Sopenharmony_ci kunmap_atomic(dest); 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci srx->skb_offset += bytes; 9362306a36Sopenharmony_ci copied += bytes; 9462306a36Sopenharmony_ci len -= bytes; 9562306a36Sopenharmony_ci dest_addr += bytes; 9662306a36Sopenharmony_ci pg_off = 0; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci srx->skb_copied += copied; 9962306a36Sopenharmony_ci srx->skb_new -= copied; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci return copied; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic int siw_rx_kva(struct siw_rx_stream *srx, void *kva, int len) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci int rv; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci siw_dbg_qp(rx_qp(srx), "kva: 0x%pK, len: %u\n", kva, len); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci rv = skb_copy_bits(srx->skb, srx->skb_offset, kva, len); 11162306a36Sopenharmony_ci if (unlikely(rv)) { 11262306a36Sopenharmony_ci pr_warn("siw: [QP %u]: %s, len %d, kva 0x%pK, rv %d\n", 11362306a36Sopenharmony_ci qp_id(rx_qp(srx)), __func__, len, kva, rv); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci return rv; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci if (srx->mpa_crc_hd) 11862306a36Sopenharmony_ci crypto_shash_update(srx->mpa_crc_hd, (u8 *)kva, len); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci srx->skb_offset += len; 12162306a36Sopenharmony_ci srx->skb_copied += len; 12262306a36Sopenharmony_ci srx->skb_new -= len; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci return len; 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic int siw_rx_pbl(struct siw_rx_stream *srx, int *pbl_idx, 12862306a36Sopenharmony_ci struct siw_mem *mem, u64 addr, int len) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct siw_pbl *pbl = mem->pbl; 13162306a36Sopenharmony_ci u64 offset = addr - mem->va; 13262306a36Sopenharmony_ci int copied = 0; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci while (len) { 13562306a36Sopenharmony_ci int bytes; 13662306a36Sopenharmony_ci dma_addr_t buf_addr = 13762306a36Sopenharmony_ci siw_pbl_get_buffer(pbl, offset, &bytes, pbl_idx); 13862306a36Sopenharmony_ci if (!buf_addr) 13962306a36Sopenharmony_ci break; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci bytes = min(bytes, len); 14262306a36Sopenharmony_ci if (siw_rx_kva(srx, ib_virt_dma_to_ptr(buf_addr), bytes) == 14362306a36Sopenharmony_ci bytes) { 14462306a36Sopenharmony_ci copied += bytes; 14562306a36Sopenharmony_ci offset += bytes; 14662306a36Sopenharmony_ci len -= bytes; 14762306a36Sopenharmony_ci } else { 14862306a36Sopenharmony_ci break; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci return copied; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/* 15562306a36Sopenharmony_ci * siw_rresp_check_ntoh() 15662306a36Sopenharmony_ci * 15762306a36Sopenharmony_ci * Check incoming RRESP fragment header against expected 15862306a36Sopenharmony_ci * header values and update expected values for potential next 15962306a36Sopenharmony_ci * fragment. 16062306a36Sopenharmony_ci * 16162306a36Sopenharmony_ci * NOTE: This function must be called only if a RRESP DDP segment 16262306a36Sopenharmony_ci * starts but not for fragmented consecutive pieces of an 16362306a36Sopenharmony_ci * already started DDP segment. 16462306a36Sopenharmony_ci */ 16562306a36Sopenharmony_cistatic int siw_rresp_check_ntoh(struct siw_rx_stream *srx, 16662306a36Sopenharmony_ci struct siw_rx_fpdu *frx) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci struct iwarp_rdma_rresp *rresp = &srx->hdr.rresp; 16962306a36Sopenharmony_ci struct siw_wqe *wqe = &frx->wqe_active; 17062306a36Sopenharmony_ci enum ddp_ecode ecode; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci u32 sink_stag = be32_to_cpu(rresp->sink_stag); 17362306a36Sopenharmony_ci u64 sink_to = be64_to_cpu(rresp->sink_to); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (frx->first_ddp_seg) { 17662306a36Sopenharmony_ci srx->ddp_stag = wqe->sqe.sge[0].lkey; 17762306a36Sopenharmony_ci srx->ddp_to = wqe->sqe.sge[0].laddr; 17862306a36Sopenharmony_ci frx->pbl_idx = 0; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci /* Below checks extend beyond the semantics of DDP, and 18162306a36Sopenharmony_ci * into RDMAP: 18262306a36Sopenharmony_ci * We check if the read response matches exactly the 18362306a36Sopenharmony_ci * read request which was send to the remote peer to 18462306a36Sopenharmony_ci * trigger this read response. RFC5040/5041 do not 18562306a36Sopenharmony_ci * always have a proper error code for the detected 18662306a36Sopenharmony_ci * error cases. We choose 'base or bounds error' for 18762306a36Sopenharmony_ci * cases where the inbound STag is valid, but offset 18862306a36Sopenharmony_ci * or length do not match our response receive state. 18962306a36Sopenharmony_ci */ 19062306a36Sopenharmony_ci if (unlikely(srx->ddp_stag != sink_stag)) { 19162306a36Sopenharmony_ci pr_warn("siw: [QP %u]: rresp stag: %08x != %08x\n", 19262306a36Sopenharmony_ci qp_id(rx_qp(srx)), sink_stag, srx->ddp_stag); 19362306a36Sopenharmony_ci ecode = DDP_ECODE_T_INVALID_STAG; 19462306a36Sopenharmony_ci goto error; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci if (unlikely(srx->ddp_to != sink_to)) { 19762306a36Sopenharmony_ci pr_warn("siw: [QP %u]: rresp off: %016llx != %016llx\n", 19862306a36Sopenharmony_ci qp_id(rx_qp(srx)), (unsigned long long)sink_to, 19962306a36Sopenharmony_ci (unsigned long long)srx->ddp_to); 20062306a36Sopenharmony_ci ecode = DDP_ECODE_T_BASE_BOUNDS; 20162306a36Sopenharmony_ci goto error; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci if (unlikely(!frx->more_ddp_segs && 20462306a36Sopenharmony_ci (wqe->processed + srx->fpdu_part_rem != wqe->bytes))) { 20562306a36Sopenharmony_ci pr_warn("siw: [QP %u]: rresp len: %d != %d\n", 20662306a36Sopenharmony_ci qp_id(rx_qp(srx)), 20762306a36Sopenharmony_ci wqe->processed + srx->fpdu_part_rem, wqe->bytes); 20862306a36Sopenharmony_ci ecode = DDP_ECODE_T_BASE_BOUNDS; 20962306a36Sopenharmony_ci goto error; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci return 0; 21262306a36Sopenharmony_cierror: 21362306a36Sopenharmony_ci siw_init_terminate(rx_qp(srx), TERM_ERROR_LAYER_DDP, 21462306a36Sopenharmony_ci DDP_ETYPE_TAGGED_BUF, ecode, 0); 21562306a36Sopenharmony_ci return -EINVAL; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci/* 21962306a36Sopenharmony_ci * siw_write_check_ntoh() 22062306a36Sopenharmony_ci * 22162306a36Sopenharmony_ci * Check incoming WRITE fragment header against expected 22262306a36Sopenharmony_ci * header values and update expected values for potential next 22362306a36Sopenharmony_ci * fragment 22462306a36Sopenharmony_ci * 22562306a36Sopenharmony_ci * NOTE: This function must be called only if a WRITE DDP segment 22662306a36Sopenharmony_ci * starts but not for fragmented consecutive pieces of an 22762306a36Sopenharmony_ci * already started DDP segment. 22862306a36Sopenharmony_ci */ 22962306a36Sopenharmony_cistatic int siw_write_check_ntoh(struct siw_rx_stream *srx, 23062306a36Sopenharmony_ci struct siw_rx_fpdu *frx) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci struct iwarp_rdma_write *write = &srx->hdr.rwrite; 23362306a36Sopenharmony_ci enum ddp_ecode ecode; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci u32 sink_stag = be32_to_cpu(write->sink_stag); 23662306a36Sopenharmony_ci u64 sink_to = be64_to_cpu(write->sink_to); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if (frx->first_ddp_seg) { 23962306a36Sopenharmony_ci srx->ddp_stag = sink_stag; 24062306a36Sopenharmony_ci srx->ddp_to = sink_to; 24162306a36Sopenharmony_ci frx->pbl_idx = 0; 24262306a36Sopenharmony_ci } else { 24362306a36Sopenharmony_ci if (unlikely(srx->ddp_stag != sink_stag)) { 24462306a36Sopenharmony_ci pr_warn("siw: [QP %u]: write stag: %08x != %08x\n", 24562306a36Sopenharmony_ci qp_id(rx_qp(srx)), sink_stag, 24662306a36Sopenharmony_ci srx->ddp_stag); 24762306a36Sopenharmony_ci ecode = DDP_ECODE_T_INVALID_STAG; 24862306a36Sopenharmony_ci goto error; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci if (unlikely(srx->ddp_to != sink_to)) { 25162306a36Sopenharmony_ci pr_warn("siw: [QP %u]: write off: %016llx != %016llx\n", 25262306a36Sopenharmony_ci qp_id(rx_qp(srx)), 25362306a36Sopenharmony_ci (unsigned long long)sink_to, 25462306a36Sopenharmony_ci (unsigned long long)srx->ddp_to); 25562306a36Sopenharmony_ci ecode = DDP_ECODE_T_BASE_BOUNDS; 25662306a36Sopenharmony_ci goto error; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci return 0; 26062306a36Sopenharmony_cierror: 26162306a36Sopenharmony_ci siw_init_terminate(rx_qp(srx), TERM_ERROR_LAYER_DDP, 26262306a36Sopenharmony_ci DDP_ETYPE_TAGGED_BUF, ecode, 0); 26362306a36Sopenharmony_ci return -EINVAL; 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci/* 26762306a36Sopenharmony_ci * siw_send_check_ntoh() 26862306a36Sopenharmony_ci * 26962306a36Sopenharmony_ci * Check incoming SEND fragment header against expected 27062306a36Sopenharmony_ci * header values and update expected MSN if no next 27162306a36Sopenharmony_ci * fragment expected 27262306a36Sopenharmony_ci * 27362306a36Sopenharmony_ci * NOTE: This function must be called only if a SEND DDP segment 27462306a36Sopenharmony_ci * starts but not for fragmented consecutive pieces of an 27562306a36Sopenharmony_ci * already started DDP segment. 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_cistatic int siw_send_check_ntoh(struct siw_rx_stream *srx, 27862306a36Sopenharmony_ci struct siw_rx_fpdu *frx) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci struct iwarp_send_inv *send = &srx->hdr.send_inv; 28162306a36Sopenharmony_ci struct siw_wqe *wqe = &frx->wqe_active; 28262306a36Sopenharmony_ci enum ddp_ecode ecode; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci u32 ddp_msn = be32_to_cpu(send->ddp_msn); 28562306a36Sopenharmony_ci u32 ddp_mo = be32_to_cpu(send->ddp_mo); 28662306a36Sopenharmony_ci u32 ddp_qn = be32_to_cpu(send->ddp_qn); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (unlikely(ddp_qn != RDMAP_UNTAGGED_QN_SEND)) { 28962306a36Sopenharmony_ci pr_warn("siw: [QP %u]: invalid ddp qn %d for send\n", 29062306a36Sopenharmony_ci qp_id(rx_qp(srx)), ddp_qn); 29162306a36Sopenharmony_ci ecode = DDP_ECODE_UT_INVALID_QN; 29262306a36Sopenharmony_ci goto error; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci if (unlikely(ddp_msn != srx->ddp_msn[RDMAP_UNTAGGED_QN_SEND])) { 29562306a36Sopenharmony_ci pr_warn("siw: [QP %u]: send msn: %u != %u\n", 29662306a36Sopenharmony_ci qp_id(rx_qp(srx)), ddp_msn, 29762306a36Sopenharmony_ci srx->ddp_msn[RDMAP_UNTAGGED_QN_SEND]); 29862306a36Sopenharmony_ci ecode = DDP_ECODE_UT_INVALID_MSN_RANGE; 29962306a36Sopenharmony_ci goto error; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci if (unlikely(ddp_mo != wqe->processed)) { 30262306a36Sopenharmony_ci pr_warn("siw: [QP %u], send mo: %u != %u\n", 30362306a36Sopenharmony_ci qp_id(rx_qp(srx)), ddp_mo, wqe->processed); 30462306a36Sopenharmony_ci ecode = DDP_ECODE_UT_INVALID_MO; 30562306a36Sopenharmony_ci goto error; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci if (frx->first_ddp_seg) { 30862306a36Sopenharmony_ci /* initialize user memory write position */ 30962306a36Sopenharmony_ci frx->sge_idx = 0; 31062306a36Sopenharmony_ci frx->sge_off = 0; 31162306a36Sopenharmony_ci frx->pbl_idx = 0; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci /* only valid for SEND_INV and SEND_SE_INV operations */ 31462306a36Sopenharmony_ci srx->inval_stag = be32_to_cpu(send->inval_stag); 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci if (unlikely(wqe->bytes < wqe->processed + srx->fpdu_part_rem)) { 31762306a36Sopenharmony_ci siw_dbg_qp(rx_qp(srx), "receive space short: %d - %d < %d\n", 31862306a36Sopenharmony_ci wqe->bytes, wqe->processed, srx->fpdu_part_rem); 31962306a36Sopenharmony_ci wqe->wc_status = SIW_WC_LOC_LEN_ERR; 32062306a36Sopenharmony_ci ecode = DDP_ECODE_UT_INVALID_MSN_NOBUF; 32162306a36Sopenharmony_ci goto error; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci return 0; 32462306a36Sopenharmony_cierror: 32562306a36Sopenharmony_ci siw_init_terminate(rx_qp(srx), TERM_ERROR_LAYER_DDP, 32662306a36Sopenharmony_ci DDP_ETYPE_UNTAGGED_BUF, ecode, 0); 32762306a36Sopenharmony_ci return -EINVAL; 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cistatic struct siw_wqe *siw_rqe_get(struct siw_qp *qp) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci struct siw_rqe *rqe; 33362306a36Sopenharmony_ci struct siw_srq *srq; 33462306a36Sopenharmony_ci struct siw_wqe *wqe = NULL; 33562306a36Sopenharmony_ci bool srq_event = false; 33662306a36Sopenharmony_ci unsigned long flags; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci srq = qp->srq; 33962306a36Sopenharmony_ci if (srq) { 34062306a36Sopenharmony_ci spin_lock_irqsave(&srq->lock, flags); 34162306a36Sopenharmony_ci if (unlikely(!srq->num_rqe)) 34262306a36Sopenharmony_ci goto out; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci rqe = &srq->recvq[srq->rq_get % srq->num_rqe]; 34562306a36Sopenharmony_ci } else { 34662306a36Sopenharmony_ci if (unlikely(!qp->recvq)) 34762306a36Sopenharmony_ci goto out; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci rqe = &qp->recvq[qp->rq_get % qp->attrs.rq_size]; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci if (likely(rqe->flags == SIW_WQE_VALID)) { 35262306a36Sopenharmony_ci int num_sge = rqe->num_sge; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (likely(num_sge <= SIW_MAX_SGE)) { 35562306a36Sopenharmony_ci int i = 0; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci wqe = rx_wqe(&qp->rx_untagged); 35862306a36Sopenharmony_ci rx_type(wqe) = SIW_OP_RECEIVE; 35962306a36Sopenharmony_ci wqe->wr_status = SIW_WR_INPROGRESS; 36062306a36Sopenharmony_ci wqe->bytes = 0; 36162306a36Sopenharmony_ci wqe->processed = 0; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci wqe->rqe.id = rqe->id; 36462306a36Sopenharmony_ci wqe->rqe.num_sge = num_sge; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci while (i < num_sge) { 36762306a36Sopenharmony_ci wqe->rqe.sge[i].laddr = rqe->sge[i].laddr; 36862306a36Sopenharmony_ci wqe->rqe.sge[i].lkey = rqe->sge[i].lkey; 36962306a36Sopenharmony_ci wqe->rqe.sge[i].length = rqe->sge[i].length; 37062306a36Sopenharmony_ci wqe->bytes += wqe->rqe.sge[i].length; 37162306a36Sopenharmony_ci wqe->mem[i] = NULL; 37262306a36Sopenharmony_ci i++; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci /* can be re-used by appl */ 37562306a36Sopenharmony_ci smp_store_mb(rqe->flags, 0); 37662306a36Sopenharmony_ci } else { 37762306a36Sopenharmony_ci siw_dbg_qp(qp, "too many sge's: %d\n", rqe->num_sge); 37862306a36Sopenharmony_ci if (srq) 37962306a36Sopenharmony_ci spin_unlock_irqrestore(&srq->lock, flags); 38062306a36Sopenharmony_ci return NULL; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci if (!srq) { 38362306a36Sopenharmony_ci qp->rq_get++; 38462306a36Sopenharmony_ci } else { 38562306a36Sopenharmony_ci if (srq->armed) { 38662306a36Sopenharmony_ci /* Test SRQ limit */ 38762306a36Sopenharmony_ci u32 off = (srq->rq_get + srq->limit) % 38862306a36Sopenharmony_ci srq->num_rqe; 38962306a36Sopenharmony_ci struct siw_rqe *rqe2 = &srq->recvq[off]; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (!(rqe2->flags & SIW_WQE_VALID)) { 39262306a36Sopenharmony_ci srq->armed = false; 39362306a36Sopenharmony_ci srq_event = true; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci srq->rq_get++; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ciout: 40062306a36Sopenharmony_ci if (srq) { 40162306a36Sopenharmony_ci spin_unlock_irqrestore(&srq->lock, flags); 40262306a36Sopenharmony_ci if (srq_event) 40362306a36Sopenharmony_ci siw_srq_event(srq, IB_EVENT_SRQ_LIMIT_REACHED); 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci return wqe; 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci/* 40962306a36Sopenharmony_ci * siw_proc_send: 41062306a36Sopenharmony_ci * 41162306a36Sopenharmony_ci * Process one incoming SEND and place data into memory referenced by 41262306a36Sopenharmony_ci * receive wqe. 41362306a36Sopenharmony_ci * 41462306a36Sopenharmony_ci * Function supports partially received sends (suspending/resuming 41562306a36Sopenharmony_ci * current receive wqe processing) 41662306a36Sopenharmony_ci * 41762306a36Sopenharmony_ci * return value: 41862306a36Sopenharmony_ci * 0: reached the end of a DDP segment 41962306a36Sopenharmony_ci * -EAGAIN: to be called again to finish the DDP segment 42062306a36Sopenharmony_ci */ 42162306a36Sopenharmony_ciint siw_proc_send(struct siw_qp *qp) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci struct siw_rx_stream *srx = &qp->rx_stream; 42462306a36Sopenharmony_ci struct siw_rx_fpdu *frx = &qp->rx_untagged; 42562306a36Sopenharmony_ci struct siw_wqe *wqe; 42662306a36Sopenharmony_ci u32 data_bytes; /* all data bytes available */ 42762306a36Sopenharmony_ci u32 rcvd_bytes; /* sum of data bytes rcvd */ 42862306a36Sopenharmony_ci int rv = 0; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (frx->first_ddp_seg) { 43162306a36Sopenharmony_ci wqe = siw_rqe_get(qp); 43262306a36Sopenharmony_ci if (unlikely(!wqe)) { 43362306a36Sopenharmony_ci siw_init_terminate(qp, TERM_ERROR_LAYER_DDP, 43462306a36Sopenharmony_ci DDP_ETYPE_UNTAGGED_BUF, 43562306a36Sopenharmony_ci DDP_ECODE_UT_INVALID_MSN_NOBUF, 0); 43662306a36Sopenharmony_ci return -ENOENT; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci } else { 43962306a36Sopenharmony_ci wqe = rx_wqe(frx); 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci if (srx->state == SIW_GET_DATA_START) { 44262306a36Sopenharmony_ci rv = siw_send_check_ntoh(srx, frx); 44362306a36Sopenharmony_ci if (unlikely(rv)) { 44462306a36Sopenharmony_ci siw_qp_event(qp, IB_EVENT_QP_FATAL); 44562306a36Sopenharmony_ci return rv; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci if (!srx->fpdu_part_rem) /* zero length SEND */ 44862306a36Sopenharmony_ci return 0; 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci data_bytes = min(srx->fpdu_part_rem, srx->skb_new); 45162306a36Sopenharmony_ci rcvd_bytes = 0; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* A zero length SEND will skip below loop */ 45462306a36Sopenharmony_ci while (data_bytes) { 45562306a36Sopenharmony_ci struct ib_pd *pd; 45662306a36Sopenharmony_ci struct siw_mem **mem, *mem_p; 45762306a36Sopenharmony_ci struct siw_sge *sge; 45862306a36Sopenharmony_ci u32 sge_bytes; /* data bytes avail for SGE */ 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci sge = &wqe->rqe.sge[frx->sge_idx]; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci if (!sge->length) { 46362306a36Sopenharmony_ci /* just skip empty sge's */ 46462306a36Sopenharmony_ci frx->sge_idx++; 46562306a36Sopenharmony_ci frx->sge_off = 0; 46662306a36Sopenharmony_ci frx->pbl_idx = 0; 46762306a36Sopenharmony_ci continue; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci sge_bytes = min(data_bytes, sge->length - frx->sge_off); 47062306a36Sopenharmony_ci mem = &wqe->mem[frx->sge_idx]; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci /* 47362306a36Sopenharmony_ci * check with QP's PD if no SRQ present, SRQ's PD otherwise 47462306a36Sopenharmony_ci */ 47562306a36Sopenharmony_ci pd = qp->srq == NULL ? qp->pd : qp->srq->base_srq.pd; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci rv = siw_check_sge(pd, sge, mem, IB_ACCESS_LOCAL_WRITE, 47862306a36Sopenharmony_ci frx->sge_off, sge_bytes); 47962306a36Sopenharmony_ci if (unlikely(rv)) { 48062306a36Sopenharmony_ci siw_init_terminate(qp, TERM_ERROR_LAYER_DDP, 48162306a36Sopenharmony_ci DDP_ETYPE_CATASTROPHIC, 48262306a36Sopenharmony_ci DDP_ECODE_CATASTROPHIC, 0); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci siw_qp_event(qp, IB_EVENT_QP_ACCESS_ERR); 48562306a36Sopenharmony_ci break; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci mem_p = *mem; 48862306a36Sopenharmony_ci if (mem_p->mem_obj == NULL) 48962306a36Sopenharmony_ci rv = siw_rx_kva(srx, 49062306a36Sopenharmony_ci ib_virt_dma_to_ptr(sge->laddr + frx->sge_off), 49162306a36Sopenharmony_ci sge_bytes); 49262306a36Sopenharmony_ci else if (!mem_p->is_pbl) 49362306a36Sopenharmony_ci rv = siw_rx_umem(srx, mem_p->umem, 49462306a36Sopenharmony_ci sge->laddr + frx->sge_off, sge_bytes); 49562306a36Sopenharmony_ci else 49662306a36Sopenharmony_ci rv = siw_rx_pbl(srx, &frx->pbl_idx, mem_p, 49762306a36Sopenharmony_ci sge->laddr + frx->sge_off, sge_bytes); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci if (unlikely(rv != sge_bytes)) { 50062306a36Sopenharmony_ci wqe->processed += rcvd_bytes; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci siw_init_terminate(qp, TERM_ERROR_LAYER_DDP, 50362306a36Sopenharmony_ci DDP_ETYPE_CATASTROPHIC, 50462306a36Sopenharmony_ci DDP_ECODE_CATASTROPHIC, 0); 50562306a36Sopenharmony_ci return -EINVAL; 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci frx->sge_off += rv; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci if (frx->sge_off == sge->length) { 51062306a36Sopenharmony_ci frx->sge_idx++; 51162306a36Sopenharmony_ci frx->sge_off = 0; 51262306a36Sopenharmony_ci frx->pbl_idx = 0; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci data_bytes -= rv; 51562306a36Sopenharmony_ci rcvd_bytes += rv; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci srx->fpdu_part_rem -= rv; 51862306a36Sopenharmony_ci srx->fpdu_part_rcvd += rv; 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci wqe->processed += rcvd_bytes; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci if (!srx->fpdu_part_rem) 52362306a36Sopenharmony_ci return 0; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci return (rv < 0) ? rv : -EAGAIN; 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci/* 52962306a36Sopenharmony_ci * siw_proc_write: 53062306a36Sopenharmony_ci * 53162306a36Sopenharmony_ci * Place incoming WRITE after referencing and checking target buffer 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci * Function supports partially received WRITEs (suspending/resuming 53462306a36Sopenharmony_ci * current receive processing) 53562306a36Sopenharmony_ci * 53662306a36Sopenharmony_ci * return value: 53762306a36Sopenharmony_ci * 0: reached the end of a DDP segment 53862306a36Sopenharmony_ci * -EAGAIN: to be called again to finish the DDP segment 53962306a36Sopenharmony_ci */ 54062306a36Sopenharmony_ciint siw_proc_write(struct siw_qp *qp) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci struct siw_rx_stream *srx = &qp->rx_stream; 54362306a36Sopenharmony_ci struct siw_rx_fpdu *frx = &qp->rx_tagged; 54462306a36Sopenharmony_ci struct siw_mem *mem; 54562306a36Sopenharmony_ci int bytes, rv; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci if (srx->state == SIW_GET_DATA_START) { 54862306a36Sopenharmony_ci if (!srx->fpdu_part_rem) /* zero length WRITE */ 54962306a36Sopenharmony_ci return 0; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci rv = siw_write_check_ntoh(srx, frx); 55262306a36Sopenharmony_ci if (unlikely(rv)) { 55362306a36Sopenharmony_ci siw_qp_event(qp, IB_EVENT_QP_FATAL); 55462306a36Sopenharmony_ci return rv; 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci bytes = min(srx->fpdu_part_rem, srx->skb_new); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci if (frx->first_ddp_seg) { 56062306a36Sopenharmony_ci struct siw_wqe *wqe = rx_wqe(frx); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci rx_mem(frx) = siw_mem_id2obj(qp->sdev, srx->ddp_stag >> 8); 56362306a36Sopenharmony_ci if (unlikely(!rx_mem(frx))) { 56462306a36Sopenharmony_ci siw_dbg_qp(qp, 56562306a36Sopenharmony_ci "sink stag not found/invalid, stag 0x%08x\n", 56662306a36Sopenharmony_ci srx->ddp_stag); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci siw_init_terminate(qp, TERM_ERROR_LAYER_DDP, 56962306a36Sopenharmony_ci DDP_ETYPE_TAGGED_BUF, 57062306a36Sopenharmony_ci DDP_ECODE_T_INVALID_STAG, 0); 57162306a36Sopenharmony_ci return -EINVAL; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci wqe->rqe.num_sge = 1; 57462306a36Sopenharmony_ci rx_type(wqe) = SIW_OP_WRITE; 57562306a36Sopenharmony_ci wqe->wr_status = SIW_WR_INPROGRESS; 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci mem = rx_mem(frx); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci /* 58062306a36Sopenharmony_ci * Check if application re-registered memory with different 58162306a36Sopenharmony_ci * key field of STag. 58262306a36Sopenharmony_ci */ 58362306a36Sopenharmony_ci if (unlikely(mem->stag != srx->ddp_stag)) { 58462306a36Sopenharmony_ci siw_init_terminate(qp, TERM_ERROR_LAYER_DDP, 58562306a36Sopenharmony_ci DDP_ETYPE_TAGGED_BUF, 58662306a36Sopenharmony_ci DDP_ECODE_T_INVALID_STAG, 0); 58762306a36Sopenharmony_ci return -EINVAL; 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci rv = siw_check_mem(qp->pd, mem, srx->ddp_to + srx->fpdu_part_rcvd, 59062306a36Sopenharmony_ci IB_ACCESS_REMOTE_WRITE, bytes); 59162306a36Sopenharmony_ci if (unlikely(rv)) { 59262306a36Sopenharmony_ci siw_init_terminate(qp, TERM_ERROR_LAYER_DDP, 59362306a36Sopenharmony_ci DDP_ETYPE_TAGGED_BUF, siw_tagged_error(-rv), 59462306a36Sopenharmony_ci 0); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci siw_qp_event(qp, IB_EVENT_QP_ACCESS_ERR); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci return -EINVAL; 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci if (mem->mem_obj == NULL) 60262306a36Sopenharmony_ci rv = siw_rx_kva(srx, 60362306a36Sopenharmony_ci (void *)(uintptr_t)(srx->ddp_to + srx->fpdu_part_rcvd), 60462306a36Sopenharmony_ci bytes); 60562306a36Sopenharmony_ci else if (!mem->is_pbl) 60662306a36Sopenharmony_ci rv = siw_rx_umem(srx, mem->umem, 60762306a36Sopenharmony_ci srx->ddp_to + srx->fpdu_part_rcvd, bytes); 60862306a36Sopenharmony_ci else 60962306a36Sopenharmony_ci rv = siw_rx_pbl(srx, &frx->pbl_idx, mem, 61062306a36Sopenharmony_ci srx->ddp_to + srx->fpdu_part_rcvd, bytes); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci if (unlikely(rv != bytes)) { 61362306a36Sopenharmony_ci siw_init_terminate(qp, TERM_ERROR_LAYER_DDP, 61462306a36Sopenharmony_ci DDP_ETYPE_CATASTROPHIC, 61562306a36Sopenharmony_ci DDP_ECODE_CATASTROPHIC, 0); 61662306a36Sopenharmony_ci return -EINVAL; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci srx->fpdu_part_rem -= rv; 61962306a36Sopenharmony_ci srx->fpdu_part_rcvd += rv; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci if (!srx->fpdu_part_rem) { 62262306a36Sopenharmony_ci srx->ddp_to += srx->fpdu_part_rcvd; 62362306a36Sopenharmony_ci return 0; 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci return -EAGAIN; 62662306a36Sopenharmony_ci} 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci/* 62962306a36Sopenharmony_ci * Inbound RREQ's cannot carry user data. 63062306a36Sopenharmony_ci */ 63162306a36Sopenharmony_ciint siw_proc_rreq(struct siw_qp *qp) 63262306a36Sopenharmony_ci{ 63362306a36Sopenharmony_ci struct siw_rx_stream *srx = &qp->rx_stream; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci if (!srx->fpdu_part_rem) 63662306a36Sopenharmony_ci return 0; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci pr_warn("siw: [QP %u]: rreq with mpa len %d\n", qp_id(qp), 63962306a36Sopenharmony_ci be16_to_cpu(srx->hdr.ctrl.mpa_len)); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci return -EPROTO; 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci/* 64562306a36Sopenharmony_ci * siw_init_rresp: 64662306a36Sopenharmony_ci * 64762306a36Sopenharmony_ci * Process inbound RDMA READ REQ. Produce a pseudo READ RESPONSE WQE. 64862306a36Sopenharmony_ci * Put it at the tail of the IRQ, if there is another WQE currently in 64962306a36Sopenharmony_ci * transmit processing. If not, make it the current WQE to be processed 65062306a36Sopenharmony_ci * and schedule transmit processing. 65162306a36Sopenharmony_ci * 65262306a36Sopenharmony_ci * Can be called from softirq context and from process 65362306a36Sopenharmony_ci * context (RREAD socket loopback case!) 65462306a36Sopenharmony_ci * 65562306a36Sopenharmony_ci * return value: 65662306a36Sopenharmony_ci * 0: success, 65762306a36Sopenharmony_ci * failure code otherwise 65862306a36Sopenharmony_ci */ 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cistatic int siw_init_rresp(struct siw_qp *qp, struct siw_rx_stream *srx) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci struct siw_wqe *tx_work = tx_wqe(qp); 66362306a36Sopenharmony_ci struct siw_sqe *resp; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci uint64_t raddr = be64_to_cpu(srx->hdr.rreq.sink_to), 66662306a36Sopenharmony_ci laddr = be64_to_cpu(srx->hdr.rreq.source_to); 66762306a36Sopenharmony_ci uint32_t length = be32_to_cpu(srx->hdr.rreq.read_size), 66862306a36Sopenharmony_ci lkey = be32_to_cpu(srx->hdr.rreq.source_stag), 66962306a36Sopenharmony_ci rkey = be32_to_cpu(srx->hdr.rreq.sink_stag), 67062306a36Sopenharmony_ci msn = be32_to_cpu(srx->hdr.rreq.ddp_msn); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci int run_sq = 1, rv = 0; 67362306a36Sopenharmony_ci unsigned long flags; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci if (unlikely(msn != srx->ddp_msn[RDMAP_UNTAGGED_QN_RDMA_READ])) { 67662306a36Sopenharmony_ci siw_init_terminate(qp, TERM_ERROR_LAYER_DDP, 67762306a36Sopenharmony_ci DDP_ETYPE_UNTAGGED_BUF, 67862306a36Sopenharmony_ci DDP_ECODE_UT_INVALID_MSN_RANGE, 0); 67962306a36Sopenharmony_ci return -EPROTO; 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci spin_lock_irqsave(&qp->sq_lock, flags); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci if (unlikely(!qp->attrs.irq_size)) { 68462306a36Sopenharmony_ci run_sq = 0; 68562306a36Sopenharmony_ci goto error_irq; 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci if (tx_work->wr_status == SIW_WR_IDLE) { 68862306a36Sopenharmony_ci /* 68962306a36Sopenharmony_ci * immediately schedule READ response w/o 69062306a36Sopenharmony_ci * consuming IRQ entry: IRQ must be empty. 69162306a36Sopenharmony_ci */ 69262306a36Sopenharmony_ci tx_work->processed = 0; 69362306a36Sopenharmony_ci tx_work->mem[0] = NULL; 69462306a36Sopenharmony_ci tx_work->wr_status = SIW_WR_QUEUED; 69562306a36Sopenharmony_ci resp = &tx_work->sqe; 69662306a36Sopenharmony_ci } else { 69762306a36Sopenharmony_ci resp = irq_alloc_free(qp); 69862306a36Sopenharmony_ci run_sq = 0; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci if (likely(resp)) { 70162306a36Sopenharmony_ci resp->opcode = SIW_OP_READ_RESPONSE; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci resp->sge[0].length = length; 70462306a36Sopenharmony_ci resp->sge[0].laddr = laddr; 70562306a36Sopenharmony_ci resp->sge[0].lkey = lkey; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci /* Keep aside message sequence number for potential 70862306a36Sopenharmony_ci * error reporting during Read Response generation. 70962306a36Sopenharmony_ci */ 71062306a36Sopenharmony_ci resp->sge[1].length = msn; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci resp->raddr = raddr; 71362306a36Sopenharmony_ci resp->rkey = rkey; 71462306a36Sopenharmony_ci resp->num_sge = length ? 1 : 0; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci /* RRESP now valid as current TX wqe or placed into IRQ */ 71762306a36Sopenharmony_ci smp_store_mb(resp->flags, SIW_WQE_VALID); 71862306a36Sopenharmony_ci } else { 71962306a36Sopenharmony_cierror_irq: 72062306a36Sopenharmony_ci pr_warn("siw: [QP %u]: IRQ exceeded or null, size %d\n", 72162306a36Sopenharmony_ci qp_id(qp), qp->attrs.irq_size); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci siw_init_terminate(qp, TERM_ERROR_LAYER_RDMAP, 72462306a36Sopenharmony_ci RDMAP_ETYPE_REMOTE_OPERATION, 72562306a36Sopenharmony_ci RDMAP_ECODE_CATASTROPHIC_STREAM, 0); 72662306a36Sopenharmony_ci rv = -EPROTO; 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->sq_lock, flags); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci if (run_sq) 73262306a36Sopenharmony_ci rv = siw_sq_start(qp); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci return rv; 73562306a36Sopenharmony_ci} 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci/* 73862306a36Sopenharmony_ci * Only called at start of Read.Resonse processing. 73962306a36Sopenharmony_ci * Transfer pending Read from tip of ORQ into currrent rx wqe, 74062306a36Sopenharmony_ci * but keep ORQ entry valid until Read.Response processing done. 74162306a36Sopenharmony_ci * No Queue locking needed. 74262306a36Sopenharmony_ci */ 74362306a36Sopenharmony_cistatic int siw_orqe_start_rx(struct siw_qp *qp) 74462306a36Sopenharmony_ci{ 74562306a36Sopenharmony_ci struct siw_sqe *orqe; 74662306a36Sopenharmony_ci struct siw_wqe *wqe = NULL; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci if (unlikely(!qp->attrs.orq_size)) 74962306a36Sopenharmony_ci return -EPROTO; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci /* make sure ORQ indices are current */ 75262306a36Sopenharmony_ci smp_mb(); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci orqe = orq_get_current(qp); 75562306a36Sopenharmony_ci if (READ_ONCE(orqe->flags) & SIW_WQE_VALID) { 75662306a36Sopenharmony_ci /* RRESP is a TAGGED RDMAP operation */ 75762306a36Sopenharmony_ci wqe = rx_wqe(&qp->rx_tagged); 75862306a36Sopenharmony_ci wqe->sqe.id = orqe->id; 75962306a36Sopenharmony_ci wqe->sqe.opcode = orqe->opcode; 76062306a36Sopenharmony_ci wqe->sqe.sge[0].laddr = orqe->sge[0].laddr; 76162306a36Sopenharmony_ci wqe->sqe.sge[0].lkey = orqe->sge[0].lkey; 76262306a36Sopenharmony_ci wqe->sqe.sge[0].length = orqe->sge[0].length; 76362306a36Sopenharmony_ci wqe->sqe.flags = orqe->flags; 76462306a36Sopenharmony_ci wqe->sqe.num_sge = 1; 76562306a36Sopenharmony_ci wqe->bytes = orqe->sge[0].length; 76662306a36Sopenharmony_ci wqe->processed = 0; 76762306a36Sopenharmony_ci wqe->mem[0] = NULL; 76862306a36Sopenharmony_ci /* make sure WQE is completely written before valid */ 76962306a36Sopenharmony_ci smp_wmb(); 77062306a36Sopenharmony_ci wqe->wr_status = SIW_WR_INPROGRESS; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci return 0; 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci return -EPROTO; 77562306a36Sopenharmony_ci} 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci/* 77862306a36Sopenharmony_ci * siw_proc_rresp: 77962306a36Sopenharmony_ci * 78062306a36Sopenharmony_ci * Place incoming RRESP data into memory referenced by RREQ WQE 78162306a36Sopenharmony_ci * which is at the tip of the ORQ 78262306a36Sopenharmony_ci * 78362306a36Sopenharmony_ci * Function supports partially received RRESP's (suspending/resuming 78462306a36Sopenharmony_ci * current receive processing) 78562306a36Sopenharmony_ci */ 78662306a36Sopenharmony_ciint siw_proc_rresp(struct siw_qp *qp) 78762306a36Sopenharmony_ci{ 78862306a36Sopenharmony_ci struct siw_rx_stream *srx = &qp->rx_stream; 78962306a36Sopenharmony_ci struct siw_rx_fpdu *frx = &qp->rx_tagged; 79062306a36Sopenharmony_ci struct siw_wqe *wqe = rx_wqe(frx); 79162306a36Sopenharmony_ci struct siw_mem **mem, *mem_p; 79262306a36Sopenharmony_ci struct siw_sge *sge; 79362306a36Sopenharmony_ci int bytes, rv; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci if (frx->first_ddp_seg) { 79662306a36Sopenharmony_ci if (unlikely(wqe->wr_status != SIW_WR_IDLE)) { 79762306a36Sopenharmony_ci pr_warn("siw: [QP %u]: proc RRESP: status %d, op %d\n", 79862306a36Sopenharmony_ci qp_id(qp), wqe->wr_status, wqe->sqe.opcode); 79962306a36Sopenharmony_ci rv = -EPROTO; 80062306a36Sopenharmony_ci goto error_term; 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci /* 80362306a36Sopenharmony_ci * fetch pending RREQ from orq 80462306a36Sopenharmony_ci */ 80562306a36Sopenharmony_ci rv = siw_orqe_start_rx(qp); 80662306a36Sopenharmony_ci if (rv) { 80762306a36Sopenharmony_ci pr_warn("siw: [QP %u]: ORQ empty, size %d\n", 80862306a36Sopenharmony_ci qp_id(qp), qp->attrs.orq_size); 80962306a36Sopenharmony_ci goto error_term; 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci rv = siw_rresp_check_ntoh(srx, frx); 81262306a36Sopenharmony_ci if (unlikely(rv)) { 81362306a36Sopenharmony_ci siw_qp_event(qp, IB_EVENT_QP_FATAL); 81462306a36Sopenharmony_ci return rv; 81562306a36Sopenharmony_ci } 81662306a36Sopenharmony_ci } else { 81762306a36Sopenharmony_ci if (unlikely(wqe->wr_status != SIW_WR_INPROGRESS)) { 81862306a36Sopenharmony_ci pr_warn("siw: [QP %u]: resume RRESP: status %d\n", 81962306a36Sopenharmony_ci qp_id(qp), wqe->wr_status); 82062306a36Sopenharmony_ci rv = -EPROTO; 82162306a36Sopenharmony_ci goto error_term; 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci if (!srx->fpdu_part_rem) /* zero length RRESPONSE */ 82562306a36Sopenharmony_ci return 0; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci sge = wqe->sqe.sge; /* there is only one */ 82862306a36Sopenharmony_ci mem = &wqe->mem[0]; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci if (!(*mem)) { 83162306a36Sopenharmony_ci /* 83262306a36Sopenharmony_ci * check target memory which resolves memory on first fragment 83362306a36Sopenharmony_ci */ 83462306a36Sopenharmony_ci rv = siw_check_sge(qp->pd, sge, mem, IB_ACCESS_LOCAL_WRITE, 0, 83562306a36Sopenharmony_ci wqe->bytes); 83662306a36Sopenharmony_ci if (unlikely(rv)) { 83762306a36Sopenharmony_ci siw_dbg_qp(qp, "target mem check: %d\n", rv); 83862306a36Sopenharmony_ci wqe->wc_status = SIW_WC_LOC_PROT_ERR; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci siw_init_terminate(qp, TERM_ERROR_LAYER_DDP, 84162306a36Sopenharmony_ci DDP_ETYPE_TAGGED_BUF, 84262306a36Sopenharmony_ci siw_tagged_error(-rv), 0); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci siw_qp_event(qp, IB_EVENT_QP_ACCESS_ERR); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci return -EINVAL; 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci } 84962306a36Sopenharmony_ci mem_p = *mem; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci bytes = min(srx->fpdu_part_rem, srx->skb_new); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci if (mem_p->mem_obj == NULL) 85462306a36Sopenharmony_ci rv = siw_rx_kva(srx, 85562306a36Sopenharmony_ci ib_virt_dma_to_ptr(sge->laddr + wqe->processed), 85662306a36Sopenharmony_ci bytes); 85762306a36Sopenharmony_ci else if (!mem_p->is_pbl) 85862306a36Sopenharmony_ci rv = siw_rx_umem(srx, mem_p->umem, sge->laddr + wqe->processed, 85962306a36Sopenharmony_ci bytes); 86062306a36Sopenharmony_ci else 86162306a36Sopenharmony_ci rv = siw_rx_pbl(srx, &frx->pbl_idx, mem_p, 86262306a36Sopenharmony_ci sge->laddr + wqe->processed, bytes); 86362306a36Sopenharmony_ci if (rv != bytes) { 86462306a36Sopenharmony_ci wqe->wc_status = SIW_WC_GENERAL_ERR; 86562306a36Sopenharmony_ci rv = -EINVAL; 86662306a36Sopenharmony_ci goto error_term; 86762306a36Sopenharmony_ci } 86862306a36Sopenharmony_ci srx->fpdu_part_rem -= rv; 86962306a36Sopenharmony_ci srx->fpdu_part_rcvd += rv; 87062306a36Sopenharmony_ci wqe->processed += rv; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci if (!srx->fpdu_part_rem) { 87362306a36Sopenharmony_ci srx->ddp_to += srx->fpdu_part_rcvd; 87462306a36Sopenharmony_ci return 0; 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci return -EAGAIN; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_cierror_term: 87962306a36Sopenharmony_ci siw_init_terminate(qp, TERM_ERROR_LAYER_DDP, DDP_ETYPE_CATASTROPHIC, 88062306a36Sopenharmony_ci DDP_ECODE_CATASTROPHIC, 0); 88162306a36Sopenharmony_ci return rv; 88262306a36Sopenharmony_ci} 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ciint siw_proc_terminate(struct siw_qp *qp) 88562306a36Sopenharmony_ci{ 88662306a36Sopenharmony_ci struct siw_rx_stream *srx = &qp->rx_stream; 88762306a36Sopenharmony_ci struct sk_buff *skb = srx->skb; 88862306a36Sopenharmony_ci struct iwarp_terminate *term = &srx->hdr.terminate; 88962306a36Sopenharmony_ci union iwarp_hdr term_info; 89062306a36Sopenharmony_ci u8 *infop = (u8 *)&term_info; 89162306a36Sopenharmony_ci enum rdma_opcode op; 89262306a36Sopenharmony_ci u16 to_copy = sizeof(struct iwarp_ctrl); 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci pr_warn("siw: got TERMINATE. layer %d, type %d, code %d\n", 89562306a36Sopenharmony_ci __rdmap_term_layer(term), __rdmap_term_etype(term), 89662306a36Sopenharmony_ci __rdmap_term_ecode(term)); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci if (be32_to_cpu(term->ddp_qn) != RDMAP_UNTAGGED_QN_TERMINATE || 89962306a36Sopenharmony_ci be32_to_cpu(term->ddp_msn) != 90062306a36Sopenharmony_ci qp->rx_stream.ddp_msn[RDMAP_UNTAGGED_QN_TERMINATE] || 90162306a36Sopenharmony_ci be32_to_cpu(term->ddp_mo) != 0) { 90262306a36Sopenharmony_ci pr_warn("siw: rx bogus TERM [QN x%08x, MSN x%08x, MO x%08x]\n", 90362306a36Sopenharmony_ci be32_to_cpu(term->ddp_qn), be32_to_cpu(term->ddp_msn), 90462306a36Sopenharmony_ci be32_to_cpu(term->ddp_mo)); 90562306a36Sopenharmony_ci return -ECONNRESET; 90662306a36Sopenharmony_ci } 90762306a36Sopenharmony_ci /* 90862306a36Sopenharmony_ci * Receive remaining pieces of TERM if indicated 90962306a36Sopenharmony_ci */ 91062306a36Sopenharmony_ci if (!term->flag_m) 91162306a36Sopenharmony_ci return -ECONNRESET; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci /* Do not take the effort to reassemble a network fragmented 91462306a36Sopenharmony_ci * TERM message 91562306a36Sopenharmony_ci */ 91662306a36Sopenharmony_ci if (srx->skb_new < sizeof(struct iwarp_ctrl_tagged)) 91762306a36Sopenharmony_ci return -ECONNRESET; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci memset(infop, 0, sizeof(term_info)); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci skb_copy_bits(skb, srx->skb_offset, infop, to_copy); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci op = __rdmap_get_opcode(&term_info.ctrl); 92462306a36Sopenharmony_ci if (op >= RDMAP_TERMINATE) 92562306a36Sopenharmony_ci goto out; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci infop += to_copy; 92862306a36Sopenharmony_ci srx->skb_offset += to_copy; 92962306a36Sopenharmony_ci srx->skb_new -= to_copy; 93062306a36Sopenharmony_ci srx->skb_copied += to_copy; 93162306a36Sopenharmony_ci srx->fpdu_part_rcvd += to_copy; 93262306a36Sopenharmony_ci srx->fpdu_part_rem -= to_copy; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci to_copy = iwarp_pktinfo[op].hdr_len - to_copy; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci /* Again, no network fragmented TERM's */ 93762306a36Sopenharmony_ci if (to_copy + MPA_CRC_SIZE > srx->skb_new) 93862306a36Sopenharmony_ci return -ECONNRESET; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci skb_copy_bits(skb, srx->skb_offset, infop, to_copy); 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci if (term->flag_r) { 94362306a36Sopenharmony_ci siw_dbg_qp(qp, "TERM reports RDMAP hdr type %u, len %u (%s)\n", 94462306a36Sopenharmony_ci op, be16_to_cpu(term_info.ctrl.mpa_len), 94562306a36Sopenharmony_ci term->flag_m ? "valid" : "invalid"); 94662306a36Sopenharmony_ci } else if (term->flag_d) { 94762306a36Sopenharmony_ci siw_dbg_qp(qp, "TERM reports DDP hdr type %u, len %u (%s)\n", 94862306a36Sopenharmony_ci op, be16_to_cpu(term_info.ctrl.mpa_len), 94962306a36Sopenharmony_ci term->flag_m ? "valid" : "invalid"); 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ciout: 95262306a36Sopenharmony_ci srx->skb_new -= to_copy; 95362306a36Sopenharmony_ci srx->skb_offset += to_copy; 95462306a36Sopenharmony_ci srx->skb_copied += to_copy; 95562306a36Sopenharmony_ci srx->fpdu_part_rcvd += to_copy; 95662306a36Sopenharmony_ci srx->fpdu_part_rem -= to_copy; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci return -ECONNRESET; 95962306a36Sopenharmony_ci} 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_cistatic int siw_get_trailer(struct siw_qp *qp, struct siw_rx_stream *srx) 96262306a36Sopenharmony_ci{ 96362306a36Sopenharmony_ci struct sk_buff *skb = srx->skb; 96462306a36Sopenharmony_ci int avail = min(srx->skb_new, srx->fpdu_part_rem); 96562306a36Sopenharmony_ci u8 *tbuf = (u8 *)&srx->trailer.crc - srx->pad; 96662306a36Sopenharmony_ci __wsum crc_in, crc_own = 0; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci siw_dbg_qp(qp, "expected %d, available %d, pad %u\n", 96962306a36Sopenharmony_ci srx->fpdu_part_rem, srx->skb_new, srx->pad); 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci skb_copy_bits(skb, srx->skb_offset, tbuf, avail); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci srx->skb_new -= avail; 97462306a36Sopenharmony_ci srx->skb_offset += avail; 97562306a36Sopenharmony_ci srx->skb_copied += avail; 97662306a36Sopenharmony_ci srx->fpdu_part_rem -= avail; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci if (srx->fpdu_part_rem) 97962306a36Sopenharmony_ci return -EAGAIN; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci if (!srx->mpa_crc_hd) 98262306a36Sopenharmony_ci return 0; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci if (srx->pad) 98562306a36Sopenharmony_ci crypto_shash_update(srx->mpa_crc_hd, tbuf, srx->pad); 98662306a36Sopenharmony_ci /* 98762306a36Sopenharmony_ci * CRC32 is computed, transmitted and received directly in NBO, 98862306a36Sopenharmony_ci * so there's never a reason to convert byte order. 98962306a36Sopenharmony_ci */ 99062306a36Sopenharmony_ci crypto_shash_final(srx->mpa_crc_hd, (u8 *)&crc_own); 99162306a36Sopenharmony_ci crc_in = (__force __wsum)srx->trailer.crc; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci if (unlikely(crc_in != crc_own)) { 99462306a36Sopenharmony_ci pr_warn("siw: crc error. in: %08x, own %08x, op %u\n", 99562306a36Sopenharmony_ci crc_in, crc_own, qp->rx_stream.rdmap_op); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci siw_init_terminate(qp, TERM_ERROR_LAYER_LLP, 99862306a36Sopenharmony_ci LLP_ETYPE_MPA, 99962306a36Sopenharmony_ci LLP_ECODE_RECEIVED_CRC, 0); 100062306a36Sopenharmony_ci return -EINVAL; 100162306a36Sopenharmony_ci } 100262306a36Sopenharmony_ci return 0; 100362306a36Sopenharmony_ci} 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci#define MIN_DDP_HDR sizeof(struct iwarp_ctrl_tagged) 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_cistatic int siw_get_hdr(struct siw_rx_stream *srx) 100862306a36Sopenharmony_ci{ 100962306a36Sopenharmony_ci struct sk_buff *skb = srx->skb; 101062306a36Sopenharmony_ci struct siw_qp *qp = rx_qp(srx); 101162306a36Sopenharmony_ci struct iwarp_ctrl *c_hdr = &srx->hdr.ctrl; 101262306a36Sopenharmony_ci struct siw_rx_fpdu *frx; 101362306a36Sopenharmony_ci u8 opcode; 101462306a36Sopenharmony_ci int bytes; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci if (srx->fpdu_part_rcvd < MIN_DDP_HDR) { 101762306a36Sopenharmony_ci /* 101862306a36Sopenharmony_ci * copy a mimimum sized (tagged) DDP frame control part 101962306a36Sopenharmony_ci */ 102062306a36Sopenharmony_ci bytes = min_t(int, srx->skb_new, 102162306a36Sopenharmony_ci MIN_DDP_HDR - srx->fpdu_part_rcvd); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci skb_copy_bits(skb, srx->skb_offset, 102462306a36Sopenharmony_ci (char *)c_hdr + srx->fpdu_part_rcvd, bytes); 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci srx->fpdu_part_rcvd += bytes; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci srx->skb_new -= bytes; 102962306a36Sopenharmony_ci srx->skb_offset += bytes; 103062306a36Sopenharmony_ci srx->skb_copied += bytes; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci if (srx->fpdu_part_rcvd < MIN_DDP_HDR) 103362306a36Sopenharmony_ci return -EAGAIN; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci if (unlikely(__ddp_get_version(c_hdr) != DDP_VERSION)) { 103662306a36Sopenharmony_ci enum ddp_etype etype; 103762306a36Sopenharmony_ci enum ddp_ecode ecode; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci pr_warn("siw: received ddp version unsupported %d\n", 104062306a36Sopenharmony_ci __ddp_get_version(c_hdr)); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci if (c_hdr->ddp_rdmap_ctrl & DDP_FLAG_TAGGED) { 104362306a36Sopenharmony_ci etype = DDP_ETYPE_TAGGED_BUF; 104462306a36Sopenharmony_ci ecode = DDP_ECODE_T_VERSION; 104562306a36Sopenharmony_ci } else { 104662306a36Sopenharmony_ci etype = DDP_ETYPE_UNTAGGED_BUF; 104762306a36Sopenharmony_ci ecode = DDP_ECODE_UT_VERSION; 104862306a36Sopenharmony_ci } 104962306a36Sopenharmony_ci siw_init_terminate(rx_qp(srx), TERM_ERROR_LAYER_DDP, 105062306a36Sopenharmony_ci etype, ecode, 0); 105162306a36Sopenharmony_ci return -EINVAL; 105262306a36Sopenharmony_ci } 105362306a36Sopenharmony_ci if (unlikely(__rdmap_get_version(c_hdr) != RDMAP_VERSION)) { 105462306a36Sopenharmony_ci pr_warn("siw: received rdmap version unsupported %d\n", 105562306a36Sopenharmony_ci __rdmap_get_version(c_hdr)); 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci siw_init_terminate(rx_qp(srx), TERM_ERROR_LAYER_RDMAP, 105862306a36Sopenharmony_ci RDMAP_ETYPE_REMOTE_OPERATION, 105962306a36Sopenharmony_ci RDMAP_ECODE_VERSION, 0); 106062306a36Sopenharmony_ci return -EINVAL; 106162306a36Sopenharmony_ci } 106262306a36Sopenharmony_ci opcode = __rdmap_get_opcode(c_hdr); 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci if (opcode > RDMAP_TERMINATE) { 106562306a36Sopenharmony_ci pr_warn("siw: received unknown packet type %u\n", 106662306a36Sopenharmony_ci opcode); 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci siw_init_terminate(rx_qp(srx), TERM_ERROR_LAYER_RDMAP, 106962306a36Sopenharmony_ci RDMAP_ETYPE_REMOTE_OPERATION, 107062306a36Sopenharmony_ci RDMAP_ECODE_OPCODE, 0); 107162306a36Sopenharmony_ci return -EINVAL; 107262306a36Sopenharmony_ci } 107362306a36Sopenharmony_ci siw_dbg_qp(rx_qp(srx), "new header, opcode %u\n", opcode); 107462306a36Sopenharmony_ci } else { 107562306a36Sopenharmony_ci opcode = __rdmap_get_opcode(c_hdr); 107662306a36Sopenharmony_ci } 107762306a36Sopenharmony_ci set_rx_fpdu_context(qp, opcode); 107862306a36Sopenharmony_ci frx = qp->rx_fpdu; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci /* 108162306a36Sopenharmony_ci * Figure out len of current hdr: variable length of 108262306a36Sopenharmony_ci * iwarp hdr may force us to copy hdr information in 108362306a36Sopenharmony_ci * two steps. Only tagged DDP messages are already 108462306a36Sopenharmony_ci * completely received. 108562306a36Sopenharmony_ci */ 108662306a36Sopenharmony_ci if (iwarp_pktinfo[opcode].hdr_len > sizeof(struct iwarp_ctrl_tagged)) { 108762306a36Sopenharmony_ci int hdrlen = iwarp_pktinfo[opcode].hdr_len; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci bytes = min_t(int, hdrlen - MIN_DDP_HDR, srx->skb_new); 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci skb_copy_bits(skb, srx->skb_offset, 109262306a36Sopenharmony_ci (char *)c_hdr + srx->fpdu_part_rcvd, bytes); 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci srx->fpdu_part_rcvd += bytes; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci srx->skb_new -= bytes; 109762306a36Sopenharmony_ci srx->skb_offset += bytes; 109862306a36Sopenharmony_ci srx->skb_copied += bytes; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci if (srx->fpdu_part_rcvd < hdrlen) 110162306a36Sopenharmony_ci return -EAGAIN; 110262306a36Sopenharmony_ci } 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci /* 110562306a36Sopenharmony_ci * DDP/RDMAP header receive completed. Check if the current 110662306a36Sopenharmony_ci * DDP segment starts a new RDMAP message or continues a previously 110762306a36Sopenharmony_ci * started RDMAP message. 110862306a36Sopenharmony_ci * 110962306a36Sopenharmony_ci * Alternating reception of DDP segments (or FPDUs) from incomplete 111062306a36Sopenharmony_ci * tagged and untagged RDMAP messages is supported, as long as 111162306a36Sopenharmony_ci * the current tagged or untagged message gets eventually completed 111262306a36Sopenharmony_ci * w/o intersection from another message of the same type 111362306a36Sopenharmony_ci * (tagged/untagged). E.g., a WRITE can get intersected by a SEND, 111462306a36Sopenharmony_ci * but not by a READ RESPONSE etc. 111562306a36Sopenharmony_ci */ 111662306a36Sopenharmony_ci if (srx->mpa_crc_hd) { 111762306a36Sopenharmony_ci /* 111862306a36Sopenharmony_ci * Restart CRC computation 111962306a36Sopenharmony_ci */ 112062306a36Sopenharmony_ci crypto_shash_init(srx->mpa_crc_hd); 112162306a36Sopenharmony_ci crypto_shash_update(srx->mpa_crc_hd, (u8 *)c_hdr, 112262306a36Sopenharmony_ci srx->fpdu_part_rcvd); 112362306a36Sopenharmony_ci } 112462306a36Sopenharmony_ci if (frx->more_ddp_segs) { 112562306a36Sopenharmony_ci frx->first_ddp_seg = 0; 112662306a36Sopenharmony_ci if (frx->prev_rdmap_op != opcode) { 112762306a36Sopenharmony_ci pr_warn("siw: packet intersection: %u : %u\n", 112862306a36Sopenharmony_ci frx->prev_rdmap_op, opcode); 112962306a36Sopenharmony_ci /* 113062306a36Sopenharmony_ci * The last inbound RDMA operation of same type 113162306a36Sopenharmony_ci * (tagged or untagged) is left unfinished. 113262306a36Sopenharmony_ci * To complete it in error, make it the current 113362306a36Sopenharmony_ci * operation again, even with the header already 113462306a36Sopenharmony_ci * overwritten. For error handling, only the opcode 113562306a36Sopenharmony_ci * and current rx context are relevant. 113662306a36Sopenharmony_ci */ 113762306a36Sopenharmony_ci set_rx_fpdu_context(qp, frx->prev_rdmap_op); 113862306a36Sopenharmony_ci __rdmap_set_opcode(c_hdr, frx->prev_rdmap_op); 113962306a36Sopenharmony_ci return -EPROTO; 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci } else { 114262306a36Sopenharmony_ci frx->prev_rdmap_op = opcode; 114362306a36Sopenharmony_ci frx->first_ddp_seg = 1; 114462306a36Sopenharmony_ci } 114562306a36Sopenharmony_ci frx->more_ddp_segs = c_hdr->ddp_rdmap_ctrl & DDP_FLAG_LAST ? 0 : 1; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci return 0; 114862306a36Sopenharmony_ci} 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_cistatic int siw_check_tx_fence(struct siw_qp *qp) 115162306a36Sopenharmony_ci{ 115262306a36Sopenharmony_ci struct siw_wqe *tx_waiting = tx_wqe(qp); 115362306a36Sopenharmony_ci struct siw_sqe *rreq; 115462306a36Sopenharmony_ci int resume_tx = 0, rv = 0; 115562306a36Sopenharmony_ci unsigned long flags; 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci spin_lock_irqsave(&qp->orq_lock, flags); 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci /* free current orq entry */ 116062306a36Sopenharmony_ci rreq = orq_get_current(qp); 116162306a36Sopenharmony_ci WRITE_ONCE(rreq->flags, 0); 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci qp->orq_get++; 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci if (qp->tx_ctx.orq_fence) { 116662306a36Sopenharmony_ci if (unlikely(tx_waiting->wr_status != SIW_WR_QUEUED)) { 116762306a36Sopenharmony_ci pr_warn("siw: [QP %u]: fence resume: bad status %d\n", 116862306a36Sopenharmony_ci qp_id(qp), tx_waiting->wr_status); 116962306a36Sopenharmony_ci rv = -EPROTO; 117062306a36Sopenharmony_ci goto out; 117162306a36Sopenharmony_ci } 117262306a36Sopenharmony_ci /* resume SQ processing, if possible */ 117362306a36Sopenharmony_ci if (tx_waiting->sqe.opcode == SIW_OP_READ || 117462306a36Sopenharmony_ci tx_waiting->sqe.opcode == SIW_OP_READ_LOCAL_INV) { 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci /* SQ processing was stopped because of a full ORQ */ 117762306a36Sopenharmony_ci rreq = orq_get_free(qp); 117862306a36Sopenharmony_ci if (unlikely(!rreq)) { 117962306a36Sopenharmony_ci pr_warn("siw: [QP %u]: no ORQE\n", qp_id(qp)); 118062306a36Sopenharmony_ci rv = -EPROTO; 118162306a36Sopenharmony_ci goto out; 118262306a36Sopenharmony_ci } 118362306a36Sopenharmony_ci siw_read_to_orq(rreq, &tx_waiting->sqe); 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci qp->orq_put++; 118662306a36Sopenharmony_ci qp->tx_ctx.orq_fence = 0; 118762306a36Sopenharmony_ci resume_tx = 1; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci } else if (siw_orq_empty(qp)) { 119062306a36Sopenharmony_ci /* 119162306a36Sopenharmony_ci * SQ processing was stopped by fenced work request. 119262306a36Sopenharmony_ci * Resume since all previous Read's are now completed. 119362306a36Sopenharmony_ci */ 119462306a36Sopenharmony_ci qp->tx_ctx.orq_fence = 0; 119562306a36Sopenharmony_ci resume_tx = 1; 119662306a36Sopenharmony_ci } 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ciout: 119962306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->orq_lock, flags); 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci if (resume_tx) 120262306a36Sopenharmony_ci rv = siw_sq_start(qp); 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci return rv; 120562306a36Sopenharmony_ci} 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci/* 120862306a36Sopenharmony_ci * siw_rdmap_complete() 120962306a36Sopenharmony_ci * 121062306a36Sopenharmony_ci * Complete processing of an RDMA message after receiving all 121162306a36Sopenharmony_ci * DDP segmens or ABort processing after encountering error case. 121262306a36Sopenharmony_ci * 121362306a36Sopenharmony_ci * o SENDs + RRESPs will need for completion, 121462306a36Sopenharmony_ci * o RREQs need for READ RESPONSE initialization 121562306a36Sopenharmony_ci * o WRITEs need memory dereferencing 121662306a36Sopenharmony_ci * 121762306a36Sopenharmony_ci * TODO: Failed WRITEs need local error to be surfaced. 121862306a36Sopenharmony_ci */ 121962306a36Sopenharmony_cistatic int siw_rdmap_complete(struct siw_qp *qp, int error) 122062306a36Sopenharmony_ci{ 122162306a36Sopenharmony_ci struct siw_rx_stream *srx = &qp->rx_stream; 122262306a36Sopenharmony_ci struct siw_wqe *wqe = rx_wqe(qp->rx_fpdu); 122362306a36Sopenharmony_ci enum siw_wc_status wc_status = wqe->wc_status; 122462306a36Sopenharmony_ci u8 opcode = __rdmap_get_opcode(&srx->hdr.ctrl); 122562306a36Sopenharmony_ci int rv = 0; 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci switch (opcode) { 122862306a36Sopenharmony_ci case RDMAP_SEND_SE: 122962306a36Sopenharmony_ci case RDMAP_SEND_SE_INVAL: 123062306a36Sopenharmony_ci wqe->rqe.flags |= SIW_WQE_SOLICITED; 123162306a36Sopenharmony_ci fallthrough; 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci case RDMAP_SEND: 123462306a36Sopenharmony_ci case RDMAP_SEND_INVAL: 123562306a36Sopenharmony_ci if (wqe->wr_status == SIW_WR_IDLE) 123662306a36Sopenharmony_ci break; 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci srx->ddp_msn[RDMAP_UNTAGGED_QN_SEND]++; 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci if (error != 0 && wc_status == SIW_WC_SUCCESS) 124162306a36Sopenharmony_ci wc_status = SIW_WC_GENERAL_ERR; 124262306a36Sopenharmony_ci /* 124362306a36Sopenharmony_ci * Handle STag invalidation request 124462306a36Sopenharmony_ci */ 124562306a36Sopenharmony_ci if (wc_status == SIW_WC_SUCCESS && 124662306a36Sopenharmony_ci (opcode == RDMAP_SEND_INVAL || 124762306a36Sopenharmony_ci opcode == RDMAP_SEND_SE_INVAL)) { 124862306a36Sopenharmony_ci rv = siw_invalidate_stag(qp->pd, srx->inval_stag); 124962306a36Sopenharmony_ci if (rv) { 125062306a36Sopenharmony_ci siw_init_terminate( 125162306a36Sopenharmony_ci qp, TERM_ERROR_LAYER_RDMAP, 125262306a36Sopenharmony_ci rv == -EACCES ? 125362306a36Sopenharmony_ci RDMAP_ETYPE_REMOTE_PROTECTION : 125462306a36Sopenharmony_ci RDMAP_ETYPE_REMOTE_OPERATION, 125562306a36Sopenharmony_ci RDMAP_ECODE_CANNOT_INVALIDATE, 0); 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci wc_status = SIW_WC_REM_INV_REQ_ERR; 125862306a36Sopenharmony_ci } 125962306a36Sopenharmony_ci rv = siw_rqe_complete(qp, &wqe->rqe, wqe->processed, 126062306a36Sopenharmony_ci rv ? 0 : srx->inval_stag, 126162306a36Sopenharmony_ci wc_status); 126262306a36Sopenharmony_ci } else { 126362306a36Sopenharmony_ci rv = siw_rqe_complete(qp, &wqe->rqe, wqe->processed, 126462306a36Sopenharmony_ci 0, wc_status); 126562306a36Sopenharmony_ci } 126662306a36Sopenharmony_ci siw_wqe_put_mem(wqe, SIW_OP_RECEIVE); 126762306a36Sopenharmony_ci break; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci case RDMAP_RDMA_READ_RESP: 127062306a36Sopenharmony_ci if (wqe->wr_status == SIW_WR_IDLE) 127162306a36Sopenharmony_ci break; 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci if (error != 0) { 127462306a36Sopenharmony_ci if ((srx->state == SIW_GET_HDR && 127562306a36Sopenharmony_ci qp->rx_fpdu->first_ddp_seg) || error == -ENODATA) 127662306a36Sopenharmony_ci /* possible RREQ in ORQ left untouched */ 127762306a36Sopenharmony_ci break; 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci if (wc_status == SIW_WC_SUCCESS) 128062306a36Sopenharmony_ci wc_status = SIW_WC_GENERAL_ERR; 128162306a36Sopenharmony_ci } else if (rdma_is_kernel_res(&qp->base_qp.res) && 128262306a36Sopenharmony_ci rx_type(wqe) == SIW_OP_READ_LOCAL_INV) { 128362306a36Sopenharmony_ci /* 128462306a36Sopenharmony_ci * Handle any STag invalidation request 128562306a36Sopenharmony_ci */ 128662306a36Sopenharmony_ci rv = siw_invalidate_stag(qp->pd, wqe->sqe.sge[0].lkey); 128762306a36Sopenharmony_ci if (rv) { 128862306a36Sopenharmony_ci siw_init_terminate(qp, TERM_ERROR_LAYER_RDMAP, 128962306a36Sopenharmony_ci RDMAP_ETYPE_CATASTROPHIC, 129062306a36Sopenharmony_ci RDMAP_ECODE_UNSPECIFIED, 0); 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci if (wc_status == SIW_WC_SUCCESS) { 129362306a36Sopenharmony_ci wc_status = SIW_WC_GENERAL_ERR; 129462306a36Sopenharmony_ci error = rv; 129562306a36Sopenharmony_ci } 129662306a36Sopenharmony_ci } 129762306a36Sopenharmony_ci } 129862306a36Sopenharmony_ci /* 129962306a36Sopenharmony_ci * All errors turn the wqe into signalled. 130062306a36Sopenharmony_ci */ 130162306a36Sopenharmony_ci if ((wqe->sqe.flags & SIW_WQE_SIGNALLED) || error != 0) 130262306a36Sopenharmony_ci rv = siw_sqe_complete(qp, &wqe->sqe, wqe->processed, 130362306a36Sopenharmony_ci wc_status); 130462306a36Sopenharmony_ci siw_wqe_put_mem(wqe, SIW_OP_READ); 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci if (!error) { 130762306a36Sopenharmony_ci rv = siw_check_tx_fence(qp); 130862306a36Sopenharmony_ci } else { 130962306a36Sopenharmony_ci /* Disable current ORQ element */ 131062306a36Sopenharmony_ci if (qp->attrs.orq_size) 131162306a36Sopenharmony_ci WRITE_ONCE(orq_get_current(qp)->flags, 0); 131262306a36Sopenharmony_ci } 131362306a36Sopenharmony_ci break; 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci case RDMAP_RDMA_READ_REQ: 131662306a36Sopenharmony_ci if (!error) { 131762306a36Sopenharmony_ci rv = siw_init_rresp(qp, srx); 131862306a36Sopenharmony_ci srx->ddp_msn[RDMAP_UNTAGGED_QN_RDMA_READ]++; 131962306a36Sopenharmony_ci } 132062306a36Sopenharmony_ci break; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci case RDMAP_RDMA_WRITE: 132362306a36Sopenharmony_ci if (wqe->wr_status == SIW_WR_IDLE) 132462306a36Sopenharmony_ci break; 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci /* 132762306a36Sopenharmony_ci * Free References from memory object if 132862306a36Sopenharmony_ci * attached to receive context (inbound WRITE). 132962306a36Sopenharmony_ci * While a zero-length WRITE is allowed, 133062306a36Sopenharmony_ci * no memory reference got created. 133162306a36Sopenharmony_ci */ 133262306a36Sopenharmony_ci if (rx_mem(&qp->rx_tagged)) { 133362306a36Sopenharmony_ci siw_mem_put(rx_mem(&qp->rx_tagged)); 133462306a36Sopenharmony_ci rx_mem(&qp->rx_tagged) = NULL; 133562306a36Sopenharmony_ci } 133662306a36Sopenharmony_ci break; 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci default: 133962306a36Sopenharmony_ci break; 134062306a36Sopenharmony_ci } 134162306a36Sopenharmony_ci wqe->wr_status = SIW_WR_IDLE; 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci return rv; 134462306a36Sopenharmony_ci} 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci/* 134762306a36Sopenharmony_ci * siw_tcp_rx_data() 134862306a36Sopenharmony_ci * 134962306a36Sopenharmony_ci * Main routine to consume inbound TCP payload 135062306a36Sopenharmony_ci * 135162306a36Sopenharmony_ci * @rd_desc: read descriptor 135262306a36Sopenharmony_ci * @skb: socket buffer 135362306a36Sopenharmony_ci * @off: offset in skb 135462306a36Sopenharmony_ci * @len: skb->len - offset : payload in skb 135562306a36Sopenharmony_ci */ 135662306a36Sopenharmony_ciint siw_tcp_rx_data(read_descriptor_t *rd_desc, struct sk_buff *skb, 135762306a36Sopenharmony_ci unsigned int off, size_t len) 135862306a36Sopenharmony_ci{ 135962306a36Sopenharmony_ci struct siw_qp *qp = rd_desc->arg.data; 136062306a36Sopenharmony_ci struct siw_rx_stream *srx = &qp->rx_stream; 136162306a36Sopenharmony_ci int rv; 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci srx->skb = skb; 136462306a36Sopenharmony_ci srx->skb_new = skb->len - off; 136562306a36Sopenharmony_ci srx->skb_offset = off; 136662306a36Sopenharmony_ci srx->skb_copied = 0; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci siw_dbg_qp(qp, "new data, len %d\n", srx->skb_new); 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci while (srx->skb_new) { 137162306a36Sopenharmony_ci int run_completion = 1; 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci if (unlikely(srx->rx_suspend)) { 137462306a36Sopenharmony_ci /* Do not process any more data */ 137562306a36Sopenharmony_ci srx->skb_copied += srx->skb_new; 137662306a36Sopenharmony_ci break; 137762306a36Sopenharmony_ci } 137862306a36Sopenharmony_ci switch (srx->state) { 137962306a36Sopenharmony_ci case SIW_GET_HDR: 138062306a36Sopenharmony_ci rv = siw_get_hdr(srx); 138162306a36Sopenharmony_ci if (!rv) { 138262306a36Sopenharmony_ci srx->fpdu_part_rem = 138362306a36Sopenharmony_ci be16_to_cpu(srx->hdr.ctrl.mpa_len) - 138462306a36Sopenharmony_ci srx->fpdu_part_rcvd + MPA_HDR_SIZE; 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci if (srx->fpdu_part_rem) 138762306a36Sopenharmony_ci srx->pad = -srx->fpdu_part_rem & 0x3; 138862306a36Sopenharmony_ci else 138962306a36Sopenharmony_ci srx->pad = 0; 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci srx->state = SIW_GET_DATA_START; 139262306a36Sopenharmony_ci srx->fpdu_part_rcvd = 0; 139362306a36Sopenharmony_ci } 139462306a36Sopenharmony_ci break; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci case SIW_GET_DATA_MORE: 139762306a36Sopenharmony_ci /* 139862306a36Sopenharmony_ci * Another data fragment of the same DDP segment. 139962306a36Sopenharmony_ci * Setting first_ddp_seg = 0 avoids repeating 140062306a36Sopenharmony_ci * initializations that shall occur only once per 140162306a36Sopenharmony_ci * DDP segment. 140262306a36Sopenharmony_ci */ 140362306a36Sopenharmony_ci qp->rx_fpdu->first_ddp_seg = 0; 140462306a36Sopenharmony_ci fallthrough; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci case SIW_GET_DATA_START: 140762306a36Sopenharmony_ci /* 140862306a36Sopenharmony_ci * Headers will be checked by the opcode-specific 140962306a36Sopenharmony_ci * data receive function below. 141062306a36Sopenharmony_ci */ 141162306a36Sopenharmony_ci rv = iwarp_pktinfo[qp->rx_stream.rdmap_op].rx_data(qp); 141262306a36Sopenharmony_ci if (!rv) { 141362306a36Sopenharmony_ci int mpa_len = 141462306a36Sopenharmony_ci be16_to_cpu(srx->hdr.ctrl.mpa_len) 141562306a36Sopenharmony_ci + MPA_HDR_SIZE; 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci srx->fpdu_part_rem = (-mpa_len & 0x3) 141862306a36Sopenharmony_ci + MPA_CRC_SIZE; 141962306a36Sopenharmony_ci srx->fpdu_part_rcvd = 0; 142062306a36Sopenharmony_ci srx->state = SIW_GET_TRAILER; 142162306a36Sopenharmony_ci } else { 142262306a36Sopenharmony_ci if (unlikely(rv == -ECONNRESET)) 142362306a36Sopenharmony_ci run_completion = 0; 142462306a36Sopenharmony_ci else 142562306a36Sopenharmony_ci srx->state = SIW_GET_DATA_MORE; 142662306a36Sopenharmony_ci } 142762306a36Sopenharmony_ci break; 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci case SIW_GET_TRAILER: 143062306a36Sopenharmony_ci /* 143162306a36Sopenharmony_ci * read CRC + any padding 143262306a36Sopenharmony_ci */ 143362306a36Sopenharmony_ci rv = siw_get_trailer(qp, srx); 143462306a36Sopenharmony_ci if (likely(!rv)) { 143562306a36Sopenharmony_ci /* 143662306a36Sopenharmony_ci * FPDU completed. 143762306a36Sopenharmony_ci * complete RDMAP message if last fragment 143862306a36Sopenharmony_ci */ 143962306a36Sopenharmony_ci srx->state = SIW_GET_HDR; 144062306a36Sopenharmony_ci srx->fpdu_part_rcvd = 0; 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci if (!(srx->hdr.ctrl.ddp_rdmap_ctrl & 144362306a36Sopenharmony_ci DDP_FLAG_LAST)) 144462306a36Sopenharmony_ci /* more frags */ 144562306a36Sopenharmony_ci break; 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci rv = siw_rdmap_complete(qp, 0); 144862306a36Sopenharmony_ci run_completion = 0; 144962306a36Sopenharmony_ci } 145062306a36Sopenharmony_ci break; 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci default: 145362306a36Sopenharmony_ci pr_warn("QP[%u]: RX out of state\n", qp_id(qp)); 145462306a36Sopenharmony_ci rv = -EPROTO; 145562306a36Sopenharmony_ci run_completion = 0; 145662306a36Sopenharmony_ci } 145762306a36Sopenharmony_ci if (unlikely(rv != 0 && rv != -EAGAIN)) { 145862306a36Sopenharmony_ci if ((srx->state > SIW_GET_HDR || 145962306a36Sopenharmony_ci qp->rx_fpdu->more_ddp_segs) && run_completion) 146062306a36Sopenharmony_ci siw_rdmap_complete(qp, rv); 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci siw_dbg_qp(qp, "rx error %d, rx state %d\n", rv, 146362306a36Sopenharmony_ci srx->state); 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci siw_qp_cm_drop(qp, 1); 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci break; 146862306a36Sopenharmony_ci } 146962306a36Sopenharmony_ci if (rv) { 147062306a36Sopenharmony_ci siw_dbg_qp(qp, "fpdu fragment, state %d, missing %d\n", 147162306a36Sopenharmony_ci srx->state, srx->fpdu_part_rem); 147262306a36Sopenharmony_ci break; 147362306a36Sopenharmony_ci } 147462306a36Sopenharmony_ci } 147562306a36Sopenharmony_ci return srx->skb_copied; 147662306a36Sopenharmony_ci} 1477