162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/skbuff.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "rxe.h" 1062306a36Sopenharmony_ci#include "rxe_loc.h" 1162306a36Sopenharmony_ci#include "rxe_queue.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_cistatic char *resp_state_name[] = { 1462306a36Sopenharmony_ci [RESPST_NONE] = "NONE", 1562306a36Sopenharmony_ci [RESPST_GET_REQ] = "GET_REQ", 1662306a36Sopenharmony_ci [RESPST_CHK_PSN] = "CHK_PSN", 1762306a36Sopenharmony_ci [RESPST_CHK_OP_SEQ] = "CHK_OP_SEQ", 1862306a36Sopenharmony_ci [RESPST_CHK_OP_VALID] = "CHK_OP_VALID", 1962306a36Sopenharmony_ci [RESPST_CHK_RESOURCE] = "CHK_RESOURCE", 2062306a36Sopenharmony_ci [RESPST_CHK_LENGTH] = "CHK_LENGTH", 2162306a36Sopenharmony_ci [RESPST_CHK_RKEY] = "CHK_RKEY", 2262306a36Sopenharmony_ci [RESPST_EXECUTE] = "EXECUTE", 2362306a36Sopenharmony_ci [RESPST_READ_REPLY] = "READ_REPLY", 2462306a36Sopenharmony_ci [RESPST_ATOMIC_REPLY] = "ATOMIC_REPLY", 2562306a36Sopenharmony_ci [RESPST_ATOMIC_WRITE_REPLY] = "ATOMIC_WRITE_REPLY", 2662306a36Sopenharmony_ci [RESPST_PROCESS_FLUSH] = "PROCESS_FLUSH", 2762306a36Sopenharmony_ci [RESPST_COMPLETE] = "COMPLETE", 2862306a36Sopenharmony_ci [RESPST_ACKNOWLEDGE] = "ACKNOWLEDGE", 2962306a36Sopenharmony_ci [RESPST_CLEANUP] = "CLEANUP", 3062306a36Sopenharmony_ci [RESPST_DUPLICATE_REQUEST] = "DUPLICATE_REQUEST", 3162306a36Sopenharmony_ci [RESPST_ERR_MALFORMED_WQE] = "ERR_MALFORMED_WQE", 3262306a36Sopenharmony_ci [RESPST_ERR_UNSUPPORTED_OPCODE] = "ERR_UNSUPPORTED_OPCODE", 3362306a36Sopenharmony_ci [RESPST_ERR_MISALIGNED_ATOMIC] = "ERR_MISALIGNED_ATOMIC", 3462306a36Sopenharmony_ci [RESPST_ERR_PSN_OUT_OF_SEQ] = "ERR_PSN_OUT_OF_SEQ", 3562306a36Sopenharmony_ci [RESPST_ERR_MISSING_OPCODE_FIRST] = "ERR_MISSING_OPCODE_FIRST", 3662306a36Sopenharmony_ci [RESPST_ERR_MISSING_OPCODE_LAST_C] = "ERR_MISSING_OPCODE_LAST_C", 3762306a36Sopenharmony_ci [RESPST_ERR_MISSING_OPCODE_LAST_D1E] = "ERR_MISSING_OPCODE_LAST_D1E", 3862306a36Sopenharmony_ci [RESPST_ERR_TOO_MANY_RDMA_ATM_REQ] = "ERR_TOO_MANY_RDMA_ATM_REQ", 3962306a36Sopenharmony_ci [RESPST_ERR_RNR] = "ERR_RNR", 4062306a36Sopenharmony_ci [RESPST_ERR_RKEY_VIOLATION] = "ERR_RKEY_VIOLATION", 4162306a36Sopenharmony_ci [RESPST_ERR_INVALIDATE_RKEY] = "ERR_INVALIDATE_RKEY_VIOLATION", 4262306a36Sopenharmony_ci [RESPST_ERR_LENGTH] = "ERR_LENGTH", 4362306a36Sopenharmony_ci [RESPST_ERR_CQ_OVERFLOW] = "ERR_CQ_OVERFLOW", 4462306a36Sopenharmony_ci [RESPST_ERROR] = "ERROR", 4562306a36Sopenharmony_ci [RESPST_DONE] = "DONE", 4662306a36Sopenharmony_ci [RESPST_EXIT] = "EXIT", 4762306a36Sopenharmony_ci}; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* rxe_recv calls here to add a request packet to the input queue */ 5062306a36Sopenharmony_civoid rxe_resp_queue_pkt(struct rxe_qp *qp, struct sk_buff *skb) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci int must_sched; 5362306a36Sopenharmony_ci struct rxe_pkt_info *pkt = SKB_TO_PKT(skb); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci skb_queue_tail(&qp->req_pkts, skb); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci must_sched = (pkt->opcode == IB_OPCODE_RC_RDMA_READ_REQUEST) || 5862306a36Sopenharmony_ci (skb_queue_len(&qp->req_pkts) > 1); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci if (must_sched) 6162306a36Sopenharmony_ci rxe_sched_task(&qp->resp.task); 6262306a36Sopenharmony_ci else 6362306a36Sopenharmony_ci rxe_run_task(&qp->resp.task); 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic inline enum resp_states get_req(struct rxe_qp *qp, 6762306a36Sopenharmony_ci struct rxe_pkt_info **pkt_p) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci struct sk_buff *skb; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci skb = skb_peek(&qp->req_pkts); 7262306a36Sopenharmony_ci if (!skb) 7362306a36Sopenharmony_ci return RESPST_EXIT; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci *pkt_p = SKB_TO_PKT(skb); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci return (qp->resp.res) ? RESPST_READ_REPLY : RESPST_CHK_PSN; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic enum resp_states check_psn(struct rxe_qp *qp, 8162306a36Sopenharmony_ci struct rxe_pkt_info *pkt) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci int diff = psn_compare(pkt->psn, qp->resp.psn); 8462306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(qp->ibqp.device); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci switch (qp_type(qp)) { 8762306a36Sopenharmony_ci case IB_QPT_RC: 8862306a36Sopenharmony_ci if (diff > 0) { 8962306a36Sopenharmony_ci if (qp->resp.sent_psn_nak) 9062306a36Sopenharmony_ci return RESPST_CLEANUP; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci qp->resp.sent_psn_nak = 1; 9362306a36Sopenharmony_ci rxe_counter_inc(rxe, RXE_CNT_OUT_OF_SEQ_REQ); 9462306a36Sopenharmony_ci return RESPST_ERR_PSN_OUT_OF_SEQ; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci } else if (diff < 0) { 9762306a36Sopenharmony_ci rxe_counter_inc(rxe, RXE_CNT_DUP_REQ); 9862306a36Sopenharmony_ci return RESPST_DUPLICATE_REQUEST; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (qp->resp.sent_psn_nak) 10262306a36Sopenharmony_ci qp->resp.sent_psn_nak = 0; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci break; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci case IB_QPT_UC: 10762306a36Sopenharmony_ci if (qp->resp.drop_msg || diff != 0) { 10862306a36Sopenharmony_ci if (pkt->mask & RXE_START_MASK) { 10962306a36Sopenharmony_ci qp->resp.drop_msg = 0; 11062306a36Sopenharmony_ci return RESPST_CHK_OP_SEQ; 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci qp->resp.drop_msg = 1; 11462306a36Sopenharmony_ci return RESPST_CLEANUP; 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci break; 11762306a36Sopenharmony_ci default: 11862306a36Sopenharmony_ci break; 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci return RESPST_CHK_OP_SEQ; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic enum resp_states check_op_seq(struct rxe_qp *qp, 12562306a36Sopenharmony_ci struct rxe_pkt_info *pkt) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci switch (qp_type(qp)) { 12862306a36Sopenharmony_ci case IB_QPT_RC: 12962306a36Sopenharmony_ci switch (qp->resp.opcode) { 13062306a36Sopenharmony_ci case IB_OPCODE_RC_SEND_FIRST: 13162306a36Sopenharmony_ci case IB_OPCODE_RC_SEND_MIDDLE: 13262306a36Sopenharmony_ci switch (pkt->opcode) { 13362306a36Sopenharmony_ci case IB_OPCODE_RC_SEND_MIDDLE: 13462306a36Sopenharmony_ci case IB_OPCODE_RC_SEND_LAST: 13562306a36Sopenharmony_ci case IB_OPCODE_RC_SEND_LAST_WITH_IMMEDIATE: 13662306a36Sopenharmony_ci case IB_OPCODE_RC_SEND_LAST_WITH_INVALIDATE: 13762306a36Sopenharmony_ci return RESPST_CHK_OP_VALID; 13862306a36Sopenharmony_ci default: 13962306a36Sopenharmony_ci return RESPST_ERR_MISSING_OPCODE_LAST_C; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci case IB_OPCODE_RC_RDMA_WRITE_FIRST: 14362306a36Sopenharmony_ci case IB_OPCODE_RC_RDMA_WRITE_MIDDLE: 14462306a36Sopenharmony_ci switch (pkt->opcode) { 14562306a36Sopenharmony_ci case IB_OPCODE_RC_RDMA_WRITE_MIDDLE: 14662306a36Sopenharmony_ci case IB_OPCODE_RC_RDMA_WRITE_LAST: 14762306a36Sopenharmony_ci case IB_OPCODE_RC_RDMA_WRITE_LAST_WITH_IMMEDIATE: 14862306a36Sopenharmony_ci return RESPST_CHK_OP_VALID; 14962306a36Sopenharmony_ci default: 15062306a36Sopenharmony_ci return RESPST_ERR_MISSING_OPCODE_LAST_C; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci default: 15462306a36Sopenharmony_ci switch (pkt->opcode) { 15562306a36Sopenharmony_ci case IB_OPCODE_RC_SEND_MIDDLE: 15662306a36Sopenharmony_ci case IB_OPCODE_RC_SEND_LAST: 15762306a36Sopenharmony_ci case IB_OPCODE_RC_SEND_LAST_WITH_IMMEDIATE: 15862306a36Sopenharmony_ci case IB_OPCODE_RC_SEND_LAST_WITH_INVALIDATE: 15962306a36Sopenharmony_ci case IB_OPCODE_RC_RDMA_WRITE_MIDDLE: 16062306a36Sopenharmony_ci case IB_OPCODE_RC_RDMA_WRITE_LAST: 16162306a36Sopenharmony_ci case IB_OPCODE_RC_RDMA_WRITE_LAST_WITH_IMMEDIATE: 16262306a36Sopenharmony_ci return RESPST_ERR_MISSING_OPCODE_FIRST; 16362306a36Sopenharmony_ci default: 16462306a36Sopenharmony_ci return RESPST_CHK_OP_VALID; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci break; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci case IB_QPT_UC: 17062306a36Sopenharmony_ci switch (qp->resp.opcode) { 17162306a36Sopenharmony_ci case IB_OPCODE_UC_SEND_FIRST: 17262306a36Sopenharmony_ci case IB_OPCODE_UC_SEND_MIDDLE: 17362306a36Sopenharmony_ci switch (pkt->opcode) { 17462306a36Sopenharmony_ci case IB_OPCODE_UC_SEND_MIDDLE: 17562306a36Sopenharmony_ci case IB_OPCODE_UC_SEND_LAST: 17662306a36Sopenharmony_ci case IB_OPCODE_UC_SEND_LAST_WITH_IMMEDIATE: 17762306a36Sopenharmony_ci return RESPST_CHK_OP_VALID; 17862306a36Sopenharmony_ci default: 17962306a36Sopenharmony_ci return RESPST_ERR_MISSING_OPCODE_LAST_D1E; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci case IB_OPCODE_UC_RDMA_WRITE_FIRST: 18362306a36Sopenharmony_ci case IB_OPCODE_UC_RDMA_WRITE_MIDDLE: 18462306a36Sopenharmony_ci switch (pkt->opcode) { 18562306a36Sopenharmony_ci case IB_OPCODE_UC_RDMA_WRITE_MIDDLE: 18662306a36Sopenharmony_ci case IB_OPCODE_UC_RDMA_WRITE_LAST: 18762306a36Sopenharmony_ci case IB_OPCODE_UC_RDMA_WRITE_LAST_WITH_IMMEDIATE: 18862306a36Sopenharmony_ci return RESPST_CHK_OP_VALID; 18962306a36Sopenharmony_ci default: 19062306a36Sopenharmony_ci return RESPST_ERR_MISSING_OPCODE_LAST_D1E; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci default: 19462306a36Sopenharmony_ci switch (pkt->opcode) { 19562306a36Sopenharmony_ci case IB_OPCODE_UC_SEND_MIDDLE: 19662306a36Sopenharmony_ci case IB_OPCODE_UC_SEND_LAST: 19762306a36Sopenharmony_ci case IB_OPCODE_UC_SEND_LAST_WITH_IMMEDIATE: 19862306a36Sopenharmony_ci case IB_OPCODE_UC_RDMA_WRITE_MIDDLE: 19962306a36Sopenharmony_ci case IB_OPCODE_UC_RDMA_WRITE_LAST: 20062306a36Sopenharmony_ci case IB_OPCODE_UC_RDMA_WRITE_LAST_WITH_IMMEDIATE: 20162306a36Sopenharmony_ci qp->resp.drop_msg = 1; 20262306a36Sopenharmony_ci return RESPST_CLEANUP; 20362306a36Sopenharmony_ci default: 20462306a36Sopenharmony_ci return RESPST_CHK_OP_VALID; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci break; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci default: 21062306a36Sopenharmony_ci return RESPST_CHK_OP_VALID; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic bool check_qp_attr_access(struct rxe_qp *qp, 21562306a36Sopenharmony_ci struct rxe_pkt_info *pkt) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci if (((pkt->mask & RXE_READ_MASK) && 21862306a36Sopenharmony_ci !(qp->attr.qp_access_flags & IB_ACCESS_REMOTE_READ)) || 21962306a36Sopenharmony_ci ((pkt->mask & (RXE_WRITE_MASK | RXE_ATOMIC_WRITE_MASK)) && 22062306a36Sopenharmony_ci !(qp->attr.qp_access_flags & IB_ACCESS_REMOTE_WRITE)) || 22162306a36Sopenharmony_ci ((pkt->mask & RXE_ATOMIC_MASK) && 22262306a36Sopenharmony_ci !(qp->attr.qp_access_flags & IB_ACCESS_REMOTE_ATOMIC))) 22362306a36Sopenharmony_ci return false; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (pkt->mask & RXE_FLUSH_MASK) { 22662306a36Sopenharmony_ci u32 flush_type = feth_plt(pkt); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if ((flush_type & IB_FLUSH_GLOBAL && 22962306a36Sopenharmony_ci !(qp->attr.qp_access_flags & IB_ACCESS_FLUSH_GLOBAL)) || 23062306a36Sopenharmony_ci (flush_type & IB_FLUSH_PERSISTENT && 23162306a36Sopenharmony_ci !(qp->attr.qp_access_flags & IB_ACCESS_FLUSH_PERSISTENT))) 23262306a36Sopenharmony_ci return false; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci return true; 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic enum resp_states check_op_valid(struct rxe_qp *qp, 23962306a36Sopenharmony_ci struct rxe_pkt_info *pkt) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci switch (qp_type(qp)) { 24262306a36Sopenharmony_ci case IB_QPT_RC: 24362306a36Sopenharmony_ci if (!check_qp_attr_access(qp, pkt)) 24462306a36Sopenharmony_ci return RESPST_ERR_UNSUPPORTED_OPCODE; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci break; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci case IB_QPT_UC: 24962306a36Sopenharmony_ci if ((pkt->mask & RXE_WRITE_MASK) && 25062306a36Sopenharmony_ci !(qp->attr.qp_access_flags & IB_ACCESS_REMOTE_WRITE)) { 25162306a36Sopenharmony_ci qp->resp.drop_msg = 1; 25262306a36Sopenharmony_ci return RESPST_CLEANUP; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci break; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci case IB_QPT_UD: 25862306a36Sopenharmony_ci case IB_QPT_GSI: 25962306a36Sopenharmony_ci break; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci default: 26262306a36Sopenharmony_ci WARN_ON_ONCE(1); 26362306a36Sopenharmony_ci break; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci return RESPST_CHK_RESOURCE; 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic enum resp_states get_srq_wqe(struct rxe_qp *qp) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci struct rxe_srq *srq = qp->srq; 27262306a36Sopenharmony_ci struct rxe_queue *q = srq->rq.queue; 27362306a36Sopenharmony_ci struct rxe_recv_wqe *wqe; 27462306a36Sopenharmony_ci struct ib_event ev; 27562306a36Sopenharmony_ci unsigned int count; 27662306a36Sopenharmony_ci size_t size; 27762306a36Sopenharmony_ci unsigned long flags; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (srq->error) 28062306a36Sopenharmony_ci return RESPST_ERR_RNR; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci spin_lock_irqsave(&srq->rq.consumer_lock, flags); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci wqe = queue_head(q, QUEUE_TYPE_FROM_CLIENT); 28562306a36Sopenharmony_ci if (!wqe) { 28662306a36Sopenharmony_ci spin_unlock_irqrestore(&srq->rq.consumer_lock, flags); 28762306a36Sopenharmony_ci return RESPST_ERR_RNR; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* don't trust user space data */ 29162306a36Sopenharmony_ci if (unlikely(wqe->dma.num_sge > srq->rq.max_sge)) { 29262306a36Sopenharmony_ci spin_unlock_irqrestore(&srq->rq.consumer_lock, flags); 29362306a36Sopenharmony_ci rxe_dbg_qp(qp, "invalid num_sge in SRQ entry\n"); 29462306a36Sopenharmony_ci return RESPST_ERR_MALFORMED_WQE; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci size = sizeof(*wqe) + wqe->dma.num_sge*sizeof(struct rxe_sge); 29762306a36Sopenharmony_ci memcpy(&qp->resp.srq_wqe, wqe, size); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci qp->resp.wqe = &qp->resp.srq_wqe.wqe; 30062306a36Sopenharmony_ci queue_advance_consumer(q, QUEUE_TYPE_FROM_CLIENT); 30162306a36Sopenharmony_ci count = queue_count(q, QUEUE_TYPE_FROM_CLIENT); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci if (srq->limit && srq->ibsrq.event_handler && (count < srq->limit)) { 30462306a36Sopenharmony_ci srq->limit = 0; 30562306a36Sopenharmony_ci goto event; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci spin_unlock_irqrestore(&srq->rq.consumer_lock, flags); 30962306a36Sopenharmony_ci return RESPST_CHK_LENGTH; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cievent: 31262306a36Sopenharmony_ci spin_unlock_irqrestore(&srq->rq.consumer_lock, flags); 31362306a36Sopenharmony_ci ev.device = qp->ibqp.device; 31462306a36Sopenharmony_ci ev.element.srq = qp->ibqp.srq; 31562306a36Sopenharmony_ci ev.event = IB_EVENT_SRQ_LIMIT_REACHED; 31662306a36Sopenharmony_ci srq->ibsrq.event_handler(&ev, srq->ibsrq.srq_context); 31762306a36Sopenharmony_ci return RESPST_CHK_LENGTH; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic enum resp_states check_resource(struct rxe_qp *qp, 32162306a36Sopenharmony_ci struct rxe_pkt_info *pkt) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci struct rxe_srq *srq = qp->srq; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if (pkt->mask & (RXE_READ_OR_ATOMIC_MASK | RXE_ATOMIC_WRITE_MASK)) { 32662306a36Sopenharmony_ci /* it is the requesters job to not send 32762306a36Sopenharmony_ci * too many read/atomic ops, we just 32862306a36Sopenharmony_ci * recycle the responder resource queue 32962306a36Sopenharmony_ci */ 33062306a36Sopenharmony_ci if (likely(qp->attr.max_dest_rd_atomic > 0)) 33162306a36Sopenharmony_ci return RESPST_CHK_LENGTH; 33262306a36Sopenharmony_ci else 33362306a36Sopenharmony_ci return RESPST_ERR_TOO_MANY_RDMA_ATM_REQ; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (pkt->mask & RXE_RWR_MASK) { 33762306a36Sopenharmony_ci if (srq) 33862306a36Sopenharmony_ci return get_srq_wqe(qp); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci qp->resp.wqe = queue_head(qp->rq.queue, 34162306a36Sopenharmony_ci QUEUE_TYPE_FROM_CLIENT); 34262306a36Sopenharmony_ci return (qp->resp.wqe) ? RESPST_CHK_LENGTH : RESPST_ERR_RNR; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci return RESPST_CHK_LENGTH; 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic enum resp_states rxe_resp_check_length(struct rxe_qp *qp, 34962306a36Sopenharmony_ci struct rxe_pkt_info *pkt) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci /* 35262306a36Sopenharmony_ci * See IBA C9-92 35362306a36Sopenharmony_ci * For UD QPs we only check if the packet will fit in the 35462306a36Sopenharmony_ci * receive buffer later. For rmda operations additional 35562306a36Sopenharmony_ci * length checks are performed in check_rkey. 35662306a36Sopenharmony_ci */ 35762306a36Sopenharmony_ci if (pkt->mask & RXE_PAYLOAD_MASK && ((qp_type(qp) == IB_QPT_RC) || 35862306a36Sopenharmony_ci (qp_type(qp) == IB_QPT_UC))) { 35962306a36Sopenharmony_ci unsigned int mtu = qp->mtu; 36062306a36Sopenharmony_ci unsigned int payload = payload_size(pkt); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci if ((pkt->mask & RXE_START_MASK) && 36362306a36Sopenharmony_ci (pkt->mask & RXE_END_MASK)) { 36462306a36Sopenharmony_ci if (unlikely(payload > mtu)) { 36562306a36Sopenharmony_ci rxe_dbg_qp(qp, "only packet too long"); 36662306a36Sopenharmony_ci return RESPST_ERR_LENGTH; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci } else if ((pkt->mask & RXE_START_MASK) || 36962306a36Sopenharmony_ci (pkt->mask & RXE_MIDDLE_MASK)) { 37062306a36Sopenharmony_ci if (unlikely(payload != mtu)) { 37162306a36Sopenharmony_ci rxe_dbg_qp(qp, "first or middle packet not mtu"); 37262306a36Sopenharmony_ci return RESPST_ERR_LENGTH; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci } else if (pkt->mask & RXE_END_MASK) { 37562306a36Sopenharmony_ci if (unlikely((payload == 0) || (payload > mtu))) { 37662306a36Sopenharmony_ci rxe_dbg_qp(qp, "last packet zero or too long"); 37762306a36Sopenharmony_ci return RESPST_ERR_LENGTH; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci /* See IBA C9-94 */ 38362306a36Sopenharmony_ci if (pkt->mask & RXE_RETH_MASK) { 38462306a36Sopenharmony_ci if (reth_len(pkt) > (1U << 31)) { 38562306a36Sopenharmony_ci rxe_dbg_qp(qp, "dma length too long"); 38662306a36Sopenharmony_ci return RESPST_ERR_LENGTH; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if (pkt->mask & RXE_RDMA_OP_MASK) 39162306a36Sopenharmony_ci return RESPST_CHK_RKEY; 39262306a36Sopenharmony_ci else 39362306a36Sopenharmony_ci return RESPST_EXECUTE; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci/* if the reth length field is zero we can assume nothing 39762306a36Sopenharmony_ci * about the rkey value and should not validate or use it. 39862306a36Sopenharmony_ci * Instead set qp->resp.rkey to 0 which is an invalid rkey 39962306a36Sopenharmony_ci * value since the minimum index part is 1. 40062306a36Sopenharmony_ci */ 40162306a36Sopenharmony_cistatic void qp_resp_from_reth(struct rxe_qp *qp, struct rxe_pkt_info *pkt) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci unsigned int length = reth_len(pkt); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci qp->resp.va = reth_va(pkt); 40662306a36Sopenharmony_ci qp->resp.offset = 0; 40762306a36Sopenharmony_ci qp->resp.resid = length; 40862306a36Sopenharmony_ci qp->resp.length = length; 40962306a36Sopenharmony_ci if (pkt->mask & RXE_READ_OR_WRITE_MASK && length == 0) 41062306a36Sopenharmony_ci qp->resp.rkey = 0; 41162306a36Sopenharmony_ci else 41262306a36Sopenharmony_ci qp->resp.rkey = reth_rkey(pkt); 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic void qp_resp_from_atmeth(struct rxe_qp *qp, struct rxe_pkt_info *pkt) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci qp->resp.va = atmeth_va(pkt); 41862306a36Sopenharmony_ci qp->resp.offset = 0; 41962306a36Sopenharmony_ci qp->resp.rkey = atmeth_rkey(pkt); 42062306a36Sopenharmony_ci qp->resp.resid = sizeof(u64); 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci/* resolve the packet rkey to qp->resp.mr or set qp->resp.mr to NULL 42462306a36Sopenharmony_ci * if an invalid rkey is received or the rdma length is zero. For middle 42562306a36Sopenharmony_ci * or last packets use the stored value of mr. 42662306a36Sopenharmony_ci */ 42762306a36Sopenharmony_cistatic enum resp_states check_rkey(struct rxe_qp *qp, 42862306a36Sopenharmony_ci struct rxe_pkt_info *pkt) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci struct rxe_mr *mr = NULL; 43162306a36Sopenharmony_ci struct rxe_mw *mw = NULL; 43262306a36Sopenharmony_ci u64 va; 43362306a36Sopenharmony_ci u32 rkey; 43462306a36Sopenharmony_ci u32 resid; 43562306a36Sopenharmony_ci u32 pktlen; 43662306a36Sopenharmony_ci int mtu = qp->mtu; 43762306a36Sopenharmony_ci enum resp_states state; 43862306a36Sopenharmony_ci int access = 0; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci /* parse RETH or ATMETH header for first/only packets 44162306a36Sopenharmony_ci * for va, length, rkey, etc. or use current value for 44262306a36Sopenharmony_ci * middle/last packets. 44362306a36Sopenharmony_ci */ 44462306a36Sopenharmony_ci if (pkt->mask & (RXE_READ_OR_WRITE_MASK | RXE_ATOMIC_WRITE_MASK)) { 44562306a36Sopenharmony_ci if (pkt->mask & RXE_RETH_MASK) 44662306a36Sopenharmony_ci qp_resp_from_reth(qp, pkt); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci access = (pkt->mask & RXE_READ_MASK) ? IB_ACCESS_REMOTE_READ 44962306a36Sopenharmony_ci : IB_ACCESS_REMOTE_WRITE; 45062306a36Sopenharmony_ci } else if (pkt->mask & RXE_FLUSH_MASK) { 45162306a36Sopenharmony_ci u32 flush_type = feth_plt(pkt); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if (pkt->mask & RXE_RETH_MASK) 45462306a36Sopenharmony_ci qp_resp_from_reth(qp, pkt); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci if (flush_type & IB_FLUSH_GLOBAL) 45762306a36Sopenharmony_ci access |= IB_ACCESS_FLUSH_GLOBAL; 45862306a36Sopenharmony_ci if (flush_type & IB_FLUSH_PERSISTENT) 45962306a36Sopenharmony_ci access |= IB_ACCESS_FLUSH_PERSISTENT; 46062306a36Sopenharmony_ci } else if (pkt->mask & RXE_ATOMIC_MASK) { 46162306a36Sopenharmony_ci qp_resp_from_atmeth(qp, pkt); 46262306a36Sopenharmony_ci access = IB_ACCESS_REMOTE_ATOMIC; 46362306a36Sopenharmony_ci } else { 46462306a36Sopenharmony_ci /* shouldn't happen */ 46562306a36Sopenharmony_ci WARN_ON(1); 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci /* A zero-byte read or write op is not required to 46962306a36Sopenharmony_ci * set an addr or rkey. See C9-88 47062306a36Sopenharmony_ci */ 47162306a36Sopenharmony_ci if ((pkt->mask & RXE_READ_OR_WRITE_MASK) && 47262306a36Sopenharmony_ci (pkt->mask & RXE_RETH_MASK) && reth_len(pkt) == 0) { 47362306a36Sopenharmony_ci qp->resp.mr = NULL; 47462306a36Sopenharmony_ci return RESPST_EXECUTE; 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci va = qp->resp.va; 47862306a36Sopenharmony_ci rkey = qp->resp.rkey; 47962306a36Sopenharmony_ci resid = qp->resp.resid; 48062306a36Sopenharmony_ci pktlen = payload_size(pkt); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci if (rkey_is_mw(rkey)) { 48362306a36Sopenharmony_ci mw = rxe_lookup_mw(qp, access, rkey); 48462306a36Sopenharmony_ci if (!mw) { 48562306a36Sopenharmony_ci rxe_dbg_qp(qp, "no MW matches rkey %#x\n", rkey); 48662306a36Sopenharmony_ci state = RESPST_ERR_RKEY_VIOLATION; 48762306a36Sopenharmony_ci goto err; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci mr = mw->mr; 49162306a36Sopenharmony_ci if (!mr) { 49262306a36Sopenharmony_ci rxe_dbg_qp(qp, "MW doesn't have an MR\n"); 49362306a36Sopenharmony_ci state = RESPST_ERR_RKEY_VIOLATION; 49462306a36Sopenharmony_ci goto err; 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (mw->access & IB_ZERO_BASED) 49862306a36Sopenharmony_ci qp->resp.offset = mw->addr; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci rxe_get(mr); 50162306a36Sopenharmony_ci rxe_put(mw); 50262306a36Sopenharmony_ci mw = NULL; 50362306a36Sopenharmony_ci } else { 50462306a36Sopenharmony_ci mr = lookup_mr(qp->pd, access, rkey, RXE_LOOKUP_REMOTE); 50562306a36Sopenharmony_ci if (!mr) { 50662306a36Sopenharmony_ci rxe_dbg_qp(qp, "no MR matches rkey %#x\n", rkey); 50762306a36Sopenharmony_ci state = RESPST_ERR_RKEY_VIOLATION; 50862306a36Sopenharmony_ci goto err; 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci if (pkt->mask & RXE_FLUSH_MASK) { 51362306a36Sopenharmony_ci /* FLUSH MR may not set va or resid 51462306a36Sopenharmony_ci * no need to check range since we will flush whole mr 51562306a36Sopenharmony_ci */ 51662306a36Sopenharmony_ci if (feth_sel(pkt) == IB_FLUSH_MR) 51762306a36Sopenharmony_ci goto skip_check_range; 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci if (mr_check_range(mr, va + qp->resp.offset, resid)) { 52162306a36Sopenharmony_ci state = RESPST_ERR_RKEY_VIOLATION; 52262306a36Sopenharmony_ci goto err; 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ciskip_check_range: 52662306a36Sopenharmony_ci if (pkt->mask & (RXE_WRITE_MASK | RXE_ATOMIC_WRITE_MASK)) { 52762306a36Sopenharmony_ci if (resid > mtu) { 52862306a36Sopenharmony_ci if (pktlen != mtu || bth_pad(pkt)) { 52962306a36Sopenharmony_ci state = RESPST_ERR_LENGTH; 53062306a36Sopenharmony_ci goto err; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci } else { 53362306a36Sopenharmony_ci if (pktlen != resid) { 53462306a36Sopenharmony_ci state = RESPST_ERR_LENGTH; 53562306a36Sopenharmony_ci goto err; 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci if ((bth_pad(pkt) != (0x3 & (-resid)))) { 53862306a36Sopenharmony_ci /* This case may not be exactly that 53962306a36Sopenharmony_ci * but nothing else fits. 54062306a36Sopenharmony_ci */ 54162306a36Sopenharmony_ci state = RESPST_ERR_LENGTH; 54262306a36Sopenharmony_ci goto err; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci WARN_ON_ONCE(qp->resp.mr); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci qp->resp.mr = mr; 55062306a36Sopenharmony_ci return RESPST_EXECUTE; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_cierr: 55362306a36Sopenharmony_ci qp->resp.mr = NULL; 55462306a36Sopenharmony_ci if (mr) 55562306a36Sopenharmony_ci rxe_put(mr); 55662306a36Sopenharmony_ci if (mw) 55762306a36Sopenharmony_ci rxe_put(mw); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci return state; 56062306a36Sopenharmony_ci} 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_cistatic enum resp_states send_data_in(struct rxe_qp *qp, void *data_addr, 56362306a36Sopenharmony_ci int data_len) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci int err; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci err = copy_data(qp->pd, IB_ACCESS_LOCAL_WRITE, &qp->resp.wqe->dma, 56862306a36Sopenharmony_ci data_addr, data_len, RXE_TO_MR_OBJ); 56962306a36Sopenharmony_ci if (unlikely(err)) 57062306a36Sopenharmony_ci return (err == -ENOSPC) ? RESPST_ERR_LENGTH 57162306a36Sopenharmony_ci : RESPST_ERR_MALFORMED_WQE; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci return RESPST_NONE; 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_cistatic enum resp_states write_data_in(struct rxe_qp *qp, 57762306a36Sopenharmony_ci struct rxe_pkt_info *pkt) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci enum resp_states rc = RESPST_NONE; 58062306a36Sopenharmony_ci int err; 58162306a36Sopenharmony_ci int data_len = payload_size(pkt); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci err = rxe_mr_copy(qp->resp.mr, qp->resp.va + qp->resp.offset, 58462306a36Sopenharmony_ci payload_addr(pkt), data_len, RXE_TO_MR_OBJ); 58562306a36Sopenharmony_ci if (err) { 58662306a36Sopenharmony_ci rc = RESPST_ERR_RKEY_VIOLATION; 58762306a36Sopenharmony_ci goto out; 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci qp->resp.va += data_len; 59162306a36Sopenharmony_ci qp->resp.resid -= data_len; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ciout: 59462306a36Sopenharmony_ci return rc; 59562306a36Sopenharmony_ci} 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_cistatic struct resp_res *rxe_prepare_res(struct rxe_qp *qp, 59862306a36Sopenharmony_ci struct rxe_pkt_info *pkt, 59962306a36Sopenharmony_ci int type) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci struct resp_res *res; 60262306a36Sopenharmony_ci u32 pkts; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci res = &qp->resp.resources[qp->resp.res_head]; 60562306a36Sopenharmony_ci rxe_advance_resp_resource(qp); 60662306a36Sopenharmony_ci free_rd_atomic_resource(res); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci res->type = type; 60962306a36Sopenharmony_ci res->replay = 0; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci switch (type) { 61262306a36Sopenharmony_ci case RXE_READ_MASK: 61362306a36Sopenharmony_ci res->read.va = qp->resp.va + qp->resp.offset; 61462306a36Sopenharmony_ci res->read.va_org = qp->resp.va + qp->resp.offset; 61562306a36Sopenharmony_ci res->read.resid = qp->resp.resid; 61662306a36Sopenharmony_ci res->read.length = qp->resp.resid; 61762306a36Sopenharmony_ci res->read.rkey = qp->resp.rkey; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci pkts = max_t(u32, (reth_len(pkt) + qp->mtu - 1)/qp->mtu, 1); 62062306a36Sopenharmony_ci res->first_psn = pkt->psn; 62162306a36Sopenharmony_ci res->cur_psn = pkt->psn; 62262306a36Sopenharmony_ci res->last_psn = (pkt->psn + pkts - 1) & BTH_PSN_MASK; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci res->state = rdatm_res_state_new; 62562306a36Sopenharmony_ci break; 62662306a36Sopenharmony_ci case RXE_ATOMIC_MASK: 62762306a36Sopenharmony_ci case RXE_ATOMIC_WRITE_MASK: 62862306a36Sopenharmony_ci res->first_psn = pkt->psn; 62962306a36Sopenharmony_ci res->last_psn = pkt->psn; 63062306a36Sopenharmony_ci res->cur_psn = pkt->psn; 63162306a36Sopenharmony_ci break; 63262306a36Sopenharmony_ci case RXE_FLUSH_MASK: 63362306a36Sopenharmony_ci res->flush.va = qp->resp.va + qp->resp.offset; 63462306a36Sopenharmony_ci res->flush.length = qp->resp.length; 63562306a36Sopenharmony_ci res->flush.type = feth_plt(pkt); 63662306a36Sopenharmony_ci res->flush.level = feth_sel(pkt); 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci return res; 64062306a36Sopenharmony_ci} 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_cistatic enum resp_states process_flush(struct rxe_qp *qp, 64362306a36Sopenharmony_ci struct rxe_pkt_info *pkt) 64462306a36Sopenharmony_ci{ 64562306a36Sopenharmony_ci u64 length, start; 64662306a36Sopenharmony_ci struct rxe_mr *mr = qp->resp.mr; 64762306a36Sopenharmony_ci struct resp_res *res = qp->resp.res; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci /* oA19-14, oA19-15 */ 65062306a36Sopenharmony_ci if (res && res->replay) 65162306a36Sopenharmony_ci return RESPST_ACKNOWLEDGE; 65262306a36Sopenharmony_ci else if (!res) { 65362306a36Sopenharmony_ci res = rxe_prepare_res(qp, pkt, RXE_FLUSH_MASK); 65462306a36Sopenharmony_ci qp->resp.res = res; 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci if (res->flush.level == IB_FLUSH_RANGE) { 65862306a36Sopenharmony_ci start = res->flush.va; 65962306a36Sopenharmony_ci length = res->flush.length; 66062306a36Sopenharmony_ci } else { /* level == IB_FLUSH_MR */ 66162306a36Sopenharmony_ci start = mr->ibmr.iova; 66262306a36Sopenharmony_ci length = mr->ibmr.length; 66362306a36Sopenharmony_ci } 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci if (res->flush.type & IB_FLUSH_PERSISTENT) { 66662306a36Sopenharmony_ci if (rxe_flush_pmem_iova(mr, start, length)) 66762306a36Sopenharmony_ci return RESPST_ERR_RKEY_VIOLATION; 66862306a36Sopenharmony_ci /* Make data persistent. */ 66962306a36Sopenharmony_ci wmb(); 67062306a36Sopenharmony_ci } else if (res->flush.type & IB_FLUSH_GLOBAL) { 67162306a36Sopenharmony_ci /* Make data global visibility. */ 67262306a36Sopenharmony_ci wmb(); 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci qp->resp.msn++; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci /* next expected psn, read handles this separately */ 67862306a36Sopenharmony_ci qp->resp.psn = (pkt->psn + 1) & BTH_PSN_MASK; 67962306a36Sopenharmony_ci qp->resp.ack_psn = qp->resp.psn; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci qp->resp.opcode = pkt->opcode; 68262306a36Sopenharmony_ci qp->resp.status = IB_WC_SUCCESS; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci return RESPST_ACKNOWLEDGE; 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_cistatic enum resp_states atomic_reply(struct rxe_qp *qp, 68862306a36Sopenharmony_ci struct rxe_pkt_info *pkt) 68962306a36Sopenharmony_ci{ 69062306a36Sopenharmony_ci struct rxe_mr *mr = qp->resp.mr; 69162306a36Sopenharmony_ci struct resp_res *res = qp->resp.res; 69262306a36Sopenharmony_ci int err; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci if (!res) { 69562306a36Sopenharmony_ci res = rxe_prepare_res(qp, pkt, RXE_ATOMIC_MASK); 69662306a36Sopenharmony_ci qp->resp.res = res; 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci if (!res->replay) { 70062306a36Sopenharmony_ci u64 iova = qp->resp.va + qp->resp.offset; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci err = rxe_mr_do_atomic_op(mr, iova, pkt->opcode, 70362306a36Sopenharmony_ci atmeth_comp(pkt), 70462306a36Sopenharmony_ci atmeth_swap_add(pkt), 70562306a36Sopenharmony_ci &res->atomic.orig_val); 70662306a36Sopenharmony_ci if (err) 70762306a36Sopenharmony_ci return err; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci qp->resp.msn++; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci /* next expected psn, read handles this separately */ 71262306a36Sopenharmony_ci qp->resp.psn = (pkt->psn + 1) & BTH_PSN_MASK; 71362306a36Sopenharmony_ci qp->resp.ack_psn = qp->resp.psn; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci qp->resp.opcode = pkt->opcode; 71662306a36Sopenharmony_ci qp->resp.status = IB_WC_SUCCESS; 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci return RESPST_ACKNOWLEDGE; 72062306a36Sopenharmony_ci} 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_cistatic enum resp_states atomic_write_reply(struct rxe_qp *qp, 72362306a36Sopenharmony_ci struct rxe_pkt_info *pkt) 72462306a36Sopenharmony_ci{ 72562306a36Sopenharmony_ci struct resp_res *res = qp->resp.res; 72662306a36Sopenharmony_ci struct rxe_mr *mr; 72762306a36Sopenharmony_ci u64 value; 72862306a36Sopenharmony_ci u64 iova; 72962306a36Sopenharmony_ci int err; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci if (!res) { 73262306a36Sopenharmony_ci res = rxe_prepare_res(qp, pkt, RXE_ATOMIC_WRITE_MASK); 73362306a36Sopenharmony_ci qp->resp.res = res; 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci if (res->replay) 73762306a36Sopenharmony_ci return RESPST_ACKNOWLEDGE; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci mr = qp->resp.mr; 74062306a36Sopenharmony_ci value = *(u64 *)payload_addr(pkt); 74162306a36Sopenharmony_ci iova = qp->resp.va + qp->resp.offset; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci err = rxe_mr_do_atomic_write(mr, iova, value); 74462306a36Sopenharmony_ci if (err) 74562306a36Sopenharmony_ci return err; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci qp->resp.resid = 0; 74862306a36Sopenharmony_ci qp->resp.msn++; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci /* next expected psn, read handles this separately */ 75162306a36Sopenharmony_ci qp->resp.psn = (pkt->psn + 1) & BTH_PSN_MASK; 75262306a36Sopenharmony_ci qp->resp.ack_psn = qp->resp.psn; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci qp->resp.opcode = pkt->opcode; 75562306a36Sopenharmony_ci qp->resp.status = IB_WC_SUCCESS; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci return RESPST_ACKNOWLEDGE; 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_cistatic struct sk_buff *prepare_ack_packet(struct rxe_qp *qp, 76162306a36Sopenharmony_ci struct rxe_pkt_info *ack, 76262306a36Sopenharmony_ci int opcode, 76362306a36Sopenharmony_ci int payload, 76462306a36Sopenharmony_ci u32 psn, 76562306a36Sopenharmony_ci u8 syndrome) 76662306a36Sopenharmony_ci{ 76762306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(qp->ibqp.device); 76862306a36Sopenharmony_ci struct sk_buff *skb; 76962306a36Sopenharmony_ci int paylen; 77062306a36Sopenharmony_ci int pad; 77162306a36Sopenharmony_ci int err; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci /* 77462306a36Sopenharmony_ci * allocate packet 77562306a36Sopenharmony_ci */ 77662306a36Sopenharmony_ci pad = (-payload) & 0x3; 77762306a36Sopenharmony_ci paylen = rxe_opcode[opcode].length + payload + pad + RXE_ICRC_SIZE; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci skb = rxe_init_packet(rxe, &qp->pri_av, paylen, ack); 78062306a36Sopenharmony_ci if (!skb) 78162306a36Sopenharmony_ci return NULL; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci ack->qp = qp; 78462306a36Sopenharmony_ci ack->opcode = opcode; 78562306a36Sopenharmony_ci ack->mask = rxe_opcode[opcode].mask; 78662306a36Sopenharmony_ci ack->paylen = paylen; 78762306a36Sopenharmony_ci ack->psn = psn; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci bth_init(ack, opcode, 0, 0, pad, IB_DEFAULT_PKEY_FULL, 79062306a36Sopenharmony_ci qp->attr.dest_qp_num, 0, psn); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci if (ack->mask & RXE_AETH_MASK) { 79362306a36Sopenharmony_ci aeth_set_syn(ack, syndrome); 79462306a36Sopenharmony_ci aeth_set_msn(ack, qp->resp.msn); 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci if (ack->mask & RXE_ATMACK_MASK) 79862306a36Sopenharmony_ci atmack_set_orig(ack, qp->resp.res->atomic.orig_val); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci err = rxe_prepare(&qp->pri_av, ack, skb); 80162306a36Sopenharmony_ci if (err) { 80262306a36Sopenharmony_ci kfree_skb(skb); 80362306a36Sopenharmony_ci return NULL; 80462306a36Sopenharmony_ci } 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci return skb; 80762306a36Sopenharmony_ci} 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci/** 81062306a36Sopenharmony_ci * rxe_recheck_mr - revalidate MR from rkey and get a reference 81162306a36Sopenharmony_ci * @qp: the qp 81262306a36Sopenharmony_ci * @rkey: the rkey 81362306a36Sopenharmony_ci * 81462306a36Sopenharmony_ci * This code allows the MR to be invalidated or deregistered or 81562306a36Sopenharmony_ci * the MW if one was used to be invalidated or deallocated. 81662306a36Sopenharmony_ci * It is assumed that the access permissions if originally good 81762306a36Sopenharmony_ci * are OK and the mappings to be unchanged. 81862306a36Sopenharmony_ci * 81962306a36Sopenharmony_ci * TODO: If someone reregisters an MR to change its size or 82062306a36Sopenharmony_ci * access permissions during the processing of an RDMA read 82162306a36Sopenharmony_ci * we should kill the responder resource and complete the 82262306a36Sopenharmony_ci * operation with an error. 82362306a36Sopenharmony_ci * 82462306a36Sopenharmony_ci * Return: mr on success else NULL 82562306a36Sopenharmony_ci */ 82662306a36Sopenharmony_cistatic struct rxe_mr *rxe_recheck_mr(struct rxe_qp *qp, u32 rkey) 82762306a36Sopenharmony_ci{ 82862306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(qp->ibqp.device); 82962306a36Sopenharmony_ci struct rxe_mr *mr; 83062306a36Sopenharmony_ci struct rxe_mw *mw; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci if (rkey_is_mw(rkey)) { 83362306a36Sopenharmony_ci mw = rxe_pool_get_index(&rxe->mw_pool, rkey >> 8); 83462306a36Sopenharmony_ci if (!mw) 83562306a36Sopenharmony_ci return NULL; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci mr = mw->mr; 83862306a36Sopenharmony_ci if (mw->rkey != rkey || mw->state != RXE_MW_STATE_VALID || 83962306a36Sopenharmony_ci !mr || mr->state != RXE_MR_STATE_VALID) { 84062306a36Sopenharmony_ci rxe_put(mw); 84162306a36Sopenharmony_ci return NULL; 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci rxe_get(mr); 84562306a36Sopenharmony_ci rxe_put(mw); 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci return mr; 84862306a36Sopenharmony_ci } 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci mr = rxe_pool_get_index(&rxe->mr_pool, rkey >> 8); 85162306a36Sopenharmony_ci if (!mr) 85262306a36Sopenharmony_ci return NULL; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci if (mr->rkey != rkey || mr->state != RXE_MR_STATE_VALID) { 85562306a36Sopenharmony_ci rxe_put(mr); 85662306a36Sopenharmony_ci return NULL; 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci return mr; 86062306a36Sopenharmony_ci} 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci/* RDMA read response. If res is not NULL, then we have a current RDMA request 86362306a36Sopenharmony_ci * being processed or replayed. 86462306a36Sopenharmony_ci */ 86562306a36Sopenharmony_cistatic enum resp_states read_reply(struct rxe_qp *qp, 86662306a36Sopenharmony_ci struct rxe_pkt_info *req_pkt) 86762306a36Sopenharmony_ci{ 86862306a36Sopenharmony_ci struct rxe_pkt_info ack_pkt; 86962306a36Sopenharmony_ci struct sk_buff *skb; 87062306a36Sopenharmony_ci int mtu = qp->mtu; 87162306a36Sopenharmony_ci enum resp_states state; 87262306a36Sopenharmony_ci int payload; 87362306a36Sopenharmony_ci int opcode; 87462306a36Sopenharmony_ci int err; 87562306a36Sopenharmony_ci struct resp_res *res = qp->resp.res; 87662306a36Sopenharmony_ci struct rxe_mr *mr; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci if (!res) { 87962306a36Sopenharmony_ci res = rxe_prepare_res(qp, req_pkt, RXE_READ_MASK); 88062306a36Sopenharmony_ci qp->resp.res = res; 88162306a36Sopenharmony_ci } 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci if (res->state == rdatm_res_state_new) { 88462306a36Sopenharmony_ci if (!res->replay || qp->resp.length == 0) { 88562306a36Sopenharmony_ci /* if length == 0 mr will be NULL (is ok) 88662306a36Sopenharmony_ci * otherwise qp->resp.mr holds a ref on mr 88762306a36Sopenharmony_ci * which we transfer to mr and drop below. 88862306a36Sopenharmony_ci */ 88962306a36Sopenharmony_ci mr = qp->resp.mr; 89062306a36Sopenharmony_ci qp->resp.mr = NULL; 89162306a36Sopenharmony_ci } else { 89262306a36Sopenharmony_ci mr = rxe_recheck_mr(qp, res->read.rkey); 89362306a36Sopenharmony_ci if (!mr) 89462306a36Sopenharmony_ci return RESPST_ERR_RKEY_VIOLATION; 89562306a36Sopenharmony_ci } 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci if (res->read.resid <= mtu) 89862306a36Sopenharmony_ci opcode = IB_OPCODE_RC_RDMA_READ_RESPONSE_ONLY; 89962306a36Sopenharmony_ci else 90062306a36Sopenharmony_ci opcode = IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST; 90162306a36Sopenharmony_ci } else { 90262306a36Sopenharmony_ci /* re-lookup mr from rkey on all later packets. 90362306a36Sopenharmony_ci * length will be non-zero. This can fail if someone 90462306a36Sopenharmony_ci * modifies or destroys the mr since the first packet. 90562306a36Sopenharmony_ci */ 90662306a36Sopenharmony_ci mr = rxe_recheck_mr(qp, res->read.rkey); 90762306a36Sopenharmony_ci if (!mr) 90862306a36Sopenharmony_ci return RESPST_ERR_RKEY_VIOLATION; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci if (res->read.resid > mtu) 91162306a36Sopenharmony_ci opcode = IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE; 91262306a36Sopenharmony_ci else 91362306a36Sopenharmony_ci opcode = IB_OPCODE_RC_RDMA_READ_RESPONSE_LAST; 91462306a36Sopenharmony_ci } 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci res->state = rdatm_res_state_next; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci payload = min_t(int, res->read.resid, mtu); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci skb = prepare_ack_packet(qp, &ack_pkt, opcode, payload, 92162306a36Sopenharmony_ci res->cur_psn, AETH_ACK_UNLIMITED); 92262306a36Sopenharmony_ci if (!skb) { 92362306a36Sopenharmony_ci state = RESPST_ERR_RNR; 92462306a36Sopenharmony_ci goto err_out; 92562306a36Sopenharmony_ci } 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci err = rxe_mr_copy(mr, res->read.va, payload_addr(&ack_pkt), 92862306a36Sopenharmony_ci payload, RXE_FROM_MR_OBJ); 92962306a36Sopenharmony_ci if (err) { 93062306a36Sopenharmony_ci kfree_skb(skb); 93162306a36Sopenharmony_ci state = RESPST_ERR_RKEY_VIOLATION; 93262306a36Sopenharmony_ci goto err_out; 93362306a36Sopenharmony_ci } 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci if (bth_pad(&ack_pkt)) { 93662306a36Sopenharmony_ci u8 *pad = payload_addr(&ack_pkt) + payload; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci memset(pad, 0, bth_pad(&ack_pkt)); 93962306a36Sopenharmony_ci } 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci /* rxe_xmit_packet always consumes the skb */ 94262306a36Sopenharmony_ci err = rxe_xmit_packet(qp, &ack_pkt, skb); 94362306a36Sopenharmony_ci if (err) { 94462306a36Sopenharmony_ci state = RESPST_ERR_RNR; 94562306a36Sopenharmony_ci goto err_out; 94662306a36Sopenharmony_ci } 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci res->read.va += payload; 94962306a36Sopenharmony_ci res->read.resid -= payload; 95062306a36Sopenharmony_ci res->cur_psn = (res->cur_psn + 1) & BTH_PSN_MASK; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci if (res->read.resid > 0) { 95362306a36Sopenharmony_ci state = RESPST_DONE; 95462306a36Sopenharmony_ci } else { 95562306a36Sopenharmony_ci qp->resp.res = NULL; 95662306a36Sopenharmony_ci if (!res->replay) 95762306a36Sopenharmony_ci qp->resp.opcode = -1; 95862306a36Sopenharmony_ci if (psn_compare(res->cur_psn, qp->resp.psn) >= 0) 95962306a36Sopenharmony_ci qp->resp.psn = res->cur_psn; 96062306a36Sopenharmony_ci state = RESPST_CLEANUP; 96162306a36Sopenharmony_ci } 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_cierr_out: 96462306a36Sopenharmony_ci if (mr) 96562306a36Sopenharmony_ci rxe_put(mr); 96662306a36Sopenharmony_ci return state; 96762306a36Sopenharmony_ci} 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_cistatic int invalidate_rkey(struct rxe_qp *qp, u32 rkey) 97062306a36Sopenharmony_ci{ 97162306a36Sopenharmony_ci if (rkey_is_mw(rkey)) 97262306a36Sopenharmony_ci return rxe_invalidate_mw(qp, rkey); 97362306a36Sopenharmony_ci else 97462306a36Sopenharmony_ci return rxe_invalidate_mr(qp, rkey); 97562306a36Sopenharmony_ci} 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci/* Executes a new request. A retried request never reach that function (send 97862306a36Sopenharmony_ci * and writes are discarded, and reads and atomics are retried elsewhere. 97962306a36Sopenharmony_ci */ 98062306a36Sopenharmony_cistatic enum resp_states execute(struct rxe_qp *qp, struct rxe_pkt_info *pkt) 98162306a36Sopenharmony_ci{ 98262306a36Sopenharmony_ci enum resp_states err; 98362306a36Sopenharmony_ci struct sk_buff *skb = PKT_TO_SKB(pkt); 98462306a36Sopenharmony_ci union rdma_network_hdr hdr; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci if (pkt->mask & RXE_SEND_MASK) { 98762306a36Sopenharmony_ci if (qp_type(qp) == IB_QPT_UD || 98862306a36Sopenharmony_ci qp_type(qp) == IB_QPT_GSI) { 98962306a36Sopenharmony_ci if (skb->protocol == htons(ETH_P_IP)) { 99062306a36Sopenharmony_ci memset(&hdr.reserved, 0, 99162306a36Sopenharmony_ci sizeof(hdr.reserved)); 99262306a36Sopenharmony_ci memcpy(&hdr.roce4grh, ip_hdr(skb), 99362306a36Sopenharmony_ci sizeof(hdr.roce4grh)); 99462306a36Sopenharmony_ci err = send_data_in(qp, &hdr, sizeof(hdr)); 99562306a36Sopenharmony_ci } else { 99662306a36Sopenharmony_ci err = send_data_in(qp, ipv6_hdr(skb), 99762306a36Sopenharmony_ci sizeof(hdr)); 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci if (err) 100062306a36Sopenharmony_ci return err; 100162306a36Sopenharmony_ci } 100262306a36Sopenharmony_ci err = send_data_in(qp, payload_addr(pkt), payload_size(pkt)); 100362306a36Sopenharmony_ci if (err) 100462306a36Sopenharmony_ci return err; 100562306a36Sopenharmony_ci } else if (pkt->mask & RXE_WRITE_MASK) { 100662306a36Sopenharmony_ci err = write_data_in(qp, pkt); 100762306a36Sopenharmony_ci if (err) 100862306a36Sopenharmony_ci return err; 100962306a36Sopenharmony_ci } else if (pkt->mask & RXE_READ_MASK) { 101062306a36Sopenharmony_ci /* For RDMA Read we can increment the msn now. See C9-148. */ 101162306a36Sopenharmony_ci qp->resp.msn++; 101262306a36Sopenharmony_ci return RESPST_READ_REPLY; 101362306a36Sopenharmony_ci } else if (pkt->mask & RXE_ATOMIC_MASK) { 101462306a36Sopenharmony_ci return RESPST_ATOMIC_REPLY; 101562306a36Sopenharmony_ci } else if (pkt->mask & RXE_ATOMIC_WRITE_MASK) { 101662306a36Sopenharmony_ci return RESPST_ATOMIC_WRITE_REPLY; 101762306a36Sopenharmony_ci } else if (pkt->mask & RXE_FLUSH_MASK) { 101862306a36Sopenharmony_ci return RESPST_PROCESS_FLUSH; 101962306a36Sopenharmony_ci } else { 102062306a36Sopenharmony_ci /* Unreachable */ 102162306a36Sopenharmony_ci WARN_ON_ONCE(1); 102262306a36Sopenharmony_ci } 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci if (pkt->mask & RXE_IETH_MASK) { 102562306a36Sopenharmony_ci u32 rkey = ieth_rkey(pkt); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci err = invalidate_rkey(qp, rkey); 102862306a36Sopenharmony_ci if (err) 102962306a36Sopenharmony_ci return RESPST_ERR_INVALIDATE_RKEY; 103062306a36Sopenharmony_ci } 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci if (pkt->mask & RXE_END_MASK) 103362306a36Sopenharmony_ci /* We successfully processed this new request. */ 103462306a36Sopenharmony_ci qp->resp.msn++; 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci /* next expected psn, read handles this separately */ 103762306a36Sopenharmony_ci qp->resp.psn = (pkt->psn + 1) & BTH_PSN_MASK; 103862306a36Sopenharmony_ci qp->resp.ack_psn = qp->resp.psn; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci qp->resp.opcode = pkt->opcode; 104162306a36Sopenharmony_ci qp->resp.status = IB_WC_SUCCESS; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci if (pkt->mask & RXE_COMP_MASK) 104462306a36Sopenharmony_ci return RESPST_COMPLETE; 104562306a36Sopenharmony_ci else if (qp_type(qp) == IB_QPT_RC) 104662306a36Sopenharmony_ci return RESPST_ACKNOWLEDGE; 104762306a36Sopenharmony_ci else 104862306a36Sopenharmony_ci return RESPST_CLEANUP; 104962306a36Sopenharmony_ci} 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_cistatic enum resp_states do_complete(struct rxe_qp *qp, 105262306a36Sopenharmony_ci struct rxe_pkt_info *pkt) 105362306a36Sopenharmony_ci{ 105462306a36Sopenharmony_ci struct rxe_cqe cqe; 105562306a36Sopenharmony_ci struct ib_wc *wc = &cqe.ibwc; 105662306a36Sopenharmony_ci struct ib_uverbs_wc *uwc = &cqe.uibwc; 105762306a36Sopenharmony_ci struct rxe_recv_wqe *wqe = qp->resp.wqe; 105862306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(qp->ibqp.device); 105962306a36Sopenharmony_ci unsigned long flags; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci if (!wqe) 106262306a36Sopenharmony_ci goto finish; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci memset(&cqe, 0, sizeof(cqe)); 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci if (qp->rcq->is_user) { 106762306a36Sopenharmony_ci uwc->status = qp->resp.status; 106862306a36Sopenharmony_ci uwc->qp_num = qp->ibqp.qp_num; 106962306a36Sopenharmony_ci uwc->wr_id = wqe->wr_id; 107062306a36Sopenharmony_ci } else { 107162306a36Sopenharmony_ci wc->status = qp->resp.status; 107262306a36Sopenharmony_ci wc->qp = &qp->ibqp; 107362306a36Sopenharmony_ci wc->wr_id = wqe->wr_id; 107462306a36Sopenharmony_ci } 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci if (wc->status == IB_WC_SUCCESS) { 107762306a36Sopenharmony_ci rxe_counter_inc(rxe, RXE_CNT_RDMA_RECV); 107862306a36Sopenharmony_ci wc->opcode = (pkt->mask & RXE_IMMDT_MASK && 107962306a36Sopenharmony_ci pkt->mask & RXE_WRITE_MASK) ? 108062306a36Sopenharmony_ci IB_WC_RECV_RDMA_WITH_IMM : IB_WC_RECV; 108162306a36Sopenharmony_ci wc->byte_len = (pkt->mask & RXE_IMMDT_MASK && 108262306a36Sopenharmony_ci pkt->mask & RXE_WRITE_MASK) ? 108362306a36Sopenharmony_ci qp->resp.length : wqe->dma.length - wqe->dma.resid; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci /* fields after byte_len are different between kernel and user 108662306a36Sopenharmony_ci * space 108762306a36Sopenharmony_ci */ 108862306a36Sopenharmony_ci if (qp->rcq->is_user) { 108962306a36Sopenharmony_ci uwc->wc_flags = IB_WC_GRH; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci if (pkt->mask & RXE_IMMDT_MASK) { 109262306a36Sopenharmony_ci uwc->wc_flags |= IB_WC_WITH_IMM; 109362306a36Sopenharmony_ci uwc->ex.imm_data = immdt_imm(pkt); 109462306a36Sopenharmony_ci } 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci if (pkt->mask & RXE_IETH_MASK) { 109762306a36Sopenharmony_ci uwc->wc_flags |= IB_WC_WITH_INVALIDATE; 109862306a36Sopenharmony_ci uwc->ex.invalidate_rkey = ieth_rkey(pkt); 109962306a36Sopenharmony_ci } 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci if (pkt->mask & RXE_DETH_MASK) 110262306a36Sopenharmony_ci uwc->src_qp = deth_sqp(pkt); 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci uwc->port_num = qp->attr.port_num; 110562306a36Sopenharmony_ci } else { 110662306a36Sopenharmony_ci struct sk_buff *skb = PKT_TO_SKB(pkt); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci wc->wc_flags = IB_WC_GRH | IB_WC_WITH_NETWORK_HDR_TYPE; 110962306a36Sopenharmony_ci if (skb->protocol == htons(ETH_P_IP)) 111062306a36Sopenharmony_ci wc->network_hdr_type = RDMA_NETWORK_IPV4; 111162306a36Sopenharmony_ci else 111262306a36Sopenharmony_ci wc->network_hdr_type = RDMA_NETWORK_IPV6; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci if (is_vlan_dev(skb->dev)) { 111562306a36Sopenharmony_ci wc->wc_flags |= IB_WC_WITH_VLAN; 111662306a36Sopenharmony_ci wc->vlan_id = vlan_dev_vlan_id(skb->dev); 111762306a36Sopenharmony_ci } 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci if (pkt->mask & RXE_IMMDT_MASK) { 112062306a36Sopenharmony_ci wc->wc_flags |= IB_WC_WITH_IMM; 112162306a36Sopenharmony_ci wc->ex.imm_data = immdt_imm(pkt); 112262306a36Sopenharmony_ci } 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci if (pkt->mask & RXE_IETH_MASK) { 112562306a36Sopenharmony_ci wc->wc_flags |= IB_WC_WITH_INVALIDATE; 112662306a36Sopenharmony_ci wc->ex.invalidate_rkey = ieth_rkey(pkt); 112762306a36Sopenharmony_ci } 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci if (pkt->mask & RXE_DETH_MASK) 113062306a36Sopenharmony_ci wc->src_qp = deth_sqp(pkt); 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci wc->port_num = qp->attr.port_num; 113362306a36Sopenharmony_ci } 113462306a36Sopenharmony_ci } else { 113562306a36Sopenharmony_ci if (wc->status != IB_WC_WR_FLUSH_ERR) 113662306a36Sopenharmony_ci rxe_err_qp(qp, "non-flush error status = %d", 113762306a36Sopenharmony_ci wc->status); 113862306a36Sopenharmony_ci } 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci /* have copy for srq and reference for !srq */ 114162306a36Sopenharmony_ci if (!qp->srq) 114262306a36Sopenharmony_ci queue_advance_consumer(qp->rq.queue, QUEUE_TYPE_FROM_CLIENT); 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci qp->resp.wqe = NULL; 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci if (rxe_cq_post(qp->rcq, &cqe, pkt ? bth_se(pkt) : 1)) 114762306a36Sopenharmony_ci return RESPST_ERR_CQ_OVERFLOW; 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_cifinish: 115062306a36Sopenharmony_ci spin_lock_irqsave(&qp->state_lock, flags); 115162306a36Sopenharmony_ci if (unlikely(qp_state(qp) == IB_QPS_ERR)) { 115262306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 115362306a36Sopenharmony_ci return RESPST_CHK_RESOURCE; 115462306a36Sopenharmony_ci } 115562306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci if (unlikely(!pkt)) 115862306a36Sopenharmony_ci return RESPST_DONE; 115962306a36Sopenharmony_ci if (qp_type(qp) == IB_QPT_RC) 116062306a36Sopenharmony_ci return RESPST_ACKNOWLEDGE; 116162306a36Sopenharmony_ci else 116262306a36Sopenharmony_ci return RESPST_CLEANUP; 116362306a36Sopenharmony_ci} 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_cistatic int send_common_ack(struct rxe_qp *qp, u8 syndrome, u32 psn, 116762306a36Sopenharmony_ci int opcode, const char *msg) 116862306a36Sopenharmony_ci{ 116962306a36Sopenharmony_ci int err; 117062306a36Sopenharmony_ci struct rxe_pkt_info ack_pkt; 117162306a36Sopenharmony_ci struct sk_buff *skb; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci skb = prepare_ack_packet(qp, &ack_pkt, opcode, 0, psn, syndrome); 117462306a36Sopenharmony_ci if (!skb) 117562306a36Sopenharmony_ci return -ENOMEM; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci err = rxe_xmit_packet(qp, &ack_pkt, skb); 117862306a36Sopenharmony_ci if (err) 117962306a36Sopenharmony_ci rxe_dbg_qp(qp, "Failed sending %s\n", msg); 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci return err; 118262306a36Sopenharmony_ci} 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_cistatic int send_ack(struct rxe_qp *qp, u8 syndrome, u32 psn) 118562306a36Sopenharmony_ci{ 118662306a36Sopenharmony_ci return send_common_ack(qp, syndrome, psn, 118762306a36Sopenharmony_ci IB_OPCODE_RC_ACKNOWLEDGE, "ACK"); 118862306a36Sopenharmony_ci} 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_cistatic int send_atomic_ack(struct rxe_qp *qp, u8 syndrome, u32 psn) 119162306a36Sopenharmony_ci{ 119262306a36Sopenharmony_ci int ret = send_common_ack(qp, syndrome, psn, 119362306a36Sopenharmony_ci IB_OPCODE_RC_ATOMIC_ACKNOWLEDGE, "ATOMIC ACK"); 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci /* have to clear this since it is used to trigger 119662306a36Sopenharmony_ci * long read replies 119762306a36Sopenharmony_ci */ 119862306a36Sopenharmony_ci qp->resp.res = NULL; 119962306a36Sopenharmony_ci return ret; 120062306a36Sopenharmony_ci} 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_cistatic int send_read_response_ack(struct rxe_qp *qp, u8 syndrome, u32 psn) 120362306a36Sopenharmony_ci{ 120462306a36Sopenharmony_ci int ret = send_common_ack(qp, syndrome, psn, 120562306a36Sopenharmony_ci IB_OPCODE_RC_RDMA_READ_RESPONSE_ONLY, 120662306a36Sopenharmony_ci "RDMA READ response of length zero ACK"); 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci /* have to clear this since it is used to trigger 120962306a36Sopenharmony_ci * long read replies 121062306a36Sopenharmony_ci */ 121162306a36Sopenharmony_ci qp->resp.res = NULL; 121262306a36Sopenharmony_ci return ret; 121362306a36Sopenharmony_ci} 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_cistatic enum resp_states acknowledge(struct rxe_qp *qp, 121662306a36Sopenharmony_ci struct rxe_pkt_info *pkt) 121762306a36Sopenharmony_ci{ 121862306a36Sopenharmony_ci if (qp_type(qp) != IB_QPT_RC) 121962306a36Sopenharmony_ci return RESPST_CLEANUP; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci if (qp->resp.aeth_syndrome != AETH_ACK_UNLIMITED) 122262306a36Sopenharmony_ci send_ack(qp, qp->resp.aeth_syndrome, pkt->psn); 122362306a36Sopenharmony_ci else if (pkt->mask & RXE_ATOMIC_MASK) 122462306a36Sopenharmony_ci send_atomic_ack(qp, AETH_ACK_UNLIMITED, pkt->psn); 122562306a36Sopenharmony_ci else if (pkt->mask & (RXE_FLUSH_MASK | RXE_ATOMIC_WRITE_MASK)) 122662306a36Sopenharmony_ci send_read_response_ack(qp, AETH_ACK_UNLIMITED, pkt->psn); 122762306a36Sopenharmony_ci else if (bth_ack(pkt)) 122862306a36Sopenharmony_ci send_ack(qp, AETH_ACK_UNLIMITED, pkt->psn); 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci return RESPST_CLEANUP; 123162306a36Sopenharmony_ci} 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_cistatic enum resp_states cleanup(struct rxe_qp *qp, 123462306a36Sopenharmony_ci struct rxe_pkt_info *pkt) 123562306a36Sopenharmony_ci{ 123662306a36Sopenharmony_ci struct sk_buff *skb; 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci if (pkt) { 123962306a36Sopenharmony_ci skb = skb_dequeue(&qp->req_pkts); 124062306a36Sopenharmony_ci rxe_put(qp); 124162306a36Sopenharmony_ci kfree_skb(skb); 124262306a36Sopenharmony_ci ib_device_put(qp->ibqp.device); 124362306a36Sopenharmony_ci } 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci if (qp->resp.mr) { 124662306a36Sopenharmony_ci rxe_put(qp->resp.mr); 124762306a36Sopenharmony_ci qp->resp.mr = NULL; 124862306a36Sopenharmony_ci } 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci return RESPST_DONE; 125162306a36Sopenharmony_ci} 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_cistatic struct resp_res *find_resource(struct rxe_qp *qp, u32 psn) 125462306a36Sopenharmony_ci{ 125562306a36Sopenharmony_ci int i; 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci for (i = 0; i < qp->attr.max_dest_rd_atomic; i++) { 125862306a36Sopenharmony_ci struct resp_res *res = &qp->resp.resources[i]; 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci if (res->type == 0) 126162306a36Sopenharmony_ci continue; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci if (psn_compare(psn, res->first_psn) >= 0 && 126462306a36Sopenharmony_ci psn_compare(psn, res->last_psn) <= 0) { 126562306a36Sopenharmony_ci return res; 126662306a36Sopenharmony_ci } 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci return NULL; 127062306a36Sopenharmony_ci} 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_cistatic enum resp_states duplicate_request(struct rxe_qp *qp, 127362306a36Sopenharmony_ci struct rxe_pkt_info *pkt) 127462306a36Sopenharmony_ci{ 127562306a36Sopenharmony_ci enum resp_states rc; 127662306a36Sopenharmony_ci u32 prev_psn = (qp->resp.ack_psn - 1) & BTH_PSN_MASK; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci if (pkt->mask & RXE_SEND_MASK || 127962306a36Sopenharmony_ci pkt->mask & RXE_WRITE_MASK) { 128062306a36Sopenharmony_ci /* SEND. Ack again and cleanup. C9-105. */ 128162306a36Sopenharmony_ci send_ack(qp, AETH_ACK_UNLIMITED, prev_psn); 128262306a36Sopenharmony_ci return RESPST_CLEANUP; 128362306a36Sopenharmony_ci } else if (pkt->mask & RXE_FLUSH_MASK) { 128462306a36Sopenharmony_ci struct resp_res *res; 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci /* Find the operation in our list of responder resources. */ 128762306a36Sopenharmony_ci res = find_resource(qp, pkt->psn); 128862306a36Sopenharmony_ci if (res) { 128962306a36Sopenharmony_ci res->replay = 1; 129062306a36Sopenharmony_ci res->cur_psn = pkt->psn; 129162306a36Sopenharmony_ci qp->resp.res = res; 129262306a36Sopenharmony_ci rc = RESPST_PROCESS_FLUSH; 129362306a36Sopenharmony_ci goto out; 129462306a36Sopenharmony_ci } 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci /* Resource not found. Class D error. Drop the request. */ 129762306a36Sopenharmony_ci rc = RESPST_CLEANUP; 129862306a36Sopenharmony_ci goto out; 129962306a36Sopenharmony_ci } else if (pkt->mask & RXE_READ_MASK) { 130062306a36Sopenharmony_ci struct resp_res *res; 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci res = find_resource(qp, pkt->psn); 130362306a36Sopenharmony_ci if (!res) { 130462306a36Sopenharmony_ci /* Resource not found. Class D error. Drop the 130562306a36Sopenharmony_ci * request. 130662306a36Sopenharmony_ci */ 130762306a36Sopenharmony_ci rc = RESPST_CLEANUP; 130862306a36Sopenharmony_ci goto out; 130962306a36Sopenharmony_ci } else { 131062306a36Sopenharmony_ci /* Ensure this new request is the same as the previous 131162306a36Sopenharmony_ci * one or a subset of it. 131262306a36Sopenharmony_ci */ 131362306a36Sopenharmony_ci u64 iova = reth_va(pkt); 131462306a36Sopenharmony_ci u32 resid = reth_len(pkt); 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci if (iova < res->read.va_org || 131762306a36Sopenharmony_ci resid > res->read.length || 131862306a36Sopenharmony_ci (iova + resid) > (res->read.va_org + 131962306a36Sopenharmony_ci res->read.length)) { 132062306a36Sopenharmony_ci rc = RESPST_CLEANUP; 132162306a36Sopenharmony_ci goto out; 132262306a36Sopenharmony_ci } 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci if (reth_rkey(pkt) != res->read.rkey) { 132562306a36Sopenharmony_ci rc = RESPST_CLEANUP; 132662306a36Sopenharmony_ci goto out; 132762306a36Sopenharmony_ci } 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci res->cur_psn = pkt->psn; 133062306a36Sopenharmony_ci res->state = (pkt->psn == res->first_psn) ? 133162306a36Sopenharmony_ci rdatm_res_state_new : 133262306a36Sopenharmony_ci rdatm_res_state_replay; 133362306a36Sopenharmony_ci res->replay = 1; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci /* Reset the resource, except length. */ 133662306a36Sopenharmony_ci res->read.va_org = iova; 133762306a36Sopenharmony_ci res->read.va = iova; 133862306a36Sopenharmony_ci res->read.resid = resid; 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci /* Replay the RDMA read reply. */ 134162306a36Sopenharmony_ci qp->resp.res = res; 134262306a36Sopenharmony_ci rc = RESPST_READ_REPLY; 134362306a36Sopenharmony_ci goto out; 134462306a36Sopenharmony_ci } 134562306a36Sopenharmony_ci } else { 134662306a36Sopenharmony_ci struct resp_res *res; 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci /* Find the operation in our list of responder resources. */ 134962306a36Sopenharmony_ci res = find_resource(qp, pkt->psn); 135062306a36Sopenharmony_ci if (res) { 135162306a36Sopenharmony_ci res->replay = 1; 135262306a36Sopenharmony_ci res->cur_psn = pkt->psn; 135362306a36Sopenharmony_ci qp->resp.res = res; 135462306a36Sopenharmony_ci rc = pkt->mask & RXE_ATOMIC_MASK ? 135562306a36Sopenharmony_ci RESPST_ATOMIC_REPLY : 135662306a36Sopenharmony_ci RESPST_ATOMIC_WRITE_REPLY; 135762306a36Sopenharmony_ci goto out; 135862306a36Sopenharmony_ci } 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci /* Resource not found. Class D error. Drop the request. */ 136162306a36Sopenharmony_ci rc = RESPST_CLEANUP; 136262306a36Sopenharmony_ci goto out; 136362306a36Sopenharmony_ci } 136462306a36Sopenharmony_ciout: 136562306a36Sopenharmony_ci return rc; 136662306a36Sopenharmony_ci} 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci/* Process a class A or C. Both are treated the same in this implementation. */ 136962306a36Sopenharmony_cistatic void do_class_ac_error(struct rxe_qp *qp, u8 syndrome, 137062306a36Sopenharmony_ci enum ib_wc_status status) 137162306a36Sopenharmony_ci{ 137262306a36Sopenharmony_ci qp->resp.aeth_syndrome = syndrome; 137362306a36Sopenharmony_ci qp->resp.status = status; 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci /* indicate that we should go through the ERROR state */ 137662306a36Sopenharmony_ci qp->resp.goto_error = 1; 137762306a36Sopenharmony_ci} 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_cistatic enum resp_states do_class_d1e_error(struct rxe_qp *qp) 138062306a36Sopenharmony_ci{ 138162306a36Sopenharmony_ci /* UC */ 138262306a36Sopenharmony_ci if (qp->srq) { 138362306a36Sopenharmony_ci /* Class E */ 138462306a36Sopenharmony_ci qp->resp.drop_msg = 1; 138562306a36Sopenharmony_ci if (qp->resp.wqe) { 138662306a36Sopenharmony_ci qp->resp.status = IB_WC_REM_INV_REQ_ERR; 138762306a36Sopenharmony_ci return RESPST_COMPLETE; 138862306a36Sopenharmony_ci } else { 138962306a36Sopenharmony_ci return RESPST_CLEANUP; 139062306a36Sopenharmony_ci } 139162306a36Sopenharmony_ci } else { 139262306a36Sopenharmony_ci /* Class D1. This packet may be the start of a 139362306a36Sopenharmony_ci * new message and could be valid. The previous 139462306a36Sopenharmony_ci * message is invalid and ignored. reset the 139562306a36Sopenharmony_ci * recv wr to its original state 139662306a36Sopenharmony_ci */ 139762306a36Sopenharmony_ci if (qp->resp.wqe) { 139862306a36Sopenharmony_ci qp->resp.wqe->dma.resid = qp->resp.wqe->dma.length; 139962306a36Sopenharmony_ci qp->resp.wqe->dma.cur_sge = 0; 140062306a36Sopenharmony_ci qp->resp.wqe->dma.sge_offset = 0; 140162306a36Sopenharmony_ci qp->resp.opcode = -1; 140262306a36Sopenharmony_ci } 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci if (qp->resp.mr) { 140562306a36Sopenharmony_ci rxe_put(qp->resp.mr); 140662306a36Sopenharmony_ci qp->resp.mr = NULL; 140762306a36Sopenharmony_ci } 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci return RESPST_CLEANUP; 141062306a36Sopenharmony_ci } 141162306a36Sopenharmony_ci} 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci/* drain incoming request packet queue */ 141462306a36Sopenharmony_cistatic void drain_req_pkts(struct rxe_qp *qp) 141562306a36Sopenharmony_ci{ 141662306a36Sopenharmony_ci struct sk_buff *skb; 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci while ((skb = skb_dequeue(&qp->req_pkts))) { 141962306a36Sopenharmony_ci rxe_put(qp); 142062306a36Sopenharmony_ci kfree_skb(skb); 142162306a36Sopenharmony_ci ib_device_put(qp->ibqp.device); 142262306a36Sopenharmony_ci } 142362306a36Sopenharmony_ci} 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci/* complete receive wqe with flush error */ 142662306a36Sopenharmony_cistatic int flush_recv_wqe(struct rxe_qp *qp, struct rxe_recv_wqe *wqe) 142762306a36Sopenharmony_ci{ 142862306a36Sopenharmony_ci struct rxe_cqe cqe = {}; 142962306a36Sopenharmony_ci struct ib_wc *wc = &cqe.ibwc; 143062306a36Sopenharmony_ci struct ib_uverbs_wc *uwc = &cqe.uibwc; 143162306a36Sopenharmony_ci int err; 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci if (qp->rcq->is_user) { 143462306a36Sopenharmony_ci uwc->wr_id = wqe->wr_id; 143562306a36Sopenharmony_ci uwc->status = IB_WC_WR_FLUSH_ERR; 143662306a36Sopenharmony_ci uwc->qp_num = qp_num(qp); 143762306a36Sopenharmony_ci } else { 143862306a36Sopenharmony_ci wc->wr_id = wqe->wr_id; 143962306a36Sopenharmony_ci wc->status = IB_WC_WR_FLUSH_ERR; 144062306a36Sopenharmony_ci wc->qp = &qp->ibqp; 144162306a36Sopenharmony_ci } 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci err = rxe_cq_post(qp->rcq, &cqe, 0); 144462306a36Sopenharmony_ci if (err) 144562306a36Sopenharmony_ci rxe_dbg_cq(qp->rcq, "post cq failed err = %d", err); 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci return err; 144862306a36Sopenharmony_ci} 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci/* drain and optionally complete the recive queue 145162306a36Sopenharmony_ci * if unable to complete a wqe stop completing and 145262306a36Sopenharmony_ci * just flush the remaining wqes 145362306a36Sopenharmony_ci */ 145462306a36Sopenharmony_cistatic void flush_recv_queue(struct rxe_qp *qp, bool notify) 145562306a36Sopenharmony_ci{ 145662306a36Sopenharmony_ci struct rxe_queue *q = qp->rq.queue; 145762306a36Sopenharmony_ci struct rxe_recv_wqe *wqe; 145862306a36Sopenharmony_ci int err; 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci if (qp->srq) { 146162306a36Sopenharmony_ci if (notify && qp->ibqp.event_handler) { 146262306a36Sopenharmony_ci struct ib_event ev; 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci ev.device = qp->ibqp.device; 146562306a36Sopenharmony_ci ev.element.qp = &qp->ibqp; 146662306a36Sopenharmony_ci ev.event = IB_EVENT_QP_LAST_WQE_REACHED; 146762306a36Sopenharmony_ci qp->ibqp.event_handler(&ev, qp->ibqp.qp_context); 146862306a36Sopenharmony_ci } 146962306a36Sopenharmony_ci return; 147062306a36Sopenharmony_ci } 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci /* recv queue not created. nothing to do. */ 147362306a36Sopenharmony_ci if (!qp->rq.queue) 147462306a36Sopenharmony_ci return; 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci while ((wqe = queue_head(q, q->type))) { 147762306a36Sopenharmony_ci if (notify) { 147862306a36Sopenharmony_ci err = flush_recv_wqe(qp, wqe); 147962306a36Sopenharmony_ci if (err) 148062306a36Sopenharmony_ci notify = 0; 148162306a36Sopenharmony_ci } 148262306a36Sopenharmony_ci queue_advance_consumer(q, q->type); 148362306a36Sopenharmony_ci } 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci qp->resp.wqe = NULL; 148662306a36Sopenharmony_ci} 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ciint rxe_responder(struct rxe_qp *qp) 148962306a36Sopenharmony_ci{ 149062306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(qp->ibqp.device); 149162306a36Sopenharmony_ci enum resp_states state; 149262306a36Sopenharmony_ci struct rxe_pkt_info *pkt = NULL; 149362306a36Sopenharmony_ci int ret; 149462306a36Sopenharmony_ci unsigned long flags; 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci spin_lock_irqsave(&qp->state_lock, flags); 149762306a36Sopenharmony_ci if (!qp->valid || qp_state(qp) == IB_QPS_ERR || 149862306a36Sopenharmony_ci qp_state(qp) == IB_QPS_RESET) { 149962306a36Sopenharmony_ci bool notify = qp->valid && (qp_state(qp) == IB_QPS_ERR); 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci drain_req_pkts(qp); 150262306a36Sopenharmony_ci flush_recv_queue(qp, notify); 150362306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 150462306a36Sopenharmony_ci goto exit; 150562306a36Sopenharmony_ci } 150662306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci qp->resp.aeth_syndrome = AETH_ACK_UNLIMITED; 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci state = RESPST_GET_REQ; 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci while (1) { 151362306a36Sopenharmony_ci rxe_dbg_qp(qp, "state = %s\n", resp_state_name[state]); 151462306a36Sopenharmony_ci switch (state) { 151562306a36Sopenharmony_ci case RESPST_GET_REQ: 151662306a36Sopenharmony_ci state = get_req(qp, &pkt); 151762306a36Sopenharmony_ci break; 151862306a36Sopenharmony_ci case RESPST_CHK_PSN: 151962306a36Sopenharmony_ci state = check_psn(qp, pkt); 152062306a36Sopenharmony_ci break; 152162306a36Sopenharmony_ci case RESPST_CHK_OP_SEQ: 152262306a36Sopenharmony_ci state = check_op_seq(qp, pkt); 152362306a36Sopenharmony_ci break; 152462306a36Sopenharmony_ci case RESPST_CHK_OP_VALID: 152562306a36Sopenharmony_ci state = check_op_valid(qp, pkt); 152662306a36Sopenharmony_ci break; 152762306a36Sopenharmony_ci case RESPST_CHK_RESOURCE: 152862306a36Sopenharmony_ci state = check_resource(qp, pkt); 152962306a36Sopenharmony_ci break; 153062306a36Sopenharmony_ci case RESPST_CHK_LENGTH: 153162306a36Sopenharmony_ci state = rxe_resp_check_length(qp, pkt); 153262306a36Sopenharmony_ci break; 153362306a36Sopenharmony_ci case RESPST_CHK_RKEY: 153462306a36Sopenharmony_ci state = check_rkey(qp, pkt); 153562306a36Sopenharmony_ci break; 153662306a36Sopenharmony_ci case RESPST_EXECUTE: 153762306a36Sopenharmony_ci state = execute(qp, pkt); 153862306a36Sopenharmony_ci break; 153962306a36Sopenharmony_ci case RESPST_COMPLETE: 154062306a36Sopenharmony_ci state = do_complete(qp, pkt); 154162306a36Sopenharmony_ci break; 154262306a36Sopenharmony_ci case RESPST_READ_REPLY: 154362306a36Sopenharmony_ci state = read_reply(qp, pkt); 154462306a36Sopenharmony_ci break; 154562306a36Sopenharmony_ci case RESPST_ATOMIC_REPLY: 154662306a36Sopenharmony_ci state = atomic_reply(qp, pkt); 154762306a36Sopenharmony_ci break; 154862306a36Sopenharmony_ci case RESPST_ATOMIC_WRITE_REPLY: 154962306a36Sopenharmony_ci state = atomic_write_reply(qp, pkt); 155062306a36Sopenharmony_ci break; 155162306a36Sopenharmony_ci case RESPST_PROCESS_FLUSH: 155262306a36Sopenharmony_ci state = process_flush(qp, pkt); 155362306a36Sopenharmony_ci break; 155462306a36Sopenharmony_ci case RESPST_ACKNOWLEDGE: 155562306a36Sopenharmony_ci state = acknowledge(qp, pkt); 155662306a36Sopenharmony_ci break; 155762306a36Sopenharmony_ci case RESPST_CLEANUP: 155862306a36Sopenharmony_ci state = cleanup(qp, pkt); 155962306a36Sopenharmony_ci break; 156062306a36Sopenharmony_ci case RESPST_DUPLICATE_REQUEST: 156162306a36Sopenharmony_ci state = duplicate_request(qp, pkt); 156262306a36Sopenharmony_ci break; 156362306a36Sopenharmony_ci case RESPST_ERR_PSN_OUT_OF_SEQ: 156462306a36Sopenharmony_ci /* RC only - Class B. Drop packet. */ 156562306a36Sopenharmony_ci send_ack(qp, AETH_NAK_PSN_SEQ_ERROR, qp->resp.psn); 156662306a36Sopenharmony_ci state = RESPST_CLEANUP; 156762306a36Sopenharmony_ci break; 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci case RESPST_ERR_TOO_MANY_RDMA_ATM_REQ: 157062306a36Sopenharmony_ci case RESPST_ERR_MISSING_OPCODE_FIRST: 157162306a36Sopenharmony_ci case RESPST_ERR_MISSING_OPCODE_LAST_C: 157262306a36Sopenharmony_ci case RESPST_ERR_UNSUPPORTED_OPCODE: 157362306a36Sopenharmony_ci case RESPST_ERR_MISALIGNED_ATOMIC: 157462306a36Sopenharmony_ci /* RC Only - Class C. */ 157562306a36Sopenharmony_ci do_class_ac_error(qp, AETH_NAK_INVALID_REQ, 157662306a36Sopenharmony_ci IB_WC_REM_INV_REQ_ERR); 157762306a36Sopenharmony_ci state = RESPST_COMPLETE; 157862306a36Sopenharmony_ci break; 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci case RESPST_ERR_MISSING_OPCODE_LAST_D1E: 158162306a36Sopenharmony_ci state = do_class_d1e_error(qp); 158262306a36Sopenharmony_ci break; 158362306a36Sopenharmony_ci case RESPST_ERR_RNR: 158462306a36Sopenharmony_ci if (qp_type(qp) == IB_QPT_RC) { 158562306a36Sopenharmony_ci rxe_counter_inc(rxe, RXE_CNT_SND_RNR); 158662306a36Sopenharmony_ci /* RC - class B */ 158762306a36Sopenharmony_ci send_ack(qp, AETH_RNR_NAK | 158862306a36Sopenharmony_ci (~AETH_TYPE_MASK & 158962306a36Sopenharmony_ci qp->attr.min_rnr_timer), 159062306a36Sopenharmony_ci pkt->psn); 159162306a36Sopenharmony_ci } else { 159262306a36Sopenharmony_ci /* UD/UC - class D */ 159362306a36Sopenharmony_ci qp->resp.drop_msg = 1; 159462306a36Sopenharmony_ci } 159562306a36Sopenharmony_ci state = RESPST_CLEANUP; 159662306a36Sopenharmony_ci break; 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci case RESPST_ERR_RKEY_VIOLATION: 159962306a36Sopenharmony_ci if (qp_type(qp) == IB_QPT_RC) { 160062306a36Sopenharmony_ci /* Class C */ 160162306a36Sopenharmony_ci do_class_ac_error(qp, AETH_NAK_REM_ACC_ERR, 160262306a36Sopenharmony_ci IB_WC_REM_ACCESS_ERR); 160362306a36Sopenharmony_ci state = RESPST_COMPLETE; 160462306a36Sopenharmony_ci } else { 160562306a36Sopenharmony_ci qp->resp.drop_msg = 1; 160662306a36Sopenharmony_ci if (qp->srq) { 160762306a36Sopenharmony_ci /* UC/SRQ Class D */ 160862306a36Sopenharmony_ci qp->resp.status = IB_WC_REM_ACCESS_ERR; 160962306a36Sopenharmony_ci state = RESPST_COMPLETE; 161062306a36Sopenharmony_ci } else { 161162306a36Sopenharmony_ci /* UC/non-SRQ Class E. */ 161262306a36Sopenharmony_ci state = RESPST_CLEANUP; 161362306a36Sopenharmony_ci } 161462306a36Sopenharmony_ci } 161562306a36Sopenharmony_ci break; 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ci case RESPST_ERR_INVALIDATE_RKEY: 161862306a36Sopenharmony_ci /* RC - Class J. */ 161962306a36Sopenharmony_ci qp->resp.goto_error = 1; 162062306a36Sopenharmony_ci qp->resp.status = IB_WC_REM_INV_REQ_ERR; 162162306a36Sopenharmony_ci state = RESPST_COMPLETE; 162262306a36Sopenharmony_ci break; 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci case RESPST_ERR_LENGTH: 162562306a36Sopenharmony_ci if (qp_type(qp) == IB_QPT_RC) { 162662306a36Sopenharmony_ci /* Class C */ 162762306a36Sopenharmony_ci do_class_ac_error(qp, AETH_NAK_INVALID_REQ, 162862306a36Sopenharmony_ci IB_WC_REM_INV_REQ_ERR); 162962306a36Sopenharmony_ci state = RESPST_COMPLETE; 163062306a36Sopenharmony_ci } else if (qp->srq) { 163162306a36Sopenharmony_ci /* UC/UD - class E */ 163262306a36Sopenharmony_ci qp->resp.status = IB_WC_REM_INV_REQ_ERR; 163362306a36Sopenharmony_ci state = RESPST_COMPLETE; 163462306a36Sopenharmony_ci } else { 163562306a36Sopenharmony_ci /* UC/UD - class D */ 163662306a36Sopenharmony_ci qp->resp.drop_msg = 1; 163762306a36Sopenharmony_ci state = RESPST_CLEANUP; 163862306a36Sopenharmony_ci } 163962306a36Sopenharmony_ci break; 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci case RESPST_ERR_MALFORMED_WQE: 164262306a36Sopenharmony_ci /* All, Class A. */ 164362306a36Sopenharmony_ci do_class_ac_error(qp, AETH_NAK_REM_OP_ERR, 164462306a36Sopenharmony_ci IB_WC_LOC_QP_OP_ERR); 164562306a36Sopenharmony_ci state = RESPST_COMPLETE; 164662306a36Sopenharmony_ci break; 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci case RESPST_ERR_CQ_OVERFLOW: 164962306a36Sopenharmony_ci /* All - Class G */ 165062306a36Sopenharmony_ci state = RESPST_ERROR; 165162306a36Sopenharmony_ci break; 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci case RESPST_DONE: 165462306a36Sopenharmony_ci if (qp->resp.goto_error) { 165562306a36Sopenharmony_ci state = RESPST_ERROR; 165662306a36Sopenharmony_ci break; 165762306a36Sopenharmony_ci } 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci goto done; 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci case RESPST_EXIT: 166262306a36Sopenharmony_ci if (qp->resp.goto_error) { 166362306a36Sopenharmony_ci state = RESPST_ERROR; 166462306a36Sopenharmony_ci break; 166562306a36Sopenharmony_ci } 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci goto exit; 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci case RESPST_ERROR: 167062306a36Sopenharmony_ci qp->resp.goto_error = 0; 167162306a36Sopenharmony_ci rxe_dbg_qp(qp, "moved to error state\n"); 167262306a36Sopenharmony_ci rxe_qp_error(qp); 167362306a36Sopenharmony_ci goto exit; 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci default: 167662306a36Sopenharmony_ci WARN_ON_ONCE(1); 167762306a36Sopenharmony_ci } 167862306a36Sopenharmony_ci } 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci /* A non-zero return value will cause rxe_do_task to 168162306a36Sopenharmony_ci * exit its loop and end the work item. A zero return 168262306a36Sopenharmony_ci * will continue looping and return to rxe_responder 168362306a36Sopenharmony_ci */ 168462306a36Sopenharmony_cidone: 168562306a36Sopenharmony_ci ret = 0; 168662306a36Sopenharmony_ci goto out; 168762306a36Sopenharmony_ciexit: 168862306a36Sopenharmony_ci ret = -EAGAIN; 168962306a36Sopenharmony_ciout: 169062306a36Sopenharmony_ci return ret; 169162306a36Sopenharmony_ci} 1692