[MTHCA\MT23108\IBAL] change to support TRAP and TRAP_REPRESS
[mirror/winof/.git] / hw / mthca / kernel / hca_smp.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  * Copyright (c) 2006 Voltaire Corporation.  All rights reserved.
4  *\r
5  * This software is available to you under the OpenIB.org BSD license\r
6  * below:\r
7  *\r
8  *     Redistribution and use in source and binary forms, with or\r
9  *     without modification, are permitted provided that the following\r
10  *     conditions are met:\r
11  *\r
12  *      - Redistributions of source code must retain the above\r
13  *        copyright notice, this list of conditions and the following\r
14  *        disclaimer.\r
15  *\r
16  *      - Redistributions in binary form must reproduce the above\r
17  *        copyright notice, this list of conditions and the following\r
18  *        disclaimer in the documentation and/or other materials\r
19  *        provided with the distribution.\r
20  *\r
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
22  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
24  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
25  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
26  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
27  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
28  * SOFTWARE.\r
29  *\r
30  * $Id$\r
31  */\r
32 \r
33 \r
34 /*\r
35  * SMP handling of IB Access Layer VPD for Mellanox MT23108 HCA\r
36  */\r
37 \r
38 \r
39 #include "hca_driver.h"\r
40 #if defined(EVENT_TRACING)\r
41 #ifdef offsetof\r
42 #undef offsetof\r
43 #endif\r
44 #include "hca_smp.tmh"\r
45 #endif\r
46 #include "mthca_dev.h"\r
47 #include "ib_mad.h"\r
48 \r
49 \r
50 boolean_t\r
51 mlnx_cachable_guid_info(\r
52         IN              const   mlnx_cache_t* const                     p_cache,\r
53         IN              const   ib_mad_t                                        *p_mad_in,\r
54                 OUT                     ib_mad_t                                        *p_mad_out )\r
55 {\r
56         uint32_t                        idx;\r
57 \r
58         /* Get the table selector from the attribute */\r
59         idx = cl_ntoh32( p_mad_in->attr_mod );\r
60 \r
61         /*\r
62          * TODO: Setup the response to fail the MAD instead of sending\r
63          * it down to the HCA.\r
64          */\r
65         if( idx > 31 )\r
66                 return FALSE;\r
67 \r
68         if( !p_cache->guid_block[idx].valid )\r
69                 return FALSE;\r
70 \r
71         /*\r
72          * If a SET, see if the set is identical to the cache,\r
73          * in which case it's a no-op.\r
74          */\r
75         if( p_mad_in->method == IB_MAD_METHOD_SET )\r
76         {\r
77                 if( cl_memcmp( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_in ),\r
78                         &p_cache->guid_block[idx].tbl, sizeof(ib_guid_info_t) ) )\r
79                 {\r
80                         /* The set is requesting a change. */\r
81                         return FALSE;\r
82                 }\r
83         }\r
84 \r
85         /* Setup the response mad. */\r
86         cl_memcpy( p_mad_out, p_mad_in, MAD_BLOCK_SIZE );\r
87         p_mad_out->method = (IB_MAD_METHOD_RESP_MASK | IB_MAD_METHOD_GET);\r
88         if( p_mad_out->mgmt_class == IB_MCLASS_SUBN_DIR )\r
89                 p_mad_out->status = IB_SMP_DIRECTION;\r
90         else\r
91                 p_mad_out->status = 0;\r
92 \r
93         /* Copy the cached data. */\r
94         cl_memcpy( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out ),\r
95                 &p_cache->guid_block[idx].tbl, sizeof(ib_guid_info_t) );\r
96 \r
97         return TRUE;\r
98 }\r
99 \r
100 \r
101 boolean_t\r
102 mlnx_cachable_pkey_table(\r
103         IN              const   mlnx_cache_t* const                     p_cache,\r
104         IN              const   ib_mad_t                                        *p_mad_in,\r
105                 OUT                     ib_mad_t                                        *p_mad_out )\r
106 {\r
107         uint16_t                        idx;\r
108 \r
109         /* Get the table selector from the attribute */\r
110         idx = ((uint16_t)cl_ntoh32( p_mad_in->attr_mod ));\r
111 \r
112         /*\r
113          * TODO: Setup the response to fail the MAD instead of sending\r
114          * it down to the HCA.\r
115          */\r
116         if( idx > 2047 )\r
117                 return FALSE;\r
118 \r
119         if( !p_cache->pkey_tbl[idx].valid )\r
120                 return FALSE;\r
121 \r
122         /*\r
123          * If a SET, see if the set is identical to the cache,\r
124          * in which case it's a no-op.\r
125          */\r
126         if( p_mad_in->method == IB_MAD_METHOD_SET )\r
127         {\r
128                 if( cl_memcmp( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_in ),\r
129                         &p_cache->pkey_tbl[idx].tbl, sizeof(ib_pkey_table_info_t) ) )\r
130                 {\r
131                         /* The set is requesting a change. */\r
132                         return FALSE;\r
133                 }\r
134         }\r
135 \r
136         /* Setup the response mad. */\r
137         cl_memcpy( p_mad_out, p_mad_in, MAD_BLOCK_SIZE );\r
138         p_mad_out->method = (IB_MAD_METHOD_RESP_MASK | IB_MAD_METHOD_GET);\r
139         if( p_mad_out->mgmt_class == IB_MCLASS_SUBN_DIR )\r
140                 p_mad_out->status = IB_SMP_DIRECTION;\r
141         else\r
142                 p_mad_out->status = 0;\r
143 \r
144         /* Copy the cached data. */\r
145         cl_memcpy( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out ),\r
146                 &p_cache->pkey_tbl[idx].tbl, sizeof(ib_pkey_table_info_t) );\r
147 \r
148         return TRUE;\r
149 }\r
150 \r
151 \r
152 boolean_t\r
153 mlnx_cachable_sl_vl_table(\r
154         IN              const   mlnx_cache_t* const                     p_cache,\r
155         IN              const   ib_mad_t                                        *p_mad_in,\r
156                 OUT                     ib_mad_t                                        *p_mad_out )\r
157 {\r
158         if( !p_cache->sl_vl.valid )\r
159                 return FALSE;\r
160 \r
161         /*\r
162          * If a SET, see if the set is identical to the cache,\r
163          * in which case it's a no-op.\r
164          */\r
165         if( p_mad_in->method == IB_MAD_METHOD_SET )\r
166         {\r
167                 if( cl_memcmp( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_in ),\r
168                         &p_cache->sl_vl.tbl, sizeof(ib_slvl_table_t) ) )\r
169                 {\r
170                         /* The set is requesting a change. */\r
171                         return FALSE;\r
172                 }\r
173         }\r
174 \r
175         /* Setup the response mad. */\r
176         cl_memcpy( p_mad_out, p_mad_in, MAD_BLOCK_SIZE );\r
177         p_mad_out->method = (IB_MAD_METHOD_RESP_MASK | IB_MAD_METHOD_GET);\r
178         if( p_mad_out->mgmt_class == IB_MCLASS_SUBN_DIR )\r
179                 p_mad_out->status = IB_SMP_DIRECTION;\r
180         else\r
181                 p_mad_out->status = 0;\r
182 \r
183         /* Copy the cached data. */\r
184         cl_memcpy( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out ),\r
185                 &p_cache->sl_vl.tbl, sizeof(ib_slvl_table_t) );\r
186 \r
187         return TRUE;\r
188 }\r
189 \r
190 \r
191 boolean_t\r
192 mlnx_cachable_vl_arb_table(\r
193         IN              const   mlnx_cache_t* const                     p_cache,\r
194         IN              const   ib_mad_t                                        *p_mad_in,\r
195                 OUT                     ib_mad_t                                        *p_mad_out )\r
196 {\r
197         uint16_t                        idx;\r
198 \r
199         /* Get the table selector from the attribute */\r
200         idx = ((uint16_t)(cl_ntoh32( p_mad_in->attr_mod ) >> 16)) - 1;\r
201 \r
202         /*\r
203          * TODO: Setup the response to fail the MAD instead of sending\r
204          * it down to the HCA.\r
205          */\r
206         if( idx > 3 )\r
207                 return FALSE;\r
208 \r
209         if( !p_cache->vl_arb[idx].valid )\r
210                 return FALSE;\r
211 \r
212         /*\r
213          * If a SET, see if the set is identical to the cache,\r
214          * in which case it's a no-op.\r
215          */\r
216         if( p_mad_in->method == IB_MAD_METHOD_SET )\r
217         {\r
218                 if( cl_memcmp( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_in ),\r
219                         &p_cache->vl_arb[idx].tbl, sizeof(ib_vl_arb_table_t) ) )\r
220                 {\r
221                         /* The set is requesting a change. */\r
222                         return FALSE;\r
223                 }\r
224         }\r
225 \r
226         /* Setup the response mad. */\r
227         cl_memcpy( p_mad_out, p_mad_in, MAD_BLOCK_SIZE );\r
228         p_mad_out->method = (IB_MAD_METHOD_RESP_MASK | IB_MAD_METHOD_GET);\r
229         if( p_mad_out->mgmt_class == IB_MCLASS_SUBN_DIR )\r
230                 p_mad_out->status = IB_SMP_DIRECTION;\r
231         else\r
232                 p_mad_out->status = 0;\r
233 \r
234         /* Copy the cached data. */\r
235         cl_memcpy( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out ),\r
236                 &p_cache->vl_arb[idx].tbl, sizeof(ib_vl_arb_table_t) );\r
237 \r
238         return TRUE;\r
239 }\r
240 \r
241 \r
242 boolean_t\r
243 mlnx_cachable_port_info(\r
244         IN              const   mlnx_cache_t* const                     p_cache,\r
245         IN              const   uint8_t                                         port_num,\r
246         IN              const   ib_mad_t                                        *p_mad_in,\r
247                 OUT                     ib_mad_t                                        *p_mad_out )\r
248 {\r
249         ib_port_info_t          *p_port_info;\r
250 \r
251         UNUSED_PARAM( p_mad_out );\r
252 \r
253         if( !p_cache->port_info.valid )\r
254                 return FALSE;\r
255 \r
256         if( p_mad_in->method == IB_MAD_METHOD_GET )\r
257                 return FALSE;\r
258 \r
259         /*\r
260          * NOTE: Even though the input MAD is const, we modify it to change\r
261          * some parameters to no-ops to compensate for problems in the HCA chip.\r
262          */\r
263         p_port_info =\r
264                 (ib_port_info_t*)ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_in );\r
265 \r
266         /* We can only cache requests for the same port that the SMP came in on. */\r
267         if( p_mad_in->attr_mod != 0 &&\r
268                 cl_ntoh32( p_mad_in->attr_mod ) != port_num )\r
269         {\r
270                 return FALSE;\r
271         }\r
272 \r
273         /*\r
274          * to avoid unnecessary glitches in port state, we translate these\r
275          * fields to NOP when there is no change.  Note these fields cannot\r
276          * change within the hardware without a Set going through here.\r
277          */\r
278         if( p_port_info->link_width_enabled ==\r
279                 p_cache->port_info.info.link_width_enabled )\r
280         {\r
281                 p_port_info->link_width_enabled = 0;\r
282         }\r
283         if( (p_port_info->state_info2 & 0x0F) ==\r
284                 (p_cache->port_info.info.state_info2 & 0x0F) )\r
285         {\r
286                 p_port_info->state_info2 &= 0xF0;\r
287         }\r
288         if( (p_port_info->link_speed & 0x0F) ==\r
289                 (p_cache->port_info.info.link_speed & 0x0F) )\r
290         {\r
291                 p_port_info->link_speed &= 0xF0;\r
292         }\r
293         if( (p_port_info->vl_enforce & 0xF0) ==\r
294                 (p_cache->port_info.info.vl_enforce & 0xF0) )\r
295         {\r
296                 p_port_info->vl_enforce &= 0x0F;\r
297         }\r
298 \r
299         /*\r
300          * We modified the input MAD to change things to no-ops, but\r
301          * we can't actually fulfill the MAD with cached data.\r
302          */\r
303         return FALSE;\r
304 }\r
305 \r
306 \r
307 boolean_t\r
308 mlnx_cachable_mad(\r
309         IN              const   ib_ca_handle_t                          h_ca,\r
310         IN              const   uint8_t                                         port_num,\r
311         IN              const   ib_mad_t                                        *p_mad_in,\r
312                 OUT                     ib_mad_t                                        *p_mad_out )\r
313 {\r
314         if( p_mad_in->mgmt_class!= IB_MCLASS_SUBN_DIR &&\r
315                 p_mad_in->mgmt_class != IB_MCLASS_SUBN_LID )\r
316         {\r
317                 return FALSE;\r
318         }\r
319 \r
320         switch( p_mad_in->attr_id )\r
321         {\r
322         case IB_MAD_ATTR_GUID_INFO:\r
323                 return mlnx_cachable_guid_info(\r
324                         &h_ca->cache[port_num-1], p_mad_in, p_mad_out );\r
325 \r
326         case IB_MAD_ATTR_P_KEY_TABLE:\r
327                 return mlnx_cachable_pkey_table(\r
328                         &h_ca->cache[port_num-1], p_mad_in, p_mad_out );\r
329 \r
330         case IB_MAD_ATTR_SLVL_TABLE:\r
331                 return mlnx_cachable_sl_vl_table(\r
332                         &h_ca->cache[port_num-1], p_mad_in, p_mad_out );\r
333 \r
334         case IB_MAD_ATTR_VL_ARBITRATION:\r
335                 return mlnx_cachable_vl_arb_table(\r
336                         &h_ca->cache[port_num-1], p_mad_in, p_mad_out );\r
337 \r
338         case IB_MAD_ATTR_PORT_INFO:\r
339                 return mlnx_cachable_port_info(\r
340                         &h_ca->cache[port_num-1], port_num, p_mad_in, p_mad_out );\r
341 \r
342         default:\r
343                 break;\r
344         }\r
345         return FALSE;\r
346 }\r
347 \r
348 \r
349 void\r
350 mlnx_update_guid_info(\r
351         IN                              mlnx_cache_t* const                     p_cache,\r
352         IN              const   ib_mad_t* const                         p_mad_out )\r
353 {\r
354         uint32_t                        idx;\r
355 \r
356         /* Get the table selector from the attribute */\r
357         idx = cl_ntoh32( p_mad_out->attr_mod );\r
358 \r
359         /*\r
360          * We only get successful MADs here, so invalid settings\r
361          * shouldn't happen.\r
362          */\r
363         CL_ASSERT( idx <= 31 );\r
364 \r
365         cl_memcpy( &p_cache->guid_block[idx].tbl,\r
366                 ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out ),\r
367                 sizeof(ib_guid_info_t) );\r
368         p_cache->guid_block[idx].valid = TRUE;\r
369 }\r
370 \r
371 \r
372 void\r
373 mlnx_update_pkey_table(\r
374         IN                              mlnx_cache_t* const                     p_cache,\r
375         IN              const   ib_mad_t* const                         p_mad_out )\r
376 {\r
377         uint16_t                        idx;\r
378 \r
379         /* Get the table selector from the attribute */\r
380         idx = ((uint16_t)cl_ntoh32( p_mad_out->attr_mod ));\r
381 \r
382         ASSERT( idx <= 2047 );\r
383 \r
384         cl_memcpy( &p_cache->pkey_tbl[idx].tbl,\r
385                 ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out ),\r
386                 sizeof(ib_pkey_table_info_t) );\r
387         p_cache->pkey_tbl[idx].valid = TRUE;\r
388 }\r
389 \r
390 \r
391 void\r
392 mlnx_update_sl_vl_table(\r
393         IN                              mlnx_cache_t* const                     p_cache,\r
394         IN              const   ib_mad_t* const                         p_mad_out )\r
395 {\r
396         cl_memcpy( &p_cache->sl_vl.tbl,\r
397                 ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out ),\r
398                 sizeof(ib_slvl_table_t) );\r
399         p_cache->sl_vl.valid = TRUE;\r
400 }\r
401 \r
402 \r
403 void\r
404 mlnx_update_vl_arb_table(\r
405         IN                              mlnx_cache_t* const                     p_cache,\r
406         IN              const   ib_mad_t* const                         p_mad_out )\r
407 {\r
408         uint16_t                        idx;\r
409 \r
410         /* Get the table selector from the attribute */\r
411         idx = ((uint16_t)(cl_ntoh32( p_mad_out->attr_mod ) >> 16)) - 1;\r
412 \r
413         CL_ASSERT( idx <= 3 );\r
414 \r
415         cl_memcpy( &p_cache->vl_arb[idx].tbl,\r
416                 ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out ),\r
417                 sizeof(ib_vl_arb_table_t) );\r
418         p_cache->vl_arb[idx].valid = TRUE;\r
419 }\r
420 \r
421 \r
422 void\r
423 mlnx_update_port_info(\r
424         IN              const   mlnx_cache_t* const                     p_cache,\r
425         IN              const   uint8_t                                         port_num,\r
426         IN              const   ib_mad_t* const                         p_mad_out )\r
427 {\r
428         UNUSED_PARAM( p_cache );\r
429 \r
430         /* We can only cache requests for the same port that the SMP came in on. */\r
431         /* TODO: Add synchronization to support getting data from other ports. */\r
432         if( p_mad_out->attr_mod != 0 &&\r
433                 cl_ntoh32( p_mad_out->attr_mod ) != port_num )\r
434         {\r
435                 return;\r
436         }\r
437 \r
438         /* TODO: Setup the capabilites mask properly. */\r
439 }\r
440 \r
441 \r
442 void\r
443 mlnx_update_cache(\r
444         IN              const   ib_ca_handle_t                          h_ca,\r
445         IN              const   uint8_t                                         port_num,\r
446         IN              const   ib_mad_t                                        *p_mad_out )\r
447 {\r
448         if( p_mad_out->mgmt_class != IB_MCLASS_SUBN_DIR &&\r
449                 p_mad_out->mgmt_class != IB_MCLASS_SUBN_LID )\r
450         {\r
451                 return;\r
452         }\r
453 \r
454         /* Any successful response updates the cache. */\r
455         if( p_mad_out->status )\r
456                 return;\r
457 \r
458 \r
459         switch( p_mad_out->attr_id )\r
460         {\r
461         case IB_MAD_ATTR_GUID_INFO:\r
462                 mlnx_update_guid_info(\r
463                         &h_ca->cache[port_num-1], p_mad_out );\r
464                 break;\r
465 \r
466         case IB_MAD_ATTR_P_KEY_TABLE:\r
467                 mlnx_update_pkey_table(\r
468                         &h_ca->cache[port_num-1], p_mad_out );\r
469                 break;\r
470 \r
471         case IB_MAD_ATTR_SLVL_TABLE:\r
472                 mlnx_update_sl_vl_table(\r
473                         &h_ca->cache[port_num-1], p_mad_out );\r
474                 break;\r
475 \r
476         case IB_MAD_ATTR_VL_ARBITRATION:\r
477                 mlnx_update_vl_arb_table(\r
478                         &h_ca->cache[port_num-1], p_mad_out );\r
479                 break;\r
480 \r
481         case IB_MAD_ATTR_PORT_INFO:\r
482                 mlnx_update_port_info(\r
483                         &h_ca->cache[port_num-1], port_num, p_mad_out );\r
484                 break;\r
485 \r
486         default:\r
487                 break;\r
488         }\r
489 \r
490 }\r
491 \r
492 \r
493 /*\r
494  * Local MAD Support Verbs. For CAs that do not support\r
495  * agents in HW.\r
496  */\r
497 \r
498 #ifdef WIN_TO_BE_REMOVED\r
499 //TODO: seems like non need in that\r
500 static void build_smp_wc(u64 wr_id, u16 slid, u16 pkey_index, \r
501         u8 port_num, struct _ib_wc *wc)\r
502 {\r
503         RtlZeroMemory(wc, sizeof *wc);\r
504         wc->wr_id = wr_id;\r
505         wc->status = IB_WC_SUCCESS;\r
506         wc->wc_type = IB_WC_RECV;\r
507         wc->length = sizeof(struct ib_mad) + sizeof(struct ib_grh);\r
508         wc->qp_num = IB_QP0;\r
509         wc->port_num = port_num;\r
510         wc->recv.ud.pkey_index = pkey_index;\r
511         wc->recv.ud.remote_qp = IB_QP0;\r
512         wc->recv.ud.remote_lid = slid;\r
513         wc->recv.ud.remote_sl = 0;\r
514         wc->recv.ud.path_bits = 0;\r
515 }\r
516 #endif\r
517 \r
518 ib_api_status_t\r
519 mlnx_local_mad (\r
520         IN              const   ib_ca_handle_t                          h_ca,\r
521         IN              const   uint8_t                                         port_num,\r
522         IN              const   ib_av_attr_t*                                   p_av_attr,\r
523         IN              const   ib_mad_t                                        *p_mad_in,\r
524         OUT             ib_mad_t                                        *p_mad_out )\r
525 {\r
526         int err;\r
527         ib_api_status_t         status = IB_SUCCESS;\r
528         mlnx_hob_t                      *hob_p = (mlnx_hob_t *)h_ca;\r
529         struct ib_device *ib_dev = IBDEV_FROM_HOB( hob_p );\r
530         //TODO: do we need use flags (IB_MAD_IGNORE_MKEY, IB_MAD_IGNORE_BKEY) ?\r
531         int mad_flags = 0;  \r
532         struct _ib_wc *wc_p = NULL;\r
533         //TODO: do we need use grh ?\r
534         struct _ib_grh *grh_p = NULL;\r
535 \r
536         HCA_ENTER(HCA_DBG_MAD);\r
537 \r
538         // sanity checks\r
539         if (port_num > 2) {\r
540                 status = IB_INVALID_PARAMETER;\r
541                 goto err_port_num;\r
542         }\r
543 \r
544         if (p_av_attr){\r
545                 wc_p = cl_zalloc(sizeof(struct _ib_wc));\r
546                 if(!wc_p){\r
547                         status =  IB_INSUFFICIENT_MEMORY ;\r
548                         goto err_wc_alloc;\r
549                 }\r
550                 //Copy part of the attributes need to fill the mad extended fields in mellanox devices\r
551                 wc_p->recv.ud.remote_lid = p_av_attr->dlid;\r
552                 wc_p->recv.ud.remote_sl  = p_av_attr->sl;\r
553                 wc_p->recv.ud.path_bits  = p_av_attr->path_bits;\r
554                 wc_p->recv.ud.recv_opt = p_av_attr->grh_valid?IB_RECV_OPT_GRH_VALID:0;\r
555 \r
556                 if(wc_p->recv.ud.recv_opt &IB_RECV_OPT_GRH_VALID){\r
557                         grh_p = cl_zalloc(sizeof(struct _ib_grh));\r
558                         if(!grh_p){\r
559                                 status =  IB_INSUFFICIENT_MEMORY ;\r
560                                 goto err_grh_alloc;\r
561                         }\r
562                         cl_memcpy(grh_p, &p_av_attr->grh, sizeof(ib_grh_t));\r
563                 }\r
564                         \r
565 \r
566         }\r
567 \r
568         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_MAD, \r
569                 ("MAD: Class %02x, Method %02x, Attr %02x, HopPtr %d, HopCnt %d, \n",\r
570                 (uint32_t)((ib_smp_t *)p_mad_in)->mgmt_class, \r
571                 (uint32_t)((ib_smp_t *)p_mad_in)->method, \r
572                 (uint32_t)((ib_smp_t *)p_mad_in)->attr_id, \r
573                 (uint32_t)((ib_smp_t *)p_mad_in)->hop_ptr,\r
574                 (uint32_t)((ib_smp_t *)p_mad_in)->hop_count));\r
575 \r
576         \r
577         // process mad\r
578         if( !mlnx_cachable_mad( h_ca, port_num, p_mad_in, p_mad_out ) )\r
579         {\r
580                 err = mthca_process_mad(ib_dev, mad_flags, (uint8_t)port_num, \r
581                         wc_p, grh_p, (struct ib_mad*)p_mad_in, (struct ib_mad*)p_mad_out);\r
582                 if (!err) {\r
583                         HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_MAD, \r
584                                 ("MAD failed:\n\tClass 0x%x\n\tMethod 0x%x\n\tAttr 0x%x",\r
585                                 p_mad_in->mgmt_class, p_mad_in->method, p_mad_in->attr_id ));\r
586                         status = IB_ERROR;\r
587                         goto err_process_mad;\r
588                 }\r
589                 \r
590                 if( (p_mad_in->mgmt_class == IB_MCLASS_SUBN_DIR ||\r
591                         p_mad_in->mgmt_class == IB_MCLASS_SUBN_LID) &&\r
592                         p_mad_in->attr_id == IB_MAD_ATTR_PORT_INFO )\r
593                 {\r
594                         ib_port_info_t  *p_pi_in, *p_pi_out;\r
595 \r
596                         if( p_mad_in->mgmt_class == IB_MCLASS_SUBN_DIR )\r
597                         {\r
598                                 p_pi_in = (ib_port_info_t*)\r
599                                         ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_in );\r
600                                 p_pi_out = (ib_port_info_t*)\r
601                                         ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out );\r
602                         }\r
603                         else\r
604                         {\r
605                                 p_pi_in = (ib_port_info_t*)(p_mad_in + 1);\r
606                                 p_pi_out = (ib_port_info_t*)(p_mad_out + 1);\r
607                         }\r
608 \r
609                         /* Work around FW bug 33958 */\r
610                         p_pi_out->subnet_timeout &= 0x7F;\r
611                         if( p_mad_in->method == IB_MAD_METHOD_SET )\r
612                                 p_pi_out->subnet_timeout |= (p_pi_in->subnet_timeout & 0x80);\r
613                 }\r
614 \r
615                 mlnx_update_cache( h_ca, port_num, p_mad_out );\r
616         }\r
617 \r
618         /* Modify direction for Direct MAD */\r
619         if ( p_mad_in->mgmt_class == IB_MCLASS_SUBN_DIR )\r
620                 p_mad_out->status |= IB_SMP_DIRECTION;\r
621 \r
622 \r
623 err_process_mad:\r
624         if(grh_p)\r
625                 cl_free(grh_p);\r
626 err_grh_alloc:\r
627         if(wc_p)\r
628                 cl_free(wc_p);\r
629 err_wc_alloc:\r
630 err_port_num:   \r
631         HCA_PRINT_EXIT(TRACE_LEVEL_ERROR  , HCA_DBG_MAD,\r
632                 ("completes with ERROR status %s\n", IB_GET_ERR_STR(status)));\r
633         return status;\r
634 }\r
635         \r