diff options
author | Jack Morgenstein <jackm@mellanox.co.il> | 2006-03-28 19:39:07 -0500 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2006-03-30 10:19:48 -0500 |
commit | fa9656bbd9af5b95adc43eaa0a143992346378cb (patch) | |
tree | 100d516324208e1a4a65b77e86bcbc94f5ef0db9 | |
parent | e1f7868c80947d40ef8e1fd37323d939a9bf311c (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.c | 58 | ||||
-rw-r--r-- | drivers/infiniband/core/mad_priv.h | 3 | ||||
-rw-r--r-- | drivers/infiniband/core/mad_rmpp.c | 35 |
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 | ||
1621 | static 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 | |||
1628 | static 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 | } | ||
1621 | struct ib_mad_send_wr_private* | 1660 | struct ib_mad_send_wr_private* |
1622 | ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, __be64 tid) | 1661 | ib_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; | |||
216 | int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr); | 216 | int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr); |
217 | 217 | ||
218 | struct ib_mad_send_wr_private * | 218 | struct ib_mad_send_wr_private * |
219 | ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, __be64 tid); | 219 | ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, |
220 | struct ib_mad_recv_wc *mad_recv_wc); | ||
220 | 221 | ||
221 | void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr, | 222 | void 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 | ||
565 | static void abort_send(struct ib_mad_agent_private *agent, __be64 tid, | 565 | static 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); |
632 | if (!mad_send_wr) | 630 | if (!mad_send_wr) |
633 | goto out; /* Unmatched ACK */ | 631 | goto out; /* Unmatched ACK */ |
634 | 632 | ||
@@ -639,8 +637,7 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent, | |||
639 | if (seg_num > mad_send_wr->send_buf.seg_count || | 637 | if (seg_num > mad_send_wr->send_buf.seg_count || |
640 | seg_num > mad_send_wr->newwin) { | 638 | seg_num > mad_send_wr->newwin) { |
641 | spin_unlock_irqrestore(&agent->lock, flags); | 639 | spin_unlock_irqrestore(&agent->lock, flags); |
642 | abort_send(agent, rmpp_mad->mad_hdr.tid, | 640 | abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_S2B); |
643 | IB_MGMT_RMPP_STATUS_S2B); | ||
644 | nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_S2B); | 641 | nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_S2B); |
645 | return; | 642 | return; |
646 | } | 643 | } |
@@ -728,12 +725,10 @@ static void process_rmpp_stop(struct ib_mad_agent_private *agent, | |||
728 | rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad; | 725 | rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad; |
729 | 726 | ||
730 | if (rmpp_mad->rmpp_hdr.rmpp_status != IB_MGMT_RMPP_STATUS_RESX) { | 727 | if (rmpp_mad->rmpp_hdr.rmpp_status != IB_MGMT_RMPP_STATUS_RESX) { |
731 | abort_send(agent, rmpp_mad->mad_hdr.tid, | 728 | abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS); |
732 | IB_MGMT_RMPP_STATUS_BAD_STATUS); | ||
733 | nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS); | 729 | nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS); |
734 | } else | 730 | } else |
735 | abort_send(agent, rmpp_mad->mad_hdr.tid, | 731 | abort_send(agent, mad_recv_wc, rmpp_mad->rmpp_hdr.rmpp_status); |
736 | rmpp_mad->rmpp_hdr.rmpp_status); | ||
737 | } | 732 | } |
738 | 733 | ||
739 | static void process_rmpp_abort(struct ib_mad_agent_private *agent, | 734 | static void process_rmpp_abort(struct ib_mad_agent_private *agent, |
@@ -745,12 +740,10 @@ static void process_rmpp_abort(struct ib_mad_agent_private *agent, | |||
745 | 740 | ||
746 | if (rmpp_mad->rmpp_hdr.rmpp_status < IB_MGMT_RMPP_STATUS_ABORT_MIN || | 741 | if (rmpp_mad->rmpp_hdr.rmpp_status < IB_MGMT_RMPP_STATUS_ABORT_MIN || |
747 | rmpp_mad->rmpp_hdr.rmpp_status > IB_MGMT_RMPP_STATUS_ABORT_MAX) { | 742 | rmpp_mad->rmpp_hdr.rmpp_status > IB_MGMT_RMPP_STATUS_ABORT_MAX) { |
748 | abort_send(agent, rmpp_mad->mad_hdr.tid, | 743 | abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS); |
749 | IB_MGMT_RMPP_STATUS_BAD_STATUS); | ||
750 | nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS); | 744 | nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS); |
751 | } else | 745 | } else |
752 | abort_send(agent, rmpp_mad->mad_hdr.tid, | 746 | abort_send(agent, mad_recv_wc, rmpp_mad->rmpp_hdr.rmpp_status); |
753 | rmpp_mad->rmpp_hdr.rmpp_status); | ||
754 | } | 747 | } |
755 | 748 | ||
756 | struct ib_mad_recv_wc * | 749 | struct ib_mad_recv_wc * |
@@ -764,8 +757,7 @@ ib_process_rmpp_recv_wc(struct ib_mad_agent_private *agent, | |||
764 | return mad_recv_wc; | 757 | return mad_recv_wc; |
765 | 758 | ||
766 | if (rmpp_mad->rmpp_hdr.rmpp_version != IB_MGMT_RMPP_VERSION) { | 759 | if (rmpp_mad->rmpp_hdr.rmpp_version != IB_MGMT_RMPP_VERSION) { |
767 | abort_send(agent, rmpp_mad->mad_hdr.tid, | 760 | abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_UNV); |
768 | IB_MGMT_RMPP_STATUS_UNV); | ||
769 | nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_UNV); | 761 | nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_UNV); |
770 | goto out; | 762 | goto out; |
771 | } | 763 | } |
@@ -783,8 +775,7 @@ ib_process_rmpp_recv_wc(struct ib_mad_agent_private *agent, | |||
783 | process_rmpp_abort(agent, mad_recv_wc); | 775 | process_rmpp_abort(agent, mad_recv_wc); |
784 | break; | 776 | break; |
785 | default: | 777 | default: |
786 | abort_send(agent, rmpp_mad->mad_hdr.tid, | 778 | abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BADT); |
787 | IB_MGMT_RMPP_STATUS_BADT); | ||
788 | nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BADT); | 779 | nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BADT); |
789 | break; | 780 | break; |
790 | } | 781 | } |