18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation. 38c2ecf20Sopenharmony_ci * All rights reserved. 48c2ecf20Sopenharmony_ci * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 78c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 88c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 98c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 108c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 138c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 148c2ecf20Sopenharmony_ci * conditions are met: 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 178c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 188c2ecf20Sopenharmony_ci * disclaimer. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 218c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 228c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 238c2ecf20Sopenharmony_ci * provided with the distribution. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 268c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 278c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 288c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 298c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 308c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 318c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 328c2ecf20Sopenharmony_ci * SOFTWARE. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include "qib.h" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* cut down ridiculously long IB macro names */ 388c2ecf20Sopenharmony_ci#define OP(x) IB_OPCODE_UC_##x 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/** 418c2ecf20Sopenharmony_ci * qib_make_uc_req - construct a request packet (SEND, RDMA write) 428c2ecf20Sopenharmony_ci * @qp: a pointer to the QP 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci * Assumes the s_lock is held. 458c2ecf20Sopenharmony_ci * 468c2ecf20Sopenharmony_ci * Return 1 if constructed; otherwise, return 0. 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_ciint qib_make_uc_req(struct rvt_qp *qp, unsigned long *flags) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci struct qib_qp_priv *priv = qp->priv; 518c2ecf20Sopenharmony_ci struct ib_other_headers *ohdr; 528c2ecf20Sopenharmony_ci struct rvt_swqe *wqe; 538c2ecf20Sopenharmony_ci u32 hwords; 548c2ecf20Sopenharmony_ci u32 bth0; 558c2ecf20Sopenharmony_ci u32 len; 568c2ecf20Sopenharmony_ci u32 pmtu = qp->pmtu; 578c2ecf20Sopenharmony_ci int ret = 0; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (!(ib_rvt_state_ops[qp->state] & RVT_PROCESS_SEND_OK)) { 608c2ecf20Sopenharmony_ci if (!(ib_rvt_state_ops[qp->state] & RVT_FLUSH_SEND)) 618c2ecf20Sopenharmony_ci goto bail; 628c2ecf20Sopenharmony_ci /* We are in the error state, flush the work request. */ 638c2ecf20Sopenharmony_ci if (qp->s_last == READ_ONCE(qp->s_head)) 648c2ecf20Sopenharmony_ci goto bail; 658c2ecf20Sopenharmony_ci /* If DMAs are in progress, we can't flush immediately. */ 668c2ecf20Sopenharmony_ci if (atomic_read(&priv->s_dma_busy)) { 678c2ecf20Sopenharmony_ci qp->s_flags |= RVT_S_WAIT_DMA; 688c2ecf20Sopenharmony_ci goto bail; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci wqe = rvt_get_swqe_ptr(qp, qp->s_last); 718c2ecf20Sopenharmony_ci rvt_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR); 728c2ecf20Sopenharmony_ci goto done; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci ohdr = &priv->s_hdr->u.oth; 768c2ecf20Sopenharmony_ci if (rdma_ah_get_ah_flags(&qp->remote_ah_attr) & IB_AH_GRH) 778c2ecf20Sopenharmony_ci ohdr = &priv->s_hdr->u.l.oth; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci /* header size in 32-bit words LRH+BTH = (8+12)/4. */ 808c2ecf20Sopenharmony_ci hwords = 5; 818c2ecf20Sopenharmony_ci bth0 = 0; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci /* Get the next send request. */ 848c2ecf20Sopenharmony_ci wqe = rvt_get_swqe_ptr(qp, qp->s_cur); 858c2ecf20Sopenharmony_ci qp->s_wqe = NULL; 868c2ecf20Sopenharmony_ci switch (qp->s_state) { 878c2ecf20Sopenharmony_ci default: 888c2ecf20Sopenharmony_ci if (!(ib_rvt_state_ops[qp->state] & 898c2ecf20Sopenharmony_ci RVT_PROCESS_NEXT_SEND_OK)) 908c2ecf20Sopenharmony_ci goto bail; 918c2ecf20Sopenharmony_ci /* Check if send work queue is empty. */ 928c2ecf20Sopenharmony_ci if (qp->s_cur == READ_ONCE(qp->s_head)) 938c2ecf20Sopenharmony_ci goto bail; 948c2ecf20Sopenharmony_ci /* 958c2ecf20Sopenharmony_ci * Start a new request. 968c2ecf20Sopenharmony_ci */ 978c2ecf20Sopenharmony_ci qp->s_psn = wqe->psn; 988c2ecf20Sopenharmony_ci qp->s_sge.sge = wqe->sg_list[0]; 998c2ecf20Sopenharmony_ci qp->s_sge.sg_list = wqe->sg_list + 1; 1008c2ecf20Sopenharmony_ci qp->s_sge.num_sge = wqe->wr.num_sge; 1018c2ecf20Sopenharmony_ci qp->s_sge.total_len = wqe->length; 1028c2ecf20Sopenharmony_ci len = wqe->length; 1038c2ecf20Sopenharmony_ci qp->s_len = len; 1048c2ecf20Sopenharmony_ci switch (wqe->wr.opcode) { 1058c2ecf20Sopenharmony_ci case IB_WR_SEND: 1068c2ecf20Sopenharmony_ci case IB_WR_SEND_WITH_IMM: 1078c2ecf20Sopenharmony_ci if (len > pmtu) { 1088c2ecf20Sopenharmony_ci qp->s_state = OP(SEND_FIRST); 1098c2ecf20Sopenharmony_ci len = pmtu; 1108c2ecf20Sopenharmony_ci break; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci if (wqe->wr.opcode == IB_WR_SEND) 1138c2ecf20Sopenharmony_ci qp->s_state = OP(SEND_ONLY); 1148c2ecf20Sopenharmony_ci else { 1158c2ecf20Sopenharmony_ci qp->s_state = 1168c2ecf20Sopenharmony_ci OP(SEND_ONLY_WITH_IMMEDIATE); 1178c2ecf20Sopenharmony_ci /* Immediate data comes after the BTH */ 1188c2ecf20Sopenharmony_ci ohdr->u.imm_data = wqe->wr.ex.imm_data; 1198c2ecf20Sopenharmony_ci hwords += 1; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci if (wqe->wr.send_flags & IB_SEND_SOLICITED) 1228c2ecf20Sopenharmony_ci bth0 |= IB_BTH_SOLICITED; 1238c2ecf20Sopenharmony_ci qp->s_wqe = wqe; 1248c2ecf20Sopenharmony_ci if (++qp->s_cur >= qp->s_size) 1258c2ecf20Sopenharmony_ci qp->s_cur = 0; 1268c2ecf20Sopenharmony_ci break; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci case IB_WR_RDMA_WRITE: 1298c2ecf20Sopenharmony_ci case IB_WR_RDMA_WRITE_WITH_IMM: 1308c2ecf20Sopenharmony_ci ohdr->u.rc.reth.vaddr = 1318c2ecf20Sopenharmony_ci cpu_to_be64(wqe->rdma_wr.remote_addr); 1328c2ecf20Sopenharmony_ci ohdr->u.rc.reth.rkey = 1338c2ecf20Sopenharmony_ci cpu_to_be32(wqe->rdma_wr.rkey); 1348c2ecf20Sopenharmony_ci ohdr->u.rc.reth.length = cpu_to_be32(len); 1358c2ecf20Sopenharmony_ci hwords += sizeof(struct ib_reth) / 4; 1368c2ecf20Sopenharmony_ci if (len > pmtu) { 1378c2ecf20Sopenharmony_ci qp->s_state = OP(RDMA_WRITE_FIRST); 1388c2ecf20Sopenharmony_ci len = pmtu; 1398c2ecf20Sopenharmony_ci break; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci if (wqe->wr.opcode == IB_WR_RDMA_WRITE) 1428c2ecf20Sopenharmony_ci qp->s_state = OP(RDMA_WRITE_ONLY); 1438c2ecf20Sopenharmony_ci else { 1448c2ecf20Sopenharmony_ci qp->s_state = 1458c2ecf20Sopenharmony_ci OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE); 1468c2ecf20Sopenharmony_ci /* Immediate data comes after the RETH */ 1478c2ecf20Sopenharmony_ci ohdr->u.rc.imm_data = wqe->wr.ex.imm_data; 1488c2ecf20Sopenharmony_ci hwords += 1; 1498c2ecf20Sopenharmony_ci if (wqe->wr.send_flags & IB_SEND_SOLICITED) 1508c2ecf20Sopenharmony_ci bth0 |= IB_BTH_SOLICITED; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci qp->s_wqe = wqe; 1538c2ecf20Sopenharmony_ci if (++qp->s_cur >= qp->s_size) 1548c2ecf20Sopenharmony_ci qp->s_cur = 0; 1558c2ecf20Sopenharmony_ci break; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci default: 1588c2ecf20Sopenharmony_ci goto bail; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci case OP(SEND_FIRST): 1638c2ecf20Sopenharmony_ci qp->s_state = OP(SEND_MIDDLE); 1648c2ecf20Sopenharmony_ci fallthrough; 1658c2ecf20Sopenharmony_ci case OP(SEND_MIDDLE): 1668c2ecf20Sopenharmony_ci len = qp->s_len; 1678c2ecf20Sopenharmony_ci if (len > pmtu) { 1688c2ecf20Sopenharmony_ci len = pmtu; 1698c2ecf20Sopenharmony_ci break; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci if (wqe->wr.opcode == IB_WR_SEND) 1728c2ecf20Sopenharmony_ci qp->s_state = OP(SEND_LAST); 1738c2ecf20Sopenharmony_ci else { 1748c2ecf20Sopenharmony_ci qp->s_state = OP(SEND_LAST_WITH_IMMEDIATE); 1758c2ecf20Sopenharmony_ci /* Immediate data comes after the BTH */ 1768c2ecf20Sopenharmony_ci ohdr->u.imm_data = wqe->wr.ex.imm_data; 1778c2ecf20Sopenharmony_ci hwords += 1; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci if (wqe->wr.send_flags & IB_SEND_SOLICITED) 1808c2ecf20Sopenharmony_ci bth0 |= IB_BTH_SOLICITED; 1818c2ecf20Sopenharmony_ci qp->s_wqe = wqe; 1828c2ecf20Sopenharmony_ci if (++qp->s_cur >= qp->s_size) 1838c2ecf20Sopenharmony_ci qp->s_cur = 0; 1848c2ecf20Sopenharmony_ci break; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci case OP(RDMA_WRITE_FIRST): 1878c2ecf20Sopenharmony_ci qp->s_state = OP(RDMA_WRITE_MIDDLE); 1888c2ecf20Sopenharmony_ci fallthrough; 1898c2ecf20Sopenharmony_ci case OP(RDMA_WRITE_MIDDLE): 1908c2ecf20Sopenharmony_ci len = qp->s_len; 1918c2ecf20Sopenharmony_ci if (len > pmtu) { 1928c2ecf20Sopenharmony_ci len = pmtu; 1938c2ecf20Sopenharmony_ci break; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci if (wqe->wr.opcode == IB_WR_RDMA_WRITE) 1968c2ecf20Sopenharmony_ci qp->s_state = OP(RDMA_WRITE_LAST); 1978c2ecf20Sopenharmony_ci else { 1988c2ecf20Sopenharmony_ci qp->s_state = 1998c2ecf20Sopenharmony_ci OP(RDMA_WRITE_LAST_WITH_IMMEDIATE); 2008c2ecf20Sopenharmony_ci /* Immediate data comes after the BTH */ 2018c2ecf20Sopenharmony_ci ohdr->u.imm_data = wqe->wr.ex.imm_data; 2028c2ecf20Sopenharmony_ci hwords += 1; 2038c2ecf20Sopenharmony_ci if (wqe->wr.send_flags & IB_SEND_SOLICITED) 2048c2ecf20Sopenharmony_ci bth0 |= IB_BTH_SOLICITED; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci qp->s_wqe = wqe; 2078c2ecf20Sopenharmony_ci if (++qp->s_cur >= qp->s_size) 2088c2ecf20Sopenharmony_ci qp->s_cur = 0; 2098c2ecf20Sopenharmony_ci break; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci qp->s_len -= len; 2128c2ecf20Sopenharmony_ci qp->s_hdrwords = hwords; 2138c2ecf20Sopenharmony_ci qp->s_cur_sge = &qp->s_sge; 2148c2ecf20Sopenharmony_ci qp->s_cur_size = len; 2158c2ecf20Sopenharmony_ci qib_make_ruc_header(qp, ohdr, bth0 | (qp->s_state << 24), 2168c2ecf20Sopenharmony_ci qp->s_psn++ & QIB_PSN_MASK); 2178c2ecf20Sopenharmony_cidone: 2188c2ecf20Sopenharmony_ci return 1; 2198c2ecf20Sopenharmony_cibail: 2208c2ecf20Sopenharmony_ci qp->s_flags &= ~RVT_S_BUSY; 2218c2ecf20Sopenharmony_ci return ret; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci/** 2258c2ecf20Sopenharmony_ci * qib_uc_rcv - handle an incoming UC packet 2268c2ecf20Sopenharmony_ci * @ibp: the port the packet came in on 2278c2ecf20Sopenharmony_ci * @hdr: the header of the packet 2288c2ecf20Sopenharmony_ci * @has_grh: true if the packet has a GRH 2298c2ecf20Sopenharmony_ci * @data: the packet data 2308c2ecf20Sopenharmony_ci * @tlen: the length of the packet 2318c2ecf20Sopenharmony_ci * @qp: the QP for this packet. 2328c2ecf20Sopenharmony_ci * 2338c2ecf20Sopenharmony_ci * This is called from qib_qp_rcv() to process an incoming UC packet 2348c2ecf20Sopenharmony_ci * for the given QP. 2358c2ecf20Sopenharmony_ci * Called at interrupt level. 2368c2ecf20Sopenharmony_ci */ 2378c2ecf20Sopenharmony_civoid qib_uc_rcv(struct qib_ibport *ibp, struct ib_header *hdr, 2388c2ecf20Sopenharmony_ci int has_grh, void *data, u32 tlen, struct rvt_qp *qp) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci struct ib_other_headers *ohdr; 2418c2ecf20Sopenharmony_ci u32 opcode; 2428c2ecf20Sopenharmony_ci u32 hdrsize; 2438c2ecf20Sopenharmony_ci u32 psn; 2448c2ecf20Sopenharmony_ci u32 pad; 2458c2ecf20Sopenharmony_ci struct ib_wc wc; 2468c2ecf20Sopenharmony_ci u32 pmtu = qp->pmtu; 2478c2ecf20Sopenharmony_ci struct ib_reth *reth; 2488c2ecf20Sopenharmony_ci int ret; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci /* Check for GRH */ 2518c2ecf20Sopenharmony_ci if (!has_grh) { 2528c2ecf20Sopenharmony_ci ohdr = &hdr->u.oth; 2538c2ecf20Sopenharmony_ci hdrsize = 8 + 12; /* LRH + BTH */ 2548c2ecf20Sopenharmony_ci } else { 2558c2ecf20Sopenharmony_ci ohdr = &hdr->u.l.oth; 2568c2ecf20Sopenharmony_ci hdrsize = 8 + 40 + 12; /* LRH + GRH + BTH */ 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci opcode = be32_to_cpu(ohdr->bth[0]); 2608c2ecf20Sopenharmony_ci if (qib_ruc_check_hdr(ibp, hdr, has_grh, qp, opcode)) 2618c2ecf20Sopenharmony_ci return; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci psn = be32_to_cpu(ohdr->bth[2]); 2648c2ecf20Sopenharmony_ci opcode >>= 24; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci /* Compare the PSN verses the expected PSN. */ 2678c2ecf20Sopenharmony_ci if (unlikely(qib_cmp24(psn, qp->r_psn) != 0)) { 2688c2ecf20Sopenharmony_ci /* 2698c2ecf20Sopenharmony_ci * Handle a sequence error. 2708c2ecf20Sopenharmony_ci * Silently drop any current message. 2718c2ecf20Sopenharmony_ci */ 2728c2ecf20Sopenharmony_ci qp->r_psn = psn; 2738c2ecf20Sopenharmony_ciinv: 2748c2ecf20Sopenharmony_ci if (qp->r_state == OP(SEND_FIRST) || 2758c2ecf20Sopenharmony_ci qp->r_state == OP(SEND_MIDDLE)) { 2768c2ecf20Sopenharmony_ci set_bit(RVT_R_REWIND_SGE, &qp->r_aflags); 2778c2ecf20Sopenharmony_ci qp->r_sge.num_sge = 0; 2788c2ecf20Sopenharmony_ci } else 2798c2ecf20Sopenharmony_ci rvt_put_ss(&qp->r_sge); 2808c2ecf20Sopenharmony_ci qp->r_state = OP(SEND_LAST); 2818c2ecf20Sopenharmony_ci switch (opcode) { 2828c2ecf20Sopenharmony_ci case OP(SEND_FIRST): 2838c2ecf20Sopenharmony_ci case OP(SEND_ONLY): 2848c2ecf20Sopenharmony_ci case OP(SEND_ONLY_WITH_IMMEDIATE): 2858c2ecf20Sopenharmony_ci goto send_first; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci case OP(RDMA_WRITE_FIRST): 2888c2ecf20Sopenharmony_ci case OP(RDMA_WRITE_ONLY): 2898c2ecf20Sopenharmony_ci case OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE): 2908c2ecf20Sopenharmony_ci goto rdma_first; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci default: 2938c2ecf20Sopenharmony_ci goto drop; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci /* Check for opcode sequence errors. */ 2988c2ecf20Sopenharmony_ci switch (qp->r_state) { 2998c2ecf20Sopenharmony_ci case OP(SEND_FIRST): 3008c2ecf20Sopenharmony_ci case OP(SEND_MIDDLE): 3018c2ecf20Sopenharmony_ci if (opcode == OP(SEND_MIDDLE) || 3028c2ecf20Sopenharmony_ci opcode == OP(SEND_LAST) || 3038c2ecf20Sopenharmony_ci opcode == OP(SEND_LAST_WITH_IMMEDIATE)) 3048c2ecf20Sopenharmony_ci break; 3058c2ecf20Sopenharmony_ci goto inv; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci case OP(RDMA_WRITE_FIRST): 3088c2ecf20Sopenharmony_ci case OP(RDMA_WRITE_MIDDLE): 3098c2ecf20Sopenharmony_ci if (opcode == OP(RDMA_WRITE_MIDDLE) || 3108c2ecf20Sopenharmony_ci opcode == OP(RDMA_WRITE_LAST) || 3118c2ecf20Sopenharmony_ci opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE)) 3128c2ecf20Sopenharmony_ci break; 3138c2ecf20Sopenharmony_ci goto inv; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci default: 3168c2ecf20Sopenharmony_ci if (opcode == OP(SEND_FIRST) || 3178c2ecf20Sopenharmony_ci opcode == OP(SEND_ONLY) || 3188c2ecf20Sopenharmony_ci opcode == OP(SEND_ONLY_WITH_IMMEDIATE) || 3198c2ecf20Sopenharmony_ci opcode == OP(RDMA_WRITE_FIRST) || 3208c2ecf20Sopenharmony_ci opcode == OP(RDMA_WRITE_ONLY) || 3218c2ecf20Sopenharmony_ci opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE)) 3228c2ecf20Sopenharmony_ci break; 3238c2ecf20Sopenharmony_ci goto inv; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (qp->state == IB_QPS_RTR && !(qp->r_flags & RVT_R_COMM_EST)) 3278c2ecf20Sopenharmony_ci rvt_comm_est(qp); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci /* OK, process the packet. */ 3308c2ecf20Sopenharmony_ci switch (opcode) { 3318c2ecf20Sopenharmony_ci case OP(SEND_FIRST): 3328c2ecf20Sopenharmony_ci case OP(SEND_ONLY): 3338c2ecf20Sopenharmony_ci case OP(SEND_ONLY_WITH_IMMEDIATE): 3348c2ecf20Sopenharmony_cisend_first: 3358c2ecf20Sopenharmony_ci if (test_and_clear_bit(RVT_R_REWIND_SGE, &qp->r_aflags)) 3368c2ecf20Sopenharmony_ci qp->r_sge = qp->s_rdma_read_sge; 3378c2ecf20Sopenharmony_ci else { 3388c2ecf20Sopenharmony_ci ret = rvt_get_rwqe(qp, false); 3398c2ecf20Sopenharmony_ci if (ret < 0) 3408c2ecf20Sopenharmony_ci goto op_err; 3418c2ecf20Sopenharmony_ci if (!ret) 3428c2ecf20Sopenharmony_ci goto drop; 3438c2ecf20Sopenharmony_ci /* 3448c2ecf20Sopenharmony_ci * qp->s_rdma_read_sge will be the owner 3458c2ecf20Sopenharmony_ci * of the mr references. 3468c2ecf20Sopenharmony_ci */ 3478c2ecf20Sopenharmony_ci qp->s_rdma_read_sge = qp->r_sge; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci qp->r_rcv_len = 0; 3508c2ecf20Sopenharmony_ci if (opcode == OP(SEND_ONLY)) 3518c2ecf20Sopenharmony_ci goto no_immediate_data; 3528c2ecf20Sopenharmony_ci else if (opcode == OP(SEND_ONLY_WITH_IMMEDIATE)) 3538c2ecf20Sopenharmony_ci goto send_last_imm; 3548c2ecf20Sopenharmony_ci fallthrough; 3558c2ecf20Sopenharmony_ci case OP(SEND_MIDDLE): 3568c2ecf20Sopenharmony_ci /* Check for invalid length PMTU or posted rwqe len. */ 3578c2ecf20Sopenharmony_ci if (unlikely(tlen != (hdrsize + pmtu + 4))) 3588c2ecf20Sopenharmony_ci goto rewind; 3598c2ecf20Sopenharmony_ci qp->r_rcv_len += pmtu; 3608c2ecf20Sopenharmony_ci if (unlikely(qp->r_rcv_len > qp->r_len)) 3618c2ecf20Sopenharmony_ci goto rewind; 3628c2ecf20Sopenharmony_ci rvt_copy_sge(qp, &qp->r_sge, data, pmtu, false, false); 3638c2ecf20Sopenharmony_ci break; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci case OP(SEND_LAST_WITH_IMMEDIATE): 3668c2ecf20Sopenharmony_cisend_last_imm: 3678c2ecf20Sopenharmony_ci wc.ex.imm_data = ohdr->u.imm_data; 3688c2ecf20Sopenharmony_ci hdrsize += 4; 3698c2ecf20Sopenharmony_ci wc.wc_flags = IB_WC_WITH_IMM; 3708c2ecf20Sopenharmony_ci goto send_last; 3718c2ecf20Sopenharmony_ci case OP(SEND_LAST): 3728c2ecf20Sopenharmony_cino_immediate_data: 3738c2ecf20Sopenharmony_ci wc.ex.imm_data = 0; 3748c2ecf20Sopenharmony_ci wc.wc_flags = 0; 3758c2ecf20Sopenharmony_cisend_last: 3768c2ecf20Sopenharmony_ci /* Get the number of bytes the message was padded by. */ 3778c2ecf20Sopenharmony_ci pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; 3788c2ecf20Sopenharmony_ci /* Check for invalid length. */ 3798c2ecf20Sopenharmony_ci /* XXX LAST len should be >= 1 */ 3808c2ecf20Sopenharmony_ci if (unlikely(tlen < (hdrsize + pad + 4))) 3818c2ecf20Sopenharmony_ci goto rewind; 3828c2ecf20Sopenharmony_ci /* Don't count the CRC. */ 3838c2ecf20Sopenharmony_ci tlen -= (hdrsize + pad + 4); 3848c2ecf20Sopenharmony_ci wc.byte_len = tlen + qp->r_rcv_len; 3858c2ecf20Sopenharmony_ci if (unlikely(wc.byte_len > qp->r_len)) 3868c2ecf20Sopenharmony_ci goto rewind; 3878c2ecf20Sopenharmony_ci wc.opcode = IB_WC_RECV; 3888c2ecf20Sopenharmony_ci rvt_copy_sge(qp, &qp->r_sge, data, tlen, false, false); 3898c2ecf20Sopenharmony_ci rvt_put_ss(&qp->s_rdma_read_sge); 3908c2ecf20Sopenharmony_cilast_imm: 3918c2ecf20Sopenharmony_ci wc.wr_id = qp->r_wr_id; 3928c2ecf20Sopenharmony_ci wc.status = IB_WC_SUCCESS; 3938c2ecf20Sopenharmony_ci wc.qp = &qp->ibqp; 3948c2ecf20Sopenharmony_ci wc.src_qp = qp->remote_qpn; 3958c2ecf20Sopenharmony_ci wc.slid = rdma_ah_get_dlid(&qp->remote_ah_attr); 3968c2ecf20Sopenharmony_ci wc.sl = rdma_ah_get_sl(&qp->remote_ah_attr); 3978c2ecf20Sopenharmony_ci /* zero fields that are N/A */ 3988c2ecf20Sopenharmony_ci wc.vendor_err = 0; 3998c2ecf20Sopenharmony_ci wc.pkey_index = 0; 4008c2ecf20Sopenharmony_ci wc.dlid_path_bits = 0; 4018c2ecf20Sopenharmony_ci wc.port_num = 0; 4028c2ecf20Sopenharmony_ci /* Signal completion event if the solicited bit is set. */ 4038c2ecf20Sopenharmony_ci rvt_recv_cq(qp, &wc, ib_bth_is_solicited(ohdr)); 4048c2ecf20Sopenharmony_ci break; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci case OP(RDMA_WRITE_FIRST): 4078c2ecf20Sopenharmony_ci case OP(RDMA_WRITE_ONLY): 4088c2ecf20Sopenharmony_ci case OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE): /* consume RWQE */ 4098c2ecf20Sopenharmony_cirdma_first: 4108c2ecf20Sopenharmony_ci if (unlikely(!(qp->qp_access_flags & 4118c2ecf20Sopenharmony_ci IB_ACCESS_REMOTE_WRITE))) { 4128c2ecf20Sopenharmony_ci goto drop; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci reth = &ohdr->u.rc.reth; 4158c2ecf20Sopenharmony_ci hdrsize += sizeof(*reth); 4168c2ecf20Sopenharmony_ci qp->r_len = be32_to_cpu(reth->length); 4178c2ecf20Sopenharmony_ci qp->r_rcv_len = 0; 4188c2ecf20Sopenharmony_ci qp->r_sge.sg_list = NULL; 4198c2ecf20Sopenharmony_ci if (qp->r_len != 0) { 4208c2ecf20Sopenharmony_ci u32 rkey = be32_to_cpu(reth->rkey); 4218c2ecf20Sopenharmony_ci u64 vaddr = be64_to_cpu(reth->vaddr); 4228c2ecf20Sopenharmony_ci int ok; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci /* Check rkey */ 4258c2ecf20Sopenharmony_ci ok = rvt_rkey_ok(qp, &qp->r_sge.sge, qp->r_len, 4268c2ecf20Sopenharmony_ci vaddr, rkey, IB_ACCESS_REMOTE_WRITE); 4278c2ecf20Sopenharmony_ci if (unlikely(!ok)) 4288c2ecf20Sopenharmony_ci goto drop; 4298c2ecf20Sopenharmony_ci qp->r_sge.num_sge = 1; 4308c2ecf20Sopenharmony_ci } else { 4318c2ecf20Sopenharmony_ci qp->r_sge.num_sge = 0; 4328c2ecf20Sopenharmony_ci qp->r_sge.sge.mr = NULL; 4338c2ecf20Sopenharmony_ci qp->r_sge.sge.vaddr = NULL; 4348c2ecf20Sopenharmony_ci qp->r_sge.sge.length = 0; 4358c2ecf20Sopenharmony_ci qp->r_sge.sge.sge_length = 0; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci if (opcode == OP(RDMA_WRITE_ONLY)) 4388c2ecf20Sopenharmony_ci goto rdma_last; 4398c2ecf20Sopenharmony_ci else if (opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE)) { 4408c2ecf20Sopenharmony_ci wc.ex.imm_data = ohdr->u.rc.imm_data; 4418c2ecf20Sopenharmony_ci goto rdma_last_imm; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci fallthrough; 4448c2ecf20Sopenharmony_ci case OP(RDMA_WRITE_MIDDLE): 4458c2ecf20Sopenharmony_ci /* Check for invalid length PMTU or posted rwqe len. */ 4468c2ecf20Sopenharmony_ci if (unlikely(tlen != (hdrsize + pmtu + 4))) 4478c2ecf20Sopenharmony_ci goto drop; 4488c2ecf20Sopenharmony_ci qp->r_rcv_len += pmtu; 4498c2ecf20Sopenharmony_ci if (unlikely(qp->r_rcv_len > qp->r_len)) 4508c2ecf20Sopenharmony_ci goto drop; 4518c2ecf20Sopenharmony_ci rvt_copy_sge(qp, &qp->r_sge, data, pmtu, true, false); 4528c2ecf20Sopenharmony_ci break; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE): 4558c2ecf20Sopenharmony_ci wc.ex.imm_data = ohdr->u.imm_data; 4568c2ecf20Sopenharmony_cirdma_last_imm: 4578c2ecf20Sopenharmony_ci hdrsize += 4; 4588c2ecf20Sopenharmony_ci wc.wc_flags = IB_WC_WITH_IMM; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci /* Get the number of bytes the message was padded by. */ 4618c2ecf20Sopenharmony_ci pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; 4628c2ecf20Sopenharmony_ci /* Check for invalid length. */ 4638c2ecf20Sopenharmony_ci /* XXX LAST len should be >= 1 */ 4648c2ecf20Sopenharmony_ci if (unlikely(tlen < (hdrsize + pad + 4))) 4658c2ecf20Sopenharmony_ci goto drop; 4668c2ecf20Sopenharmony_ci /* Don't count the CRC. */ 4678c2ecf20Sopenharmony_ci tlen -= (hdrsize + pad + 4); 4688c2ecf20Sopenharmony_ci if (unlikely(tlen + qp->r_rcv_len != qp->r_len)) 4698c2ecf20Sopenharmony_ci goto drop; 4708c2ecf20Sopenharmony_ci if (test_and_clear_bit(RVT_R_REWIND_SGE, &qp->r_aflags)) 4718c2ecf20Sopenharmony_ci rvt_put_ss(&qp->s_rdma_read_sge); 4728c2ecf20Sopenharmony_ci else { 4738c2ecf20Sopenharmony_ci ret = rvt_get_rwqe(qp, true); 4748c2ecf20Sopenharmony_ci if (ret < 0) 4758c2ecf20Sopenharmony_ci goto op_err; 4768c2ecf20Sopenharmony_ci if (!ret) 4778c2ecf20Sopenharmony_ci goto drop; 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci wc.byte_len = qp->r_len; 4808c2ecf20Sopenharmony_ci wc.opcode = IB_WC_RECV_RDMA_WITH_IMM; 4818c2ecf20Sopenharmony_ci rvt_copy_sge(qp, &qp->r_sge, data, tlen, true, false); 4828c2ecf20Sopenharmony_ci rvt_put_ss(&qp->r_sge); 4838c2ecf20Sopenharmony_ci goto last_imm; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci case OP(RDMA_WRITE_LAST): 4868c2ecf20Sopenharmony_cirdma_last: 4878c2ecf20Sopenharmony_ci /* Get the number of bytes the message was padded by. */ 4888c2ecf20Sopenharmony_ci pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; 4898c2ecf20Sopenharmony_ci /* Check for invalid length. */ 4908c2ecf20Sopenharmony_ci /* XXX LAST len should be >= 1 */ 4918c2ecf20Sopenharmony_ci if (unlikely(tlen < (hdrsize + pad + 4))) 4928c2ecf20Sopenharmony_ci goto drop; 4938c2ecf20Sopenharmony_ci /* Don't count the CRC. */ 4948c2ecf20Sopenharmony_ci tlen -= (hdrsize + pad + 4); 4958c2ecf20Sopenharmony_ci if (unlikely(tlen + qp->r_rcv_len != qp->r_len)) 4968c2ecf20Sopenharmony_ci goto drop; 4978c2ecf20Sopenharmony_ci rvt_copy_sge(qp, &qp->r_sge, data, tlen, true, false); 4988c2ecf20Sopenharmony_ci rvt_put_ss(&qp->r_sge); 4998c2ecf20Sopenharmony_ci break; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci default: 5028c2ecf20Sopenharmony_ci /* Drop packet for unknown opcodes. */ 5038c2ecf20Sopenharmony_ci goto drop; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci qp->r_psn++; 5068c2ecf20Sopenharmony_ci qp->r_state = opcode; 5078c2ecf20Sopenharmony_ci return; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_cirewind: 5108c2ecf20Sopenharmony_ci set_bit(RVT_R_REWIND_SGE, &qp->r_aflags); 5118c2ecf20Sopenharmony_ci qp->r_sge.num_sge = 0; 5128c2ecf20Sopenharmony_cidrop: 5138c2ecf20Sopenharmony_ci ibp->rvp.n_pkt_drops++; 5148c2ecf20Sopenharmony_ci return; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ciop_err: 5178c2ecf20Sopenharmony_ci rvt_rc_error(qp, IB_WC_LOC_QP_OP_ERR); 5188c2ecf20Sopenharmony_ci return; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci} 521