aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRalph Campbell <ralph.campbell@qlogic.com>2007-06-18 17:24:44 -0400
committerRoland Dreier <rolandd@cisco.com>2007-07-09 23:12:26 -0400
commitd781b129f1e8b3e2f369d8035a61a5233832e65c (patch)
tree7ff0bfbcd2e32a4693fa2007b773a7ca87968464
parent30d149ab58cc3ed8e4bc9c4dc45bebbed0e84b6e (diff)
IB/ipath: Duplicate RDMA reads can cause responder to NAK inappropriately
A duplicate RDMA read request can fool the responder into NAKing a new RDMA read request because the responder wasn't keeping track of whether the queue of RDMA read requests had been sent at least once. For example, requester sends 4 2K byte RDMA read requests, times out, and resends the first, then sees the 4 responses, then sends a 5th RDMA read or atomic operation. The responder sees the 4 requests, sends 4 responses, sees the resent 1st request, rewinds the queue, then sees the 5th request but thinks the queue is full and that the requester is invalidly sending a 5th new request. Signed-off-by: Ralph Campbell <ralph.campbell@qlogic.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
-rw-r--r--drivers/infiniband/hw/ipath/ipath_rc.c38
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.h1
2 files changed, 34 insertions, 5 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c
index 014d811d222d..9e7123987ae6 100644
--- a/drivers/infiniband/hw/ipath/ipath_rc.c
+++ b/drivers/infiniband/hw/ipath/ipath_rc.c
@@ -125,8 +125,10 @@ static int ipath_make_rc_ack(struct ipath_qp *qp,
125 if (len > pmtu) { 125 if (len > pmtu) {
126 len = pmtu; 126 len = pmtu;
127 qp->s_ack_state = OP(RDMA_READ_RESPONSE_FIRST); 127 qp->s_ack_state = OP(RDMA_READ_RESPONSE_FIRST);
128 } else 128 } else {
129 qp->s_ack_state = OP(RDMA_READ_RESPONSE_ONLY); 129 qp->s_ack_state = OP(RDMA_READ_RESPONSE_ONLY);
130 e->sent = 1;
131 }
130 ohdr->u.aeth = ipath_compute_aeth(qp); 132 ohdr->u.aeth = ipath_compute_aeth(qp);
131 hwords++; 133 hwords++;
132 qp->s_ack_rdma_psn = e->psn; 134 qp->s_ack_rdma_psn = e->psn;
@@ -143,6 +145,7 @@ static int ipath_make_rc_ack(struct ipath_qp *qp,
143 cpu_to_be32(e->atomic_data); 145 cpu_to_be32(e->atomic_data);
144 hwords += sizeof(ohdr->u.at) / sizeof(u32); 146 hwords += sizeof(ohdr->u.at) / sizeof(u32);
145 bth2 = e->psn; 147 bth2 = e->psn;
148 e->sent = 1;
146 } 149 }
147 bth0 = qp->s_ack_state << 24; 150 bth0 = qp->s_ack_state << 24;
148 break; 151 break;
@@ -158,6 +161,7 @@ static int ipath_make_rc_ack(struct ipath_qp *qp,
158 ohdr->u.aeth = ipath_compute_aeth(qp); 161 ohdr->u.aeth = ipath_compute_aeth(qp);
159 hwords++; 162 hwords++;
160 qp->s_ack_state = OP(RDMA_READ_RESPONSE_LAST); 163 qp->s_ack_state = OP(RDMA_READ_RESPONSE_LAST);
164 qp->s_ack_queue[qp->s_tail_ack_queue].sent = 1;
161 } 165 }
162 bth0 = qp->s_ack_state << 24; 166 bth0 = qp->s_ack_state << 24;
163 bth2 = qp->s_ack_rdma_psn++ & IPATH_PSN_MASK; 167 bth2 = qp->s_ack_rdma_psn++ & IPATH_PSN_MASK;
@@ -1479,6 +1483,22 @@ static void ipath_rc_error(struct ipath_qp *qp, enum ib_wc_status err)
1479 spin_unlock_irqrestore(&qp->s_lock, flags); 1483 spin_unlock_irqrestore(&qp->s_lock, flags);
1480} 1484}
1481 1485
1486static inline void ipath_update_ack_queue(struct ipath_qp *qp, unsigned n)
1487{
1488 unsigned long flags;
1489 unsigned next;
1490
1491 next = n + 1;
1492 if (next > IPATH_MAX_RDMA_ATOMIC)
1493 next = 0;
1494 spin_lock_irqsave(&qp->s_lock, flags);
1495 if (n == qp->s_tail_ack_queue) {
1496 qp->s_tail_ack_queue = next;
1497 qp->s_ack_state = OP(ACKNOWLEDGE);
1498 }
1499 spin_unlock_irqrestore(&qp->s_lock, flags);
1500}
1501
1482/** 1502/**
1483 * ipath_rc_rcv - process an incoming RC packet 1503 * ipath_rc_rcv - process an incoming RC packet
1484 * @dev: the device this packet came in on 1504 * @dev: the device this packet came in on
@@ -1741,8 +1761,11 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
1741 next = qp->r_head_ack_queue + 1; 1761 next = qp->r_head_ack_queue + 1;
1742 if (next > IPATH_MAX_RDMA_ATOMIC) 1762 if (next > IPATH_MAX_RDMA_ATOMIC)
1743 next = 0; 1763 next = 0;
1744 if (unlikely(next == qp->s_tail_ack_queue)) 1764 if (unlikely(next == qp->s_tail_ack_queue)) {
1745 goto nack_inv; 1765 if (!qp->s_ack_queue[next].sent)
1766 goto nack_inv;
1767 ipath_update_ack_queue(qp, next);
1768 }
1746 e = &qp->s_ack_queue[qp->r_head_ack_queue]; 1769 e = &qp->s_ack_queue[qp->r_head_ack_queue];
1747 /* RETH comes after BTH */ 1770 /* RETH comes after BTH */
1748 if (!header_in_data) 1771 if (!header_in_data)
@@ -1777,6 +1800,7 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
1777 e->rdma_sge.sge.sge_length = 0; 1800 e->rdma_sge.sge.sge_length = 0;
1778 } 1801 }
1779 e->opcode = opcode; 1802 e->opcode = opcode;
1803 e->sent = 0;
1780 e->psn = psn; 1804 e->psn = psn;
1781 /* 1805 /*
1782 * We need to increment the MSN here instead of when we 1806 * We need to increment the MSN here instead of when we
@@ -1812,8 +1836,11 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
1812 next = qp->r_head_ack_queue + 1; 1836 next = qp->r_head_ack_queue + 1;
1813 if (next > IPATH_MAX_RDMA_ATOMIC) 1837 if (next > IPATH_MAX_RDMA_ATOMIC)
1814 next = 0; 1838 next = 0;
1815 if (unlikely(next == qp->s_tail_ack_queue)) 1839 if (unlikely(next == qp->s_tail_ack_queue)) {
1816 goto nack_inv; 1840 if (!qp->s_ack_queue[next].sent)
1841 goto nack_inv;
1842 ipath_update_ack_queue(qp, next);
1843 }
1817 if (!header_in_data) 1844 if (!header_in_data)
1818 ateth = &ohdr->u.atomic_eth; 1845 ateth = &ohdr->u.atomic_eth;
1819 else 1846 else
@@ -1838,6 +1865,7 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
1838 be64_to_cpu(ateth->compare_data), 1865 be64_to_cpu(ateth->compare_data),
1839 sdata); 1866 sdata);
1840 e->opcode = opcode; 1867 e->opcode = opcode;
1868 e->sent = 0;
1841 e->psn = psn & IPATH_PSN_MASK; 1869 e->psn = psn & IPATH_PSN_MASK;
1842 qp->r_msn++; 1870 qp->r_msn++;
1843 qp->r_psn++; 1871 qp->r_psn++;
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h
index 088b837ebea8..458f8227fa36 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.h
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.h
@@ -321,6 +321,7 @@ struct ipath_sge_state {
321 */ 321 */
322struct ipath_ack_entry { 322struct ipath_ack_entry {
323 u8 opcode; 323 u8 opcode;
324 u8 sent;
324 u32 psn; 325 u32 psn;
325 union { 326 union {
326 struct ipath_sge_state rdma_sge; 327 struct ipath_sge_state rdma_sge;