162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation. 362306a36Sopenharmony_ci * All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This software is available to you under a choice of one of two 762306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 862306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 962306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 1062306a36Sopenharmony_ci * OpenIB.org BSD license below: 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1362306a36Sopenharmony_ci * without modification, are permitted provided that the following 1462306a36Sopenharmony_ci * conditions are met: 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1762306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1862306a36Sopenharmony_ci * disclaimer. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 2162306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2262306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2362306a36Sopenharmony_ci * provided with the distribution. 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2662306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2762306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2862306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2962306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 3062306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 3162306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3262306a36Sopenharmony_ci * SOFTWARE. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include "qib.h" 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* cut down ridiculously long IB macro names */ 3862306a36Sopenharmony_ci#define OP(x) IB_OPCODE_UC_##x 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/** 4162306a36Sopenharmony_ci * qib_make_uc_req - construct a request packet (SEND, RDMA write) 4262306a36Sopenharmony_ci * @qp: a pointer to the QP 4362306a36Sopenharmony_ci * @flags: unused 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * Assumes the s_lock is held. 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * Return 1 if constructed; otherwise, return 0. 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_ciint qib_make_uc_req(struct rvt_qp *qp, unsigned long *flags) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci struct qib_qp_priv *priv = qp->priv; 5262306a36Sopenharmony_ci struct ib_other_headers *ohdr; 5362306a36Sopenharmony_ci struct rvt_swqe *wqe; 5462306a36Sopenharmony_ci u32 hwords; 5562306a36Sopenharmony_ci u32 bth0; 5662306a36Sopenharmony_ci u32 len; 5762306a36Sopenharmony_ci u32 pmtu = qp->pmtu; 5862306a36Sopenharmony_ci int ret = 0; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci if (!(ib_rvt_state_ops[qp->state] & RVT_PROCESS_SEND_OK)) { 6162306a36Sopenharmony_ci if (!(ib_rvt_state_ops[qp->state] & RVT_FLUSH_SEND)) 6262306a36Sopenharmony_ci goto bail; 6362306a36Sopenharmony_ci /* We are in the error state, flush the work request. */ 6462306a36Sopenharmony_ci if (qp->s_last == READ_ONCE(qp->s_head)) 6562306a36Sopenharmony_ci goto bail; 6662306a36Sopenharmony_ci /* If DMAs are in progress, we can't flush immediately. */ 6762306a36Sopenharmony_ci if (atomic_read(&priv->s_dma_busy)) { 6862306a36Sopenharmony_ci qp->s_flags |= RVT_S_WAIT_DMA; 6962306a36Sopenharmony_ci goto bail; 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci wqe = rvt_get_swqe_ptr(qp, qp->s_last); 7262306a36Sopenharmony_ci rvt_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR); 7362306a36Sopenharmony_ci goto done; 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci ohdr = &priv->s_hdr->u.oth; 7762306a36Sopenharmony_ci if (rdma_ah_get_ah_flags(&qp->remote_ah_attr) & IB_AH_GRH) 7862306a36Sopenharmony_ci ohdr = &priv->s_hdr->u.l.oth; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci /* header size in 32-bit words LRH+BTH = (8+12)/4. */ 8162306a36Sopenharmony_ci hwords = 5; 8262306a36Sopenharmony_ci bth0 = 0; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci /* Get the next send request. */ 8562306a36Sopenharmony_ci wqe = rvt_get_swqe_ptr(qp, qp->s_cur); 8662306a36Sopenharmony_ci qp->s_wqe = NULL; 8762306a36Sopenharmony_ci switch (qp->s_state) { 8862306a36Sopenharmony_ci default: 8962306a36Sopenharmony_ci if (!(ib_rvt_state_ops[qp->state] & 9062306a36Sopenharmony_ci RVT_PROCESS_NEXT_SEND_OK)) 9162306a36Sopenharmony_ci goto bail; 9262306a36Sopenharmony_ci /* Check if send work queue is empty. */ 9362306a36Sopenharmony_ci if (qp->s_cur == READ_ONCE(qp->s_head)) 9462306a36Sopenharmony_ci goto bail; 9562306a36Sopenharmony_ci /* 9662306a36Sopenharmony_ci * Start a new request. 9762306a36Sopenharmony_ci */ 9862306a36Sopenharmony_ci qp->s_psn = wqe->psn; 9962306a36Sopenharmony_ci qp->s_sge.sge = wqe->sg_list[0]; 10062306a36Sopenharmony_ci qp->s_sge.sg_list = wqe->sg_list + 1; 10162306a36Sopenharmony_ci qp->s_sge.num_sge = wqe->wr.num_sge; 10262306a36Sopenharmony_ci qp->s_sge.total_len = wqe->length; 10362306a36Sopenharmony_ci len = wqe->length; 10462306a36Sopenharmony_ci qp->s_len = len; 10562306a36Sopenharmony_ci switch (wqe->wr.opcode) { 10662306a36Sopenharmony_ci case IB_WR_SEND: 10762306a36Sopenharmony_ci case IB_WR_SEND_WITH_IMM: 10862306a36Sopenharmony_ci if (len > pmtu) { 10962306a36Sopenharmony_ci qp->s_state = OP(SEND_FIRST); 11062306a36Sopenharmony_ci len = pmtu; 11162306a36Sopenharmony_ci break; 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci if (wqe->wr.opcode == IB_WR_SEND) 11462306a36Sopenharmony_ci qp->s_state = OP(SEND_ONLY); 11562306a36Sopenharmony_ci else { 11662306a36Sopenharmony_ci qp->s_state = 11762306a36Sopenharmony_ci OP(SEND_ONLY_WITH_IMMEDIATE); 11862306a36Sopenharmony_ci /* Immediate data comes after the BTH */ 11962306a36Sopenharmony_ci ohdr->u.imm_data = wqe->wr.ex.imm_data; 12062306a36Sopenharmony_ci hwords += 1; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci if (wqe->wr.send_flags & IB_SEND_SOLICITED) 12362306a36Sopenharmony_ci bth0 |= IB_BTH_SOLICITED; 12462306a36Sopenharmony_ci qp->s_wqe = wqe; 12562306a36Sopenharmony_ci if (++qp->s_cur >= qp->s_size) 12662306a36Sopenharmony_ci qp->s_cur = 0; 12762306a36Sopenharmony_ci break; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci case IB_WR_RDMA_WRITE: 13062306a36Sopenharmony_ci case IB_WR_RDMA_WRITE_WITH_IMM: 13162306a36Sopenharmony_ci ohdr->u.rc.reth.vaddr = 13262306a36Sopenharmony_ci cpu_to_be64(wqe->rdma_wr.remote_addr); 13362306a36Sopenharmony_ci ohdr->u.rc.reth.rkey = 13462306a36Sopenharmony_ci cpu_to_be32(wqe->rdma_wr.rkey); 13562306a36Sopenharmony_ci ohdr->u.rc.reth.length = cpu_to_be32(len); 13662306a36Sopenharmony_ci hwords += sizeof(struct ib_reth) / 4; 13762306a36Sopenharmony_ci if (len > pmtu) { 13862306a36Sopenharmony_ci qp->s_state = OP(RDMA_WRITE_FIRST); 13962306a36Sopenharmony_ci len = pmtu; 14062306a36Sopenharmony_ci break; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci if (wqe->wr.opcode == IB_WR_RDMA_WRITE) 14362306a36Sopenharmony_ci qp->s_state = OP(RDMA_WRITE_ONLY); 14462306a36Sopenharmony_ci else { 14562306a36Sopenharmony_ci qp->s_state = 14662306a36Sopenharmony_ci OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE); 14762306a36Sopenharmony_ci /* Immediate data comes after the RETH */ 14862306a36Sopenharmony_ci ohdr->u.rc.imm_data = wqe->wr.ex.imm_data; 14962306a36Sopenharmony_ci hwords += 1; 15062306a36Sopenharmony_ci if (wqe->wr.send_flags & IB_SEND_SOLICITED) 15162306a36Sopenharmony_ci bth0 |= IB_BTH_SOLICITED; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci qp->s_wqe = wqe; 15462306a36Sopenharmony_ci if (++qp->s_cur >= qp->s_size) 15562306a36Sopenharmony_ci qp->s_cur = 0; 15662306a36Sopenharmony_ci break; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci default: 15962306a36Sopenharmony_ci goto bail; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci break; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci case OP(SEND_FIRST): 16462306a36Sopenharmony_ci qp->s_state = OP(SEND_MIDDLE); 16562306a36Sopenharmony_ci fallthrough; 16662306a36Sopenharmony_ci case OP(SEND_MIDDLE): 16762306a36Sopenharmony_ci len = qp->s_len; 16862306a36Sopenharmony_ci if (len > pmtu) { 16962306a36Sopenharmony_ci len = pmtu; 17062306a36Sopenharmony_ci break; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci if (wqe->wr.opcode == IB_WR_SEND) 17362306a36Sopenharmony_ci qp->s_state = OP(SEND_LAST); 17462306a36Sopenharmony_ci else { 17562306a36Sopenharmony_ci qp->s_state = OP(SEND_LAST_WITH_IMMEDIATE); 17662306a36Sopenharmony_ci /* Immediate data comes after the BTH */ 17762306a36Sopenharmony_ci ohdr->u.imm_data = wqe->wr.ex.imm_data; 17862306a36Sopenharmony_ci hwords += 1; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci if (wqe->wr.send_flags & IB_SEND_SOLICITED) 18162306a36Sopenharmony_ci bth0 |= IB_BTH_SOLICITED; 18262306a36Sopenharmony_ci qp->s_wqe = wqe; 18362306a36Sopenharmony_ci if (++qp->s_cur >= qp->s_size) 18462306a36Sopenharmony_ci qp->s_cur = 0; 18562306a36Sopenharmony_ci break; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci case OP(RDMA_WRITE_FIRST): 18862306a36Sopenharmony_ci qp->s_state = OP(RDMA_WRITE_MIDDLE); 18962306a36Sopenharmony_ci fallthrough; 19062306a36Sopenharmony_ci case OP(RDMA_WRITE_MIDDLE): 19162306a36Sopenharmony_ci len = qp->s_len; 19262306a36Sopenharmony_ci if (len > pmtu) { 19362306a36Sopenharmony_ci len = pmtu; 19462306a36Sopenharmony_ci break; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci if (wqe->wr.opcode == IB_WR_RDMA_WRITE) 19762306a36Sopenharmony_ci qp->s_state = OP(RDMA_WRITE_LAST); 19862306a36Sopenharmony_ci else { 19962306a36Sopenharmony_ci qp->s_state = 20062306a36Sopenharmony_ci OP(RDMA_WRITE_LAST_WITH_IMMEDIATE); 20162306a36Sopenharmony_ci /* Immediate data comes after the BTH */ 20262306a36Sopenharmony_ci ohdr->u.imm_data = wqe->wr.ex.imm_data; 20362306a36Sopenharmony_ci hwords += 1; 20462306a36Sopenharmony_ci if (wqe->wr.send_flags & IB_SEND_SOLICITED) 20562306a36Sopenharmony_ci bth0 |= IB_BTH_SOLICITED; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci qp->s_wqe = wqe; 20862306a36Sopenharmony_ci if (++qp->s_cur >= qp->s_size) 20962306a36Sopenharmony_ci qp->s_cur = 0; 21062306a36Sopenharmony_ci break; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci qp->s_len -= len; 21362306a36Sopenharmony_ci qp->s_hdrwords = hwords; 21462306a36Sopenharmony_ci qp->s_cur_sge = &qp->s_sge; 21562306a36Sopenharmony_ci qp->s_cur_size = len; 21662306a36Sopenharmony_ci qib_make_ruc_header(qp, ohdr, bth0 | (qp->s_state << 24), 21762306a36Sopenharmony_ci qp->s_psn++ & QIB_PSN_MASK); 21862306a36Sopenharmony_cidone: 21962306a36Sopenharmony_ci return 1; 22062306a36Sopenharmony_cibail: 22162306a36Sopenharmony_ci qp->s_flags &= ~RVT_S_BUSY; 22262306a36Sopenharmony_ci return ret; 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci/** 22662306a36Sopenharmony_ci * qib_uc_rcv - handle an incoming UC packet 22762306a36Sopenharmony_ci * @ibp: the port the packet came in on 22862306a36Sopenharmony_ci * @hdr: the header of the packet 22962306a36Sopenharmony_ci * @has_grh: true if the packet has a GRH 23062306a36Sopenharmony_ci * @data: the packet data 23162306a36Sopenharmony_ci * @tlen: the length of the packet 23262306a36Sopenharmony_ci * @qp: the QP for this packet. 23362306a36Sopenharmony_ci * 23462306a36Sopenharmony_ci * This is called from qib_qp_rcv() to process an incoming UC packet 23562306a36Sopenharmony_ci * for the given QP. 23662306a36Sopenharmony_ci * Called at interrupt level. 23762306a36Sopenharmony_ci */ 23862306a36Sopenharmony_civoid qib_uc_rcv(struct qib_ibport *ibp, struct ib_header *hdr, 23962306a36Sopenharmony_ci int has_grh, void *data, u32 tlen, struct rvt_qp *qp) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci struct ib_other_headers *ohdr; 24262306a36Sopenharmony_ci u32 opcode; 24362306a36Sopenharmony_ci u32 hdrsize; 24462306a36Sopenharmony_ci u32 psn; 24562306a36Sopenharmony_ci u32 pad; 24662306a36Sopenharmony_ci struct ib_wc wc; 24762306a36Sopenharmony_ci u32 pmtu = qp->pmtu; 24862306a36Sopenharmony_ci struct ib_reth *reth; 24962306a36Sopenharmony_ci int ret; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* Check for GRH */ 25262306a36Sopenharmony_ci if (!has_grh) { 25362306a36Sopenharmony_ci ohdr = &hdr->u.oth; 25462306a36Sopenharmony_ci hdrsize = 8 + 12; /* LRH + BTH */ 25562306a36Sopenharmony_ci } else { 25662306a36Sopenharmony_ci ohdr = &hdr->u.l.oth; 25762306a36Sopenharmony_ci hdrsize = 8 + 40 + 12; /* LRH + GRH + BTH */ 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci opcode = be32_to_cpu(ohdr->bth[0]); 26162306a36Sopenharmony_ci if (qib_ruc_check_hdr(ibp, hdr, has_grh, qp, opcode)) 26262306a36Sopenharmony_ci return; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci psn = be32_to_cpu(ohdr->bth[2]); 26562306a36Sopenharmony_ci opcode >>= 24; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci /* Compare the PSN verses the expected PSN. */ 26862306a36Sopenharmony_ci if (unlikely(qib_cmp24(psn, qp->r_psn) != 0)) { 26962306a36Sopenharmony_ci /* 27062306a36Sopenharmony_ci * Handle a sequence error. 27162306a36Sopenharmony_ci * Silently drop any current message. 27262306a36Sopenharmony_ci */ 27362306a36Sopenharmony_ci qp->r_psn = psn; 27462306a36Sopenharmony_ciinv: 27562306a36Sopenharmony_ci if (qp->r_state == OP(SEND_FIRST) || 27662306a36Sopenharmony_ci qp->r_state == OP(SEND_MIDDLE)) { 27762306a36Sopenharmony_ci set_bit(RVT_R_REWIND_SGE, &qp->r_aflags); 27862306a36Sopenharmony_ci qp->r_sge.num_sge = 0; 27962306a36Sopenharmony_ci } else 28062306a36Sopenharmony_ci rvt_put_ss(&qp->r_sge); 28162306a36Sopenharmony_ci qp->r_state = OP(SEND_LAST); 28262306a36Sopenharmony_ci switch (opcode) { 28362306a36Sopenharmony_ci case OP(SEND_FIRST): 28462306a36Sopenharmony_ci case OP(SEND_ONLY): 28562306a36Sopenharmony_ci case OP(SEND_ONLY_WITH_IMMEDIATE): 28662306a36Sopenharmony_ci goto send_first; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci case OP(RDMA_WRITE_FIRST): 28962306a36Sopenharmony_ci case OP(RDMA_WRITE_ONLY): 29062306a36Sopenharmony_ci case OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE): 29162306a36Sopenharmony_ci goto rdma_first; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci default: 29462306a36Sopenharmony_ci goto drop; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci /* Check for opcode sequence errors. */ 29962306a36Sopenharmony_ci switch (qp->r_state) { 30062306a36Sopenharmony_ci case OP(SEND_FIRST): 30162306a36Sopenharmony_ci case OP(SEND_MIDDLE): 30262306a36Sopenharmony_ci if (opcode == OP(SEND_MIDDLE) || 30362306a36Sopenharmony_ci opcode == OP(SEND_LAST) || 30462306a36Sopenharmony_ci opcode == OP(SEND_LAST_WITH_IMMEDIATE)) 30562306a36Sopenharmony_ci break; 30662306a36Sopenharmony_ci goto inv; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci case OP(RDMA_WRITE_FIRST): 30962306a36Sopenharmony_ci case OP(RDMA_WRITE_MIDDLE): 31062306a36Sopenharmony_ci if (opcode == OP(RDMA_WRITE_MIDDLE) || 31162306a36Sopenharmony_ci opcode == OP(RDMA_WRITE_LAST) || 31262306a36Sopenharmony_ci opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE)) 31362306a36Sopenharmony_ci break; 31462306a36Sopenharmony_ci goto inv; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci default: 31762306a36Sopenharmony_ci if (opcode == OP(SEND_FIRST) || 31862306a36Sopenharmony_ci opcode == OP(SEND_ONLY) || 31962306a36Sopenharmony_ci opcode == OP(SEND_ONLY_WITH_IMMEDIATE) || 32062306a36Sopenharmony_ci opcode == OP(RDMA_WRITE_FIRST) || 32162306a36Sopenharmony_ci opcode == OP(RDMA_WRITE_ONLY) || 32262306a36Sopenharmony_ci opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE)) 32362306a36Sopenharmony_ci break; 32462306a36Sopenharmony_ci goto inv; 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if (qp->state == IB_QPS_RTR && !(qp->r_flags & RVT_R_COMM_EST)) 32862306a36Sopenharmony_ci rvt_comm_est(qp); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* OK, process the packet. */ 33162306a36Sopenharmony_ci switch (opcode) { 33262306a36Sopenharmony_ci case OP(SEND_FIRST): 33362306a36Sopenharmony_ci case OP(SEND_ONLY): 33462306a36Sopenharmony_ci case OP(SEND_ONLY_WITH_IMMEDIATE): 33562306a36Sopenharmony_cisend_first: 33662306a36Sopenharmony_ci if (test_and_clear_bit(RVT_R_REWIND_SGE, &qp->r_aflags)) 33762306a36Sopenharmony_ci qp->r_sge = qp->s_rdma_read_sge; 33862306a36Sopenharmony_ci else { 33962306a36Sopenharmony_ci ret = rvt_get_rwqe(qp, false); 34062306a36Sopenharmony_ci if (ret < 0) 34162306a36Sopenharmony_ci goto op_err; 34262306a36Sopenharmony_ci if (!ret) 34362306a36Sopenharmony_ci goto drop; 34462306a36Sopenharmony_ci /* 34562306a36Sopenharmony_ci * qp->s_rdma_read_sge will be the owner 34662306a36Sopenharmony_ci * of the mr references. 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_ci qp->s_rdma_read_sge = qp->r_sge; 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci qp->r_rcv_len = 0; 35162306a36Sopenharmony_ci if (opcode == OP(SEND_ONLY)) 35262306a36Sopenharmony_ci goto no_immediate_data; 35362306a36Sopenharmony_ci else if (opcode == OP(SEND_ONLY_WITH_IMMEDIATE)) 35462306a36Sopenharmony_ci goto send_last_imm; 35562306a36Sopenharmony_ci fallthrough; 35662306a36Sopenharmony_ci case OP(SEND_MIDDLE): 35762306a36Sopenharmony_ci /* Check for invalid length PMTU or posted rwqe len. */ 35862306a36Sopenharmony_ci if (unlikely(tlen != (hdrsize + pmtu + 4))) 35962306a36Sopenharmony_ci goto rewind; 36062306a36Sopenharmony_ci qp->r_rcv_len += pmtu; 36162306a36Sopenharmony_ci if (unlikely(qp->r_rcv_len > qp->r_len)) 36262306a36Sopenharmony_ci goto rewind; 36362306a36Sopenharmony_ci rvt_copy_sge(qp, &qp->r_sge, data, pmtu, false, false); 36462306a36Sopenharmony_ci break; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci case OP(SEND_LAST_WITH_IMMEDIATE): 36762306a36Sopenharmony_cisend_last_imm: 36862306a36Sopenharmony_ci wc.ex.imm_data = ohdr->u.imm_data; 36962306a36Sopenharmony_ci hdrsize += 4; 37062306a36Sopenharmony_ci wc.wc_flags = IB_WC_WITH_IMM; 37162306a36Sopenharmony_ci goto send_last; 37262306a36Sopenharmony_ci case OP(SEND_LAST): 37362306a36Sopenharmony_cino_immediate_data: 37462306a36Sopenharmony_ci wc.ex.imm_data = 0; 37562306a36Sopenharmony_ci wc.wc_flags = 0; 37662306a36Sopenharmony_cisend_last: 37762306a36Sopenharmony_ci /* Get the number of bytes the message was padded by. */ 37862306a36Sopenharmony_ci pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; 37962306a36Sopenharmony_ci /* Check for invalid length. */ 38062306a36Sopenharmony_ci /* XXX LAST len should be >= 1 */ 38162306a36Sopenharmony_ci if (unlikely(tlen < (hdrsize + pad + 4))) 38262306a36Sopenharmony_ci goto rewind; 38362306a36Sopenharmony_ci /* Don't count the CRC. */ 38462306a36Sopenharmony_ci tlen -= (hdrsize + pad + 4); 38562306a36Sopenharmony_ci wc.byte_len = tlen + qp->r_rcv_len; 38662306a36Sopenharmony_ci if (unlikely(wc.byte_len > qp->r_len)) 38762306a36Sopenharmony_ci goto rewind; 38862306a36Sopenharmony_ci wc.opcode = IB_WC_RECV; 38962306a36Sopenharmony_ci rvt_copy_sge(qp, &qp->r_sge, data, tlen, false, false); 39062306a36Sopenharmony_ci rvt_put_ss(&qp->s_rdma_read_sge); 39162306a36Sopenharmony_cilast_imm: 39262306a36Sopenharmony_ci wc.wr_id = qp->r_wr_id; 39362306a36Sopenharmony_ci wc.status = IB_WC_SUCCESS; 39462306a36Sopenharmony_ci wc.qp = &qp->ibqp; 39562306a36Sopenharmony_ci wc.src_qp = qp->remote_qpn; 39662306a36Sopenharmony_ci wc.slid = rdma_ah_get_dlid(&qp->remote_ah_attr); 39762306a36Sopenharmony_ci wc.sl = rdma_ah_get_sl(&qp->remote_ah_attr); 39862306a36Sopenharmony_ci /* zero fields that are N/A */ 39962306a36Sopenharmony_ci wc.vendor_err = 0; 40062306a36Sopenharmony_ci wc.pkey_index = 0; 40162306a36Sopenharmony_ci wc.dlid_path_bits = 0; 40262306a36Sopenharmony_ci wc.port_num = 0; 40362306a36Sopenharmony_ci /* Signal completion event if the solicited bit is set. */ 40462306a36Sopenharmony_ci rvt_recv_cq(qp, &wc, ib_bth_is_solicited(ohdr)); 40562306a36Sopenharmony_ci break; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci case OP(RDMA_WRITE_FIRST): 40862306a36Sopenharmony_ci case OP(RDMA_WRITE_ONLY): 40962306a36Sopenharmony_ci case OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE): /* consume RWQE */ 41062306a36Sopenharmony_cirdma_first: 41162306a36Sopenharmony_ci if (unlikely(!(qp->qp_access_flags & 41262306a36Sopenharmony_ci IB_ACCESS_REMOTE_WRITE))) { 41362306a36Sopenharmony_ci goto drop; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci reth = &ohdr->u.rc.reth; 41662306a36Sopenharmony_ci hdrsize += sizeof(*reth); 41762306a36Sopenharmony_ci qp->r_len = be32_to_cpu(reth->length); 41862306a36Sopenharmony_ci qp->r_rcv_len = 0; 41962306a36Sopenharmony_ci qp->r_sge.sg_list = NULL; 42062306a36Sopenharmony_ci if (qp->r_len != 0) { 42162306a36Sopenharmony_ci u32 rkey = be32_to_cpu(reth->rkey); 42262306a36Sopenharmony_ci u64 vaddr = be64_to_cpu(reth->vaddr); 42362306a36Sopenharmony_ci int ok; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci /* Check rkey */ 42662306a36Sopenharmony_ci ok = rvt_rkey_ok(qp, &qp->r_sge.sge, qp->r_len, 42762306a36Sopenharmony_ci vaddr, rkey, IB_ACCESS_REMOTE_WRITE); 42862306a36Sopenharmony_ci if (unlikely(!ok)) 42962306a36Sopenharmony_ci goto drop; 43062306a36Sopenharmony_ci qp->r_sge.num_sge = 1; 43162306a36Sopenharmony_ci } else { 43262306a36Sopenharmony_ci qp->r_sge.num_sge = 0; 43362306a36Sopenharmony_ci qp->r_sge.sge.mr = NULL; 43462306a36Sopenharmony_ci qp->r_sge.sge.vaddr = NULL; 43562306a36Sopenharmony_ci qp->r_sge.sge.length = 0; 43662306a36Sopenharmony_ci qp->r_sge.sge.sge_length = 0; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci if (opcode == OP(RDMA_WRITE_ONLY)) 43962306a36Sopenharmony_ci goto rdma_last; 44062306a36Sopenharmony_ci else if (opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE)) { 44162306a36Sopenharmony_ci wc.ex.imm_data = ohdr->u.rc.imm_data; 44262306a36Sopenharmony_ci goto rdma_last_imm; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci fallthrough; 44562306a36Sopenharmony_ci case OP(RDMA_WRITE_MIDDLE): 44662306a36Sopenharmony_ci /* Check for invalid length PMTU or posted rwqe len. */ 44762306a36Sopenharmony_ci if (unlikely(tlen != (hdrsize + pmtu + 4))) 44862306a36Sopenharmony_ci goto drop; 44962306a36Sopenharmony_ci qp->r_rcv_len += pmtu; 45062306a36Sopenharmony_ci if (unlikely(qp->r_rcv_len > qp->r_len)) 45162306a36Sopenharmony_ci goto drop; 45262306a36Sopenharmony_ci rvt_copy_sge(qp, &qp->r_sge, data, pmtu, true, false); 45362306a36Sopenharmony_ci break; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE): 45662306a36Sopenharmony_ci wc.ex.imm_data = ohdr->u.imm_data; 45762306a36Sopenharmony_cirdma_last_imm: 45862306a36Sopenharmony_ci hdrsize += 4; 45962306a36Sopenharmony_ci wc.wc_flags = IB_WC_WITH_IMM; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci /* Get the number of bytes the message was padded by. */ 46262306a36Sopenharmony_ci pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; 46362306a36Sopenharmony_ci /* Check for invalid length. */ 46462306a36Sopenharmony_ci /* XXX LAST len should be >= 1 */ 46562306a36Sopenharmony_ci if (unlikely(tlen < (hdrsize + pad + 4))) 46662306a36Sopenharmony_ci goto drop; 46762306a36Sopenharmony_ci /* Don't count the CRC. */ 46862306a36Sopenharmony_ci tlen -= (hdrsize + pad + 4); 46962306a36Sopenharmony_ci if (unlikely(tlen + qp->r_rcv_len != qp->r_len)) 47062306a36Sopenharmony_ci goto drop; 47162306a36Sopenharmony_ci if (test_and_clear_bit(RVT_R_REWIND_SGE, &qp->r_aflags)) 47262306a36Sopenharmony_ci rvt_put_ss(&qp->s_rdma_read_sge); 47362306a36Sopenharmony_ci else { 47462306a36Sopenharmony_ci ret = rvt_get_rwqe(qp, true); 47562306a36Sopenharmony_ci if (ret < 0) 47662306a36Sopenharmony_ci goto op_err; 47762306a36Sopenharmony_ci if (!ret) 47862306a36Sopenharmony_ci goto drop; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci wc.byte_len = qp->r_len; 48162306a36Sopenharmony_ci wc.opcode = IB_WC_RECV_RDMA_WITH_IMM; 48262306a36Sopenharmony_ci rvt_copy_sge(qp, &qp->r_sge, data, tlen, true, false); 48362306a36Sopenharmony_ci rvt_put_ss(&qp->r_sge); 48462306a36Sopenharmony_ci goto last_imm; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci case OP(RDMA_WRITE_LAST): 48762306a36Sopenharmony_cirdma_last: 48862306a36Sopenharmony_ci /* Get the number of bytes the message was padded by. */ 48962306a36Sopenharmony_ci pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; 49062306a36Sopenharmony_ci /* Check for invalid length. */ 49162306a36Sopenharmony_ci /* XXX LAST len should be >= 1 */ 49262306a36Sopenharmony_ci if (unlikely(tlen < (hdrsize + pad + 4))) 49362306a36Sopenharmony_ci goto drop; 49462306a36Sopenharmony_ci /* Don't count the CRC. */ 49562306a36Sopenharmony_ci tlen -= (hdrsize + pad + 4); 49662306a36Sopenharmony_ci if (unlikely(tlen + qp->r_rcv_len != qp->r_len)) 49762306a36Sopenharmony_ci goto drop; 49862306a36Sopenharmony_ci rvt_copy_sge(qp, &qp->r_sge, data, tlen, true, false); 49962306a36Sopenharmony_ci rvt_put_ss(&qp->r_sge); 50062306a36Sopenharmony_ci break; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci default: 50362306a36Sopenharmony_ci /* Drop packet for unknown opcodes. */ 50462306a36Sopenharmony_ci goto drop; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci qp->r_psn++; 50762306a36Sopenharmony_ci qp->r_state = opcode; 50862306a36Sopenharmony_ci return; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cirewind: 51162306a36Sopenharmony_ci set_bit(RVT_R_REWIND_SGE, &qp->r_aflags); 51262306a36Sopenharmony_ci qp->r_sge.num_sge = 0; 51362306a36Sopenharmony_cidrop: 51462306a36Sopenharmony_ci ibp->rvp.n_pkt_drops++; 51562306a36Sopenharmony_ci return; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ciop_err: 51862306a36Sopenharmony_ci rvt_rc_error(qp, IB_WC_LOC_QP_OP_ERR); 51962306a36Sopenharmony_ci return; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci} 522