aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Morgenstein <jackm@mellanox.co.il>2006-03-28 19:39:07 -0500
committerRoland Dreier <rolandd@cisco.com>2006-03-30 10:19:48 -0500
commitfa9656bbd9af5b95adc43eaa0a143992346378cb (patch)
tree100d516324208e1a4a65b77e86bcbc94f5ef0db9
parente1f7868c80947d40ef8e1fd37323d939a9bf311c (diff)
IB/mad: include GID/class when matching receives
Received responses are currently matched against sent requests based on TID only. According to the spec, responses should match based on the combination of TID, management class, and requester LID/GID. Without the additional qualification, an agent that is responding to two requests, both of which have the same TID, can match RMPP ACKs with the incorrect transaction. This problem can occur on the SM node when responding to SA queries. Signed-off-by: Jack Morgenstein <jackm@mellanox.co.il> Signed-off-by: Sean Hefty <sean.hefty@intel.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
-rw-r--r--drivers/infiniband/core/mad.c58
-rw-r--r--drivers/infiniband/core/mad_priv.h3
-rw-r--r--drivers/infiniband/core/mad_rmpp.c35
3 files changed, 67 insertions, 29 deletions
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index f7854b65fd55..d4d07012a5ca 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -1618,14 +1618,59 @@ static int is_data_mad(struct ib_mad_agent_private *mad_agent_priv,
1618 (rmpp_mad->rmpp_hdr.rmpp_type == IB_MGMT_RMPP_TYPE_DATA); 1618 (rmpp_mad->rmpp_hdr.rmpp_type == IB_MGMT_RMPP_TYPE_DATA);
1619} 1619}
1620 1620
1621static inline int rcv_has_same_class(struct ib_mad_send_wr_private *wr,
1622 struct ib_mad_recv_wc *rwc)
1623{
1624 return ((struct ib_mad *)(wr->send_buf.mad))->mad_hdr.mgmt_class ==
1625 rwc->recv_buf.mad->mad_hdr.mgmt_class;
1626}
1627
1628static inline int rcv_has_same_gid(struct ib_mad_send_wr_private *wr,
1629 struct ib_mad_recv_wc *rwc )
1630{
1631 struct ib_ah_attr attr;
1632 u8 send_resp, rcv_resp;
1633
1634 send_resp = ((struct ib_mad *)(wr->send_buf.mad))->
1635 mad_hdr.method & IB_MGMT_METHOD_RESP;
1636 rcv_resp = rwc->recv_buf.mad->mad_hdr.method & IB_MGMT_METHOD_RESP;
1637
1638 if (!send_resp && rcv_resp)
1639 /* is request/response. GID/LIDs are both local (same). */
1640 return 1;
1641
1642 if (send_resp == rcv_resp)
1643 /* both requests, or both responses. GIDs different */
1644 return 0;
1645
1646 if (ib_query_ah(wr->send_buf.ah, &attr))
1647 /* Assume not equal, to avoid false positives. */
1648 return 0;
1649
1650 if (!(attr.ah_flags & IB_AH_GRH) && !(rwc->wc->wc_flags & IB_WC_GRH))
1651 return attr.dlid == rwc->wc->slid;
1652 else if ((attr.ah_flags & IB_AH_GRH) &&
1653 (rwc->wc->wc_flags & IB_WC_GRH))
1654 return memcmp(attr.grh.dgid.raw,
1655 rwc->recv_buf.grh->sgid.raw, 16) == 0;
1656 else
1657 /* one has GID, other does not. Assume different */
1658 return 0;
1659}
1621struct ib_mad_send_wr_private* 1660struct ib_mad_send_wr_private*
1622ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, __be64 tid) 1661ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv,
1662 struct ib_mad_recv_wc *mad_recv_wc)
1623{ 1663{
1624 struct ib_mad_send_wr_private *mad_send_wr; 1664 struct ib_mad_send_wr_private *mad_send_wr;
1665 struct ib_mad *mad;
1666
1667 mad = (struct ib_mad *)mad_recv_wc->recv_buf.mad;
1625 1668
1626 list_for_each_entry(mad_send_wr, &mad_agent_priv->wait_list, 1669 list_for_each_entry(mad_send_wr, &mad_agent_priv->wait_list,
1627 agent_list) { 1670 agent_list) {
1628 if (mad_send_wr->tid == tid) 1671 if ((mad_send_wr->tid == mad->mad_hdr.tid) &&
1672 rcv_has_same_class(mad_send_wr, mad_recv_wc) &&
1673 rcv_has_same_gid(mad_send_wr, mad_recv_wc))
1629 return mad_send_wr; 1674 return mad_send_wr;
1630 } 1675 }
1631 1676
@@ -1636,7 +1681,10 @@ ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, __be64 tid)
1636 list_for_each_entry(mad_send_wr, &mad_agent_priv->send_list, 1681 list_for_each_entry(mad_send_wr, &mad_agent_priv->send_list,
1637 agent_list) { 1682 agent_list) {
1638 if (is_data_mad(mad_agent_priv, mad_send_wr->send_buf.mad) && 1683 if (is_data_mad(mad_agent_priv, mad_send_wr->send_buf.mad) &&
1639 mad_send_wr->tid == tid && mad_send_wr->timeout) { 1684 mad_send_wr->tid == mad->mad_hdr.tid &&
1685 mad_send_wr->timeout &&
1686 rcv_has_same_class(mad_send_wr, mad_recv_wc) &&
1687 rcv_has_same_gid(mad_send_wr, mad_recv_wc)) {
1640 /* Verify request has not been canceled */ 1688 /* Verify request has not been canceled */
1641 return (mad_send_wr->status == IB_WC_SUCCESS) ? 1689 return (mad_send_wr->status == IB_WC_SUCCESS) ?
1642 mad_send_wr : NULL; 1690 mad_send_wr : NULL;
@@ -1661,7 +1709,6 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv,
1661 struct ib_mad_send_wr_private *mad_send_wr; 1709 struct ib_mad_send_wr_private *mad_send_wr;
1662 struct ib_mad_send_wc mad_send_wc; 1710 struct ib_mad_send_wc mad_send_wc;
1663 unsigned long flags; 1711 unsigned long flags;
1664 __be64 tid;
1665 1712
1666 INIT_LIST_HEAD(&mad_recv_wc->rmpp_list); 1713 INIT_LIST_HEAD(&mad_recv_wc->rmpp_list);
1667 list_add(&mad_recv_wc->recv_buf.list, &mad_recv_wc->rmpp_list); 1714 list_add(&mad_recv_wc->recv_buf.list, &mad_recv_wc->rmpp_list);
@@ -1677,9 +1724,8 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv,
1677 1724
1678 /* Complete corresponding request */ 1725 /* Complete corresponding request */
1679 if (response_mad(mad_recv_wc->recv_buf.mad)) { 1726 if (response_mad(mad_recv_wc->recv_buf.mad)) {
1680 tid = mad_recv_wc->recv_buf.mad->mad_hdr.tid;
1681 spin_lock_irqsave(&mad_agent_priv->lock, flags); 1727 spin_lock_irqsave(&mad_agent_priv->lock, flags);
1682 mad_send_wr = ib_find_send_mad(mad_agent_priv, tid); 1728 mad_send_wr = ib_find_send_mad(mad_agent_priv, mad_recv_wc);
1683 if (!mad_send_wr) { 1729 if (!mad_send_wr) {
1684 spin_unlock_irqrestore(&mad_agent_priv->lock, flags); 1730 spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
1685 ib_free_recv_mad(mad_recv_wc); 1731 ib_free_recv_mad(mad_recv_wc);
diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h
index a7125d4b5ccf..6c9c133d71ef 100644
--- a/drivers/infiniband/core/mad_priv.h
+++ b/drivers/infiniband/core/mad_priv.h
@@ -216,7 +216,8 @@ extern kmem_cache_t *ib_mad_cache;
216int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr); 216int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr);
217 217
218struct ib_mad_send_wr_private * 218struct ib_mad_send_wr_private *
219ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, __be64 tid); 219ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv,
220 struct ib_mad_recv_wc *mad_recv_wc);
220 221
221void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr, 222void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr,
222 struct ib_mad_send_wc *mad_send_wc); 223 struct ib_mad_send_wc *mad_send_wc);
diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c
index bacfdd5bddad..a6405079c285 100644
--- a/drivers/infiniband/core/mad_rmpp.c
+++ b/drivers/infiniband/core/mad_rmpp.c
@@ -562,15 +562,15 @@ static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr)
562 return ib_send_mad(mad_send_wr); 562 return ib_send_mad(mad_send_wr);
563} 563}
564 564
565static void abort_send(struct ib_mad_agent_private *agent, __be64 tid, 565static void abort_send(struct ib_mad_agent_private *agent,
566 u8 rmpp_status) 566 struct ib_mad_recv_wc *mad_recv_wc, u8 rmpp_status)
567{ 567{
568 struct ib_mad_send_wr_private *mad_send_wr; 568 struct ib_mad_send_wr_private *mad_send_wr;
569 struct ib_mad_send_wc wc; 569 struct ib_mad_send_wc wc;
570 unsigned long flags; 570 unsigned long flags;
571 571
572 spin_lock_irqsave(&agent->lock, flags); 572 spin_lock_irqsave(&agent->lock, flags);
573 mad_send_wr = ib_find_send_mad(agent, tid); 573 mad_send_wr = ib_find_send_mad(agent, mad_recv_wc);
574 if (!mad_send_wr) 574 if (!mad_send_wr)
575 goto out; /* Unmatched send */ 575 goto out; /* Unmatched send */
576 576
@@ -612,8 +612,7 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent,
612 612
613 rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad; 613 rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad;
614 if (rmpp_mad->rmpp_hdr.rmpp_status) { 614 if (rmpp_mad->rmpp_hdr.rmpp_status) {
615 abort_send(agent, rmpp_mad->mad_hdr.tid, 615 abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
616 IB_MGMT_RMPP_STATUS_BAD_STATUS);
617 nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS); 616 nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);
618 return; 617 return;
619 } 618 }
@@ -621,14 +620,13 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent,
621 seg_num = be32_to_cpu(rmpp_mad->rmpp_hdr.seg_num); 620 seg_num = be32_to_cpu(rmpp_mad->rmpp_hdr.seg_num);
622 newwin = be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin); 621 newwin = be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin);
623 if (newwin < seg_num) { 622 if (newwin < seg_num) {
624 abort_send(agent, rmpp_mad->mad_hdr.tid, 623 abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_W2S);
625 IB_MGMT_RMPP_STATUS_W2S);
626 nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_W2S); 624 nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_W2S);
627 return; 625 return;
628 } 626 }
629 627
630 spin_lock_irqsave(&agent->lock, flags); 628 spin_lock_irqsave(&agent->lock, flags);
631 mad_send_wr = ib_find_send_mad(agent, rmpp_mad->mad_hdr.tid); 629 mad_send_wr = ib_find_send_mad(agent, mad_recv_wc);