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