]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/infiniband/core/mad.c
Merge git://git.infradead.org/hdrcleanup-2.6
[linux-2.6-omap-h63xx.git] / drivers / infiniband / core / mad.c
index 92c7362f5887d0d4f3242e9ccc92b3a1f3850e94..b38e02a5db356c2b8dfdc612032e5fd73a860397 100644 (file)
@@ -34,6 +34,7 @@
  * $Id: mad.c 5596 2006-03-03 01:00:07Z sean.hefty $
  */
 #include <linux/dma-mapping.h>
+#include <rdma/ib_cache.h>
 
 #include "mad_priv.h"
 #include "mad_rmpp.h"
@@ -1672,20 +1673,21 @@ static inline int rcv_has_same_class(struct ib_mad_send_wr_private *wr,
                rwc->recv_buf.mad->mad_hdr.mgmt_class;
 }
 
-static inline int rcv_has_same_gid(struct ib_mad_send_wr_private *wr,
+static inline int rcv_has_same_gid(struct ib_mad_agent_private *mad_agent_priv,
+                                  struct ib_mad_send_wr_private *wr,
                                   struct ib_mad_recv_wc *rwc )
 {
        struct ib_ah_attr attr;
        u8 send_resp, rcv_resp;
+       union ib_gid sgid;
+       struct ib_device *device = mad_agent_priv->agent.device;
+       u8 port_num = mad_agent_priv->agent.port_num;
+       u8 lmc;
 
        send_resp = ((struct ib_mad *)(wr->send_buf.mad))->
                     mad_hdr.method & IB_MGMT_METHOD_RESP;
        rcv_resp = rwc->recv_buf.mad->mad_hdr.method & IB_MGMT_METHOD_RESP;
 
-       if (!send_resp && rcv_resp)
-               /* is request/response. GID/LIDs are both local (same). */
-               return 1;
-
        if (send_resp == rcv_resp)
                /* both requests, or both responses. GIDs different */
                return 0;
@@ -1694,48 +1696,78 @@ static inline int rcv_has_same_gid(struct ib_mad_send_wr_private *wr,
                /* Assume not equal, to avoid false positives. */
                return 0;
 
-       if (!(attr.ah_flags & IB_AH_GRH) && !(rwc->wc->wc_flags & IB_WC_GRH))
-               return attr.dlid == rwc->wc->slid;
-       else if ((attr.ah_flags & IB_AH_GRH) &&
-                (rwc->wc->wc_flags & IB_WC_GRH))
-               return memcmp(attr.grh.dgid.raw,
-                             rwc->recv_buf.grh->sgid.raw, 16) == 0;
-       else
+       if (!!(attr.ah_flags & IB_AH_GRH) !=
+           !!(rwc->wc->wc_flags & IB_WC_GRH))
                /* one has GID, other does not.  Assume different */
                return 0;
+
+       if (!send_resp && rcv_resp) {
+               /* is request/response. */
+               if (!(attr.ah_flags & IB_AH_GRH)) {
+                       if (ib_get_cached_lmc(device, port_num, &lmc))
+                               return 0;
+                       return (!lmc || !((attr.src_path_bits ^
+                                          rwc->wc->dlid_path_bits) &
+                                         ((1 << lmc) - 1)));
+               } else {
+                       if (ib_get_cached_gid(device, port_num,
+                                             attr.grh.sgid_index, &sgid))
+                               return 0;
+                       return !memcmp(sgid.raw, rwc->recv_buf.grh->dgid.raw,
+                                      16);
+               }
+       }
+
+       if (!(attr.ah_flags & IB_AH_GRH))
+               return attr.dlid == rwc->wc->slid;
+       else
+               return !memcmp(attr.grh.dgid.raw, rwc->recv_buf.grh->sgid.raw,
+                              16);
 }
+
+static inline int is_direct(u8 class)
+{
+       return (class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE);
+}
+
 struct ib_mad_send_wr_private*
 ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv,
-                struct ib_mad_recv_wc *mad_recv_wc)
+                struct ib_mad_recv_wc *wc)
 {
-       struct ib_mad_send_wr_private *mad_send_wr;
+       struct ib_mad_send_wr_private *wr;
        struct ib_mad *mad;
 
-       mad = (struct ib_mad *)mad_recv_wc->recv_buf.mad;
+       mad = (struct ib_mad *)wc->recv_buf.mad;
 
-       list_for_each_entry(mad_send_wr, &mad_agent_priv->wait_list,
-                           agent_list) {
-               if ((mad_send_wr->tid == mad->mad_hdr.tid) &&
-                   rcv_has_same_class(mad_send_wr, mad_recv_wc) &&
-                   rcv_has_same_gid(mad_send_wr, mad_recv_wc))
-                       return mad_send_wr;
+       list_for_each_entry(wr, &mad_agent_priv->wait_list, agent_list) {
+               if ((wr->tid == mad->mad_hdr.tid) &&
+                   rcv_has_same_class(wr, wc) &&
+                   /*
+                    * Don't check GID for direct routed MADs.
+                    * These might have permissive LIDs.
+                    */
+                   (is_direct(wc->recv_buf.mad->mad_hdr.mgmt_class) ||
+                    rcv_has_same_gid(mad_agent_priv, wr, wc)))
+                       return wr;
        }
 
        /*
         * It's possible to receive the response before we've
         * been notified that the send has completed
         */
-       list_for_each_entry(mad_send_wr, &mad_agent_priv->send_list,
-                           agent_list) {
-               if (is_data_mad(mad_agent_priv, mad_send_wr->send_buf.mad) &&
-                   mad_send_wr->tid == mad->mad_hdr.tid &&
-                   mad_send_wr->timeout &&
-                   rcv_has_same_class(mad_send_wr, mad_recv_wc) &&
-                   rcv_has_same_gid(mad_send_wr, mad_recv_wc)) {
+       list_for_each_entry(wr, &mad_agent_priv->send_list, agent_list) {
+               if (is_data_mad(mad_agent_priv, wr->send_buf.mad) &&
+                   wr->tid == mad->mad_hdr.tid &&
+                   wr->timeout &&
+                   rcv_has_same_class(wr, wc) &&
+                   /*
+                    * Don't check GID for direct routed MADs.
+                    * These might have permissive LIDs.
+                    */
+                   (is_direct(wc->recv_buf.mad->mad_hdr.mgmt_class) ||
+                    rcv_has_same_gid(mad_agent_priv, wr, wc)))
                        /* Verify request has not been canceled */
-                       return (mad_send_wr->status == IB_WC_SUCCESS) ?
-                               mad_send_wr : NULL;
-               }
+                       return (wr->status == IB_WC_SUCCESS) ? wr : NULL;
        }
        return NULL;
 }