root/drivers/infiniband/hw/mthca/mthca_mad.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mthca_update_rate
  2. update_sm_ah
  3. smp_snoop
  4. node_desc_override
  5. forward_trap
  6. mthca_process_mad
  7. send_handler
  8. mthca_create_agents
  9. mthca_free_agents

   1 /*
   2  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
   3  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
   4  * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
   5  *
   6  * This software is available to you under a choice of one of two
   7  * licenses.  You may choose to be licensed under the terms of the GNU
   8  * General Public License (GPL) Version 2, available from the file
   9  * COPYING in the main directory of this source tree, or the
  10  * OpenIB.org BSD license below:
  11  *
  12  *     Redistribution and use in source and binary forms, with or
  13  *     without modification, are permitted provided that the following
  14  *     conditions are met:
  15  *
  16  *      - Redistributions of source code must retain the above
  17  *        copyright notice, this list of conditions and the following
  18  *        disclaimer.
  19  *
  20  *      - Redistributions in binary form must reproduce the above
  21  *        copyright notice, this list of conditions and the following
  22  *        disclaimer in the documentation and/or other materials
  23  *        provided with the distribution.
  24  *
  25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  26  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  27  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  28  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  29  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  30  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  31  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  32  * SOFTWARE.
  33  */
  34 
  35 #include <linux/string.h>
  36 #include <linux/slab.h>
  37 
  38 #include <rdma/ib_verbs.h>
  39 #include <rdma/ib_mad.h>
  40 #include <rdma/ib_smi.h>
  41 
  42 #include "mthca_dev.h"
  43 #include "mthca_cmd.h"
  44 
  45 enum {
  46         MTHCA_VENDOR_CLASS1 = 0x9,
  47         MTHCA_VENDOR_CLASS2 = 0xa
  48 };
  49 
  50 static int mthca_update_rate(struct mthca_dev *dev, u8 port_num)
  51 {
  52         struct ib_port_attr *tprops = NULL;
  53         int                  ret;
  54 
  55         tprops = kmalloc(sizeof *tprops, GFP_KERNEL);
  56         if (!tprops)
  57                 return -ENOMEM;
  58 
  59         ret = ib_query_port(&dev->ib_dev, port_num, tprops);
  60         if (ret) {
  61                 dev_warn(&dev->ib_dev.dev,
  62                          "ib_query_port failed (%d) forport %d\n", ret,
  63                          port_num);
  64                 goto out;
  65         }
  66 
  67         dev->rate[port_num - 1] = tprops->active_speed *
  68                                   ib_width_enum_to_int(tprops->active_width);
  69 
  70 out:
  71         kfree(tprops);
  72         return ret;
  73 }
  74 
  75 static void update_sm_ah(struct mthca_dev *dev,
  76                          u8 port_num, u16 lid, u8 sl)
  77 {
  78         struct ib_ah *new_ah;
  79         struct rdma_ah_attr ah_attr;
  80         unsigned long flags;
  81 
  82         if (!dev->send_agent[port_num - 1][0])
  83                 return;
  84 
  85         memset(&ah_attr, 0, sizeof ah_attr);
  86         ah_attr.type = rdma_ah_find_type(&dev->ib_dev, port_num);
  87         rdma_ah_set_dlid(&ah_attr, lid);
  88         rdma_ah_set_sl(&ah_attr, sl);
  89         rdma_ah_set_port_num(&ah_attr, port_num);
  90 
  91         new_ah = rdma_create_ah(dev->send_agent[port_num - 1][0]->qp->pd,
  92                                 &ah_attr, 0);
  93         if (IS_ERR(new_ah))
  94                 return;
  95 
  96         spin_lock_irqsave(&dev->sm_lock, flags);
  97         if (dev->sm_ah[port_num - 1])
  98                 rdma_destroy_ah(dev->sm_ah[port_num - 1], 0);
  99         dev->sm_ah[port_num - 1] = new_ah;
 100         spin_unlock_irqrestore(&dev->sm_lock, flags);
 101 }
 102 
 103 /*
 104  * Snoop SM MADs for port info and P_Key table sets, so we can
 105  * synthesize LID change and P_Key change events.
 106  */
 107 static void smp_snoop(struct ib_device *ibdev,
 108                       u8 port_num,
 109                       const struct ib_mad *mad,
 110                       u16 prev_lid)
 111 {
 112         struct ib_event event;
 113 
 114         if ((mad->mad_hdr.mgmt_class  == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
 115              mad->mad_hdr.mgmt_class  == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) &&
 116             mad->mad_hdr.method     == IB_MGMT_METHOD_SET) {
 117                 if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO) {
 118                         struct ib_port_info *pinfo =
 119                                 (struct ib_port_info *) ((struct ib_smp *) mad)->data;
 120                         u16 lid = be16_to_cpu(pinfo->lid);
 121 
 122                         mthca_update_rate(to_mdev(ibdev), port_num);
 123                         update_sm_ah(to_mdev(ibdev), port_num,
 124                                      be16_to_cpu(pinfo->sm_lid),
 125                                      pinfo->neighbormtu_mastersmsl & 0xf);
 126 
 127                         event.device           = ibdev;
 128                         event.element.port_num = port_num;
 129 
 130                         if (pinfo->clientrereg_resv_subnetto & 0x80) {
 131                                 event.event    = IB_EVENT_CLIENT_REREGISTER;
 132                                 ib_dispatch_event(&event);
 133                         }
 134 
 135                         if (prev_lid != lid) {
 136                                 event.event    = IB_EVENT_LID_CHANGE;
 137                                 ib_dispatch_event(&event);
 138                         }
 139                 }
 140 
 141                 if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PKEY_TABLE) {
 142                         event.device           = ibdev;
 143                         event.event            = IB_EVENT_PKEY_CHANGE;
 144                         event.element.port_num = port_num;
 145                         ib_dispatch_event(&event);
 146                 }
 147         }
 148 }
 149 
 150 static void node_desc_override(struct ib_device *dev,
 151                                struct ib_mad *mad)
 152 {
 153         if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
 154              mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) &&
 155             mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP &&
 156             mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) {
 157                 mutex_lock(&to_mdev(dev)->cap_mask_mutex);
 158                 memcpy(((struct ib_smp *) mad)->data, dev->node_desc,
 159                        IB_DEVICE_NODE_DESC_MAX);
 160                 mutex_unlock(&to_mdev(dev)->cap_mask_mutex);
 161         }
 162 }
 163 
 164 static void forward_trap(struct mthca_dev *dev,
 165                          u8 port_num,
 166                          const struct ib_mad *mad)
 167 {
 168         int qpn = mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED;
 169         struct ib_mad_send_buf *send_buf;
 170         struct ib_mad_agent *agent = dev->send_agent[port_num - 1][qpn];
 171         int ret;
 172         unsigned long flags;
 173 
 174         if (agent) {
 175                 send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR,
 176                                               IB_MGMT_MAD_DATA, GFP_ATOMIC,
 177                                               IB_MGMT_BASE_VERSION);
 178                 if (IS_ERR(send_buf))
 179                         return;
 180                 /*
 181                  * We rely here on the fact that MLX QPs don't use the
 182                  * address handle after the send is posted (this is
 183                  * wrong following the IB spec strictly, but we know
 184                  * it's OK for our devices).
 185                  */
 186                 spin_lock_irqsave(&dev->sm_lock, flags);
 187                 memcpy(send_buf->mad, mad, sizeof *mad);
 188                 if ((send_buf->ah = dev->sm_ah[port_num - 1]))
 189                         ret = ib_post_send_mad(send_buf, NULL);
 190                 else
 191                         ret = -EINVAL;
 192                 spin_unlock_irqrestore(&dev->sm_lock, flags);
 193 
 194                 if (ret)
 195                         ib_free_send_mad(send_buf);
 196         }
 197 }
 198 
 199 int mthca_process_mad(struct ib_device *ibdev,
 200                       int mad_flags,
 201                       u8 port_num,
 202                       const struct ib_wc *in_wc,
 203                       const struct ib_grh *in_grh,
 204                       const struct ib_mad_hdr *in, size_t in_mad_size,
 205                       struct ib_mad_hdr *out, size_t *out_mad_size,
 206                       u16 *out_mad_pkey_index)
 207 {
 208         int err;
 209         u16 slid = in_wc ? ib_lid_cpu16(in_wc->slid) : be16_to_cpu(IB_LID_PERMISSIVE);
 210         u16 prev_lid = 0;
 211         struct ib_port_attr pattr;
 212         const struct ib_mad *in_mad = (const struct ib_mad *)in;
 213         struct ib_mad *out_mad = (struct ib_mad *)out;
 214 
 215         if (WARN_ON_ONCE(in_mad_size != sizeof(*in_mad) ||
 216                          *out_mad_size != sizeof(*out_mad)))
 217                 return IB_MAD_RESULT_FAILURE;
 218 
 219         /* Forward locally generated traps to the SM */
 220         if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP &&
 221             slid == 0) {
 222                 forward_trap(to_mdev(ibdev), port_num, in_mad);
 223                 return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
 224         }
 225 
 226         /*
 227          * Only handle SM gets, sets and trap represses for SM class
 228          *
 229          * Only handle PMA and Mellanox vendor-specific class gets and
 230          * sets for other classes.
 231          */
 232         if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
 233             in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {
 234                 if (in_mad->mad_hdr.method   != IB_MGMT_METHOD_GET &&
 235                     in_mad->mad_hdr.method   != IB_MGMT_METHOD_SET &&
 236                     in_mad->mad_hdr.method   != IB_MGMT_METHOD_TRAP_REPRESS)
 237                         return IB_MAD_RESULT_SUCCESS;
 238 
 239                 /*
 240                  * Don't process SMInfo queries or vendor-specific
 241                  * MADs -- the SMA can't handle them.
 242                  */
 243                 if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO ||
 244                     ((in_mad->mad_hdr.attr_id & IB_SMP_ATTR_VENDOR_MASK) ==
 245                      IB_SMP_ATTR_VENDOR_MASK))
 246                         return IB_MAD_RESULT_SUCCESS;
 247         } else if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT ||
 248                    in_mad->mad_hdr.mgmt_class == MTHCA_VENDOR_CLASS1     ||
 249                    in_mad->mad_hdr.mgmt_class == MTHCA_VENDOR_CLASS2) {
 250                 if (in_mad->mad_hdr.method  != IB_MGMT_METHOD_GET &&
 251                     in_mad->mad_hdr.method  != IB_MGMT_METHOD_SET)
 252                         return IB_MAD_RESULT_SUCCESS;
 253         } else
 254                 return IB_MAD_RESULT_SUCCESS;
 255         if ((in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
 256              in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) &&
 257             in_mad->mad_hdr.method == IB_MGMT_METHOD_SET &&
 258             in_mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO &&
 259             !ib_query_port(ibdev, port_num, &pattr))
 260                 prev_lid = ib_lid_cpu16(pattr.lid);
 261 
 262         err = mthca_MAD_IFC(to_mdev(ibdev),
 263                             mad_flags & IB_MAD_IGNORE_MKEY,
 264                             mad_flags & IB_MAD_IGNORE_BKEY,
 265                             port_num, in_wc, in_grh, in_mad, out_mad);
 266         if (err == -EBADMSG)
 267                 return IB_MAD_RESULT_SUCCESS;
 268         else if (err) {
 269                 mthca_err(to_mdev(ibdev), "MAD_IFC returned %d\n", err);
 270                 return IB_MAD_RESULT_FAILURE;
 271         }
 272 
 273         if (!out_mad->mad_hdr.status) {
 274                 smp_snoop(ibdev, port_num, in_mad, prev_lid);
 275                 node_desc_override(ibdev, out_mad);
 276         }
 277 
 278         /* set return bit in status of directed route responses */
 279         if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
 280                 out_mad->mad_hdr.status |= cpu_to_be16(1 << 15);
 281 
 282         if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS)
 283                 /* no response for trap repress */
 284                 return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
 285 
 286         return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
 287 }
 288 
 289 static void send_handler(struct ib_mad_agent *agent,
 290                          struct ib_mad_send_wc *mad_send_wc)
 291 {
 292         ib_free_send_mad(mad_send_wc->send_buf);
 293 }
 294 
 295 int mthca_create_agents(struct mthca_dev *dev)
 296 {
 297         struct ib_mad_agent *agent;
 298         int p, q;
 299         int ret;
 300 
 301         spin_lock_init(&dev->sm_lock);
 302 
 303         for (p = 0; p < dev->limits.num_ports; ++p)
 304                 for (q = 0; q <= 1; ++q) {
 305                         agent = ib_register_mad_agent(&dev->ib_dev, p + 1,
 306                                                       q ? IB_QPT_GSI : IB_QPT_SMI,
 307                                                       NULL, 0, send_handler,
 308                                                       NULL, NULL, 0);
 309                         if (IS_ERR(agent)) {
 310                                 ret = PTR_ERR(agent);
 311                                 goto err;
 312                         }
 313                         dev->send_agent[p][q] = agent;
 314                 }
 315 
 316 
 317         for (p = 1; p <= dev->limits.num_ports; ++p) {
 318                 ret = mthca_update_rate(dev, p);
 319                 if (ret) {
 320                         mthca_err(dev, "Failed to obtain port %d rate."
 321                                   " aborting.\n", p);
 322                         goto err;
 323                 }
 324         }
 325 
 326         return 0;
 327 
 328 err:
 329         for (p = 0; p < dev->limits.num_ports; ++p)
 330                 for (q = 0; q <= 1; ++q)
 331                         if (dev->send_agent[p][q])
 332                                 ib_unregister_mad_agent(dev->send_agent[p][q]);
 333 
 334         return ret;
 335 }
 336 
 337 void mthca_free_agents(struct mthca_dev *dev)
 338 {
 339         struct ib_mad_agent *agent;
 340         int p, q;
 341 
 342         for (p = 0; p < dev->limits.num_ports; ++p) {
 343                 for (q = 0; q <= 1; ++q) {
 344                         agent = dev->send_agent[p][q];
 345                         dev->send_agent[p][q] = NULL;
 346                         ib_unregister_mad_agent(agent);
 347                 }
 348 
 349                 if (dev->sm_ah[p])
 350                         rdma_destroy_ah(dev->sm_ah[p],
 351                                         RDMA_DESTROY_AH_SLEEPABLE);
 352         }
 353 }

/* [<][>][^][v][top][bottom][index][help] */