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 struct ib_port_info *pinfo = 118 (struct ib_port_info *) ((struct ib_smp *) mad)->data; 119 120 mthca_update_rate(to_mdev(ibdev), port_num); 121 update_sm_ah(to_mdev(ibdev), port_num, 122 be16_to_cpu(pinfo->sm_lid), 123 pinfo->neighbormtu_mastersmsl & 0xf); 124 125 event.device = ibdev; 126 event.element.port_num = port_num; 127 128 if(pinfo->clientrereg_resv_subnetto & 0x80) 129 event.event = IB_EVENT_CLIENT_REREGISTER; 130 else 131 event.event = IB_EVENT_LID_CHANGE; 132 133 ib_dispatch_event(&event); 134 } 135 136 if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PKEY_TABLE) { 137 event.device = ibdev; 138 event.event = IB_EVENT_PKEY_CHANGE; 139 event.element.port_num = port_num; 140 ib_dispatch_event(&event); 141 } 142 } 143 } 144 145 static void node_desc_override(struct ib_device *dev, 146 struct ib_mad *mad) 147 { 148 if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 149 mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && 150 mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP && 151 mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) { 152 mutex_lock(&to_mdev(dev)->cap_mask_mutex); 153 memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 64); 154 mutex_unlock(&to_mdev(dev)->cap_mask_mutex); 155 } 156 } 157 158 static void forward_trap(struct mthca_dev *dev, 159 u8 port_num, 160 struct ib_mad *mad) 161 { 162 int qpn = mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED; 163 struct ib_mad_send_buf *send_buf; 164 struct ib_mad_agent *agent = dev->send_agent[port_num - 1][qpn]; 165 int ret; 166 unsigned long flags; 167 168 if (agent) { 169 send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR, 170 IB_MGMT_MAD_DATA, GFP_ATOMIC); 171 /* 172 * We rely here on the fact that MLX QPs don't use the 173 * address handle after the send is posted (this is 174 * wrong following the IB spec strictly, but we know 175 * it's OK for our devices). 176 */ 177 spin_lock_irqsave(&dev->sm_lock, flags); 178 memcpy(send_buf->mad, mad, sizeof *mad); 179 if ((send_buf->ah = dev->sm_ah[port_num - 1])) 180 ret = ib_post_send_mad(send_buf, NULL); 181 else 182 ret = -EINVAL; 183 spin_unlock_irqrestore(&dev->sm_lock, flags); 184 185 if (ret) 186 ib_free_send_mad(send_buf); 187 } 188 } 189 190 int mthca_process_mad(struct ib_device *ibdev, 191 int mad_flags, 192 u8 port_num, 193 struct ib_wc *in_wc, 194 struct ib_grh *in_grh, 195 struct ib_mad *in_mad, 196 struct ib_mad *out_mad) 197 { 198 int err; 199 u8 status; 200 u16 slid = in_wc ? in_wc->slid : be16_to_cpu(IB_LID_PERMISSIVE); 201 202 /* Forward locally generated traps to the SM */ 203 if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP && 204 slid == 0) { 205 forward_trap(to_mdev(ibdev), port_num, in_mad); 206 return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 207 } 208 209 /* 210 * Only handle SM gets, sets and trap represses for SM class 211 * 212 * Only handle PMA and Mellanox vendor-specific class gets and 213 * sets for other classes. 214 */ 215 if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 216 in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { 217 if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && 218 in_mad->mad_hdr.method != IB_MGMT_METHOD_SET && 219 in_mad->mad_hdr.method != IB_MGMT_METHOD_TRAP_REPRESS) 220 return IB_MAD_RESULT_SUCCESS; 221 222 /* 223 * Don't process SMInfo queries or vendor-specific 224 * MADs -- the SMA can't handle them. 225 */ 226 if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO || 227 ((in_mad->mad_hdr.attr_id & IB_SMP_ATTR_VENDOR_MASK) == 228 IB_SMP_ATTR_VENDOR_MASK)) 229 return IB_MAD_RESULT_SUCCESS; 230 } else if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT || 231 in_mad->mad_hdr.mgmt_class == MTHCA_VENDOR_CLASS1 || 232 in_mad->mad_hdr.mgmt_class == MTHCA_VENDOR_CLASS2) { 233 if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && 234 in_mad->mad_hdr.method != IB_MGMT_METHOD_SET) 235 return IB_MAD_RESULT_SUCCESS; 236 } else 237 return IB_MAD_RESULT_SUCCESS; 238 239 err = mthca_MAD_IFC(to_mdev(ibdev), 240 mad_flags & IB_MAD_IGNORE_MKEY, 241 mad_flags & IB_MAD_IGNORE_BKEY, 242 port_num, in_wc, in_grh, in_mad, out_mad, 243 &status); 244 if (err) { 245 mthca_err(to_mdev(ibdev), "MAD_IFC failed\n"); 246 return IB_MAD_RESULT_FAILURE; 247 } 248 if (status == MTHCA_CMD_STAT_BAD_PKT) 249 return IB_MAD_RESULT_SUCCESS; 250 if (status) { 251 mthca_err(to_mdev(ibdev), "MAD_IFC returned status %02x\n", 252 status); 253 return IB_MAD_RESULT_FAILURE; 254 } 255 256 if (!out_mad->mad_hdr.status) { 257 smp_snoop(ibdev, port_num, in_mad); 258 node_desc_override(ibdev, out_mad); 259 } 260 261 /* set return bit in status of directed route responses */ 262 if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) 263 out_mad->mad_hdr.status |= cpu_to_be16(1 << 15); 264 265 if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) 266 /* no response for trap repress */ 267 return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 268 269 return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; 270 } 271 272 static void send_handler(struct ib_mad_agent *agent, 273 struct ib_mad_send_wc *mad_send_wc) 274 { 275 ib_free_send_mad(mad_send_wc->send_buf); 276 } 277 278 int mthca_create_agents(struct mthca_dev *dev) 279 { 280 struct ib_mad_agent *agent; 281 int p, q; 282 int ret; 283 284 spin_lock_init(&dev->sm_lock); 285 286 for (p = 0; p < dev->limits.num_ports; ++p) 287 for (q = 0; q <= 1; ++q) { 288 agent = ib_register_mad_agent(&dev->ib_dev, p + 1, 289 q ? IB_QPT_GSI : IB_QPT_SMI, 290 NULL, 0, send_handler, 291 NULL, NULL); 292 if (IS_ERR(agent)) { 293 ret = PTR_ERR(agent); 294 goto err; 295 } 296 dev->send_agent[p][q] = agent; 297 } 298 299 300 for (p = 1; p <= dev->limits.num_ports; ++p) { 301 ret = mthca_update_rate(dev, p); 302 if (ret) { 303 mthca_err(dev, "Failed to obtain port %d rate." 304 " aborting.\n", p); 305 goto err; 306 } 307 } 308 309 return 0; 310 311 err: 312 for (p = 0; p < dev->limits.num_ports; ++p) 313 for (q = 0; q <= 1; ++q) 314 if (dev->send_agent[p][q]) 315 ib_unregister_mad_agent(dev->send_agent[p][q]); 316 317 return ret; 318 } 319 320 void mthca_free_agents(struct mthca_dev *dev) 321 { 322 struct ib_mad_agent *agent; 323 int p, q; 324 325 for (p = 0; p < dev->limits.num_ports; ++p) { 326 for (q = 0; q <= 1; ++q) { 327 agent = dev->send_agent[p][q]; 328 dev->send_agent[p][q] = NULL; 329 ib_unregister_mad_agent(agent); 330 } 331 332 if (dev->sm_ah[p]) 333 ib_destroy_ah(dev->sm_ah[p]); 334 } 335 } 336