mlx4/mthca: define common vendor mgmt class
[mirror/winof/.git] / hw / mlx4 / kernel / bus / ib / mad.c
1 /*\r
2  * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.\r
3  *\r
4  * This software is available to you under a choice of one of two\r
5  * licenses.  You may choose to be licensed under the terms of the GNU\r
6  * General Public License (GPL) Version 2, available from the file\r
7  * COPYING in the main directory of this source tree, or the\r
8  * OpenIB.org BSD license below:\r
9  *\r
10  *     Redistribution and use in source and binary forms, with or\r
11  *     without modification, are permitted provided that the following\r
12  *     conditions are met:\r
13  *\r
14  *      - Redistributions of source code must retain the above\r
15  *        copyright notice, this list of conditions and the following\r
16  *        disclaimer.\r
17  *\r
18  *      - Redistributions in binary form must reproduce the above\r
19  *        copyright notice, this list of conditions and the following\r
20  *        disclaimer in the documentation and/or other materials\r
21  *        provided with the distribution.\r
22  *\r
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
30  * SOFTWARE.\r
31  */\r
32 \r
33 #include <mlx4_debug.h>\r
34 #include "mlx4_ib.h"\r
35 #include <ib_mad.h>\r
36 #include <ib_smi.h>\r
37 #include "cmd.h"\r
38 \r
39 #if defined(EVENT_TRACING)\r
40 #ifdef offsetof\r
41 #undef offsetof\r
42 #endif\r
43 #include "mad.tmh"\r
44 #endif\r
45 \r
46 \r
47 int mlx4_MAD_IFC(struct mlx4_ib_dev *dev, int ignore_mkey, int ignore_bkey,\r
48                  int port, ib_wc_t *in_wc, struct ib_grh *in_grh,\r
49                  void *in_mad, void *response_mad)\r
50 {\r
51         struct mlx4_cmd_mailbox *inmailbox, *outmailbox;\r
52         u8 *inbox;\r
53         int err;\r
54         u32 in_modifier = port;\r
55         u8 op_modifier = 0;\r
56 \r
57         inmailbox = mlx4_alloc_cmd_mailbox(dev->dev);\r
58         if (IS_ERR(inmailbox))\r
59                 return PTR_ERR(inmailbox);\r
60         inbox = inmailbox->buf;\r
61 \r
62         outmailbox = mlx4_alloc_cmd_mailbox(dev->dev);\r
63         if (IS_ERR(outmailbox)) {\r
64                 mlx4_free_cmd_mailbox(dev->dev, inmailbox);\r
65                 return PTR_ERR(outmailbox);\r
66         }\r
67 \r
68         memcpy(inbox, in_mad, 256);\r
69 \r
70         /*\r
71          * Key check traps can't be generated unless we have in_wc to\r
72          * tell us where to send the trap.\r
73          */\r
74         if (ignore_mkey || !in_wc)\r
75                 op_modifier |= 0x1;\r
76         if (ignore_bkey || !in_wc)\r
77                 op_modifier |= 0x2;\r
78 \r
79         if (in_wc) {\r
80                 struct {\r
81                         __be32          my_qpn;\r
82                         u32             reserved1;\r
83                         __be32          rqpn;\r
84                         u8              sl;\r
85                         u8              g_path;\r
86                         u16             reserved2[2];\r
87                         __be16          pkey;\r
88                         u32             reserved3[11];\r
89                         u8              grh[40];\r
90                 } *ext_info;\r
91 \r
92                 memset(inbox + 256, 0, 256);\r
93                 ext_info = (void*)(inbox + 256);\r
94 \r
95                 ext_info->rqpn   = in_wc->recv.ud.remote_qp;\r
96                 ext_info->sl     = in_wc->recv.ud.remote_sl << 4;\r
97                 ext_info->g_path = in_wc->recv.ud.path_bits |\r
98                         (in_wc->recv.ud.recv_opt & IB_RECV_OPT_GRH_VALID ? 0x80 : 0);\r
99                 ext_info->pkey   = cpu_to_be16(in_wc->recv.ud.pkey_index);\r
100 \r
101                 if (in_grh)\r
102                         memcpy(ext_info->grh, in_grh, 40);\r
103 \r
104                 op_modifier |= 0x4;\r
105 \r
106                 in_modifier |= be16_to_cpu(in_wc->recv.ud.remote_lid) << 16;\r
107         }\r
108 \r
109         err = mlx4_cmd_box(dev->dev, inmailbox->dma.da, outmailbox->dma.da,\r
110                            in_modifier, op_modifier,\r
111                            MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C);\r
112 \r
113         if (!err)\r
114                 memcpy(response_mad, outmailbox->buf, 256);\r
115 \r
116 //      mlx4_dbg( dev->dev, "[MLX4_BUS] mlx4_MAD_IFC : port %d, err %d \n", port, err );\r
117 \r
118         mlx4_free_cmd_mailbox(dev->dev, inmailbox);\r
119         mlx4_free_cmd_mailbox(dev->dev, outmailbox);\r
120 \r
121         return err;\r
122 }\r
123 \r
124 static void update_sm_ah(struct mlx4_ib_dev *dev, u8 port_num, u16 lid, u8 sl)\r
125 {\r
126         struct ib_ah *new_ah;\r
127         struct ib_ah_attr ah_attr;\r
128 \r
129         if (!dev->send_agent[port_num - 1][0])\r
130                 return;\r
131 \r
132         memset(&ah_attr, 0, sizeof ah_attr);\r
133         ah_attr.dlid     = lid;\r
134         ah_attr.sl       = sl;\r
135         ah_attr.port_num = port_num;\r
136 \r
137         new_ah = ib_create_ah(dev->send_agent[port_num - 1][0]->qp->pd,\r
138                               &ah_attr);\r
139         if (IS_ERR(new_ah))\r
140                 return;\r
141 \r
142         spin_lock(&dev->sm_lock);\r
143         if (dev->sm_ah[port_num - 1])\r
144                 ib_destroy_ah(dev->sm_ah[port_num - 1]);\r
145         dev->sm_ah[port_num - 1] = new_ah;\r
146         spin_unlock(&dev->sm_lock);\r
147 }\r
148 \r
149 /*\r
150  * Snoop SM MADs for port info and P_Key table sets, so we can\r
151  * synthesize LID change and P_Key change events.\r
152  */\r
153 static void smp_snoop(struct ib_device *ibdev, u8 port_num, struct ib_mad *mad)\r
154 {\r
155         struct ib_event event;\r
156 \r
157         if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||\r
158              mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) &&\r
159             mad->mad_hdr.method == IB_MGMT_METHOD_SET) {\r
160                 if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO) {\r
161                         struct ib_port_info *pinfo =\r
162                                 (struct ib_port_info *) ((struct ib_smp *) mad)->data;\r
163 \r
164                         update_sm_ah(to_mdev(ibdev), port_num,\r
165                                      be16_to_cpu(pinfo->sm_lid),\r
166                                      pinfo->neighbormtu_mastersmsl & 0xf);\r
167 \r
168                         event.device           = ibdev;\r
169                         event.element.port_num = port_num;\r
170 \r
171                         if(pinfo->clientrereg_resv_subnetto & 0x80)\r
172                                 event.event    = IB_EVENT_CLIENT_REREGISTER;\r
173                         else\r
174                                 event.event    = IB_EVENT_LID_CHANGE;\r
175 \r
176                         ib_dispatch_event(&event);\r
177                 }\r
178 \r
179                 if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PKEY_TABLE) {\r
180                         event.device           = ibdev;\r
181                         event.event            = IB_EVENT_PKEY_CHANGE;\r
182                         event.element.port_num = port_num;\r
183                         ib_dispatch_event(&event);\r
184                 }\r
185         }\r
186 }\r
187 \r
188 static void node_desc_override(struct ib_device *dev,\r
189                                struct ib_mad *mad)\r
190 {\r
191         if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||\r
192              mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) &&\r
193             mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP &&\r
194             mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) {\r
195                 spin_lock(&to_mdev(dev)->sm_lock);\r
196                 memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 64);\r
197                 spin_unlock(&to_mdev(dev)->sm_lock);\r
198         }\r
199 }\r
200 \r
201 int mlx4_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,\r
202                         ib_wc_t *in_wc, struct ib_grh *in_grh,\r
203                         struct ib_mad *in_mad, struct ib_mad *out_mad)\r
204 {\r
205         u16 slid;\r
206         int err;\r
207 \r
208         if (mlx4_is_barred(ibdev->dma_device))\r
209                 return -EFAULT;\r
210 \r
211         slid = in_wc ? be16_to_cpu(in_wc->recv.ud.remote_lid) : be16_to_cpu(XIB_LID_PERMISSIVE);\r
212 \r
213         if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP && slid == 0) {\r
214                 // we never comes here !\r
215                 ASSERT(0);\r
216                 MLX4_PRINT( TRACE_LEVEL_ERROR ,MLX4_DBG_MAD ,\r
217                         (" Received a trap from HCA, which is unexpected here !\n" ));\r
218                 // forward_trap(to_mdev(ibdev), port_num, in_mad);\r
219                 return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;\r
220         }\r
221 \r
222         if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||\r
223             in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {\r
224                 if (in_mad->mad_hdr.method   != IB_MGMT_METHOD_GET &&\r
225                     in_mad->mad_hdr.method   != IB_MGMT_METHOD_SET &&\r
226                     in_mad->mad_hdr.method   != IB_MGMT_METHOD_TRAP_REPRESS)\r
227                         return IB_MAD_RESULT_SUCCESS;\r
228 \r
229                 /*\r
230                  * Don't process SMInfo queries or vendor-specific\r
231                  * MADs -- the SMA can't handle them.\r
232                  */\r
233                 if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO ||\r
234                     ((in_mad->mad_hdr.attr_id & IB_SMP_ATTR_VENDOR_MASK) ==\r
235                      IB_SMP_ATTR_VENDOR_MASK))\r
236                         return IB_MAD_RESULT_SUCCESS;\r
237         } else if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT ||\r
238                    in_mad->mad_hdr.mgmt_class == IB_MLX_VENDOR_CLASS1   ||\r
239                    in_mad->mad_hdr.mgmt_class == IB_MLX_VENDOR_CLASS2) {\r
240                 if (in_mad->mad_hdr.method  != IB_MGMT_METHOD_GET &&\r
241                     in_mad->mad_hdr.method  != IB_MGMT_METHOD_SET)\r
242                         return IB_MAD_RESULT_SUCCESS;\r
243         } else\r
244                 return IB_MAD_RESULT_SUCCESS;\r
245 \r
246         err = mlx4_MAD_IFC(to_mdev(ibdev),\r
247                            mad_flags & IB_MAD_IGNORE_MKEY,\r
248                            mad_flags & IB_MAD_IGNORE_BKEY,\r
249                            port_num, in_wc, in_grh, in_mad, out_mad);\r
250         if (err)\r
251                 return IB_MAD_RESULT_FAILURE;\r
252 \r
253         if (!out_mad->mad_hdr.status) {\r
254                 smp_snoop(ibdev, port_num, in_mad);\r
255                 node_desc_override(ibdev, out_mad);\r
256         }\r
257 \r
258         /* set return bit in status of directed route responses */\r
259         if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)\r
260                 out_mad->mad_hdr.status |= cpu_to_be16(1 << 15);\r
261 \r
262         if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS)\r
263                 /* no response for trap repress */\r
264                 return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;\r
265 \r
266         return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;\r
267 }\r