diff options
Diffstat (limited to 'drivers/infiniband/core/mad.c')
-rw-r--r-- | drivers/infiniband/core/mad.c | 58 |
1 files changed, 52 insertions, 6 deletions
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index f7854b65fd5..d4d07012a5c 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); |