staticenum resp_states check_op_seq(struct rxe_qp *qp, struct rxe_pkt_info *pkt)
{ switch (qp_type(qp)) { case IB_QPT_RC: switch (qp->resp.opcode) { case IB_OPCODE_RC_SEND_FIRST: case IB_OPCODE_RC_SEND_MIDDLE: switch (pkt->opcode) { case IB_OPCODE_RC_SEND_MIDDLE: case IB_OPCODE_RC_SEND_LAST: case IB_OPCODE_RC_SEND_LAST_WITH_IMMEDIATE: case IB_OPCODE_RC_SEND_LAST_WITH_INVALIDATE: return RESPST_CHK_OP_VALID; default: return RESPST_ERR_MISSING_OPCODE_LAST_C;
}
case IB_OPCODE_RC_RDMA_WRITE_FIRST: case IB_OPCODE_RC_RDMA_WRITE_MIDDLE: switch (pkt->opcode) { case IB_OPCODE_RC_RDMA_WRITE_MIDDLE: case IB_OPCODE_RC_RDMA_WRITE_LAST: case IB_OPCODE_RC_RDMA_WRITE_LAST_WITH_IMMEDIATE: return RESPST_CHK_OP_VALID; default: return RESPST_ERR_MISSING_OPCODE_LAST_C;
}
default: switch (pkt->opcode) { case IB_OPCODE_RC_SEND_MIDDLE: case IB_OPCODE_RC_SEND_LAST: case IB_OPCODE_RC_SEND_LAST_WITH_IMMEDIATE: case IB_OPCODE_RC_SEND_LAST_WITH_INVALIDATE: case IB_OPCODE_RC_RDMA_WRITE_MIDDLE: case IB_OPCODE_RC_RDMA_WRITE_LAST: case IB_OPCODE_RC_RDMA_WRITE_LAST_WITH_IMMEDIATE: return RESPST_ERR_MISSING_OPCODE_FIRST; default: return RESPST_CHK_OP_VALID;
}
} break;
case IB_QPT_UC: switch (qp->resp.opcode) { case IB_OPCODE_UC_SEND_FIRST: case IB_OPCODE_UC_SEND_MIDDLE: switch (pkt->opcode) { case IB_OPCODE_UC_SEND_MIDDLE: case IB_OPCODE_UC_SEND_LAST: case IB_OPCODE_UC_SEND_LAST_WITH_IMMEDIATE: return RESPST_CHK_OP_VALID; default: return RESPST_ERR_MISSING_OPCODE_LAST_D1E;
}
case IB_OPCODE_UC_RDMA_WRITE_FIRST: case IB_OPCODE_UC_RDMA_WRITE_MIDDLE: switch (pkt->opcode) { case IB_OPCODE_UC_RDMA_WRITE_MIDDLE: case IB_OPCODE_UC_RDMA_WRITE_LAST: case IB_OPCODE_UC_RDMA_WRITE_LAST_WITH_IMMEDIATE: return RESPST_CHK_OP_VALID; default: return RESPST_ERR_MISSING_OPCODE_LAST_D1E;
}
default: switch (pkt->opcode) { case IB_OPCODE_UC_SEND_MIDDLE: case IB_OPCODE_UC_SEND_LAST: case IB_OPCODE_UC_SEND_LAST_WITH_IMMEDIATE: case IB_OPCODE_UC_RDMA_WRITE_MIDDLE: case IB_OPCODE_UC_RDMA_WRITE_LAST: case IB_OPCODE_UC_RDMA_WRITE_LAST_WITH_IMMEDIATE:
qp->resp.drop_msg = 1; return RESPST_CLEANUP; default: return RESPST_CHK_OP_VALID;
}
} break;
if (pkt->mask & (RXE_READ_OR_ATOMIC_MASK | RXE_ATOMIC_WRITE_MASK)) { /* it is the requesters job to not send *toomanyread/atomicops,wejust *recycletheresponderresourcequeue
*/ if (likely(qp->attr.max_dest_rd_atomic > 0)) return RESPST_CHK_LENGTH; else return RESPST_ERR_TOO_MANY_RDMA_ATM_REQ;
}
if (pkt->mask & RXE_RWR_MASK) { if (srq) return get_srq_wqe(qp);
for (i = 0; i < qp->resp.wqe->dma.num_sge; i++)
recv_buffer_len += qp->resp.wqe->dma.sge[i].length; if (payload + sizeof(union rdma_network_hdr) > recv_buffer_len) {
rxe_dbg_qp(qp, "The receive buffer is too small for this UD packet.\n"); return RESPST_ERR_LENGTH;
}
}
if ((pkt->mask & RXE_START_MASK) &&
(pkt->mask & RXE_END_MASK)) { if (unlikely(payload > mtu)) {
rxe_dbg_qp(qp, "only packet too long\n"); return RESPST_ERR_LENGTH;
}
} elseif ((pkt->mask & RXE_START_MASK) ||
(pkt->mask & RXE_MIDDLE_MASK)) { if (unlikely(payload != mtu)) {
rxe_dbg_qp(qp, "first or middle packet not mtu\n"); return RESPST_ERR_LENGTH;
}
} elseif (pkt->mask & RXE_END_MASK) { if (unlikely((payload == 0) || (payload > mtu))) {
rxe_dbg_qp(qp, "last packet zero or too long\n"); return RESPST_ERR_LENGTH;
}
}
}
/* See IBA C9-94 */ if (pkt->mask & RXE_RETH_MASK) { if (reth_len(pkt) > (1U << 31)) {
rxe_dbg_qp(qp, "dma length too long\n"); return RESPST_ERR_LENGTH;
}
}
if (pkt->mask & RXE_RDMA_OP_MASK) return RESPST_CHK_RKEY; else return RESPST_EXECUTE;
}
/* if the reth length field is zero we can assume nothing *abouttherkeyvalueandshouldnotvalidateoruseit. *Insteadsetqp->resp.rkeyto0whichisaninvalidrkey *valuesincetheminimumindexpartis1.
*/ staticvoid qp_resp_from_reth(struct rxe_qp *qp, struct rxe_pkt_info *pkt)
{ unsignedint length = reth_len(pkt);
/* A zero-byte read or write op is not required to *setanaddrorrkey.SeeC9-88
*/ if ((pkt->mask & RXE_READ_OR_WRITE_MASK) &&
(pkt->mask & RXE_RETH_MASK) && reth_len(pkt) == 0) {
qp->resp.mr = NULL; return RESPST_EXECUTE;
}
if (pkt->mask & RXE_FLUSH_MASK) { /* FLUSH MR may not set va or resid *noneedtocheckrangesincewewillflushwholemr
*/ if (feth_sel(pkt) == IB_FLUSH_MR) goto skip_check_range;
}
if (mr_check_range(mr, va + qp->resp.offset, resid)) {
state = RESPST_ERR_RKEY_VIOLATION; goto err;
}
skip_check_range: if (pkt->mask & (RXE_WRITE_MASK | RXE_ATOMIC_WRITE_MASK)) { if (resid > mtu) { if (pktlen != mtu || bth_pad(pkt)) {
state = RESPST_ERR_LENGTH; goto err;
}
} else { if (pktlen != resid) {
state = RESPST_ERR_LENGTH; goto err;
} if ((bth_pad(pkt) != (0x3 & (-resid)))) { /* This case may not be exactly that *butnothingelsefits.
*/
state = RESPST_ERR_LENGTH; goto err;
}
}
}
WARN_ON_ONCE(qp->resp.mr);
qp->resp.mr = mr; return RESPST_EXECUTE;
err:
qp->resp.mr = NULL; if (mr)
rxe_put(mr); if (mw)
rxe_put(mw);
return state;
}
staticenum resp_states send_data_in(struct rxe_qp *qp, void *data_addr, int data_len)
{ int err;
if (res->flush.type & IB_FLUSH_PERSISTENT) { if (rxe_flush_pmem_iova(mr, start, length)) return RESPST_ERR_RKEY_VIOLATION; /* Make data persistent. */
wmb();
} elseif (res->flush.type & IB_FLUSH_GLOBAL) { /* Make data global visibility. */
wmb();
}
qp->resp.msn++;
/* next expected psn, read handles this separately */
qp->resp.psn = (pkt->psn + 1) & BTH_PSN_MASK;
qp->resp.ack_psn = qp->resp.psn;
/* RDMA read response. If res is not NULL, then we have a current RDMA request *beingprocessedorreplayed.
*/ staticenum resp_states read_reply(struct rxe_qp *qp, struct rxe_pkt_info *req_pkt)
{ struct rxe_pkt_info ack_pkt; struct sk_buff *skb; int mtu = qp->mtu; enum resp_states state; int payload; int opcode; int err; struct resp_res *res = qp->resp.res; struct rxe_mr *mr;
if (!res) {
res = rxe_prepare_res(qp, req_pkt, RXE_READ_MASK);
qp->resp.res = res;
}
if (res->state == rdatm_res_state_new) { if (!res->replay || qp->resp.length == 0) { /* if length == 0 mr will be NULL (is ok) *otherwiseqp->resp.mrholdsarefonmr *whichwetransfertomranddropbelow.
*/
mr = qp->resp.mr;
qp->resp.mr = NULL;
} else {
mr = rxe_recheck_mr(qp, res->read.rkey); if (!mr) return RESPST_ERR_RKEY_VIOLATION;
}
if (res->read.resid <= mtu)
opcode = IB_OPCODE_RC_RDMA_READ_RESPONSE_ONLY; else
opcode = IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST;
} else { /* re-lookup mr from rkey on all later packets. *lengthwillbenon-zero.Thiscanfailifsomeone *modifiesordestroysthemrsincethefirstpacket.
*/
mr = rxe_recheck_mr(qp, res->read.rkey); if (!mr) return RESPST_ERR_RKEY_VIOLATION;
/* Executes a new request. A retried request never reach that function (send *andwritesarediscarded,andreadsandatomicsareretriedelsewhere.
*/ staticenum resp_states execute(struct rxe_qp *qp, struct rxe_pkt_info *pkt)
{ enum resp_states err; struct sk_buff *skb = PKT_TO_SKB(pkt); union rdma_network_hdr hdr;
/* Find the operation in our list of responder resources. */
res = find_resource(qp, pkt->psn); if (res) {
res->replay = 1;
res->cur_psn = pkt->psn;
qp->resp.res = res;
rc = RESPST_PROCESS_FLUSH; goto out;
}
/* Resource not found. Class D error. Drop the request. */
rc = RESPST_CLEANUP; goto out;
} elseif (pkt->mask & RXE_READ_MASK) { struct resp_res *res;
res = find_resource(qp, pkt->psn); if (!res) { /* Resource not found. Class D error. Drop the *request.
*/
rc = RESPST_CLEANUP; goto out;
} else { /* Ensure this new request is the same as the previous *oneorasubsetofit.
*/
u64 iova = reth_va(pkt);
u32 resid = reth_len(pkt);
/* Find the operation in our list of responder resources. */
res = find_resource(qp, pkt->psn); if (res) {
res->replay = 1;
res->cur_psn = pkt->psn;
qp->resp.res = res;
rc = pkt->mask & RXE_ATOMIC_MASK ?
RESPST_ATOMIC_REPLY :
RESPST_ATOMIC_WRITE_REPLY; goto out;
}
/* Resource not found. Class D error. Drop the request. */
rc = RESPST_CLEANUP; goto out;
}
out: return rc;
}
/* Process a class A or C. Both are treated the same in this implementation. */ staticvoid do_class_ac_error(struct rxe_qp *qp, u8 syndrome, enum ib_wc_status status)
{
qp->resp.aeth_syndrome = syndrome;
qp->resp.status = status;
/* indicate that we should go through the ERROR state */
qp->resp.goto_error = 1;
}
staticenum resp_states do_class_d1e_error(struct rxe_qp *qp)
{ /* UC */ if (qp->srq) { /* Class E */
qp->resp.drop_msg = 1; if (qp->resp.wqe) {
qp->resp.status = IB_WC_REM_INV_REQ_ERR; return RESPST_COMPLETE;
} else { return RESPST_CLEANUP;
}
} else { /* Class D1. This packet may be the start of a *newmessageandcouldbevalid.Theprevious *messageisinvalidandignored.resetthe *recvwrtoitsoriginalstate
*/ if (qp->resp.wqe) {
qp->resp.wqe->dma.resid = qp->resp.wqe->dma.length;
qp->resp.wqe->dma.cur_sge = 0;
qp->resp.wqe->dma.sge_offset = 0;
qp->resp.opcode = -1;
}
if (qp->resp.mr) {
rxe_put(qp->resp.mr);
qp->resp.mr = NULL;
}
while (1) {
rxe_dbg_qp(qp, "state = %s\n", resp_state_name[state]); switch (state) { case RESPST_GET_REQ:
state = get_req(qp, &pkt); break; case RESPST_CHK_PSN:
state = check_psn(qp, pkt); break; case RESPST_CHK_OP_SEQ:
state = check_op_seq(qp, pkt); break; case RESPST_CHK_OP_VALID:
state = check_op_valid(qp, pkt); break; case RESPST_CHK_RESOURCE:
state = check_resource(qp, pkt); break; case RESPST_CHK_LENGTH:
state = rxe_resp_check_length(qp, pkt); break; case RESPST_CHK_RKEY:
state = check_rkey(qp, pkt); break; case RESPST_EXECUTE:
state = execute(qp, pkt); break; case RESPST_COMPLETE:
state = do_complete(qp, pkt); break; case RESPST_READ_REPLY:
state = read_reply(qp, pkt); break; case RESPST_ATOMIC_REPLY:
state = atomic_reply(qp, pkt); break; case RESPST_ATOMIC_WRITE_REPLY:
state = atomic_write_reply(qp, pkt); break; case RESPST_PROCESS_FLUSH:
state = process_flush(qp, pkt); break; case RESPST_ACKNOWLEDGE:
state = acknowledge(qp, pkt); break; case RESPST_CLEANUP:
state = cleanup(qp, pkt); break; case RESPST_DUPLICATE_REQUEST:
state = duplicate_request(qp, pkt); break; case RESPST_ERR_PSN_OUT_OF_SEQ: /* RC only - Class B. Drop packet. */
send_ack(qp, AETH_NAK_PSN_SEQ_ERROR, qp->resp.psn);
state = RESPST_CLEANUP; break;
case RESPST_ERR_TOO_MANY_RDMA_ATM_REQ: case RESPST_ERR_MISSING_OPCODE_FIRST: case RESPST_ERR_MISSING_OPCODE_LAST_C: case RESPST_ERR_UNSUPPORTED_OPCODE: case RESPST_ERR_MISALIGNED_ATOMIC: /* RC Only - Class C. */
do_class_ac_error(qp, AETH_NAK_INVALID_REQ,
IB_WC_REM_INV_REQ_ERR);
state = RESPST_COMPLETE; break;
case RESPST_ERR_MISSING_OPCODE_LAST_D1E:
state = do_class_d1e_error(qp); break; case RESPST_ERR_RNR: if (qp_type(qp) == IB_QPT_RC) {
rxe_counter_inc(rxe, RXE_CNT_SND_RNR); /* RC - class B */
send_ack(qp, AETH_RNR_NAK |
(~AETH_TYPE_MASK &
qp->attr.min_rnr_timer),
pkt->psn);
} else { /* UD/UC - class D */
qp->resp.drop_msg = 1;
}
state = RESPST_CLEANUP; break;
case RESPST_ERR_RKEY_VIOLATION: if (qp_type(qp) == IB_QPT_RC) { /* Class C */
do_class_ac_error(qp, AETH_NAK_REM_ACC_ERR,
IB_WC_REM_ACCESS_ERR);
state = RESPST_COMPLETE;
} else {
qp->resp.drop_msg = 1; if (qp->srq) { /* UC/SRQ Class D */
qp->resp.status = IB_WC_REM_ACCESS_ERR;
state = RESPST_COMPLETE;
} else { /* UC/non-SRQ Class E. */
state = RESPST_CLEANUP;
}
} break;
case RESPST_ERR_INVALIDATE_RKEY: /* RC - Class J. */
qp->resp.goto_error = 1;
qp->resp.status = IB_WC_REM_INV_REQ_ERR;
state = RESPST_COMPLETE; break;
case RESPST_ERR_LENGTH: if (qp_type(qp) == IB_QPT_RC) { /* Class C */
do_class_ac_error(qp, AETH_NAK_INVALID_REQ,
IB_WC_REM_INV_REQ_ERR);
state = RESPST_COMPLETE;
} elseif (qp->srq) { /* UC/UD - class E */
qp->resp.status = IB_WC_REM_INV_REQ_ERR;
state = RESPST_COMPLETE;
} else { /* UC/UD - class D */
qp->resp.drop_msg = 1;
state = RESPST_CLEANUP;
} break;
case RESPST_ERR_MALFORMED_WQE: /* All, Class A. */
do_class_ac_error(qp, AETH_NAK_REM_OP_ERR,
IB_WC_LOC_QP_OP_ERR);
state = RESPST_COMPLETE; break;
case RESPST_ERR_CQ_OVERFLOW: /* All - Class G */
state = RESPST_ERROR; break;
case RESPST_DONE: if (qp->resp.goto_error) {
state = RESPST_ERROR; break;
}
goto done;
case RESPST_EXIT: if (qp->resp.goto_error) {
state = RESPST_ERROR; break;
}
gotoexit;
case RESPST_ERROR:
qp->resp.goto_error = 0;
rxe_dbg_qp(qp, "moved to error state\n");
rxe_qp_error(qp); gotoexit;
default:
WARN_ON_ONCE(1);
}
}
/* A non-zero return value will cause rxe_do_task to *exititsloopandendtheworkitem.Azeroreturn *willcontinueloopingandreturntorxe_responder
*/
done:
ret = 0; goto out; exit:
ret = -EAGAIN;
out: return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.