162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci/* Authors: Bernard Metzler <bmt@zurich.ibm.com> */ 462306a36Sopenharmony_ci/* Copyright (c) 2008-2019, IBM Corporation */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/errno.h> 762306a36Sopenharmony_ci#include <linux/types.h> 862306a36Sopenharmony_ci#include <linux/net.h> 962306a36Sopenharmony_ci#include <linux/scatterlist.h> 1062306a36Sopenharmony_ci#include <linux/llist.h> 1162306a36Sopenharmony_ci#include <asm/barrier.h> 1262306a36Sopenharmony_ci#include <net/tcp.h> 1362306a36Sopenharmony_ci#include <trace/events/sock.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "siw.h" 1662306a36Sopenharmony_ci#include "siw_verbs.h" 1762306a36Sopenharmony_ci#include "siw_mem.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic char siw_qp_state_to_string[SIW_QP_STATE_COUNT][sizeof "TERMINATE"] = { 2062306a36Sopenharmony_ci [SIW_QP_STATE_IDLE] = "IDLE", 2162306a36Sopenharmony_ci [SIW_QP_STATE_RTR] = "RTR", 2262306a36Sopenharmony_ci [SIW_QP_STATE_RTS] = "RTS", 2362306a36Sopenharmony_ci [SIW_QP_STATE_CLOSING] = "CLOSING", 2462306a36Sopenharmony_ci [SIW_QP_STATE_TERMINATE] = "TERMINATE", 2562306a36Sopenharmony_ci [SIW_QP_STATE_ERROR] = "ERROR" 2662306a36Sopenharmony_ci}; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* 2962306a36Sopenharmony_ci * iWARP (RDMAP, DDP and MPA) parameters as well as Softiwarp settings on a 3062306a36Sopenharmony_ci * per-RDMAP message basis. Please keep order of initializer. All MPA len 3162306a36Sopenharmony_ci * is initialized to minimum packet size. 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_cistruct iwarp_msg_info iwarp_pktinfo[RDMAP_TERMINATE + 1] = { 3462306a36Sopenharmony_ci { /* RDMAP_RDMA_WRITE */ 3562306a36Sopenharmony_ci .hdr_len = sizeof(struct iwarp_rdma_write), 3662306a36Sopenharmony_ci .ctrl.mpa_len = htons(sizeof(struct iwarp_rdma_write) - 2), 3762306a36Sopenharmony_ci .ctrl.ddp_rdmap_ctrl = DDP_FLAG_TAGGED | DDP_FLAG_LAST | 3862306a36Sopenharmony_ci cpu_to_be16(DDP_VERSION << 8) | 3962306a36Sopenharmony_ci cpu_to_be16(RDMAP_VERSION << 6) | 4062306a36Sopenharmony_ci cpu_to_be16(RDMAP_RDMA_WRITE), 4162306a36Sopenharmony_ci .rx_data = siw_proc_write }, 4262306a36Sopenharmony_ci { /* RDMAP_RDMA_READ_REQ */ 4362306a36Sopenharmony_ci .hdr_len = sizeof(struct iwarp_rdma_rreq), 4462306a36Sopenharmony_ci .ctrl.mpa_len = htons(sizeof(struct iwarp_rdma_rreq) - 2), 4562306a36Sopenharmony_ci .ctrl.ddp_rdmap_ctrl = DDP_FLAG_LAST | cpu_to_be16(DDP_VERSION << 8) | 4662306a36Sopenharmony_ci cpu_to_be16(RDMAP_VERSION << 6) | 4762306a36Sopenharmony_ci cpu_to_be16(RDMAP_RDMA_READ_REQ), 4862306a36Sopenharmony_ci .rx_data = siw_proc_rreq }, 4962306a36Sopenharmony_ci { /* RDMAP_RDMA_READ_RESP */ 5062306a36Sopenharmony_ci .hdr_len = sizeof(struct iwarp_rdma_rresp), 5162306a36Sopenharmony_ci .ctrl.mpa_len = htons(sizeof(struct iwarp_rdma_rresp) - 2), 5262306a36Sopenharmony_ci .ctrl.ddp_rdmap_ctrl = DDP_FLAG_TAGGED | DDP_FLAG_LAST | 5362306a36Sopenharmony_ci cpu_to_be16(DDP_VERSION << 8) | 5462306a36Sopenharmony_ci cpu_to_be16(RDMAP_VERSION << 6) | 5562306a36Sopenharmony_ci cpu_to_be16(RDMAP_RDMA_READ_RESP), 5662306a36Sopenharmony_ci .rx_data = siw_proc_rresp }, 5762306a36Sopenharmony_ci { /* RDMAP_SEND */ 5862306a36Sopenharmony_ci .hdr_len = sizeof(struct iwarp_send), 5962306a36Sopenharmony_ci .ctrl.mpa_len = htons(sizeof(struct iwarp_send) - 2), 6062306a36Sopenharmony_ci .ctrl.ddp_rdmap_ctrl = DDP_FLAG_LAST | cpu_to_be16(DDP_VERSION << 8) | 6162306a36Sopenharmony_ci cpu_to_be16(RDMAP_VERSION << 6) | 6262306a36Sopenharmony_ci cpu_to_be16(RDMAP_SEND), 6362306a36Sopenharmony_ci .rx_data = siw_proc_send }, 6462306a36Sopenharmony_ci { /* RDMAP_SEND_INVAL */ 6562306a36Sopenharmony_ci .hdr_len = sizeof(struct iwarp_send_inv), 6662306a36Sopenharmony_ci .ctrl.mpa_len = htons(sizeof(struct iwarp_send_inv) - 2), 6762306a36Sopenharmony_ci .ctrl.ddp_rdmap_ctrl = DDP_FLAG_LAST | cpu_to_be16(DDP_VERSION << 8) | 6862306a36Sopenharmony_ci cpu_to_be16(RDMAP_VERSION << 6) | 6962306a36Sopenharmony_ci cpu_to_be16(RDMAP_SEND_INVAL), 7062306a36Sopenharmony_ci .rx_data = siw_proc_send }, 7162306a36Sopenharmony_ci { /* RDMAP_SEND_SE */ 7262306a36Sopenharmony_ci .hdr_len = sizeof(struct iwarp_send), 7362306a36Sopenharmony_ci .ctrl.mpa_len = htons(sizeof(struct iwarp_send) - 2), 7462306a36Sopenharmony_ci .ctrl.ddp_rdmap_ctrl = DDP_FLAG_LAST | cpu_to_be16(DDP_VERSION << 8) | 7562306a36Sopenharmony_ci cpu_to_be16(RDMAP_VERSION << 6) | 7662306a36Sopenharmony_ci cpu_to_be16(RDMAP_SEND_SE), 7762306a36Sopenharmony_ci .rx_data = siw_proc_send }, 7862306a36Sopenharmony_ci { /* RDMAP_SEND_SE_INVAL */ 7962306a36Sopenharmony_ci .hdr_len = sizeof(struct iwarp_send_inv), 8062306a36Sopenharmony_ci .ctrl.mpa_len = htons(sizeof(struct iwarp_send_inv) - 2), 8162306a36Sopenharmony_ci .ctrl.ddp_rdmap_ctrl = DDP_FLAG_LAST | cpu_to_be16(DDP_VERSION << 8) | 8262306a36Sopenharmony_ci cpu_to_be16(RDMAP_VERSION << 6) | 8362306a36Sopenharmony_ci cpu_to_be16(RDMAP_SEND_SE_INVAL), 8462306a36Sopenharmony_ci .rx_data = siw_proc_send }, 8562306a36Sopenharmony_ci { /* RDMAP_TERMINATE */ 8662306a36Sopenharmony_ci .hdr_len = sizeof(struct iwarp_terminate), 8762306a36Sopenharmony_ci .ctrl.mpa_len = htons(sizeof(struct iwarp_terminate) - 2), 8862306a36Sopenharmony_ci .ctrl.ddp_rdmap_ctrl = DDP_FLAG_LAST | cpu_to_be16(DDP_VERSION << 8) | 8962306a36Sopenharmony_ci cpu_to_be16(RDMAP_VERSION << 6) | 9062306a36Sopenharmony_ci cpu_to_be16(RDMAP_TERMINATE), 9162306a36Sopenharmony_ci .rx_data = siw_proc_terminate } 9262306a36Sopenharmony_ci}; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_civoid siw_qp_llp_data_ready(struct sock *sk) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci struct siw_qp *qp; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci trace_sk_data_ready(sk); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci read_lock(&sk->sk_callback_lock); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci if (unlikely(!sk->sk_user_data || !sk_to_qp(sk))) 10362306a36Sopenharmony_ci goto done; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci qp = sk_to_qp(sk); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci if (likely(!qp->rx_stream.rx_suspend && 10862306a36Sopenharmony_ci down_read_trylock(&qp->state_lock))) { 10962306a36Sopenharmony_ci read_descriptor_t rd_desc = { .arg.data = qp, .count = 1 }; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (likely(qp->attrs.state == SIW_QP_STATE_RTS)) 11262306a36Sopenharmony_ci /* 11362306a36Sopenharmony_ci * Implements data receive operation during 11462306a36Sopenharmony_ci * socket callback. TCP gracefully catches 11562306a36Sopenharmony_ci * the case where there is nothing to receive 11662306a36Sopenharmony_ci * (not calling siw_tcp_rx_data() then). 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_ci tcp_read_sock(sk, &rd_desc, siw_tcp_rx_data); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci up_read(&qp->state_lock); 12162306a36Sopenharmony_ci } else { 12262306a36Sopenharmony_ci siw_dbg_qp(qp, "unable to process RX, suspend: %d\n", 12362306a36Sopenharmony_ci qp->rx_stream.rx_suspend); 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_cidone: 12662306a36Sopenharmony_ci read_unlock(&sk->sk_callback_lock); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_civoid siw_qp_llp_close(struct siw_qp *qp) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci siw_dbg_qp(qp, "enter llp close, state = %s\n", 13262306a36Sopenharmony_ci siw_qp_state_to_string[qp->attrs.state]); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci down_write(&qp->state_lock); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci qp->rx_stream.rx_suspend = 1; 13762306a36Sopenharmony_ci qp->tx_ctx.tx_suspend = 1; 13862306a36Sopenharmony_ci qp->attrs.sk = NULL; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci switch (qp->attrs.state) { 14162306a36Sopenharmony_ci case SIW_QP_STATE_RTS: 14262306a36Sopenharmony_ci case SIW_QP_STATE_RTR: 14362306a36Sopenharmony_ci case SIW_QP_STATE_IDLE: 14462306a36Sopenharmony_ci case SIW_QP_STATE_TERMINATE: 14562306a36Sopenharmony_ci qp->attrs.state = SIW_QP_STATE_ERROR; 14662306a36Sopenharmony_ci break; 14762306a36Sopenharmony_ci /* 14862306a36Sopenharmony_ci * SIW_QP_STATE_CLOSING: 14962306a36Sopenharmony_ci * 15062306a36Sopenharmony_ci * This is a forced close. shall the QP be moved to 15162306a36Sopenharmony_ci * ERROR or IDLE ? 15262306a36Sopenharmony_ci */ 15362306a36Sopenharmony_ci case SIW_QP_STATE_CLOSING: 15462306a36Sopenharmony_ci if (tx_wqe(qp)->wr_status == SIW_WR_IDLE) 15562306a36Sopenharmony_ci qp->attrs.state = SIW_QP_STATE_ERROR; 15662306a36Sopenharmony_ci else 15762306a36Sopenharmony_ci qp->attrs.state = SIW_QP_STATE_IDLE; 15862306a36Sopenharmony_ci break; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci default: 16162306a36Sopenharmony_ci siw_dbg_qp(qp, "llp close: no state transition needed: %s\n", 16262306a36Sopenharmony_ci siw_qp_state_to_string[qp->attrs.state]); 16362306a36Sopenharmony_ci break; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci siw_sq_flush(qp); 16662306a36Sopenharmony_ci siw_rq_flush(qp); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci /* 16962306a36Sopenharmony_ci * Dereference closing CEP 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_ci if (qp->cep) { 17262306a36Sopenharmony_ci siw_cep_put(qp->cep); 17362306a36Sopenharmony_ci qp->cep = NULL; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci up_write(&qp->state_lock); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci siw_dbg_qp(qp, "llp close exit: state %s\n", 17962306a36Sopenharmony_ci siw_qp_state_to_string[qp->attrs.state]); 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci/* 18362306a36Sopenharmony_ci * socket callback routine informing about newly available send space. 18462306a36Sopenharmony_ci * Function schedules SQ work for processing SQ items. 18562306a36Sopenharmony_ci */ 18662306a36Sopenharmony_civoid siw_qp_llp_write_space(struct sock *sk) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci struct siw_cep *cep; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci read_lock(&sk->sk_callback_lock); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci cep = sk_to_cep(sk); 19362306a36Sopenharmony_ci if (cep) { 19462306a36Sopenharmony_ci cep->sk_write_space(sk); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (!test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) 19762306a36Sopenharmony_ci (void)siw_sq_start(cep->qp); 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci read_unlock(&sk->sk_callback_lock); 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic int siw_qp_readq_init(struct siw_qp *qp, int irq_size, int orq_size) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci if (irq_size) { 20662306a36Sopenharmony_ci irq_size = roundup_pow_of_two(irq_size); 20762306a36Sopenharmony_ci qp->irq = vcalloc(irq_size, sizeof(struct siw_sqe)); 20862306a36Sopenharmony_ci if (!qp->irq) { 20962306a36Sopenharmony_ci qp->attrs.irq_size = 0; 21062306a36Sopenharmony_ci return -ENOMEM; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci if (orq_size) { 21462306a36Sopenharmony_ci orq_size = roundup_pow_of_two(orq_size); 21562306a36Sopenharmony_ci qp->orq = vcalloc(orq_size, sizeof(struct siw_sqe)); 21662306a36Sopenharmony_ci if (!qp->orq) { 21762306a36Sopenharmony_ci qp->attrs.orq_size = 0; 21862306a36Sopenharmony_ci qp->attrs.irq_size = 0; 21962306a36Sopenharmony_ci vfree(qp->irq); 22062306a36Sopenharmony_ci return -ENOMEM; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci qp->attrs.irq_size = irq_size; 22462306a36Sopenharmony_ci qp->attrs.orq_size = orq_size; 22562306a36Sopenharmony_ci siw_dbg_qp(qp, "ORD %d, IRD %d\n", orq_size, irq_size); 22662306a36Sopenharmony_ci return 0; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic int siw_qp_enable_crc(struct siw_qp *qp) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci struct siw_rx_stream *c_rx = &qp->rx_stream; 23262306a36Sopenharmony_ci struct siw_iwarp_tx *c_tx = &qp->tx_ctx; 23362306a36Sopenharmony_ci int size; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci if (siw_crypto_shash == NULL) 23662306a36Sopenharmony_ci return -ENOENT; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci size = crypto_shash_descsize(siw_crypto_shash) + 23962306a36Sopenharmony_ci sizeof(struct shash_desc); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci c_tx->mpa_crc_hd = kzalloc(size, GFP_KERNEL); 24262306a36Sopenharmony_ci c_rx->mpa_crc_hd = kzalloc(size, GFP_KERNEL); 24362306a36Sopenharmony_ci if (!c_tx->mpa_crc_hd || !c_rx->mpa_crc_hd) { 24462306a36Sopenharmony_ci kfree(c_tx->mpa_crc_hd); 24562306a36Sopenharmony_ci kfree(c_rx->mpa_crc_hd); 24662306a36Sopenharmony_ci c_tx->mpa_crc_hd = NULL; 24762306a36Sopenharmony_ci c_rx->mpa_crc_hd = NULL; 24862306a36Sopenharmony_ci return -ENOMEM; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci c_tx->mpa_crc_hd->tfm = siw_crypto_shash; 25162306a36Sopenharmony_ci c_rx->mpa_crc_hd->tfm = siw_crypto_shash; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci return 0; 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci/* 25762306a36Sopenharmony_ci * Send a non signalled READ or WRITE to peer side as negotiated 25862306a36Sopenharmony_ci * with MPAv2 P2P setup protocol. The work request is only created 25962306a36Sopenharmony_ci * as a current active WR and does not consume Send Queue space. 26062306a36Sopenharmony_ci * 26162306a36Sopenharmony_ci * Caller must hold QP state lock. 26262306a36Sopenharmony_ci */ 26362306a36Sopenharmony_ciint siw_qp_mpa_rts(struct siw_qp *qp, enum mpa_v2_ctrl ctrl) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci struct siw_wqe *wqe = tx_wqe(qp); 26662306a36Sopenharmony_ci unsigned long flags; 26762306a36Sopenharmony_ci int rv = 0; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci spin_lock_irqsave(&qp->sq_lock, flags); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci if (unlikely(wqe->wr_status != SIW_WR_IDLE)) { 27262306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->sq_lock, flags); 27362306a36Sopenharmony_ci return -EIO; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci memset(wqe->mem, 0, sizeof(*wqe->mem) * SIW_MAX_SGE); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci wqe->wr_status = SIW_WR_QUEUED; 27862306a36Sopenharmony_ci wqe->sqe.flags = 0; 27962306a36Sopenharmony_ci wqe->sqe.num_sge = 1; 28062306a36Sopenharmony_ci wqe->sqe.sge[0].length = 0; 28162306a36Sopenharmony_ci wqe->sqe.sge[0].laddr = 0; 28262306a36Sopenharmony_ci wqe->sqe.sge[0].lkey = 0; 28362306a36Sopenharmony_ci /* 28462306a36Sopenharmony_ci * While it must not be checked for inbound zero length 28562306a36Sopenharmony_ci * READ/WRITE, some HW may treat STag 0 special. 28662306a36Sopenharmony_ci */ 28762306a36Sopenharmony_ci wqe->sqe.rkey = 1; 28862306a36Sopenharmony_ci wqe->sqe.raddr = 0; 28962306a36Sopenharmony_ci wqe->processed = 0; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (ctrl & MPA_V2_RDMA_WRITE_RTR) 29262306a36Sopenharmony_ci wqe->sqe.opcode = SIW_OP_WRITE; 29362306a36Sopenharmony_ci else if (ctrl & MPA_V2_RDMA_READ_RTR) { 29462306a36Sopenharmony_ci struct siw_sqe *rreq = NULL; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci wqe->sqe.opcode = SIW_OP_READ; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci spin_lock(&qp->orq_lock); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (qp->attrs.orq_size) 30162306a36Sopenharmony_ci rreq = orq_get_free(qp); 30262306a36Sopenharmony_ci if (rreq) { 30362306a36Sopenharmony_ci siw_read_to_orq(rreq, &wqe->sqe); 30462306a36Sopenharmony_ci qp->orq_put++; 30562306a36Sopenharmony_ci } else 30662306a36Sopenharmony_ci rv = -EIO; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci spin_unlock(&qp->orq_lock); 30962306a36Sopenharmony_ci } else 31062306a36Sopenharmony_ci rv = -EINVAL; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (rv) 31362306a36Sopenharmony_ci wqe->wr_status = SIW_WR_IDLE; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->sq_lock, flags); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (!rv) 31862306a36Sopenharmony_ci rv = siw_sq_start(qp); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci return rv; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci/* 32462306a36Sopenharmony_ci * Map memory access error to DDP tagged error 32562306a36Sopenharmony_ci */ 32662306a36Sopenharmony_cienum ddp_ecode siw_tagged_error(enum siw_access_state state) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci switch (state) { 32962306a36Sopenharmony_ci case E_STAG_INVALID: 33062306a36Sopenharmony_ci return DDP_ECODE_T_INVALID_STAG; 33162306a36Sopenharmony_ci case E_BASE_BOUNDS: 33262306a36Sopenharmony_ci return DDP_ECODE_T_BASE_BOUNDS; 33362306a36Sopenharmony_ci case E_PD_MISMATCH: 33462306a36Sopenharmony_ci return DDP_ECODE_T_STAG_NOT_ASSOC; 33562306a36Sopenharmony_ci case E_ACCESS_PERM: 33662306a36Sopenharmony_ci /* 33762306a36Sopenharmony_ci * RFC 5041 (DDP) lacks an ecode for insufficient access 33862306a36Sopenharmony_ci * permissions. 'Invalid STag' seem to be the closest 33962306a36Sopenharmony_ci * match though. 34062306a36Sopenharmony_ci */ 34162306a36Sopenharmony_ci return DDP_ECODE_T_INVALID_STAG; 34262306a36Sopenharmony_ci default: 34362306a36Sopenharmony_ci WARN_ON(1); 34462306a36Sopenharmony_ci return DDP_ECODE_T_INVALID_STAG; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci/* 34962306a36Sopenharmony_ci * Map memory access error to RDMAP protection error 35062306a36Sopenharmony_ci */ 35162306a36Sopenharmony_cienum rdmap_ecode siw_rdmap_error(enum siw_access_state state) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci switch (state) { 35462306a36Sopenharmony_ci case E_STAG_INVALID: 35562306a36Sopenharmony_ci return RDMAP_ECODE_INVALID_STAG; 35662306a36Sopenharmony_ci case E_BASE_BOUNDS: 35762306a36Sopenharmony_ci return RDMAP_ECODE_BASE_BOUNDS; 35862306a36Sopenharmony_ci case E_PD_MISMATCH: 35962306a36Sopenharmony_ci return RDMAP_ECODE_STAG_NOT_ASSOC; 36062306a36Sopenharmony_ci case E_ACCESS_PERM: 36162306a36Sopenharmony_ci return RDMAP_ECODE_ACCESS_RIGHTS; 36262306a36Sopenharmony_ci default: 36362306a36Sopenharmony_ci return RDMAP_ECODE_UNSPECIFIED; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_civoid siw_init_terminate(struct siw_qp *qp, enum term_elayer layer, u8 etype, 36862306a36Sopenharmony_ci u8 ecode, int in_tx) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci if (!qp->term_info.valid) { 37162306a36Sopenharmony_ci memset(&qp->term_info, 0, sizeof(qp->term_info)); 37262306a36Sopenharmony_ci qp->term_info.layer = layer; 37362306a36Sopenharmony_ci qp->term_info.etype = etype; 37462306a36Sopenharmony_ci qp->term_info.ecode = ecode; 37562306a36Sopenharmony_ci qp->term_info.in_tx = in_tx; 37662306a36Sopenharmony_ci qp->term_info.valid = 1; 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci siw_dbg_qp(qp, "init TERM: layer %d, type %d, code %d, in tx %s\n", 37962306a36Sopenharmony_ci layer, etype, ecode, in_tx ? "yes" : "no"); 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci/* 38362306a36Sopenharmony_ci * Send a TERMINATE message, as defined in RFC's 5040/5041/5044/6581. 38462306a36Sopenharmony_ci * Sending TERMINATE messages is best effort - such messages 38562306a36Sopenharmony_ci * can only be send if the QP is still connected and it does 38662306a36Sopenharmony_ci * not have another outbound message in-progress, i.e. the 38762306a36Sopenharmony_ci * TERMINATE message must not interfer with an incomplete current 38862306a36Sopenharmony_ci * transmit operation. 38962306a36Sopenharmony_ci */ 39062306a36Sopenharmony_civoid siw_send_terminate(struct siw_qp *qp) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci struct kvec iov[3]; 39362306a36Sopenharmony_ci struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_EOR }; 39462306a36Sopenharmony_ci struct iwarp_terminate *term = NULL; 39562306a36Sopenharmony_ci union iwarp_hdr *err_hdr = NULL; 39662306a36Sopenharmony_ci struct socket *s = qp->attrs.sk; 39762306a36Sopenharmony_ci struct siw_rx_stream *srx = &qp->rx_stream; 39862306a36Sopenharmony_ci union iwarp_hdr *rx_hdr = &srx->hdr; 39962306a36Sopenharmony_ci u32 crc = 0; 40062306a36Sopenharmony_ci int num_frags, len_terminate, rv; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (!qp->term_info.valid) 40362306a36Sopenharmony_ci return; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci qp->term_info.valid = 0; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci if (tx_wqe(qp)->wr_status == SIW_WR_INPROGRESS) { 40862306a36Sopenharmony_ci siw_dbg_qp(qp, "cannot send TERMINATE: op %d in progress\n", 40962306a36Sopenharmony_ci tx_type(tx_wqe(qp))); 41062306a36Sopenharmony_ci return; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci if (!s && qp->cep) 41362306a36Sopenharmony_ci /* QP not yet in RTS. Take socket from connection end point */ 41462306a36Sopenharmony_ci s = qp->cep->sock; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if (!s) { 41762306a36Sopenharmony_ci siw_dbg_qp(qp, "cannot send TERMINATE: not connected\n"); 41862306a36Sopenharmony_ci return; 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci term = kzalloc(sizeof(*term), GFP_KERNEL); 42262306a36Sopenharmony_ci if (!term) 42362306a36Sopenharmony_ci return; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci term->ddp_qn = cpu_to_be32(RDMAP_UNTAGGED_QN_TERMINATE); 42662306a36Sopenharmony_ci term->ddp_mo = 0; 42762306a36Sopenharmony_ci term->ddp_msn = cpu_to_be32(1); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci iov[0].iov_base = term; 43062306a36Sopenharmony_ci iov[0].iov_len = sizeof(*term); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci if ((qp->term_info.layer == TERM_ERROR_LAYER_DDP) || 43362306a36Sopenharmony_ci ((qp->term_info.layer == TERM_ERROR_LAYER_RDMAP) && 43462306a36Sopenharmony_ci (qp->term_info.etype != RDMAP_ETYPE_CATASTROPHIC))) { 43562306a36Sopenharmony_ci err_hdr = kzalloc(sizeof(*err_hdr), GFP_KERNEL); 43662306a36Sopenharmony_ci if (!err_hdr) { 43762306a36Sopenharmony_ci kfree(term); 43862306a36Sopenharmony_ci return; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci memcpy(&term->ctrl, &iwarp_pktinfo[RDMAP_TERMINATE].ctrl, 44262306a36Sopenharmony_ci sizeof(struct iwarp_ctrl)); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci __rdmap_term_set_layer(term, qp->term_info.layer); 44562306a36Sopenharmony_ci __rdmap_term_set_etype(term, qp->term_info.etype); 44662306a36Sopenharmony_ci __rdmap_term_set_ecode(term, qp->term_info.ecode); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci switch (qp->term_info.layer) { 44962306a36Sopenharmony_ci case TERM_ERROR_LAYER_RDMAP: 45062306a36Sopenharmony_ci if (qp->term_info.etype == RDMAP_ETYPE_CATASTROPHIC) 45162306a36Sopenharmony_ci /* No additional DDP/RDMAP header to be included */ 45262306a36Sopenharmony_ci break; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci if (qp->term_info.etype == RDMAP_ETYPE_REMOTE_PROTECTION) { 45562306a36Sopenharmony_ci /* 45662306a36Sopenharmony_ci * Complete RDMAP frame will get attached, and 45762306a36Sopenharmony_ci * DDP segment length is valid 45862306a36Sopenharmony_ci */ 45962306a36Sopenharmony_ci term->flag_m = 1; 46062306a36Sopenharmony_ci term->flag_d = 1; 46162306a36Sopenharmony_ci term->flag_r = 1; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci if (qp->term_info.in_tx) { 46462306a36Sopenharmony_ci struct iwarp_rdma_rreq *rreq; 46562306a36Sopenharmony_ci struct siw_wqe *wqe = tx_wqe(qp); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci /* Inbound RREQ error, detected during 46862306a36Sopenharmony_ci * RRESP creation. Take state from 46962306a36Sopenharmony_ci * current TX work queue element to 47062306a36Sopenharmony_ci * reconstruct peers RREQ. 47162306a36Sopenharmony_ci */ 47262306a36Sopenharmony_ci rreq = (struct iwarp_rdma_rreq *)err_hdr; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci memcpy(&rreq->ctrl, 47562306a36Sopenharmony_ci &iwarp_pktinfo[RDMAP_RDMA_READ_REQ].ctrl, 47662306a36Sopenharmony_ci sizeof(struct iwarp_ctrl)); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci rreq->rsvd = 0; 47962306a36Sopenharmony_ci rreq->ddp_qn = 48062306a36Sopenharmony_ci htonl(RDMAP_UNTAGGED_QN_RDMA_READ); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* Provide RREQ's MSN as kept aside */ 48362306a36Sopenharmony_ci rreq->ddp_msn = htonl(wqe->sqe.sge[0].length); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci rreq->ddp_mo = htonl(wqe->processed); 48662306a36Sopenharmony_ci rreq->sink_stag = htonl(wqe->sqe.rkey); 48762306a36Sopenharmony_ci rreq->sink_to = cpu_to_be64(wqe->sqe.raddr); 48862306a36Sopenharmony_ci rreq->read_size = htonl(wqe->sqe.sge[0].length); 48962306a36Sopenharmony_ci rreq->source_stag = htonl(wqe->sqe.sge[0].lkey); 49062306a36Sopenharmony_ci rreq->source_to = 49162306a36Sopenharmony_ci cpu_to_be64(wqe->sqe.sge[0].laddr); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci iov[1].iov_base = rreq; 49462306a36Sopenharmony_ci iov[1].iov_len = sizeof(*rreq); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci rx_hdr = (union iwarp_hdr *)rreq; 49762306a36Sopenharmony_ci } else { 49862306a36Sopenharmony_ci /* Take RDMAP/DDP information from 49962306a36Sopenharmony_ci * current (failed) inbound frame. 50062306a36Sopenharmony_ci */ 50162306a36Sopenharmony_ci iov[1].iov_base = rx_hdr; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci if (__rdmap_get_opcode(&rx_hdr->ctrl) == 50462306a36Sopenharmony_ci RDMAP_RDMA_READ_REQ) 50562306a36Sopenharmony_ci iov[1].iov_len = 50662306a36Sopenharmony_ci sizeof(struct iwarp_rdma_rreq); 50762306a36Sopenharmony_ci else /* SEND type */ 50862306a36Sopenharmony_ci iov[1].iov_len = 50962306a36Sopenharmony_ci sizeof(struct iwarp_send); 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci } else { 51262306a36Sopenharmony_ci /* Do not report DDP hdr information if packet 51362306a36Sopenharmony_ci * layout is unknown 51462306a36Sopenharmony_ci */ 51562306a36Sopenharmony_ci if ((qp->term_info.ecode == RDMAP_ECODE_VERSION) || 51662306a36Sopenharmony_ci (qp->term_info.ecode == RDMAP_ECODE_OPCODE)) 51762306a36Sopenharmony_ci break; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci iov[1].iov_base = rx_hdr; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci /* Only DDP frame will get attached */ 52262306a36Sopenharmony_ci if (rx_hdr->ctrl.ddp_rdmap_ctrl & DDP_FLAG_TAGGED) 52362306a36Sopenharmony_ci iov[1].iov_len = 52462306a36Sopenharmony_ci sizeof(struct iwarp_rdma_write); 52562306a36Sopenharmony_ci else 52662306a36Sopenharmony_ci iov[1].iov_len = sizeof(struct iwarp_send); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci term->flag_m = 1; 52962306a36Sopenharmony_ci term->flag_d = 1; 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci term->ctrl.mpa_len = cpu_to_be16(iov[1].iov_len); 53262306a36Sopenharmony_ci break; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci case TERM_ERROR_LAYER_DDP: 53562306a36Sopenharmony_ci /* Report error encountered while DDP processing. 53662306a36Sopenharmony_ci * This can only happen as a result of inbound 53762306a36Sopenharmony_ci * DDP processing 53862306a36Sopenharmony_ci */ 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci /* Do not report DDP hdr information if packet 54162306a36Sopenharmony_ci * layout is unknown 54262306a36Sopenharmony_ci */ 54362306a36Sopenharmony_ci if (((qp->term_info.etype == DDP_ETYPE_TAGGED_BUF) && 54462306a36Sopenharmony_ci (qp->term_info.ecode == DDP_ECODE_T_VERSION)) || 54562306a36Sopenharmony_ci ((qp->term_info.etype == DDP_ETYPE_UNTAGGED_BUF) && 54662306a36Sopenharmony_ci (qp->term_info.ecode == DDP_ECODE_UT_VERSION))) 54762306a36Sopenharmony_ci break; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci iov[1].iov_base = rx_hdr; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci if (rx_hdr->ctrl.ddp_rdmap_ctrl & DDP_FLAG_TAGGED) 55262306a36Sopenharmony_ci iov[1].iov_len = sizeof(struct iwarp_ctrl_tagged); 55362306a36Sopenharmony_ci else 55462306a36Sopenharmony_ci iov[1].iov_len = sizeof(struct iwarp_ctrl_untagged); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci term->flag_m = 1; 55762306a36Sopenharmony_ci term->flag_d = 1; 55862306a36Sopenharmony_ci break; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci default: 56162306a36Sopenharmony_ci break; 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci if (term->flag_m || term->flag_d || term->flag_r) { 56462306a36Sopenharmony_ci iov[2].iov_base = &crc; 56562306a36Sopenharmony_ci iov[2].iov_len = sizeof(crc); 56662306a36Sopenharmony_ci len_terminate = sizeof(*term) + iov[1].iov_len + MPA_CRC_SIZE; 56762306a36Sopenharmony_ci num_frags = 3; 56862306a36Sopenharmony_ci } else { 56962306a36Sopenharmony_ci iov[1].iov_base = &crc; 57062306a36Sopenharmony_ci iov[1].iov_len = sizeof(crc); 57162306a36Sopenharmony_ci len_terminate = sizeof(*term) + MPA_CRC_SIZE; 57262306a36Sopenharmony_ci num_frags = 2; 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci /* Adjust DDP Segment Length parameter, if valid */ 57662306a36Sopenharmony_ci if (term->flag_m) { 57762306a36Sopenharmony_ci u32 real_ddp_len = be16_to_cpu(rx_hdr->ctrl.mpa_len); 57862306a36Sopenharmony_ci enum rdma_opcode op = __rdmap_get_opcode(&rx_hdr->ctrl); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci real_ddp_len -= iwarp_pktinfo[op].hdr_len - MPA_HDR_SIZE; 58162306a36Sopenharmony_ci rx_hdr->ctrl.mpa_len = cpu_to_be16(real_ddp_len); 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci term->ctrl.mpa_len = 58562306a36Sopenharmony_ci cpu_to_be16(len_terminate - (MPA_HDR_SIZE + MPA_CRC_SIZE)); 58662306a36Sopenharmony_ci if (qp->tx_ctx.mpa_crc_hd) { 58762306a36Sopenharmony_ci crypto_shash_init(qp->tx_ctx.mpa_crc_hd); 58862306a36Sopenharmony_ci if (crypto_shash_update(qp->tx_ctx.mpa_crc_hd, 58962306a36Sopenharmony_ci (u8 *)iov[0].iov_base, 59062306a36Sopenharmony_ci iov[0].iov_len)) 59162306a36Sopenharmony_ci goto out; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci if (num_frags == 3) { 59462306a36Sopenharmony_ci if (crypto_shash_update(qp->tx_ctx.mpa_crc_hd, 59562306a36Sopenharmony_ci (u8 *)iov[1].iov_base, 59662306a36Sopenharmony_ci iov[1].iov_len)) 59762306a36Sopenharmony_ci goto out; 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci crypto_shash_final(qp->tx_ctx.mpa_crc_hd, (u8 *)&crc); 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci rv = kernel_sendmsg(s, &msg, iov, num_frags, len_terminate); 60362306a36Sopenharmony_ci siw_dbg_qp(qp, "sent TERM: %s, layer %d, type %d, code %d (%d bytes)\n", 60462306a36Sopenharmony_ci rv == len_terminate ? "success" : "failure", 60562306a36Sopenharmony_ci __rdmap_term_layer(term), __rdmap_term_etype(term), 60662306a36Sopenharmony_ci __rdmap_term_ecode(term), rv); 60762306a36Sopenharmony_ciout: 60862306a36Sopenharmony_ci kfree(term); 60962306a36Sopenharmony_ci kfree(err_hdr); 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci/* 61362306a36Sopenharmony_ci * Handle all attrs other than state 61462306a36Sopenharmony_ci */ 61562306a36Sopenharmony_cistatic void siw_qp_modify_nonstate(struct siw_qp *qp, 61662306a36Sopenharmony_ci struct siw_qp_attrs *attrs, 61762306a36Sopenharmony_ci enum siw_qp_attr_mask mask) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci if (mask & SIW_QP_ATTR_ACCESS_FLAGS) { 62062306a36Sopenharmony_ci if (attrs->flags & SIW_RDMA_BIND_ENABLED) 62162306a36Sopenharmony_ci qp->attrs.flags |= SIW_RDMA_BIND_ENABLED; 62262306a36Sopenharmony_ci else 62362306a36Sopenharmony_ci qp->attrs.flags &= ~SIW_RDMA_BIND_ENABLED; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci if (attrs->flags & SIW_RDMA_WRITE_ENABLED) 62662306a36Sopenharmony_ci qp->attrs.flags |= SIW_RDMA_WRITE_ENABLED; 62762306a36Sopenharmony_ci else 62862306a36Sopenharmony_ci qp->attrs.flags &= ~SIW_RDMA_WRITE_ENABLED; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (attrs->flags & SIW_RDMA_READ_ENABLED) 63162306a36Sopenharmony_ci qp->attrs.flags |= SIW_RDMA_READ_ENABLED; 63262306a36Sopenharmony_ci else 63362306a36Sopenharmony_ci qp->attrs.flags &= ~SIW_RDMA_READ_ENABLED; 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_cistatic int siw_qp_nextstate_from_idle(struct siw_qp *qp, 63862306a36Sopenharmony_ci struct siw_qp_attrs *attrs, 63962306a36Sopenharmony_ci enum siw_qp_attr_mask mask) 64062306a36Sopenharmony_ci{ 64162306a36Sopenharmony_ci int rv = 0; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci switch (attrs->state) { 64462306a36Sopenharmony_ci case SIW_QP_STATE_RTS: 64562306a36Sopenharmony_ci if (attrs->flags & SIW_MPA_CRC) { 64662306a36Sopenharmony_ci rv = siw_qp_enable_crc(qp); 64762306a36Sopenharmony_ci if (rv) 64862306a36Sopenharmony_ci break; 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci if (!(mask & SIW_QP_ATTR_LLP_HANDLE)) { 65162306a36Sopenharmony_ci siw_dbg_qp(qp, "no socket\n"); 65262306a36Sopenharmony_ci rv = -EINVAL; 65362306a36Sopenharmony_ci break; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci if (!(mask & SIW_QP_ATTR_MPA)) { 65662306a36Sopenharmony_ci siw_dbg_qp(qp, "no MPA\n"); 65762306a36Sopenharmony_ci rv = -EINVAL; 65862306a36Sopenharmony_ci break; 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci /* 66162306a36Sopenharmony_ci * Initialize iWARP TX state 66262306a36Sopenharmony_ci */ 66362306a36Sopenharmony_ci qp->tx_ctx.ddp_msn[RDMAP_UNTAGGED_QN_SEND] = 0; 66462306a36Sopenharmony_ci qp->tx_ctx.ddp_msn[RDMAP_UNTAGGED_QN_RDMA_READ] = 0; 66562306a36Sopenharmony_ci qp->tx_ctx.ddp_msn[RDMAP_UNTAGGED_QN_TERMINATE] = 0; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci /* 66862306a36Sopenharmony_ci * Initialize iWARP RX state 66962306a36Sopenharmony_ci */ 67062306a36Sopenharmony_ci qp->rx_stream.ddp_msn[RDMAP_UNTAGGED_QN_SEND] = 1; 67162306a36Sopenharmony_ci qp->rx_stream.ddp_msn[RDMAP_UNTAGGED_QN_RDMA_READ] = 1; 67262306a36Sopenharmony_ci qp->rx_stream.ddp_msn[RDMAP_UNTAGGED_QN_TERMINATE] = 1; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci /* 67562306a36Sopenharmony_ci * init IRD free queue, caller has already checked 67662306a36Sopenharmony_ci * limits. 67762306a36Sopenharmony_ci */ 67862306a36Sopenharmony_ci rv = siw_qp_readq_init(qp, attrs->irq_size, 67962306a36Sopenharmony_ci attrs->orq_size); 68062306a36Sopenharmony_ci if (rv) 68162306a36Sopenharmony_ci break; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci qp->attrs.sk = attrs->sk; 68462306a36Sopenharmony_ci qp->attrs.state = SIW_QP_STATE_RTS; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci siw_dbg_qp(qp, "enter RTS: crc=%s, ord=%u, ird=%u\n", 68762306a36Sopenharmony_ci attrs->flags & SIW_MPA_CRC ? "y" : "n", 68862306a36Sopenharmony_ci qp->attrs.orq_size, qp->attrs.irq_size); 68962306a36Sopenharmony_ci break; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci case SIW_QP_STATE_ERROR: 69262306a36Sopenharmony_ci siw_rq_flush(qp); 69362306a36Sopenharmony_ci qp->attrs.state = SIW_QP_STATE_ERROR; 69462306a36Sopenharmony_ci if (qp->cep) { 69562306a36Sopenharmony_ci siw_cep_put(qp->cep); 69662306a36Sopenharmony_ci qp->cep = NULL; 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci break; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci default: 70162306a36Sopenharmony_ci break; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci return rv; 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_cistatic int siw_qp_nextstate_from_rts(struct siw_qp *qp, 70762306a36Sopenharmony_ci struct siw_qp_attrs *attrs) 70862306a36Sopenharmony_ci{ 70962306a36Sopenharmony_ci int drop_conn = 0; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci switch (attrs->state) { 71262306a36Sopenharmony_ci case SIW_QP_STATE_CLOSING: 71362306a36Sopenharmony_ci /* 71462306a36Sopenharmony_ci * Verbs: move to IDLE if SQ and ORQ are empty. 71562306a36Sopenharmony_ci * Move to ERROR otherwise. But first of all we must 71662306a36Sopenharmony_ci * close the connection. So we keep CLOSING or ERROR 71762306a36Sopenharmony_ci * as a transient state, schedule connection drop work 71862306a36Sopenharmony_ci * and wait for the socket state change upcall to 71962306a36Sopenharmony_ci * come back closed. 72062306a36Sopenharmony_ci */ 72162306a36Sopenharmony_ci if (tx_wqe(qp)->wr_status == SIW_WR_IDLE) { 72262306a36Sopenharmony_ci qp->attrs.state = SIW_QP_STATE_CLOSING; 72362306a36Sopenharmony_ci } else { 72462306a36Sopenharmony_ci qp->attrs.state = SIW_QP_STATE_ERROR; 72562306a36Sopenharmony_ci siw_sq_flush(qp); 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci siw_rq_flush(qp); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci drop_conn = 1; 73062306a36Sopenharmony_ci break; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci case SIW_QP_STATE_TERMINATE: 73362306a36Sopenharmony_ci qp->attrs.state = SIW_QP_STATE_TERMINATE; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci siw_init_terminate(qp, TERM_ERROR_LAYER_RDMAP, 73662306a36Sopenharmony_ci RDMAP_ETYPE_CATASTROPHIC, 73762306a36Sopenharmony_ci RDMAP_ECODE_UNSPECIFIED, 1); 73862306a36Sopenharmony_ci drop_conn = 1; 73962306a36Sopenharmony_ci break; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci case SIW_QP_STATE_ERROR: 74262306a36Sopenharmony_ci /* 74362306a36Sopenharmony_ci * This is an emergency close. 74462306a36Sopenharmony_ci * 74562306a36Sopenharmony_ci * Any in progress transmit operation will get 74662306a36Sopenharmony_ci * cancelled. 74762306a36Sopenharmony_ci * This will likely result in a protocol failure, 74862306a36Sopenharmony_ci * if a TX operation is in transit. The caller 74962306a36Sopenharmony_ci * could unconditional wait to give the current 75062306a36Sopenharmony_ci * operation a chance to complete. 75162306a36Sopenharmony_ci * Esp., how to handle the non-empty IRQ case? 75262306a36Sopenharmony_ci * The peer was asking for data transfer at a valid 75362306a36Sopenharmony_ci * point in time. 75462306a36Sopenharmony_ci */ 75562306a36Sopenharmony_ci siw_sq_flush(qp); 75662306a36Sopenharmony_ci siw_rq_flush(qp); 75762306a36Sopenharmony_ci qp->attrs.state = SIW_QP_STATE_ERROR; 75862306a36Sopenharmony_ci drop_conn = 1; 75962306a36Sopenharmony_ci break; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci default: 76262306a36Sopenharmony_ci break; 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci return drop_conn; 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_cistatic void siw_qp_nextstate_from_term(struct siw_qp *qp, 76862306a36Sopenharmony_ci struct siw_qp_attrs *attrs) 76962306a36Sopenharmony_ci{ 77062306a36Sopenharmony_ci switch (attrs->state) { 77162306a36Sopenharmony_ci case SIW_QP_STATE_ERROR: 77262306a36Sopenharmony_ci siw_rq_flush(qp); 77362306a36Sopenharmony_ci qp->attrs.state = SIW_QP_STATE_ERROR; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci if (tx_wqe(qp)->wr_status != SIW_WR_IDLE) 77662306a36Sopenharmony_ci siw_sq_flush(qp); 77762306a36Sopenharmony_ci break; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci default: 78062306a36Sopenharmony_ci break; 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_cistatic int siw_qp_nextstate_from_close(struct siw_qp *qp, 78562306a36Sopenharmony_ci struct siw_qp_attrs *attrs) 78662306a36Sopenharmony_ci{ 78762306a36Sopenharmony_ci int rv = 0; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci switch (attrs->state) { 79062306a36Sopenharmony_ci case SIW_QP_STATE_IDLE: 79162306a36Sopenharmony_ci WARN_ON(tx_wqe(qp)->wr_status != SIW_WR_IDLE); 79262306a36Sopenharmony_ci qp->attrs.state = SIW_QP_STATE_IDLE; 79362306a36Sopenharmony_ci break; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci case SIW_QP_STATE_CLOSING: 79662306a36Sopenharmony_ci /* 79762306a36Sopenharmony_ci * The LLP may already moved the QP to closing 79862306a36Sopenharmony_ci * due to graceful peer close init 79962306a36Sopenharmony_ci */ 80062306a36Sopenharmony_ci break; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci case SIW_QP_STATE_ERROR: 80362306a36Sopenharmony_ci /* 80462306a36Sopenharmony_ci * QP was moved to CLOSING by LLP event 80562306a36Sopenharmony_ci * not yet seen by user. 80662306a36Sopenharmony_ci */ 80762306a36Sopenharmony_ci qp->attrs.state = SIW_QP_STATE_ERROR; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci if (tx_wqe(qp)->wr_status != SIW_WR_IDLE) 81062306a36Sopenharmony_ci siw_sq_flush(qp); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci siw_rq_flush(qp); 81362306a36Sopenharmony_ci break; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci default: 81662306a36Sopenharmony_ci siw_dbg_qp(qp, "state transition undefined: %s => %s\n", 81762306a36Sopenharmony_ci siw_qp_state_to_string[qp->attrs.state], 81862306a36Sopenharmony_ci siw_qp_state_to_string[attrs->state]); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci rv = -ECONNABORTED; 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci return rv; 82362306a36Sopenharmony_ci} 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci/* 82662306a36Sopenharmony_ci * Caller must hold qp->state_lock 82762306a36Sopenharmony_ci */ 82862306a36Sopenharmony_ciint siw_qp_modify(struct siw_qp *qp, struct siw_qp_attrs *attrs, 82962306a36Sopenharmony_ci enum siw_qp_attr_mask mask) 83062306a36Sopenharmony_ci{ 83162306a36Sopenharmony_ci int drop_conn = 0, rv = 0; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci if (!mask) 83462306a36Sopenharmony_ci return 0; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci siw_dbg_qp(qp, "state: %s => %s\n", 83762306a36Sopenharmony_ci siw_qp_state_to_string[qp->attrs.state], 83862306a36Sopenharmony_ci siw_qp_state_to_string[attrs->state]); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci if (mask != SIW_QP_ATTR_STATE) 84162306a36Sopenharmony_ci siw_qp_modify_nonstate(qp, attrs, mask); 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci if (!(mask & SIW_QP_ATTR_STATE)) 84462306a36Sopenharmony_ci return 0; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci switch (qp->attrs.state) { 84762306a36Sopenharmony_ci case SIW_QP_STATE_IDLE: 84862306a36Sopenharmony_ci case SIW_QP_STATE_RTR: 84962306a36Sopenharmony_ci rv = siw_qp_nextstate_from_idle(qp, attrs, mask); 85062306a36Sopenharmony_ci break; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci case SIW_QP_STATE_RTS: 85362306a36Sopenharmony_ci drop_conn = siw_qp_nextstate_from_rts(qp, attrs); 85462306a36Sopenharmony_ci break; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci case SIW_QP_STATE_TERMINATE: 85762306a36Sopenharmony_ci siw_qp_nextstate_from_term(qp, attrs); 85862306a36Sopenharmony_ci break; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci case SIW_QP_STATE_CLOSING: 86162306a36Sopenharmony_ci siw_qp_nextstate_from_close(qp, attrs); 86262306a36Sopenharmony_ci break; 86362306a36Sopenharmony_ci default: 86462306a36Sopenharmony_ci break; 86562306a36Sopenharmony_ci } 86662306a36Sopenharmony_ci if (drop_conn) 86762306a36Sopenharmony_ci siw_qp_cm_drop(qp, 0); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci return rv; 87062306a36Sopenharmony_ci} 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_civoid siw_read_to_orq(struct siw_sqe *rreq, struct siw_sqe *sqe) 87362306a36Sopenharmony_ci{ 87462306a36Sopenharmony_ci rreq->id = sqe->id; 87562306a36Sopenharmony_ci rreq->opcode = sqe->opcode; 87662306a36Sopenharmony_ci rreq->sge[0].laddr = sqe->sge[0].laddr; 87762306a36Sopenharmony_ci rreq->sge[0].length = sqe->sge[0].length; 87862306a36Sopenharmony_ci rreq->sge[0].lkey = sqe->sge[0].lkey; 87962306a36Sopenharmony_ci rreq->sge[1].lkey = sqe->sge[1].lkey; 88062306a36Sopenharmony_ci rreq->flags = sqe->flags | SIW_WQE_VALID; 88162306a36Sopenharmony_ci rreq->num_sge = 1; 88262306a36Sopenharmony_ci} 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_cistatic int siw_activate_tx_from_sq(struct siw_qp *qp) 88562306a36Sopenharmony_ci{ 88662306a36Sopenharmony_ci struct siw_sqe *sqe; 88762306a36Sopenharmony_ci struct siw_wqe *wqe = tx_wqe(qp); 88862306a36Sopenharmony_ci int rv = 1; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci sqe = sq_get_next(qp); 89162306a36Sopenharmony_ci if (!sqe) 89262306a36Sopenharmony_ci return 0; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci memset(wqe->mem, 0, sizeof(*wqe->mem) * SIW_MAX_SGE); 89562306a36Sopenharmony_ci wqe->wr_status = SIW_WR_QUEUED; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci /* First copy SQE to kernel private memory */ 89862306a36Sopenharmony_ci memcpy(&wqe->sqe, sqe, sizeof(*sqe)); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci if (wqe->sqe.opcode >= SIW_NUM_OPCODES) { 90162306a36Sopenharmony_ci rv = -EINVAL; 90262306a36Sopenharmony_ci goto out; 90362306a36Sopenharmony_ci } 90462306a36Sopenharmony_ci if (wqe->sqe.flags & SIW_WQE_INLINE) { 90562306a36Sopenharmony_ci if (wqe->sqe.opcode != SIW_OP_SEND && 90662306a36Sopenharmony_ci wqe->sqe.opcode != SIW_OP_WRITE) { 90762306a36Sopenharmony_ci rv = -EINVAL; 90862306a36Sopenharmony_ci goto out; 90962306a36Sopenharmony_ci } 91062306a36Sopenharmony_ci if (wqe->sqe.sge[0].length > SIW_MAX_INLINE) { 91162306a36Sopenharmony_ci rv = -EINVAL; 91262306a36Sopenharmony_ci goto out; 91362306a36Sopenharmony_ci } 91462306a36Sopenharmony_ci wqe->sqe.sge[0].laddr = (uintptr_t)&wqe->sqe.sge[1]; 91562306a36Sopenharmony_ci wqe->sqe.sge[0].lkey = 0; 91662306a36Sopenharmony_ci wqe->sqe.num_sge = 1; 91762306a36Sopenharmony_ci } 91862306a36Sopenharmony_ci if (wqe->sqe.flags & SIW_WQE_READ_FENCE) { 91962306a36Sopenharmony_ci /* A READ cannot be fenced */ 92062306a36Sopenharmony_ci if (unlikely(wqe->sqe.opcode == SIW_OP_READ || 92162306a36Sopenharmony_ci wqe->sqe.opcode == 92262306a36Sopenharmony_ci SIW_OP_READ_LOCAL_INV)) { 92362306a36Sopenharmony_ci siw_dbg_qp(qp, "cannot fence read\n"); 92462306a36Sopenharmony_ci rv = -EINVAL; 92562306a36Sopenharmony_ci goto out; 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci spin_lock(&qp->orq_lock); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci if (qp->attrs.orq_size && !siw_orq_empty(qp)) { 93062306a36Sopenharmony_ci qp->tx_ctx.orq_fence = 1; 93162306a36Sopenharmony_ci rv = 0; 93262306a36Sopenharmony_ci } 93362306a36Sopenharmony_ci spin_unlock(&qp->orq_lock); 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci } else if (wqe->sqe.opcode == SIW_OP_READ || 93662306a36Sopenharmony_ci wqe->sqe.opcode == SIW_OP_READ_LOCAL_INV) { 93762306a36Sopenharmony_ci struct siw_sqe *rreq; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci if (unlikely(!qp->attrs.orq_size)) { 94062306a36Sopenharmony_ci /* We negotiated not to send READ req's */ 94162306a36Sopenharmony_ci rv = -EINVAL; 94262306a36Sopenharmony_ci goto out; 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci wqe->sqe.num_sge = 1; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci spin_lock(&qp->orq_lock); 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci rreq = orq_get_free(qp); 94962306a36Sopenharmony_ci if (rreq) { 95062306a36Sopenharmony_ci /* 95162306a36Sopenharmony_ci * Make an immediate copy in ORQ to be ready 95262306a36Sopenharmony_ci * to process loopback READ reply 95362306a36Sopenharmony_ci */ 95462306a36Sopenharmony_ci siw_read_to_orq(rreq, &wqe->sqe); 95562306a36Sopenharmony_ci qp->orq_put++; 95662306a36Sopenharmony_ci } else { 95762306a36Sopenharmony_ci qp->tx_ctx.orq_fence = 1; 95862306a36Sopenharmony_ci rv = 0; 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci spin_unlock(&qp->orq_lock); 96162306a36Sopenharmony_ci } 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci /* Clear SQE, can be re-used by application */ 96462306a36Sopenharmony_ci smp_store_mb(sqe->flags, 0); 96562306a36Sopenharmony_ci qp->sq_get++; 96662306a36Sopenharmony_ciout: 96762306a36Sopenharmony_ci if (unlikely(rv < 0)) { 96862306a36Sopenharmony_ci siw_dbg_qp(qp, "error %d\n", rv); 96962306a36Sopenharmony_ci wqe->wr_status = SIW_WR_IDLE; 97062306a36Sopenharmony_ci } 97162306a36Sopenharmony_ci return rv; 97262306a36Sopenharmony_ci} 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci/* 97562306a36Sopenharmony_ci * Must be called with SQ locked. 97662306a36Sopenharmony_ci * To avoid complete SQ starvation by constant inbound READ requests, 97762306a36Sopenharmony_ci * the active IRQ will not be served after qp->irq_burst, if the 97862306a36Sopenharmony_ci * SQ has pending work. 97962306a36Sopenharmony_ci */ 98062306a36Sopenharmony_ciint siw_activate_tx(struct siw_qp *qp) 98162306a36Sopenharmony_ci{ 98262306a36Sopenharmony_ci struct siw_sqe *irqe; 98362306a36Sopenharmony_ci struct siw_wqe *wqe = tx_wqe(qp); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci if (!qp->attrs.irq_size) 98662306a36Sopenharmony_ci return siw_activate_tx_from_sq(qp); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci irqe = &qp->irq[qp->irq_get % qp->attrs.irq_size]; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci if (!(irqe->flags & SIW_WQE_VALID)) 99162306a36Sopenharmony_ci return siw_activate_tx_from_sq(qp); 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci /* 99462306a36Sopenharmony_ci * Avoid local WQE processing starvation in case 99562306a36Sopenharmony_ci * of constant inbound READ request stream 99662306a36Sopenharmony_ci */ 99762306a36Sopenharmony_ci if (sq_get_next(qp) && ++qp->irq_burst >= SIW_IRQ_MAXBURST_SQ_ACTIVE) { 99862306a36Sopenharmony_ci qp->irq_burst = 0; 99962306a36Sopenharmony_ci return siw_activate_tx_from_sq(qp); 100062306a36Sopenharmony_ci } 100162306a36Sopenharmony_ci memset(wqe->mem, 0, sizeof(*wqe->mem) * SIW_MAX_SGE); 100262306a36Sopenharmony_ci wqe->wr_status = SIW_WR_QUEUED; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci /* start READ RESPONSE */ 100562306a36Sopenharmony_ci wqe->sqe.opcode = SIW_OP_READ_RESPONSE; 100662306a36Sopenharmony_ci wqe->sqe.flags = 0; 100762306a36Sopenharmony_ci if (irqe->num_sge) { 100862306a36Sopenharmony_ci wqe->sqe.num_sge = 1; 100962306a36Sopenharmony_ci wqe->sqe.sge[0].length = irqe->sge[0].length; 101062306a36Sopenharmony_ci wqe->sqe.sge[0].laddr = irqe->sge[0].laddr; 101162306a36Sopenharmony_ci wqe->sqe.sge[0].lkey = irqe->sge[0].lkey; 101262306a36Sopenharmony_ci } else { 101362306a36Sopenharmony_ci wqe->sqe.num_sge = 0; 101462306a36Sopenharmony_ci } 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci /* Retain original RREQ's message sequence number for 101762306a36Sopenharmony_ci * potential error reporting cases. 101862306a36Sopenharmony_ci */ 101962306a36Sopenharmony_ci wqe->sqe.sge[1].length = irqe->sge[1].length; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci wqe->sqe.rkey = irqe->rkey; 102262306a36Sopenharmony_ci wqe->sqe.raddr = irqe->raddr; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci wqe->processed = 0; 102562306a36Sopenharmony_ci qp->irq_get++; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci /* mark current IRQ entry free */ 102862306a36Sopenharmony_ci smp_store_mb(irqe->flags, 0); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci return 1; 103162306a36Sopenharmony_ci} 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci/* 103462306a36Sopenharmony_ci * Check if current CQ state qualifies for calling CQ completion 103562306a36Sopenharmony_ci * handler. Must be called with CQ lock held. 103662306a36Sopenharmony_ci */ 103762306a36Sopenharmony_cistatic bool siw_cq_notify_now(struct siw_cq *cq, u32 flags) 103862306a36Sopenharmony_ci{ 103962306a36Sopenharmony_ci u32 cq_notify; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci if (!cq->base_cq.comp_handler) 104262306a36Sopenharmony_ci return false; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci /* Read application shared notification state */ 104562306a36Sopenharmony_ci cq_notify = READ_ONCE(cq->notify->flags); 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci if ((cq_notify & SIW_NOTIFY_NEXT_COMPLETION) || 104862306a36Sopenharmony_ci ((cq_notify & SIW_NOTIFY_SOLICITED) && 104962306a36Sopenharmony_ci (flags & SIW_WQE_SOLICITED))) { 105062306a36Sopenharmony_ci /* 105162306a36Sopenharmony_ci * CQ notification is one-shot: Since the 105262306a36Sopenharmony_ci * current CQE causes user notification, 105362306a36Sopenharmony_ci * the CQ gets dis-aremd and must be re-aremd 105462306a36Sopenharmony_ci * by the user for a new notification. 105562306a36Sopenharmony_ci */ 105662306a36Sopenharmony_ci WRITE_ONCE(cq->notify->flags, SIW_NOTIFY_NOT); 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci return true; 105962306a36Sopenharmony_ci } 106062306a36Sopenharmony_ci return false; 106162306a36Sopenharmony_ci} 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ciint siw_sqe_complete(struct siw_qp *qp, struct siw_sqe *sqe, u32 bytes, 106462306a36Sopenharmony_ci enum siw_wc_status status) 106562306a36Sopenharmony_ci{ 106662306a36Sopenharmony_ci struct siw_cq *cq = qp->scq; 106762306a36Sopenharmony_ci int rv = 0; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci if (cq) { 107062306a36Sopenharmony_ci u32 sqe_flags = sqe->flags; 107162306a36Sopenharmony_ci struct siw_cqe *cqe; 107262306a36Sopenharmony_ci u32 idx; 107362306a36Sopenharmony_ci unsigned long flags; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci spin_lock_irqsave(&cq->lock, flags); 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci idx = cq->cq_put % cq->num_cqe; 107862306a36Sopenharmony_ci cqe = &cq->queue[idx]; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci if (!READ_ONCE(cqe->flags)) { 108162306a36Sopenharmony_ci bool notify; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci cqe->id = sqe->id; 108462306a36Sopenharmony_ci cqe->opcode = sqe->opcode; 108562306a36Sopenharmony_ci cqe->status = status; 108662306a36Sopenharmony_ci cqe->imm_data = 0; 108762306a36Sopenharmony_ci cqe->bytes = bytes; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci if (rdma_is_kernel_res(&cq->base_cq.res)) 109062306a36Sopenharmony_ci cqe->base_qp = &qp->base_qp; 109162306a36Sopenharmony_ci else 109262306a36Sopenharmony_ci cqe->qp_id = qp_id(qp); 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci /* mark CQE valid for application */ 109562306a36Sopenharmony_ci WRITE_ONCE(cqe->flags, SIW_WQE_VALID); 109662306a36Sopenharmony_ci /* recycle SQE */ 109762306a36Sopenharmony_ci smp_store_mb(sqe->flags, 0); 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci cq->cq_put++; 110062306a36Sopenharmony_ci notify = siw_cq_notify_now(cq, sqe_flags); 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci spin_unlock_irqrestore(&cq->lock, flags); 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci if (notify) { 110562306a36Sopenharmony_ci siw_dbg_cq(cq, "Call completion handler\n"); 110662306a36Sopenharmony_ci cq->base_cq.comp_handler(&cq->base_cq, 110762306a36Sopenharmony_ci cq->base_cq.cq_context); 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci } else { 111062306a36Sopenharmony_ci spin_unlock_irqrestore(&cq->lock, flags); 111162306a36Sopenharmony_ci rv = -ENOMEM; 111262306a36Sopenharmony_ci siw_cq_event(cq, IB_EVENT_CQ_ERR); 111362306a36Sopenharmony_ci } 111462306a36Sopenharmony_ci } else { 111562306a36Sopenharmony_ci /* recycle SQE */ 111662306a36Sopenharmony_ci smp_store_mb(sqe->flags, 0); 111762306a36Sopenharmony_ci } 111862306a36Sopenharmony_ci return rv; 111962306a36Sopenharmony_ci} 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ciint siw_rqe_complete(struct siw_qp *qp, struct siw_rqe *rqe, u32 bytes, 112262306a36Sopenharmony_ci u32 inval_stag, enum siw_wc_status status) 112362306a36Sopenharmony_ci{ 112462306a36Sopenharmony_ci struct siw_cq *cq = qp->rcq; 112562306a36Sopenharmony_ci int rv = 0; 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci if (cq) { 112862306a36Sopenharmony_ci struct siw_cqe *cqe; 112962306a36Sopenharmony_ci u32 idx; 113062306a36Sopenharmony_ci unsigned long flags; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci spin_lock_irqsave(&cq->lock, flags); 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci idx = cq->cq_put % cq->num_cqe; 113562306a36Sopenharmony_ci cqe = &cq->queue[idx]; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci if (!READ_ONCE(cqe->flags)) { 113862306a36Sopenharmony_ci bool notify; 113962306a36Sopenharmony_ci u8 cqe_flags = SIW_WQE_VALID; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci cqe->id = rqe->id; 114262306a36Sopenharmony_ci cqe->opcode = SIW_OP_RECEIVE; 114362306a36Sopenharmony_ci cqe->status = status; 114462306a36Sopenharmony_ci cqe->imm_data = 0; 114562306a36Sopenharmony_ci cqe->bytes = bytes; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci if (rdma_is_kernel_res(&cq->base_cq.res)) { 114862306a36Sopenharmony_ci cqe->base_qp = &qp->base_qp; 114962306a36Sopenharmony_ci if (inval_stag) { 115062306a36Sopenharmony_ci cqe_flags |= SIW_WQE_REM_INVAL; 115162306a36Sopenharmony_ci cqe->inval_stag = inval_stag; 115262306a36Sopenharmony_ci } 115362306a36Sopenharmony_ci } else { 115462306a36Sopenharmony_ci cqe->qp_id = qp_id(qp); 115562306a36Sopenharmony_ci } 115662306a36Sopenharmony_ci /* mark CQE valid for application */ 115762306a36Sopenharmony_ci WRITE_ONCE(cqe->flags, cqe_flags); 115862306a36Sopenharmony_ci /* recycle RQE */ 115962306a36Sopenharmony_ci smp_store_mb(rqe->flags, 0); 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci cq->cq_put++; 116262306a36Sopenharmony_ci notify = siw_cq_notify_now(cq, SIW_WQE_SIGNALLED); 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci spin_unlock_irqrestore(&cq->lock, flags); 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci if (notify) { 116762306a36Sopenharmony_ci siw_dbg_cq(cq, "Call completion handler\n"); 116862306a36Sopenharmony_ci cq->base_cq.comp_handler(&cq->base_cq, 116962306a36Sopenharmony_ci cq->base_cq.cq_context); 117062306a36Sopenharmony_ci } 117162306a36Sopenharmony_ci } else { 117262306a36Sopenharmony_ci spin_unlock_irqrestore(&cq->lock, flags); 117362306a36Sopenharmony_ci rv = -ENOMEM; 117462306a36Sopenharmony_ci siw_cq_event(cq, IB_EVENT_CQ_ERR); 117562306a36Sopenharmony_ci } 117662306a36Sopenharmony_ci } else { 117762306a36Sopenharmony_ci /* recycle RQE */ 117862306a36Sopenharmony_ci smp_store_mb(rqe->flags, 0); 117962306a36Sopenharmony_ci } 118062306a36Sopenharmony_ci return rv; 118162306a36Sopenharmony_ci} 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci/* 118462306a36Sopenharmony_ci * siw_sq_flush() 118562306a36Sopenharmony_ci * 118662306a36Sopenharmony_ci * Flush SQ and ORRQ entries to CQ. 118762306a36Sopenharmony_ci * 118862306a36Sopenharmony_ci * Must be called with QP state write lock held. 118962306a36Sopenharmony_ci * Therefore, SQ and ORQ lock must not be taken. 119062306a36Sopenharmony_ci */ 119162306a36Sopenharmony_civoid siw_sq_flush(struct siw_qp *qp) 119262306a36Sopenharmony_ci{ 119362306a36Sopenharmony_ci struct siw_sqe *sqe; 119462306a36Sopenharmony_ci struct siw_wqe *wqe = tx_wqe(qp); 119562306a36Sopenharmony_ci int async_event = 0; 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci /* 119862306a36Sopenharmony_ci * Start with completing any work currently on the ORQ 119962306a36Sopenharmony_ci */ 120062306a36Sopenharmony_ci while (qp->attrs.orq_size) { 120162306a36Sopenharmony_ci sqe = &qp->orq[qp->orq_get % qp->attrs.orq_size]; 120262306a36Sopenharmony_ci if (!READ_ONCE(sqe->flags)) 120362306a36Sopenharmony_ci break; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci if (siw_sqe_complete(qp, sqe, 0, SIW_WC_WR_FLUSH_ERR) != 0) 120662306a36Sopenharmony_ci break; 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci WRITE_ONCE(sqe->flags, 0); 120962306a36Sopenharmony_ci qp->orq_get++; 121062306a36Sopenharmony_ci } 121162306a36Sopenharmony_ci /* 121262306a36Sopenharmony_ci * Flush an in-progress WQE if present 121362306a36Sopenharmony_ci */ 121462306a36Sopenharmony_ci if (wqe->wr_status != SIW_WR_IDLE) { 121562306a36Sopenharmony_ci siw_dbg_qp(qp, "flush current SQE, type %d, status %d\n", 121662306a36Sopenharmony_ci tx_type(wqe), wqe->wr_status); 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci siw_wqe_put_mem(wqe, tx_type(wqe)); 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci if (tx_type(wqe) != SIW_OP_READ_RESPONSE && 122162306a36Sopenharmony_ci ((tx_type(wqe) != SIW_OP_READ && 122262306a36Sopenharmony_ci tx_type(wqe) != SIW_OP_READ_LOCAL_INV) || 122362306a36Sopenharmony_ci wqe->wr_status == SIW_WR_QUEUED)) 122462306a36Sopenharmony_ci /* 122562306a36Sopenharmony_ci * An in-progress Read Request is already in 122662306a36Sopenharmony_ci * the ORQ 122762306a36Sopenharmony_ci */ 122862306a36Sopenharmony_ci siw_sqe_complete(qp, &wqe->sqe, wqe->bytes, 122962306a36Sopenharmony_ci SIW_WC_WR_FLUSH_ERR); 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci wqe->wr_status = SIW_WR_IDLE; 123262306a36Sopenharmony_ci } 123362306a36Sopenharmony_ci /* 123462306a36Sopenharmony_ci * Flush the Send Queue 123562306a36Sopenharmony_ci */ 123662306a36Sopenharmony_ci while (qp->attrs.sq_size) { 123762306a36Sopenharmony_ci sqe = &qp->sendq[qp->sq_get % qp->attrs.sq_size]; 123862306a36Sopenharmony_ci if (!READ_ONCE(sqe->flags)) 123962306a36Sopenharmony_ci break; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci async_event = 1; 124262306a36Sopenharmony_ci if (siw_sqe_complete(qp, sqe, 0, SIW_WC_WR_FLUSH_ERR) != 0) 124362306a36Sopenharmony_ci /* 124462306a36Sopenharmony_ci * Shall IB_EVENT_SQ_DRAINED be supressed if work 124562306a36Sopenharmony_ci * completion fails? 124662306a36Sopenharmony_ci */ 124762306a36Sopenharmony_ci break; 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci WRITE_ONCE(sqe->flags, 0); 125062306a36Sopenharmony_ci qp->sq_get++; 125162306a36Sopenharmony_ci } 125262306a36Sopenharmony_ci if (async_event) 125362306a36Sopenharmony_ci siw_qp_event(qp, IB_EVENT_SQ_DRAINED); 125462306a36Sopenharmony_ci} 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci/* 125762306a36Sopenharmony_ci * siw_rq_flush() 125862306a36Sopenharmony_ci * 125962306a36Sopenharmony_ci * Flush recv queue entries to CQ. Also 126062306a36Sopenharmony_ci * takes care of pending active tagged and untagged 126162306a36Sopenharmony_ci * inbound transfers, which have target memory 126262306a36Sopenharmony_ci * referenced. 126362306a36Sopenharmony_ci * 126462306a36Sopenharmony_ci * Must be called with QP state write lock held. 126562306a36Sopenharmony_ci * Therefore, RQ lock must not be taken. 126662306a36Sopenharmony_ci */ 126762306a36Sopenharmony_civoid siw_rq_flush(struct siw_qp *qp) 126862306a36Sopenharmony_ci{ 126962306a36Sopenharmony_ci struct siw_wqe *wqe = &qp->rx_untagged.wqe_active; 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci /* 127262306a36Sopenharmony_ci * Flush an in-progress untagged operation if present 127362306a36Sopenharmony_ci */ 127462306a36Sopenharmony_ci if (wqe->wr_status != SIW_WR_IDLE) { 127562306a36Sopenharmony_ci siw_dbg_qp(qp, "flush current rqe, type %d, status %d\n", 127662306a36Sopenharmony_ci rx_type(wqe), wqe->wr_status); 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci siw_wqe_put_mem(wqe, rx_type(wqe)); 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci if (rx_type(wqe) == SIW_OP_RECEIVE) { 128162306a36Sopenharmony_ci siw_rqe_complete(qp, &wqe->rqe, wqe->bytes, 128262306a36Sopenharmony_ci 0, SIW_WC_WR_FLUSH_ERR); 128362306a36Sopenharmony_ci } else if (rx_type(wqe) != SIW_OP_READ && 128462306a36Sopenharmony_ci rx_type(wqe) != SIW_OP_READ_RESPONSE && 128562306a36Sopenharmony_ci rx_type(wqe) != SIW_OP_WRITE) { 128662306a36Sopenharmony_ci siw_sqe_complete(qp, &wqe->sqe, 0, SIW_WC_WR_FLUSH_ERR); 128762306a36Sopenharmony_ci } 128862306a36Sopenharmony_ci wqe->wr_status = SIW_WR_IDLE; 128962306a36Sopenharmony_ci } 129062306a36Sopenharmony_ci wqe = &qp->rx_tagged.wqe_active; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci if (wqe->wr_status != SIW_WR_IDLE) { 129362306a36Sopenharmony_ci siw_wqe_put_mem(wqe, rx_type(wqe)); 129462306a36Sopenharmony_ci wqe->wr_status = SIW_WR_IDLE; 129562306a36Sopenharmony_ci } 129662306a36Sopenharmony_ci /* 129762306a36Sopenharmony_ci * Flush the Receive Queue 129862306a36Sopenharmony_ci */ 129962306a36Sopenharmony_ci while (qp->attrs.rq_size) { 130062306a36Sopenharmony_ci struct siw_rqe *rqe = 130162306a36Sopenharmony_ci &qp->recvq[qp->rq_get % qp->attrs.rq_size]; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci if (!READ_ONCE(rqe->flags)) 130462306a36Sopenharmony_ci break; 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci if (siw_rqe_complete(qp, rqe, 0, 0, SIW_WC_WR_FLUSH_ERR) != 0) 130762306a36Sopenharmony_ci break; 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci WRITE_ONCE(rqe->flags, 0); 131062306a36Sopenharmony_ci qp->rq_get++; 131162306a36Sopenharmony_ci } 131262306a36Sopenharmony_ci} 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ciint siw_qp_add(struct siw_device *sdev, struct siw_qp *qp) 131562306a36Sopenharmony_ci{ 131662306a36Sopenharmony_ci int rv = xa_alloc(&sdev->qp_xa, &qp->base_qp.qp_num, qp, xa_limit_32b, 131762306a36Sopenharmony_ci GFP_KERNEL); 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci if (!rv) { 132062306a36Sopenharmony_ci kref_init(&qp->ref); 132162306a36Sopenharmony_ci qp->sdev = sdev; 132262306a36Sopenharmony_ci siw_dbg_qp(qp, "new QP\n"); 132362306a36Sopenharmony_ci } 132462306a36Sopenharmony_ci return rv; 132562306a36Sopenharmony_ci} 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_civoid siw_free_qp(struct kref *ref) 132862306a36Sopenharmony_ci{ 132962306a36Sopenharmony_ci struct siw_qp *found, *qp = container_of(ref, struct siw_qp, ref); 133062306a36Sopenharmony_ci struct siw_device *sdev = qp->sdev; 133162306a36Sopenharmony_ci unsigned long flags; 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci if (qp->cep) 133462306a36Sopenharmony_ci siw_cep_put(qp->cep); 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci found = xa_erase(&sdev->qp_xa, qp_id(qp)); 133762306a36Sopenharmony_ci WARN_ON(found != qp); 133862306a36Sopenharmony_ci spin_lock_irqsave(&sdev->lock, flags); 133962306a36Sopenharmony_ci list_del(&qp->devq); 134062306a36Sopenharmony_ci spin_unlock_irqrestore(&sdev->lock, flags); 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci vfree(qp->sendq); 134362306a36Sopenharmony_ci vfree(qp->recvq); 134462306a36Sopenharmony_ci vfree(qp->irq); 134562306a36Sopenharmony_ci vfree(qp->orq); 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci siw_put_tx_cpu(qp->tx_cpu); 134862306a36Sopenharmony_ci complete(&qp->qp_free); 134962306a36Sopenharmony_ci atomic_dec(&sdev->num_qp); 135062306a36Sopenharmony_ci} 1351