Commit dd5190b6 authored by Ralph Campbell's avatar Ralph Campbell Committed by Roland Dreier

IB/ipath: Fix RDMA reads of length zero and error handling

Fix RDMA read response length checking for RDMA_READ_RESPONSE_ONLY to
allow a zero length response.  RDMA read responses which don't match
the expected length or occur in response to some other operation
should generate a completion queue error (see table 56, ch. 9.9.2.3 in
the IB spec).
Signed-off-by: default avatarBryan O'Sullivan <bryan.osullivan@qlogic.com>
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent c7e29ff1
...@@ -1136,7 +1136,7 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev, ...@@ -1136,7 +1136,7 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
goto ack_done; goto ack_done;
hdrsize += 4; hdrsize += 4;
if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ)) if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ))
goto ack_done; goto ack_op_err;
/* /*
* If this is a response to a resent RDMA read, we * If this is a response to a resent RDMA read, we
* have to be careful to copy the data to the right * have to be careful to copy the data to the right
...@@ -1154,12 +1154,12 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev, ...@@ -1154,12 +1154,12 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
goto ack_done; goto ack_done;
} }
if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ)) if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ))
goto ack_done; goto ack_op_err;
read_middle: read_middle:
if (unlikely(tlen != (hdrsize + pmtu + 4))) if (unlikely(tlen != (hdrsize + pmtu + 4)))
goto ack_done; goto ack_len_err;
if (unlikely(pmtu >= qp->s_rdma_read_len)) if (unlikely(pmtu >= qp->s_rdma_read_len))
goto ack_done; goto ack_len_err;
/* We got a response so update the timeout. */ /* We got a response so update the timeout. */
spin_lock(&dev->pending_lock); spin_lock(&dev->pending_lock);
...@@ -1184,12 +1184,20 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev, ...@@ -1184,12 +1184,20 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
goto ack_done; goto ack_done;
} }
if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ)) if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ))
goto ack_done; goto ack_op_err;
/* Get the number of bytes the message was padded by. */
pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
/*
* Check that the data size is >= 0 && <= pmtu.
* Remember to account for the AETH header (4) and
* ICRC (4).
*/
if (unlikely(tlen < (hdrsize + pad + 8)))
goto ack_len_err;
/* /*
* If this is a response to a resent RDMA read, we * If this is a response to a resent RDMA read, we
* have to be careful to copy the data to the right * have to be careful to copy the data to the right
* location. * location.
* XXX should check PSN and wqe opcode first.
*/ */
qp->s_rdma_read_len = restart_sge(&qp->s_rdma_read_sge, qp->s_rdma_read_len = restart_sge(&qp->s_rdma_read_sge,
wqe, psn, pmtu); wqe, psn, pmtu);
...@@ -1203,26 +1211,20 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev, ...@@ -1203,26 +1211,20 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
goto ack_done; goto ack_done;
} }
if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ)) if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ))
goto ack_done; goto ack_op_err;
read_last: /* Get the number of bytes the message was padded by. */
/*
* Get the number of bytes the message was padded by.
*/
pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
/* /*
* Check that the data size is >= 1 && <= pmtu. * Check that the data size is >= 1 && <= pmtu.
* Remember to account for the AETH header (4) and * Remember to account for the AETH header (4) and
* ICRC (4). * ICRC (4).
*/ */
if (unlikely(tlen <= (hdrsize + pad + 8))) { if (unlikely(tlen <= (hdrsize + pad + 8)))
/* XXX Need to generate an error CQ entry. */ goto ack_len_err;
goto ack_done; read_last:
}
tlen -= hdrsize + pad + 8; tlen -= hdrsize + pad + 8;
if (unlikely(tlen != qp->s_rdma_read_len)) { if (unlikely(tlen != qp->s_rdma_read_len))
/* XXX Need to generate an error CQ entry. */ goto ack_len_err;
goto ack_done;
}
if (!header_in_data) if (!header_in_data)
aeth = be32_to_cpu(ohdr->u.aeth); aeth = be32_to_cpu(ohdr->u.aeth);
else { else {
...@@ -1236,6 +1238,29 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev, ...@@ -1236,6 +1238,29 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
ack_done: ack_done:
spin_unlock_irqrestore(&qp->s_lock, flags); spin_unlock_irqrestore(&qp->s_lock, flags);
goto bail;
ack_op_err:
wc.status = IB_WC_LOC_QP_OP_ERR;
goto ack_err;
ack_len_err:
wc.status = IB_WC_LOC_LEN_ERR;
ack_err:
wc.wr_id = wqe->wr.wr_id;
wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
wc.vendor_err = 0;
wc.byte_len = 0;
wc.imm_data = 0;
wc.qp = &qp->ibqp;
wc.src_qp = qp->remote_qpn;
wc.wc_flags = 0;
wc.pkey_index = 0;
wc.slid = qp->remote_ah_attr.dlid;
wc.sl = qp->remote_ah_attr.sl;
wc.dlid_path_bits = 0;
wc.port_num = 0;
ipath_sqerror_qp(qp, &wc);
bail: bail:
return; return;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment