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 void update_sm_ah(struct mthca_dev *dev, 53 u8 port_num, u16 lid, u8 sl) 54 { 55 struct ib_ah *new_ah; 56 struct ib_ah_attr ah_attr; 57 unsigned long flags; 58 59 if (!dev->send_agent[port_num - 1][0]) 60 return; 61 62 memset(&ah_attr, 0, sizeof ah_attr); 63 ah_attr.dlid = lid; 64 ah_attr.sl = sl; 65 ah_attr.port_num = port_num; 66 67 new_ah = ib_create_ah(dev->send_agent[port_num - 1][0]->qp->pd, 68 &ah_attr); 69 if (IS_ERR(new_ah)) 70 return; 71 72 spin_lock_irqsave(&dev->sm_lock, flags); 73 if (dev->sm_ah[port_num - 1]) 74 ib_destroy_ah(dev->sm_ah[port_num - 1]); 75 dev->sm_ah[port_num - 1] = new_ah; 76 spin_unlock_irqrestore(&dev->sm_lock, flags); 77 } 78 79 /* 80 * Snoop SM MADs for port info and P_Key table sets, so we can 81 * synthesize LID change and P_Key change events. 82 */ 83 static void smp_snoop(struct ib_device *ibdev, 84 u8 port_num, 85 struct ib_mad *mad) 86 { 87 struct ib_event event; 88 89 if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 90 mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && 91 mad->mad_hdr.method == IB_MGMT_METHOD_SET) { 92 if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO) { 93 update_sm_ah(to_mdev(ibdev), port_num, 94 be16_to_cpup((__be16 *) (mad->data + 58)), 95 (*(u8 *) (mad->data + 76)) & 0xf); 96 97 event.device = ibdev; 98 event.event = IB_EVENT_LID_CHANGE; 99 event.element.port_num = port_num; 100 ib_dispatch_event(&event); 101 } 102 103 if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PKEY_TABLE) { 104 event.device = ibdev; 105 event.event = IB_EVENT_PKEY_CHANGE; 106 event.element.port_num = port_num; 107 ib_dispatch_event(&event); 108 } 109 } 110 } 111 112 static void forward_trap(struct mthca_dev *dev, 113 u8 port_num, 114 struct ib_mad *mad) 115 { 116 int qpn = mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED; 117 struct ib_mad_send_buf *send_buf; 118 struct ib_mad_agent *agent = dev->send_agent[port_num - 1][qpn]; 119 int ret; 120 unsigned long flags; 121 122 if (agent) { 123 send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR, 124 IB_MGMT_MAD_DATA, GFP_ATOMIC); 125 /* 126 * We rely here on the fact that MLX QPs don't use the 127 * address handle after the send is posted (this is 128 * wrong following the IB spec strictly, but we know 129 * it's OK for our devices). 130 */ 131 spin_lock_irqsave(&dev->sm_lock, flags); 132 memcpy(send_buf->mad, mad, sizeof *mad); 133 if ((send_buf->ah = dev->sm_ah[port_num - 1])) 134 ret = ib_post_send_mad(send_buf, NULL); 135 else 136 ret = -EINVAL; 137 spin_unlock_irqrestore(&dev->sm_lock, flags); 138 139 if (ret) 140 ib_free_send_mad(send_buf); 141 } 142 } 143 144 int mthca_process_mad(struct ib_device *ibdev, 145 int mad_flags, 146 u8 port_num, 147 struct ib_wc *in_wc, 148 struct ib_grh *in_grh, 149 struct ib_mad *in_mad, 150 struct ib_mad *out_mad) 151 { 152 int err; 153 u8 status; 154 u16 slid = in_wc ? in_wc->slid : be16_to_cpu(IB_LID_PERMISSIVE); 155 156 /* Forward locally generated traps to the SM */ 157 if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP && 158 slid == 0) { 159 forward_trap(to_mdev(ibdev), port_num, in_mad); 160 return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 161 } 162 163 /* 164 * Only handle SM gets, sets and trap represses for SM class 165 * 166 * Only handle PMA and Mellanox vendor-specific class gets and 167 * sets for other classes. 168 */ 169 if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 170 in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { 171 if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && 172 in_mad->mad_hdr.method != IB_MGMT_METHOD_SET && 173 in_mad->mad_hdr.method != IB_MGMT_METHOD_TRAP_REPRESS) 174 return IB_MAD_RESULT_SUCCESS; 175 176 /* 177 * Don't process SMInfo queries or vendor-specific 178 * MADs -- the SMA can't handle them. 179 */ 180 if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO || 181 ((in_mad->mad_hdr.attr_id & IB_SMP_ATTR_VENDOR_MASK) == 182 IB_SMP_ATTR_VENDOR_MASK)) 183 return IB_MAD_RESULT_SUCCESS; 184 } else if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT || 185 in_mad->mad_hdr.mgmt_class == MTHCA_VENDOR_CLASS1 || 186 in_mad->mad_hdr.mgmt_class == MTHCA_VENDOR_CLASS2) { 187 if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && 188 in_mad->mad_hdr.method != IB_MGMT_METHOD_SET) 189 return IB_MAD_RESULT_SUCCESS; 190 } else 191 return IB_MAD_RESULT_SUCCESS; 192 193 err = mthca_MAD_IFC(to_mdev(ibdev), 194 mad_flags & IB_MAD_IGNORE_MKEY, 195 mad_flags & IB_MAD_IGNORE_BKEY, 196 port_num, in_wc, in_grh, in_mad, out_mad, 197 &status); 198 if (err) { 199 mthca_err(to_mdev(ibdev), "MAD_IFC failed\n"); 200 return IB_MAD_RESULT_FAILURE; 201 } 202 if (status == MTHCA_CMD_STAT_BAD_PKT) 203 return IB_MAD_RESULT_SUCCESS; 204 if (status) { 205 mthca_err(to_mdev(ibdev), "MAD_IFC returned status %02x\n", 206 status); 207 return IB_MAD_RESULT_FAILURE; 208 } 209 210 if (!out_mad->mad_hdr.status) 211 smp_snoop(ibdev, port_num, in_mad); 212 213 /* set return bit in status of directed route responses */ 214 if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) 215 out_mad->mad_hdr.status |= cpu_to_be16(1 << 15); 216 217 if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) 218 /* no response for trap repress */ 219 return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 220 221 return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; 222 } 223 224 static void send_handler(struct ib_mad_agent *agent, 225 struct ib_mad_send_wc *mad_send_wc) 226 { 227 ib_free_send_mad(mad_send_wc->send_buf); 228 } 229 230 int mthca_create_agents(struct mthca_dev *dev) 231 { 232 struct ib_mad_agent *agent; 233 int p, q; 234 235 spin_lock_init(&dev->sm_lock); 236 237 for (p = 0; p < dev->limits.num_ports; ++p) 238 for (q = 0; q <= 1; ++q) { 239 agent = ib_register_mad_agent(&dev->ib_dev, p + 1, 240 q ? IB_QPT_GSI : IB_QPT_SMI, 241 NULL, 0, send_handler, 242 NULL, NULL); 243 if (IS_ERR(agent)) 244 goto err; 245 dev->send_agent[p][q] = agent; 246 } 247 248 return 0; 249 250 err: 251 for (p = 0; p < dev->limits.num_ports; ++p) 252 for (q = 0; q <= 1; ++q) 253 if (dev->send_agent[p][q]) 254 ib_unregister_mad_agent(dev->send_agent[p][q]); 255 256 return PTR_ERR(agent); 257 } 258 259 void mthca_free_agents(struct mthca_dev *dev) 260 { 261 struct ib_mad_agent *agent; 262 int p, q; 263 264 for (p = 0; p < dev->limits.num_ports; ++p) { 265 for (q = 0; q <= 1; ++q) { 266 agent = dev->send_agent[p][q]; 267 dev->send_agent[p][q] = NULL; 268 ib_unregister_mad_agent(agent); 269 } 270 271 if (dev->sm_ah[p]) 272 ib_destroy_ah(dev->sm_ah[p]); 273 } 274 } 275