[MTHCA\MT23108\IBAL] change to support TRAP and TRAP_REPRESS
[mirror/winof/.git] / hw / mthca / kernel / mthca_mad.c
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$
35  */
36
37 #include <ib_verbs.h>
38 #include <ib_mad.h>
39 #include <ib_smi.h>
40
41 #include "mthca_dev.h"
42 #if defined(EVENT_TRACING)
43 #ifdef offsetof
44 #undef offsetof
45 #endif
46 #include "mthca_mad.tmh"
47 #endif
48 #include "mthca_cmd.h"
49
50 enum {
51         MTHCA_VENDOR_CLASS1 = 0x9,
52         MTHCA_VENDOR_CLASS2 = 0xa
53 };
54
55 struct mthca_trap_mad {
56         struct scatterlist sg;
57 };
58
59 static void update_sm_ah(struct mthca_dev *dev,
60                          u8 port_num, u16 lid, u8 sl)
61 {
62         struct ib_ah *new_ah;
63         struct ib_ah_attr ah_attr;
64         SPIN_LOCK_PREP(lh);
65
66         if (!dev->send_agent[port_num - 1][0])
67                 return;
68
69         RtlZeroMemory(&ah_attr, sizeof ah_attr);
70         ah_attr.dlid     = lid;
71         ah_attr.sl       = sl;
72         ah_attr.port_num = port_num;
73
74         new_ah = ibv_create_ah(dev->send_agent[port_num - 1][0]->qp->pd,
75                               &ah_attr, NULL, NULL);
76         if (IS_ERR(new_ah))
77                 return;
78
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]);
82         }
83         dev->sm_ah[port_num - 1] = new_ah;
84         spin_unlock_irqrestore(&lh);
85 }
86
87 /*
88  * Snoop SM MADs for port info and P_Key table sets, so we can
89  * synthesize LID change and P_Key change events.
90  */
91 static void smp_snoop(struct ib_device *ibdev,
92                       u8 port_num,
93                       struct ib_mad *mad)
94 {
95         struct ib_event event;
96
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);
104
105                         event.device           = ibdev;
106                         event.event            = IB_EVENT_LID_CHANGE;
107                         event.element.port_num = port_num;
108                         ib_dispatch_event(&event);
109                 }
110
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);
116                 }
117         }
118 }
119
120 static void forward_trap(struct mthca_dev *dev,
121                          u8 port_num,
122                          struct ib_mad *mad)
123 {
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];
129         int ret;
130         SPIN_LOCK_PREP(lh);
131
132         /* fill the template */
133         wr.ds_array = (ib_local_ds_t* __ptr64)(void*)&gather_list;
134         wr.num_ds = 1;
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;
139         
140         if (agent) {
141                 tmad = kmalloc(sizeof *tmad, GFP_KERNEL);
142                 if (!tmad)
143                         return;
144
145                 alloc_dma_zmem(dev, sizeof *mad, &tmad->sg);
146                 if (!tmad->sg.page) {
147                         kfree(tmad);
148                         return;
149                 }
150
151                 memcpy(tmad->sg.page, mad, sizeof *mad);
152
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;
158
159                 /*
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).
164                  */
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" ));
169                                 ret = -EINVAL;
170                 }
171                 else
172                         ret = -EINVAL;
173                 spin_unlock_irqrestore(&lh);
174
175                 if (ret) {
176                         free_dma_mem_map(dev, &tmad->sg, PCI_DMA_BIDIRECTIONAL );
177                         kfree(tmad);
178                 }
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->recv.ud.remote_lid : cl_ntoh16(IB_LID_PERMISSIVE);
193
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 ));
198
199         /* Forward locally generated traps to the SM */
200         if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP &&
201             slid == 0) {
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;
205         }
206
207         /*
208          * Only handle SM gets, sets and trap represses for SM class
209          *
210          * Only handle PMA and Mellanox vendor-specific class gets and
211          * sets for other classes.
212          */
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) {
215
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;
221                 }
222
223                 /*
224                  * Don't process SMInfo queries or vendor-specific
225                  * MADs -- the SMA can't handle them.
226                  */
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;
232                 }
233         } 
234         else {
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) {
238
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;
243                         }
244                 } 
245                 else {
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;
248                 }       
249         }
250
251         // send MAD
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,
256                             &status);
257         if (err) {
258                 HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MAD ,("MAD_IFC failed\n"));
259                 return IB_MAD_RESULT_FAILURE;
260         }
261         if (status == MTHCA_CMD_STAT_BAD_PKT)
262                 return IB_MAD_RESULT_SUCCESS;
263         if (status) {
264                 HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MAD ,("MAD_IFC returned status %02x\n", status));
265                 return IB_MAD_RESULT_FAILURE;
266         }
267
268         if (!out_mad->mad_hdr.status)
269                 smp_snoop(ibdev, port_num, in_mad);
270
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 ));
276
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;
280         }
281
282         return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
283 }
284
285 static void send_handler(struct ib_mad_agent *agent,
286                          struct ib_mad_send_wc *mad_send_wc)
287 {
288         struct mthca_trap_mad *tmad =
289                 (void *) (ULONG_PTR) mad_send_wc->wr_id;
290
291         free_dma_mem_map(agent->device->mdev, &tmad->sg, PCI_DMA_BIDIRECTIONAL );
292         kfree(tmad);
293 }