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 * $Id: mthca_mad.c 1349 2004-12-16 21:09:43Z roland $ 35 */ 36 37 #include <linux/string.h> 38 #include <linux/slab.h> 39 40 #include <rdma/ib_verbs.h> 41 #include <rdma/ib_mad.h> 42 #include <rdma/ib_smi.h> 43 44 #include "mthca_dev.h" 45 #include "mthca_cmd.h" 46 47 enum { 48 MTHCA_VENDOR_CLASS1 = 0x9, 49 MTHCA_VENDOR_CLASS2 = 0xa 50 }; 51 52 static int mthca_update_rate(struct mthca_dev *dev, u8 port_num) 53 { 54 struct ib_port_attr *tprops = NULL; 55 int ret; 56 57 tprops = kmalloc(sizeof *tprops, GFP_KERNEL); 58 if (!tprops) 59 return -ENOMEM; 60 61 ret = ib_query_port(&dev->ib_dev, port_num, tprops); 62 if (ret) { 63 printk(KERN_WARNING "ib_query_port failed (%d) for %s port %d\n", 64 ret, dev->ib_dev.name, port_num); 65 goto out; 66 } 67 68 dev->rate[port_num - 1] = tprops->active_speed * 69 ib_width_enum_to_int(tprops->active_width); 70 71 out: 72 kfree(tprops); 73 return ret; 74 } 75 76 static void update_sm_ah(struct mthca_dev *dev, 77 u8 port_num, u16 lid, u8 sl) 78 { 79 struct ib_ah *new_ah; 80 struct ib_ah_attr ah_attr; 81 unsigned long flags; 82 83 if (!dev->send_agent[port_num - 1][0]) 84 return; 85 86 memset(&ah_attr, 0, sizeof ah_attr); 87 ah_attr.dlid = lid; 88 ah_attr.sl = sl; 89 ah_attr.port_num = port_num; 90 91 new_ah = ib_create_ah(dev->send_agent[port_num - 1][0]->qp->pd, 92 &ah_attr); 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 ib_destroy_ah(dev->sm_ah[port_num - 1]); 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 struct ib_mad *mad) 110 { 111 struct ib_event event; 112 113 if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 114 mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && 115 mad->mad_hdr.method == IB_MGMT_METHOD_SET) { 116 if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO) { 117 mthca_update_rate(to_mdev(ibdev), port_num); 118 update_sm_ah(to_mdev(ibdev), port_num, 119 be16_to_cpup((__be16 *) (mad->data + 58)), 120 (*(u8 *) (mad->data + 76)) & 0xf); 121 122 event.device = ibdev; 123 event.event = IB_EVENT_LID_CHANGE; 124 event.element.port_num = port_num; 125 ib_dispatch_event(&event); 126 } 127 128 if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PKEY_TABLE) { 129 event.device = ibdev; 130 event.event = IB_EVENT_PKEY_CHANGE; 131 event.element.port_num = port_num; 132 ib_dispatch_event(&event); 133 } 134 } 135 } 136 137 static void node_desc_override(struct ib_device *dev, 138 struct ib_mad *mad) 139 { 140 if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 141 mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && 142 mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP && 143 mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) { 144 mutex_lock(&to_mdev(dev)->cap_mask_mutex); 145 memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 64); 146 mutex_unlock(&to_mdev(dev)->cap_mask_mutex); 147 } 148 } 149 150 static void forward_trap(struct mthca_dev *dev, 151 u8 port_num, 152 struct ib_mad *mad) 153 { 154 int qpn = mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED; 155 struct ib_mad_send_buf *send_buf; 156 struct ib_mad_agent *agent = dev->send_agent[port_num - 1][qpn]; 157 int ret; 158 unsigned long flags; 159 160 if (agent) { 161 send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR, 162 IB_MGMT_MAD_DATA, GFP_ATOMIC); 163 /* 164 * We rely here on the fact that MLX QPs don't use the 165 * address handle after the send is posted (this is 166 * wrong following the IB spec strictly, but we know 167 * it's OK for our devices). 168 */ 169 spin_lock_irqsave(&dev->sm_lock, flags); 170 memcpy(send_buf->mad, mad, sizeof *mad); 171 if ((send_buf->ah = dev->sm_ah[port_num - 1])) 172 ret = ib_post_send_mad(send_buf, NULL); 173 else 174 ret = -EINVAL; 175 spin_unlock_irqrestore(&dev->sm_lock, flags); 176 177 if (ret) 178 ib_free_send_mad(send_buf); 179 } 180 } 181 182 int mthca_process_mad(struct ib_device *ibdev, 183 int mad_flags, 184 u8 port_num, 185 struct ib_wc *in_wc, 186 struct ib_grh *in_grh, 187 struct ib_mad *in_mad, 188 struct ib_mad *out_mad) 189 { 190 int err; 191 u8 status; 192 u16 slid = in_wc ? in_wc->slid : be16_to_cpu(IB_LID_PERMISSIVE); 193 194 /* Forward locally generated traps to the SM */ 195 if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP && 196 slid == 0) { 197 forward_trap(to_mdev(ibdev), port_num, in_mad); 198 return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 199 } 200 201 /* 202 * Only handle SM gets, sets and trap represses for SM class 203 * 204 * Only handle PMA and Mellanox vendor-specific class gets and 205 * sets for other classes. 206 */ 207 if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 208 in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { 209 if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && 210 in_mad->mad_hdr.method != IB_MGMT_METHOD_SET && 211 in_mad->mad_hdr.method != IB_MGMT_METHOD_TRAP_REPRESS) 212 return IB_MAD_RESULT_SUCCESS; 213 214 /* 215 * Don't process SMInfo queries or vendor-specific 216 * MADs -- the SMA can't handle them. 217 */ 218 if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO || 219 ((in_mad->mad_hdr.attr_id & IB_SMP_ATTR_VENDOR_MASK) == 220 IB_SMP_ATTR_VENDOR_MASK)) 221 return IB_MAD_RESULT_SUCCESS; 222 } else if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT || 223 in_mad->mad_hdr.mgmt_class == MTHCA_VENDOR_CLASS1 || 224 in_mad->mad_hdr.mgmt_class == MTHCA_VENDOR_CLASS2) { 225 if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && 226 in_mad->mad_hdr.method != IB_MGMT_METHOD_SET) 227 return IB_MAD_RESULT_SUCCESS; 228 } else 229 return IB_MAD_RESULT_SUCCESS; 230 231 err = mthca_MAD_IFC(to_mdev(ibdev), 232 mad_flags & IB_MAD_IGNORE_MKEY, 233 mad_flags & IB_MAD_IGNORE_BKEY, 234 port_num, in_wc, in_grh, in_mad, out_mad, 235 &status); 236 if (err) { 237 mthca_err(to_mdev(ibdev), "MAD_IFC failed\n"); 238 return IB_MAD_RESULT_FAILURE; 239 } 240 if (status == MTHCA_CMD_STAT_BAD_PKT) 241 return IB_MAD_RESULT_SUCCESS; 242 if (status) { 243 mthca_err(to_mdev(ibdev), "MAD_IFC returned status %02x\n", 244 status); 245 return IB_MAD_RESULT_FAILURE; 246 } 247 248 if (!out_mad->mad_hdr.status) { 249 smp_snoop(ibdev, port_num, in_mad); 250 node_desc_override(ibdev, out_mad); 251 } 252 253 /* set return bit in status of directed route responses */ 254 if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) 255 out_mad->mad_hdr.status |= cpu_to_be16(1 << 15); 256 257 if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) 258 /* no response for trap repress */ 259 return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 260 261 return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; 262 } 263 264 static void send_handler(struct ib_mad_agent *agent, 265 struct ib_mad_send_wc *mad_send_wc) 266 { 267 ib_free_send_mad(mad_send_wc->send_buf); 268 } 269 270 int mthca_create_agents(struct mthca_dev *dev) 271 { 272 struct ib_mad_agent *agent; 273 int p, q; 274 int ret; 275 276 spin_lock_init(&dev->sm_lock); 277 278 for (p = 0; p < dev->limits.num_ports; ++p) 279 for (q = 0; q <= 1; ++q) { 280 agent = ib_register_mad_agent(&dev->ib_dev, p + 1, 281 q ? IB_QPT_GSI : IB_QPT_SMI, 282 NULL, 0, send_handler, 283 NULL, NULL); 284 if (IS_ERR(agent)) { 285 ret = PTR_ERR(agent); 286 goto err; 287 } 288 dev->send_agent[p][q] = agent; 289 } 290 291 292 for (p = 1; p <= dev->limits.num_ports; ++p) { 293 ret = mthca_update_rate(dev, p); 294 if (ret) { 295 mthca_err(dev, "Failed to obtain port %d rate." 296 " aborting.\n", p); 297 goto err; 298 } 299 } 300 301 return 0; 302 303 err: 304 for (p = 0; p < dev->limits.num_ports; ++p) 305 for (q = 0; q <= 1; ++q) 306 if (dev->send_agent[p][q]) 307 ib_unregister_mad_agent(dev->send_agent[p][q]); 308 309 return ret; 310 } 311 312 void __devexit mthca_free_agents(struct mthca_dev *dev) 313 { 314 struct ib_mad_agent *agent; 315 int p, q; 316 317 for (p = 0; p < dev->limits.num_ports; ++p) { 318 for (q = 0; q <= 1; ++q) { 319 agent = dev->send_agent[p][q]; 320 dev->send_agent[p][q] = NULL; 321 ib_unregister_mad_agent(agent); 322 } 323 324 if (dev->sm_ah[p]) 325 ib_destroy_ah(dev->sm_ah[p]); 326 } 327 } 328