On Fri, Apr 26, 2019 at 03:18:47PM +0200, Bernard Metzler wrote: > From: Bernard Metzler <bmt@xxxxxxxxxxxxxxxxxxx> > > Signed-off-by: Bernard Metzler <bmt@xxxxxxxxxxxxxx> > --- > drivers/infiniband/sw/siw/siw_qp.c | 1354 ++++++++++++++++++++++++++++ > 1 file changed, 1354 insertions(+) > create mode 100644 drivers/infiniband/sw/siw/siw_qp.c > > diff --git a/drivers/infiniband/sw/siw/siw_qp.c b/drivers/infiniband/sw/siw/siw_qp.c > new file mode 100644 > index 000000000000..9c94a406288c > --- /dev/null > +++ b/drivers/infiniband/sw/siw/siw_qp.c > @@ -0,0 +1,1354 @@ ... > +int siw_qp_modify(struct siw_qp *qp, struct siw_qp_attrs *attrs, > + enum siw_qp_attr_mask mask) > +{ > + int drop_conn = 0, rv = 0; > + > + if (!mask) > + return 0; > + > + siw_dbg_qp(qp, "state: %s => %s\n", > + siw_qp_state_to_string[qp->attrs.state], > + siw_qp_state_to_string[attrs->state]); > + > + if (mask != SIW_QP_ATTR_STATE) > + siw_qp_modify_nonstate(qp, attrs, mask); > + > + if (!(mask & SIW_QP_ATTR_STATE)) > + return 0; > + > + switch (qp->attrs.state) { > + case SIW_QP_STATE_IDLE: > + case SIW_QP_STATE_RTR: > + switch (attrs->state) { > + case SIW_QP_STATE_RTS: > + > + if (attrs->flags & SIW_MPA_CRC) { > + rv = siw_qp_enable_crc(qp); > + if (rv) > + break; > + } > + if (!(mask & SIW_QP_ATTR_LLP_HANDLE)) { > + siw_dbg_qp(qp, "no socket\n"); > + rv = -EINVAL; > + break; > + } > + if (!(mask & SIW_QP_ATTR_MPA)) { > + siw_dbg_qp(qp, "no MPA\n"); > + rv = -EINVAL; > + break; > + } > + siw_dbg_qp(qp, "enter rts, peer 0x%08x, loc 0x%08x\n", > + qp->cep->llp.raddr.sin_addr.s_addr, > + qp->cep->llp.laddr.sin_addr.s_addr); > + /* > + * Initialize iWARP TX state > + */ > + qp->tx_ctx.ddp_msn[RDMAP_UNTAGGED_QN_SEND] = 0; > + qp->tx_ctx.ddp_msn[RDMAP_UNTAGGED_QN_RDMA_READ] = 0; > + qp->tx_ctx.ddp_msn[RDMAP_UNTAGGED_QN_TERMINATE] = 0; > + > + /* > + * Initialize iWARP RX state > + */ > + qp->rx_ctx.ddp_msn[RDMAP_UNTAGGED_QN_SEND] = 1; > + qp->rx_ctx.ddp_msn[RDMAP_UNTAGGED_QN_RDMA_READ] = 1; > + qp->rx_ctx.ddp_msn[RDMAP_UNTAGGED_QN_TERMINATE] = 1; > + > + /* > + * init IRD free queue, caller has already checked > + * limits. > + */ > + rv = siw_qp_readq_init(qp, attrs->irq_size, > + attrs->orq_size); > + if (rv) > + break; > + > + qp->attrs.sk = attrs->sk; > + qp->attrs.state = SIW_QP_STATE_RTS; > + break; > + > + case SIW_QP_STATE_ERROR: > + siw_rq_flush(qp); > + qp->attrs.state = SIW_QP_STATE_ERROR; > + if (qp->cep) { > + siw_cep_put(qp->cep); > + qp->cep = NULL; > + } > + break; > + > + case SIW_QP_STATE_RTR: > + /* ignore */ > + break; > + > + default: > + siw_dbg_qp(qp, "state transition undefined: %s => %s\n", > + siw_qp_state_to_string[qp->attrs.state], > + siw_qp_state_to_string[attrs->state]); > + break; > + } > + break; > + > + case SIW_QP_STATE_RTS: > + switch (attrs->state) { > + case SIW_QP_STATE_CLOSING: > + /* > + * Verbs: move to IDLE if SQ and ORQ are empty. > + * Move to ERROR otherwise. But first of all we must > + * close the connection. So we keep CLOSING or ERROR > + * as a transient state, schedule connection drop work > + * and wait for the socket state change upcall to > + * come back closed. > + */ > + if (tx_wqe(qp)->wr_status == SIW_WR_IDLE) { > + qp->attrs.state = SIW_QP_STATE_CLOSING; > + } else { > + qp->attrs.state = SIW_QP_STATE_ERROR; > + siw_sq_flush(qp); > + } > + siw_rq_flush(qp); > + > + drop_conn = 1; > + break; > + > + case SIW_QP_STATE_TERMINATE: > + qp->attrs.state = SIW_QP_STATE_TERMINATE; > + > + siw_init_terminate(qp, TERM_ERROR_LAYER_RDMAP, > + RDMAP_ETYPE_CATASTROPHIC, > + RDMAP_ECODE_UNSPECIFIED, 1); > + drop_conn = 1; > + break; > + > + case SIW_QP_STATE_ERROR: > + /* > + * This is an emergency close. > + * > + * Any in progress transmit operation will get > + * cancelled. > + * This will likely result in a protocol failure, > + * if a TX operation is in transit. The caller > + * could unconditional wait to give the current > + * operation a chance to complete. > + * Esp., how to handle the non-empty IRQ case? > + * The peer was asking for data transfer at a valid > + * point in time. > + */ > + siw_sq_flush(qp); > + siw_rq_flush(qp); > + qp->attrs.state = SIW_QP_STATE_ERROR; > + drop_conn = 1; > + break; > + > + default: > + siw_dbg_qp(qp, "state transition undefined: %s => %s\n", > + siw_qp_state_to_string[qp->attrs.state], > + siw_qp_state_to_string[attrs->state]); > + break; > + } > + break; > + > + case SIW_QP_STATE_TERMINATE: > + switch (attrs->state) { > + case SIW_QP_STATE_ERROR: > + siw_rq_flush(qp); > + qp->attrs.state = SIW_QP_STATE_ERROR; > + > + if (tx_wqe(qp)->wr_status != SIW_WR_IDLE) > + siw_sq_flush(qp); > + break; > + > + default: > + siw_dbg_qp(qp, "state transition undefined: %s => %s\n", > + siw_qp_state_to_string[qp->attrs.state], > + siw_qp_state_to_string[attrs->state]); > + } > + break; > + > + case SIW_QP_STATE_CLOSING: > + switch (attrs->state) { > + case SIW_QP_STATE_IDLE: > + WARN_ON(tx_wqe(qp)->wr_status != SIW_WR_IDLE); > + qp->attrs.state = SIW_QP_STATE_IDLE; > + break; > + > + case SIW_QP_STATE_CLOSING: > + /* > + * The LLP may already moved the QP to closing > + * due to graceful peer close init > + */ > + break; > + > + case SIW_QP_STATE_ERROR: > + /* > + * QP was moved to CLOSING by LLP event > + * not yet seen by user. > + */ > + qp->attrs.state = SIW_QP_STATE_ERROR; > + > + if (tx_wqe(qp)->wr_status != SIW_WR_IDLE) > + siw_sq_flush(qp); > + > + siw_rq_flush(qp); > + break; > + > + default: > + siw_dbg_qp(qp, "state transition undefined: %s => %s\n", > + siw_qp_state_to_string[qp->attrs.state], > + siw_qp_state_to_string[attrs->state]); > + > + return -ECONNABORTED; > + } > + break; > + > + default: > + siw_dbg_qp(qp, " noop: state %s\n", > + siw_qp_state_to_string[qp->attrs.state]); > + break; > + } > + if (drop_conn) > + siw_qp_cm_drop(qp, 0); I wonder if it is just a bad name, but why modify QP should handle connections? Thanks