diff options
author | Ralph Campbell <ralph.campbell@qlogic.com> | 2007-03-15 14:45:00 -0700 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2007-04-18 20:20:57 -0700 |
commit | dd5190b6be0f3e27b6a4933a6a6d2d59957fc748 (patch) | |
tree | b359f97ede9c4d78bd25f0ed70fdc2b49570bc3d /drivers/infiniband/hw/ipath/ipath_rc.c | |
parent | c7e29ff11f23ec78b3caf691789c2b791bb596bf (diff) |
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: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/hw/ipath/ipath_rc.c')
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_rc.c | 63 |
1 files changed, 44 insertions, 19 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c index d6aa14afa26..b4b88d0b53f 100644 --- a/drivers/infiniband/hw/ipath/ipath_rc.c +++ b/drivers/infiniband/hw/ipath/ipath_rc.c @@ -1136,7 +1136,7 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev, goto ack_done; hdrsize += 4; 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 * 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, goto ack_done; } if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ)) - goto ack_done; + goto ack_op_err; read_middle: if (unlikely(tlen != (hdrsize + pmtu + 4))) - goto ack_done; + goto ack_len_err; if (unlikely(pmtu >= qp->s_rdma_read_len)) - goto ack_done; + goto ack_len_err; /* We got a response so update the timeout. */ spin_lock(&dev->pending_lock); @@ -1184,12 +1184,20 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev, goto ack_done; } 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 * have to be careful to copy the data to the right * location. - * XXX should check PSN and wqe opcode first. */ qp->s_rdma_read_len = restart_sge(&qp->s_rdma_read_sge, wqe, psn, pmtu); @@ -1203,26 +1211,20 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev, goto ack_done; } if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ)) - goto ack_done; - read_last: - /* - * Get the number of bytes the message was padded by. - */ + 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 >= 1 && <= pmtu. * Remember to account for the AETH header (4) and * ICRC (4). */ - if (unlikely(tlen <= (hdrsize + pad + 8))) { - /* XXX Need to generate an error CQ entry. */ - goto ack_done; - } + if (unlikely(tlen <= (hdrsize + pad + 8))) + goto ack_len_err; + read_last: tlen -= hdrsize + pad + 8; - if (unlikely(tlen != qp->s_rdma_read_len)) { - /* XXX Need to generate an error CQ entry. */ - goto ack_done; - } + if (unlikely(tlen != qp->s_rdma_read_len)) + goto ack_len_err; if (!header_in_data) aeth = be32_to_cpu(ohdr->u.aeth); else { @@ -1236,6 +1238,29 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev, ack_done: 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: return; } |