Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / infiniband / hw / mthca / mthca_mad.c
index 7df2236..4730863 100644 (file)
@@ -1,5 +1,7 @@
 /*
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
  * $Id: mthca_mad.c 1349 2004-12-16 21:09:43Z roland $
  */
 
-#include <ib_verbs.h>
-#include <ib_mad.h>
-#include <ib_smi.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_mad.h>
+#include <rdma/ib_smi.h>
 
 #include "mthca_dev.h"
 #include "mthca_cmd.h"
@@ -44,10 +49,29 @@ enum {
        MTHCA_VENDOR_CLASS2 = 0xa
 };
 
-struct mthca_trap_mad {
-       struct ib_mad *mad;
-       DECLARE_PCI_UNMAP_ADDR(mapping)
-};
+static int mthca_update_rate(struct mthca_dev *dev, u8 port_num)
+{
+       struct ib_port_attr *tprops = NULL;
+       int                  ret;
+
+       tprops = kmalloc(sizeof *tprops, GFP_KERNEL);
+       if (!tprops)
+               return -ENOMEM;
+
+       ret = ib_query_port(&dev->ib_dev, port_num, tprops);
+       if (ret) {
+               printk(KERN_WARNING "ib_query_port failed (%d) for %s port %d\n",
+                      ret, dev->ib_dev.name, port_num);
+               goto out;
+       }
+
+       dev->rate[port_num - 1] = tprops->active_speed *
+                                 ib_width_enum_to_int(tprops->active_width);
+
+out:
+       kfree(tprops);
+       return ret;
+}
 
 static void update_sm_ah(struct mthca_dev *dev,
                         u8 port_num, u16 lid, u8 sl)
@@ -90,6 +114,7 @@ static void smp_snoop(struct ib_device *ibdev,
             mad->mad_hdr.mgmt_class  == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) &&
            mad->mad_hdr.method     == IB_MGMT_METHOD_SET) {
                if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO) {
+                       mthca_update_rate(to_mdev(ibdev), port_num);
                        update_sm_ah(to_mdev(ibdev), port_num,
                                     be16_to_cpup((__be16 *) (mad->data + 58)),
                                     (*(u8 *) (mad->data + 76)) & 0xf);
@@ -109,54 +134,32 @@ static void smp_snoop(struct ib_device *ibdev,
        }
 }
 
+static void node_desc_override(struct ib_device *dev,
+                              struct ib_mad *mad)
+{
+       if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
+            mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) &&
+           mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP &&
+           mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) {
+               mutex_lock(&to_mdev(dev)->cap_mask_mutex);
+               memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 64);
+               mutex_unlock(&to_mdev(dev)->cap_mask_mutex);
+       }
+}
+
 static void forward_trap(struct mthca_dev *dev,
                         u8 port_num,
                         struct ib_mad *mad)
 {
        int qpn = mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED;
-       struct mthca_trap_mad *tmad;
-       struct ib_sge      gather_list;
-       struct ib_send_wr *bad_wr, wr = {
-               .opcode      = IB_WR_SEND,
-               .sg_list     = &gather_list,
-               .num_sge     = 1,
-               .send_flags  = IB_SEND_SIGNALED,
-               .wr          = {
-                        .ud = {
-                                .remote_qpn  = qpn,
-                                .remote_qkey = qpn ? IB_QP1_QKEY : 0,
-                                .timeout_ms  = 0
-                        }
-                }
-       };
+       struct ib_mad_send_buf *send_buf;
        struct ib_mad_agent *agent = dev->send_agent[port_num - 1][qpn];
        int ret;
        unsigned long flags;
 
        if (agent) {
-               tmad = kmalloc(sizeof *tmad, GFP_KERNEL);
-               if (!tmad)
-                       return;
-
-               tmad->mad = kmalloc(sizeof *tmad->mad, GFP_KERNEL);
-               if (!tmad->mad) {
-                       kfree(tmad);
-                       return;
-               }
-
-               memcpy(tmad->mad, mad, sizeof *mad);
-
-               wr.wr.ud.mad_hdr = &tmad->mad->mad_hdr;
-               wr.wr_id         = (unsigned long) tmad;
-
-               gather_list.addr   = dma_map_single(agent->device->dma_device,
-                                                   tmad->mad,
-                                                   sizeof *tmad->mad,
-                                                   DMA_TO_DEVICE);
-               gather_list.length = sizeof *tmad->mad;
-               gather_list.lkey   = to_mpd(agent->qp->pd)->ntmr.ibmr.lkey;
-               pci_unmap_addr_set(tmad, mapping, gather_list.addr);
-
+               send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR,
+                                             IB_MGMT_MAD_DATA, GFP_ATOMIC);
                /*
                 * We rely here on the fact that MLX QPs don't use the
                 * address handle after the send is posted (this is
@@ -164,21 +167,15 @@ static void forward_trap(struct mthca_dev *dev,
                 * it's OK for our devices).
                 */
                spin_lock_irqsave(&dev->sm_lock, flags);
-               wr.wr.ud.ah      = dev->sm_ah[port_num - 1];
-               if (wr.wr.ud.ah)
-                       ret = ib_post_send_mad(agent, &wr, &bad_wr);
+               memcpy(send_buf->mad, mad, sizeof *mad);
+               if ((send_buf->ah = dev->sm_ah[port_num - 1]))
+                       ret = ib_post_send_mad(send_buf, NULL);
                else
                        ret = -EINVAL;
                spin_unlock_irqrestore(&dev->sm_lock, flags);
 
-               if (ret) {
-                       dma_unmap_single(agent->device->dma_device,
-                                        pci_unmap_addr(tmad, mapping),
-                                        sizeof *tmad->mad,
-                                        DMA_TO_DEVICE);
-                       kfree(tmad->mad);
-                       kfree(tmad);
-               }
+               if (ret)
+                       ib_free_send_mad(send_buf);
        }
 }
 
@@ -192,7 +189,7 @@ int mthca_process_mad(struct ib_device *ibdev,
 {
        int err;
        u8 status;
-       u16 slid = in_wc ? in_wc->slid : IB_LID_PERMISSIVE;
+       u16 slid = in_wc ? in_wc->slid : be16_to_cpu(IB_LID_PERMISSIVE);
 
        /* Forward locally generated traps to the SM */
        if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP &&
@@ -248,8 +245,10 @@ int mthca_process_mad(struct ib_device *ibdev,
                return IB_MAD_RESULT_FAILURE;
        }
 
-       if (!out_mad->mad_hdr.status)
+       if (!out_mad->mad_hdr.status) {
                smp_snoop(ibdev, port_num, in_mad);
+               node_desc_override(ibdev, out_mad);
+       }
 
        /* set return bit in status of directed route responses */
        if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
@@ -265,21 +264,14 @@ int mthca_process_mad(struct ib_device *ibdev,
 static void send_handler(struct ib_mad_agent *agent,
                         struct ib_mad_send_wc *mad_send_wc)
 {
-       struct mthca_trap_mad *tmad =
-               (void *) (unsigned long) mad_send_wc->wr_id;
-
-       dma_unmap_single(agent->device->dma_device,
-                        pci_unmap_addr(tmad, mapping),
-                        sizeof *tmad->mad,
-                        DMA_TO_DEVICE);
-       kfree(tmad->mad);
-       kfree(tmad);
+       ib_free_send_mad(mad_send_wc->send_buf);
 }
 
 int mthca_create_agents(struct mthca_dev *dev)
 {
        struct ib_mad_agent *agent;
        int p, q;
+       int ret;
 
        spin_lock_init(&dev->sm_lock);
 
@@ -289,11 +281,23 @@ int mthca_create_agents(struct mthca_dev *dev)
                                                      q ? IB_QPT_GSI : IB_QPT_SMI,
                                                      NULL, 0, send_handler,
                                                      NULL, NULL);
-                       if (IS_ERR(agent))
+                       if (IS_ERR(agent)) {
+                               ret = PTR_ERR(agent);
                                goto err;
+                       }
                        dev->send_agent[p][q] = agent;
                }
 
+
+       for (p = 1; p <= dev->limits.num_ports; ++p) {
+               ret = mthca_update_rate(dev, p);
+               if (ret) {
+                       mthca_err(dev, "Failed to obtain port %d rate."
+                                 " aborting.\n", p);
+                       goto err;
+               }
+       }
+
        return 0;
 
 err:
@@ -302,10 +306,10 @@ err:
                        if (dev->send_agent[p][q])
                                ib_unregister_mad_agent(dev->send_agent[p][q]);
 
-       return PTR_ERR(agent);
+       return ret;
 }
 
-void mthca_free_agents(struct mthca_dev *dev)
+void __devexit mthca_free_agents(struct mthca_dev *dev)
 {
        struct ib_mad_agent *agent;
        int p, q;