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.
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:
12 * Redistribution and use in source and binary forms, with or
13 * without modification, are permitted provided that the following
16 * - Redistributions of source code must retain the above
17 * copyright notice, this list of conditions and the following
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.
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
41 #include "mthca_dev.h"
42 #if defined(EVENT_TRACING)
46 #include "mthca_mad.tmh"
48 #include "mthca_cmd.h"
51 MTHCA_VENDOR_CLASS1 = 0x9,
52 MTHCA_VENDOR_CLASS2 = 0xa
55 struct mthca_trap_mad {
56 struct scatterlist sg;
59 static void update_sm_ah(struct mthca_dev *dev,
60 u8 port_num, u16 lid, u8 sl)
63 struct ib_ah_attr ah_attr;
66 if (!dev->send_agent[port_num - 1][0])
69 RtlZeroMemory(&ah_attr, sizeof ah_attr);
72 ah_attr.port_num = port_num;
74 new_ah = ibv_create_ah(dev->send_agent[port_num - 1][0]->qp->pd,
75 &ah_attr, NULL, NULL);
79 spin_lock_irqsave(&dev->sm_lock, &lh);
80 if (dev->sm_ah[port_num - 1]) {
81 ibv_destroy_ah(dev->sm_ah[port_num - 1]);
83 dev->sm_ah[port_num - 1] = new_ah;
84 spin_unlock_irqrestore(&lh);
88 * Snoop SM MADs for port info and P_Key table sets, so we can
89 * synthesize LID change and P_Key change events.
91 static void smp_snoop(struct ib_device *ibdev,
95 struct ib_event event;
97 if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
98 mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) &&
99 mad->mad_hdr.method == IB_MGMT_METHOD_SET) {
100 if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO) {
101 update_sm_ah(to_mdev(ibdev), port_num,
102 cl_ntoh16(*(__be16 *) (mad->data + 58)),
103 (*(u8 *) (mad->data + 76)) & 0xf);
105 event.device = ibdev;
106 event.event = IB_EVENT_LID_CHANGE;
107 event.element.port_num = port_num;
108 ib_dispatch_event(&event);
111 if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PKEY_TABLE) {
112 event.device = ibdev;
113 event.event = IB_EVENT_PKEY_CHANGE;
114 event.element.port_num = port_num;
115 ib_dispatch_event(&event);
120 static void forward_trap(struct mthca_dev *dev,
124 int qpn = mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED;
125 struct mthca_trap_mad *tmad;
126 struct ib_sge gather_list;
127 struct _ib_send_wr wr;
128 struct ib_mad_agent *agent = dev->send_agent[port_num - 1][qpn];
132 /* fill the template */
133 wr.ds_array = (ib_local_ds_t* __ptr64)(void*)&gather_list;
135 wr.wr_type = WR_SEND;
136 wr.send_opt = IB_SEND_OPT_SIGNALED;
137 wr.dgrm.ud.remote_qp = cl_hton32(qpn);
138 wr.dgrm.ud.remote_qkey = qpn ? IB_QP1_QKEY : 0;
141 tmad = kmalloc(sizeof *tmad, GFP_KERNEL);
145 alloc_dma_zmem(dev, sizeof *mad, &tmad->sg);
146 if (!tmad->sg.page) {
151 memcpy(tmad->sg.page, mad, sizeof *mad);
153 wr.dgrm.ud.rsvd = (void* __ptr64)&((struct ib_mad *)tmad->sg.page)->mad_hdr;
154 wr.wr_id = (u64)(ULONG_PTR)tmad;
155 gather_list.addr = tmad->sg.dma_address;
156 gather_list.length = tmad->sg.length;
157 gather_list.lkey = to_mpd(agent->qp->pd)->ntmr.ibmr.lkey;
160 * We rely here on the fact that MLX QPs don't use the
161 * address handle after the send is posted (this is
162 * wrong following the IB spec strictly, but we know
163 * it's OK for our devices).
165 spin_lock_irqsave(&dev->sm_lock, &lh);
166 wr.dgrm.ud.h_av = (ib_av_handle_t)dev->sm_ah[port_num - 1];
167 if (wr.dgrm.ud.h_av) {
168 HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_MAD ,(" ib_post_send_mad not ported \n" ));
173 spin_unlock_irqrestore(&lh);
176 free_dma_mem_map(dev, &tmad->sg, PCI_DMA_BIDIRECTIONAL );
182 int mthca_process_mad(struct ib_device *ibdev,
185 struct _ib_wc *in_wc,
186 struct _ib_grh *in_grh,
187 struct ib_mad *in_mad,
188 struct ib_mad *out_mad)
192 u16 slid = in_wc ? in_wc->recv.ud.remote_lid : cl_ntoh16(IB_LID_PERMISSIVE);
194 HCA_PRINT( TRACE_LEVEL_VERBOSE ,HCA_DBG_MAD ,("in: Class %02x, Method %02x, AttrId %x, AttrMod %x, ClSpec %x, Tid %I64x\n",
195 (u32)in_mad->mad_hdr.mgmt_class, (u32)in_mad->mad_hdr.method,
196 (u32)in_mad->mad_hdr.attr_id, in_mad->mad_hdr.attr_mod,
197 (u32)in_mad->mad_hdr.class_specific, in_mad->mad_hdr.tid ));
199 /* Forward locally generated traps to the SM */
200 if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP &&
202 forward_trap(to_mdev(ibdev), port_num, in_mad);
203 HCA_PRINT( TRACE_LEVEL_VERBOSE ,HCA_DBG_MAD ,("Not sent, but locally forwarded\n"));
204 return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
208 * Only handle SM gets, sets and trap represses for SM class
210 * Only handle PMA and Mellanox vendor-specific class gets and
211 * sets for other classes.
213 if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
214 in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {
216 if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET &&
217 in_mad->mad_hdr.method != IB_MGMT_METHOD_SET &&
218 in_mad->mad_hdr.method != IB_MGMT_METHOD_TRAP_REPRESS) {
219 HCA_PRINT( TRACE_LEVEL_VERBOSE,HCA_DBG_MAD,(" Skip some methods. Nothing done !\n"));
220 return IB_MAD_RESULT_SUCCESS;
224 * Don't process SMInfo queries or vendor-specific
225 * MADs -- the SMA can't handle them.
227 if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO ||
228 ((in_mad->mad_hdr.attr_id & IB_SMP_ATTR_VENDOR_MASK) ==
229 IB_SMP_ATTR_VENDOR_MASK)) {
230 HCA_PRINT( TRACE_LEVEL_VERBOSE ,HCA_DBG_MAD ,("Skip SMInfo queries or vendor-specific MADs. Nothing done !\n"));
231 return IB_MAD_RESULT_SUCCESS;
235 if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT ||
236 in_mad->mad_hdr.mgmt_class == MTHCA_VENDOR_CLASS1 ||
237 in_mad->mad_hdr.mgmt_class == MTHCA_VENDOR_CLASS2) {
239 if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET &&
240 in_mad->mad_hdr.method != IB_MGMT_METHOD_SET) {
241 HCA_PRINT( TRACE_LEVEL_VERBOSE ,HCA_DBG_MAD ,("Skip some management methods. Nothing done !\n"));
242 return IB_MAD_RESULT_SUCCESS;
246 HCA_PRINT( TRACE_LEVEL_VERBOSE ,HCA_DBG_MAD ,("Skip IB_MGMT_CLASS_PERF_MGMT et al. Nothing done !\n"));
247 return IB_MAD_RESULT_SUCCESS;
252 err = mthca_MAD_IFC(to_mdev(ibdev),
253 mad_flags & IB_MAD_IGNORE_MKEY,
254 mad_flags & IB_MAD_IGNORE_BKEY,
255 port_num, in_wc, in_grh, in_mad, out_mad,
258 HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MAD ,("MAD_IFC failed\n"));
259 return IB_MAD_RESULT_FAILURE;
261 if (status == MTHCA_CMD_STAT_BAD_PKT)
262 return IB_MAD_RESULT_SUCCESS;
264 HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MAD ,("MAD_IFC returned status %02x\n", status));
265 return IB_MAD_RESULT_FAILURE;
268 if (!out_mad->mad_hdr.status)
269 smp_snoop(ibdev, port_num, in_mad);
271 HCA_PRINT( TRACE_LEVEL_VERBOSE ,HCA_DBG_MAD,("out: Class %02x, Method %02x, AttrId %x, AttrMod %x, ClSpec %x, Tid %I64x, Status %x\n",
272 (u32)out_mad->mad_hdr.mgmt_class, (u32)out_mad->mad_hdr.method,
273 (u32)out_mad->mad_hdr.attr_id, out_mad->mad_hdr.attr_mod,
274 (u32)out_mad->mad_hdr.class_specific, out_mad->mad_hdr.tid,
275 (u32)out_mad->mad_hdr.status ));
277 if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) {
278 /* no response for trap repress */
279 return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
282 return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
285 static void send_handler(struct ib_mad_agent *agent,
286 struct ib_mad_send_wc *mad_send_wc)
288 struct mthca_trap_mad *tmad =
289 (void *) (ULONG_PTR) mad_send_wc->wr_id;
291 free_dma_mem_map(agent->device->mdev, &tmad->sg, PCI_DMA_BIDIRECTIONAL );