[MTHCA\MT23108\IBAL] change to support TRAP and TRAP_REPRESS
[mirror/winof/.git] / hw / mt23108 / 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.\r
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_data.h"\r
40 #include "hca_debug.h"\r
41 \r
42 \r
43 boolean_t\r
44 mlnx_cachable_guid_info(\r
45         IN              const   mlnx_cache_t* const                     p_cache,\r
46         IN              const   ib_mad_t                                        *p_mad_in,\r
47                 OUT                     ib_mad_t                                        *p_mad_out )\r
48 {\r
49         uint32_t                        idx;\r
50 \r
51         /* Get the table selector from the attribute */\r
52         idx = cl_ntoh32( p_mad_in->attr_mod );\r
53 \r
54         /*\r
55          * TODO: Setup the response to fail the MAD instead of sending\r
56          * it down to the HCA.\r
57          */\r
58         if( idx > 31 )\r
59                 return FALSE;\r
60 \r
61         if( !p_cache->guid_block[idx].valid )\r
62                 return FALSE;\r
63 \r
64         /*\r
65          * If a SET, see if the set is identical to the cache,\r
66          * in which case it's a no-op.\r
67          */\r
68         if( p_mad_in->method == IB_MAD_METHOD_SET )\r
69         {\r
70                 if( cl_memcmp( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_in ),\r
71                         &p_cache->guid_block[idx].tbl, sizeof(ib_guid_info_t) ) )\r
72                 {\r
73                         /* The set is requesting a change. */\r
74                         return FALSE;\r
75                 }\r
76         }\r
77 \r
78         /* Setup the response mad. */\r
79         cl_memcpy( p_mad_out, p_mad_in, MAD_BLOCK_SIZE );\r
80         p_mad_out->method = (IB_MAD_METHOD_RESP_MASK | IB_MAD_METHOD_GET);\r
81         if( p_mad_out->mgmt_class == IB_MCLASS_SUBN_DIR )\r
82                 p_mad_out->status = IB_SMP_DIRECTION;\r
83         else\r
84                 p_mad_out->status = 0;\r
85 \r
86         /* Copy the cached data. */\r
87         cl_memcpy( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out ),\r
88                 &p_cache->guid_block[idx].tbl, sizeof(ib_guid_info_t) );\r
89 \r
90         return TRUE;\r
91 }\r
92 \r
93 \r
94 boolean_t\r
95 mlnx_cachable_pkey_table(\r
96         IN              const   mlnx_cache_t* const                     p_cache,\r
97         IN              const   ib_mad_t                                        *p_mad_in,\r
98                 OUT                     ib_mad_t                                        *p_mad_out )\r
99 {\r
100         uint16_t                        idx;\r
101 \r
102         /* Get the table selector from the attribute */\r
103         idx = ((uint16_t)cl_ntoh32( p_mad_in->attr_mod ));\r
104 \r
105         /*\r
106          * TODO: Setup the response to fail the MAD instead of sending\r
107          * it down to the HCA.\r
108          */\r
109         if( idx > 2047 )\r
110                 return FALSE;\r
111 \r
112         if( !p_cache->pkey_tbl[idx].valid )\r
113                 return FALSE;\r
114 \r
115         /*\r
116          * If a SET, see if the set is identical to the cache,\r
117          * in which case it's a no-op.\r
118          */\r
119         if( p_mad_in->method == IB_MAD_METHOD_SET )\r
120         {\r
121                 if( cl_memcmp( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_in ),\r
122                         &p_cache->pkey_tbl[idx].tbl, sizeof(ib_pkey_table_info_t) ) )\r
123                 {\r
124                         /* The set is requesting a change. */\r
125                         return FALSE;\r
126                 }\r
127         }\r
128 \r
129         /* Setup the response mad. */\r
130         cl_memcpy( p_mad_out, p_mad_in, MAD_BLOCK_SIZE );\r
131         p_mad_out->method = (IB_MAD_METHOD_RESP_MASK | IB_MAD_METHOD_GET);\r
132         if( p_mad_out->mgmt_class == IB_MCLASS_SUBN_DIR )\r
133                 p_mad_out->status = IB_SMP_DIRECTION;\r
134         else\r
135                 p_mad_out->status = 0;\r
136 \r
137         /* Copy the cached data. */\r
138         cl_memcpy( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out ),\r
139                 &p_cache->pkey_tbl[idx].tbl, sizeof(ib_pkey_table_info_t) );\r
140 \r
141         return TRUE;\r
142 }\r
143 \r
144 \r
145 boolean_t\r
146 mlnx_cachable_sl_vl_table(\r
147         IN              const   mlnx_cache_t* const                     p_cache,\r
148         IN              const   ib_mad_t                                        *p_mad_in,\r
149                 OUT                     ib_mad_t                                        *p_mad_out )\r
150 {\r
151         if( !p_cache->sl_vl.valid )\r
152                 return FALSE;\r
153 \r
154         /*\r
155          * If a SET, see if the set is identical to the cache,\r
156          * in which case it's a no-op.\r
157          */\r
158         if( p_mad_in->method == IB_MAD_METHOD_SET )\r
159         {\r
160                 if( cl_memcmp( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_in ),\r
161                         &p_cache->sl_vl.tbl, sizeof(ib_slvl_table_t) ) )\r
162                 {\r
163                         /* The set is requesting a change. */\r
164                         return FALSE;\r
165                 }\r
166         }\r
167 \r
168         /* Setup the response mad. */\r
169         cl_memcpy( p_mad_out, p_mad_in, MAD_BLOCK_SIZE );\r
170         p_mad_out->method = (IB_MAD_METHOD_RESP_MASK | IB_MAD_METHOD_GET);\r
171         if( p_mad_out->mgmt_class == IB_MCLASS_SUBN_DIR )\r
172                 p_mad_out->status = IB_SMP_DIRECTION;\r
173         else\r
174                 p_mad_out->status = 0;\r
175 \r
176         /* Copy the cached data. */\r
177         cl_memcpy( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out ),\r
178                 &p_cache->sl_vl.tbl, sizeof(ib_slvl_table_t) );\r
179 \r
180         return TRUE;\r
181 }\r
182 \r
183 \r
184 boolean_t\r
185 mlnx_cachable_vl_arb_table(\r
186         IN              const   mlnx_cache_t* const                     p_cache,\r
187         IN              const   ib_mad_t                                        *p_mad_in,\r
188                 OUT                     ib_mad_t                                        *p_mad_out )\r
189 {\r
190         uint16_t                        idx;\r
191 \r
192         /* Get the table selector from the attribute */\r
193         idx = ((uint16_t)(cl_ntoh32( p_mad_in->attr_mod ) >> 16)) - 1;\r
194 \r
195         /*\r
196          * TODO: Setup the response to fail the MAD instead of sending\r
197          * it down to the HCA.\r
198          */\r
199         if( idx > 3 )\r
200                 return FALSE;\r
201 \r
202         if( !p_cache->vl_arb[idx].valid )\r
203                 return FALSE;\r
204 \r
205         /*\r
206          * If a SET, see if the set is identical to the cache,\r
207          * in which case it's a no-op.\r
208          */\r
209         if( p_mad_in->method == IB_MAD_METHOD_SET )\r
210         {\r
211                 if( cl_memcmp( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_in ),\r
212                         &p_cache->vl_arb[idx].tbl, sizeof(ib_vl_arb_table_t) ) )\r
213                 {\r
214                         /* The set is requesting a change. */\r
215                         return FALSE;\r
216                 }\r
217         }\r
218 \r
219         /* Setup the response mad. */\r
220         cl_memcpy( p_mad_out, p_mad_in, MAD_BLOCK_SIZE );\r
221         p_mad_out->method = (IB_MAD_METHOD_RESP_MASK | IB_MAD_METHOD_GET);\r
222         if( p_mad_out->mgmt_class == IB_MCLASS_SUBN_DIR )\r
223                 p_mad_out->status = IB_SMP_DIRECTION;\r
224         else\r
225                 p_mad_out->status = 0;\r
226 \r
227         /* Copy the cached data. */\r
228         cl_memcpy( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out ),\r
229                 &p_cache->vl_arb[idx].tbl, sizeof(ib_vl_arb_table_t) );\r
230 \r
231         return TRUE;\r
232 }\r
233 \r
234 \r
235 boolean_t\r
236 mlnx_cachable_port_info(\r
237         IN              const   mlnx_cache_t* const                     p_cache,\r
238         IN              const   uint8_t                                         port_num,\r
239         IN              const   ib_mad_t                                        *p_mad_in,\r
240                 OUT                     ib_mad_t                                        *p_mad_out )\r
241 {\r
242         ib_port_info_t          *p_port_info;\r
243 \r
244         UNUSED_PARAM( p_mad_out );\r
245 \r
246         if( !p_cache->port_info.valid )\r
247                 return FALSE;\r
248 \r
249         if( p_mad_in->method == IB_MAD_METHOD_GET )\r
250                 return FALSE;\r
251 \r
252         /*\r
253          * NOTE: Even though the input MAD is const, we modify it to change\r
254          * some parameters to no-ops to compensate for problems in the HCA chip.\r
255          */\r
256         p_port_info =\r
257                 (ib_port_info_t*)ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_in );\r
258 \r
259         /* We can only cache requests for the same port that the SMP came in on. */\r
260         if( p_mad_in->attr_mod != 0 &&\r
261                 cl_ntoh32( p_mad_in->attr_mod ) != port_num )\r
262         {\r
263                 return FALSE;\r
264         }\r
265 \r
266         /*\r
267          * to avoid unnecessary glitches in port state, we translate these\r
268          * fields to NOP when there is no change.  Note these fields cannot\r
269          * change within the hardware without a Set going through here.\r
270          */\r
271         if( p_port_info->link_width_enabled ==\r
272                 p_cache->port_info.info.link_width_enabled )\r
273         {\r
274                 p_port_info->link_width_enabled = 0;\r
275         }\r
276         if( (p_port_info->state_info2 & 0x0F) ==\r
277                 (p_cache->port_info.info.state_info2 & 0x0F) )\r
278         {\r
279                 p_port_info->state_info2 &= 0xF0;\r
280         }\r
281         if( (p_port_info->link_speed & 0x0F) ==\r
282                 (p_cache->port_info.info.link_speed & 0x0F) )\r
283         {\r
284                 p_port_info->link_speed &= 0xF0;\r
285         }\r
286         if( (p_port_info->vl_enforce & 0xF0) ==\r
287                 (p_cache->port_info.info.vl_enforce & 0xF0) )\r
288         {\r
289                 p_port_info->vl_enforce &= 0x0F;\r
290         }\r
291 \r
292         /*\r
293          * We modified the input MAD to change things to no-ops, but\r
294          * we can't actually fulfill the MAD with cached data.\r
295          */\r
296         return FALSE;\r
297 }\r
298 \r
299 \r
300 boolean_t\r
301 mlnx_cachable_mad(\r
302         IN              const   ib_ca_handle_t                          h_ca,\r
303         IN              const   uint8_t                                         port_num,\r
304         IN              const   ib_mad_t                                        *p_mad_in,\r
305                 OUT                     ib_mad_t                                        *p_mad_out )\r
306 {\r
307         if( p_mad_in->mgmt_class!= IB_MCLASS_SUBN_DIR &&\r
308                 p_mad_in->mgmt_class != IB_MCLASS_SUBN_LID )\r
309         {\r
310                 return FALSE;\r
311         }\r
312 \r
313         switch( p_mad_in->attr_id )\r
314         {\r
315         case IB_MAD_ATTR_GUID_INFO:\r
316                 return mlnx_cachable_guid_info(\r
317                         &h_ca->cache[port_num-1], p_mad_in, p_mad_out );\r
318 \r
319         case IB_MAD_ATTR_P_KEY_TABLE:\r
320                 return mlnx_cachable_pkey_table(\r
321                         &h_ca->cache[port_num-1], p_mad_in, p_mad_out );\r
322 \r
323         case IB_MAD_ATTR_SLVL_TABLE:\r
324                 return mlnx_cachable_sl_vl_table(\r
325                         &h_ca->cache[port_num-1], p_mad_in, p_mad_out );\r
326 \r
327         case IB_MAD_ATTR_VL_ARBITRATION:\r
328                 return mlnx_cachable_vl_arb_table(\r
329                         &h_ca->cache[port_num-1], p_mad_in, p_mad_out );\r
330 \r
331         case IB_MAD_ATTR_PORT_INFO:\r
332                 return mlnx_cachable_port_info(\r
333                         &h_ca->cache[port_num-1], port_num, p_mad_in, p_mad_out );\r
334 \r
335         default:\r
336                 break;\r
337         }\r
338         return FALSE;\r
339 }\r
340 \r
341 \r
342 void\r
343 mlnx_update_guid_info(\r
344         IN                              mlnx_cache_t* const                     p_cache,\r
345         IN              const   ib_mad_t* const                         p_mad_out )\r
346 {\r
347         uint32_t                        idx;\r
348 \r
349         /* Get the table selector from the attribute */\r
350         idx = cl_ntoh32( p_mad_out->attr_mod );\r
351 \r
352         /*\r
353          * We only get successful MADs here, so invalid settings\r
354          * shouldn't happen.\r
355          */\r
356         CL_ASSERT( idx <= 31 );\r
357 \r
358         cl_memcpy( &p_cache->guid_block[idx].tbl,\r
359                 ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out ),\r
360                 sizeof(ib_guid_info_t) );\r
361         p_cache->guid_block[idx].valid = TRUE;\r
362 }\r
363 \r
364 \r
365 void\r
366 mlnx_update_pkey_table(\r
367         IN                              mlnx_cache_t* const                     p_cache,\r
368         IN              const   ib_mad_t* const                         p_mad_out )\r
369 {\r
370         uint16_t                        idx;\r
371 \r
372         /* Get the table selector from the attribute */\r
373         idx = ((uint16_t)cl_ntoh32( p_mad_out->attr_mod ));\r
374 \r
375         ASSERT( idx <= 2047 );\r
376 \r
377         cl_memcpy( &p_cache->pkey_tbl[idx].tbl,\r
378                 ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out ),\r
379                 sizeof(ib_pkey_table_info_t) );\r
380         p_cache->pkey_tbl[idx].valid = TRUE;\r
381 }\r
382 \r
383 \r
384 void\r
385 mlnx_update_sl_vl_table(\r
386         IN                              mlnx_cache_t* const                     p_cache,\r
387         IN              const   ib_mad_t* const                         p_mad_out )\r
388 {\r
389         cl_memcpy( &p_cache->sl_vl.tbl,\r
390                 ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out ),\r
391                 sizeof(ib_slvl_table_t) );\r
392         p_cache->sl_vl.valid = TRUE;\r
393 }\r
394 \r
395 \r
396 void\r
397 mlnx_update_vl_arb_table(\r
398         IN                              mlnx_cache_t* const                     p_cache,\r
399         IN              const   ib_mad_t* const                         p_mad_out )\r
400 {\r
401         uint16_t                        idx;\r
402 \r
403         /* Get the table selector from the attribute */\r
404         idx = ((uint16_t)(cl_ntoh32( p_mad_out->attr_mod ) >> 16)) - 1;\r
405 \r
406         CL_ASSERT( idx <= 3 );\r
407 \r
408         cl_memcpy( &p_cache->vl_arb[idx].tbl,\r
409                 ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out ),\r
410                 sizeof(ib_vl_arb_table_t) );\r
411         p_cache->vl_arb[idx].valid = TRUE;\r
412 }\r
413 \r
414 \r
415 void\r
416 mlnx_update_port_info(\r
417         IN              const   mlnx_cache_t* const                     p_cache,\r
418         IN              const   uint8_t                                         port_num,\r
419         IN              const   ib_mad_t* const                         p_mad_out )\r
420 {\r
421         UNUSED_PARAM( p_cache );\r
422 \r
423         /* We can only cache requests for the same port that the SMP came in on. */\r
424         /* TODO: Add synchronization to support getting data from other ports. */\r
425         if( p_mad_out->attr_mod != 0 &&\r
426                 cl_ntoh32( p_mad_out->attr_mod ) != port_num )\r
427         {\r
428                 return;\r
429         }\r
430 \r
431         /* TODO: Setup the capabilites mask properly. */\r
432 }\r
433 \r
434 \r
435 void\r
436 mlnx_update_cache(\r
437         IN              const   ib_ca_handle_t                          h_ca,\r
438         IN              const   uint8_t                                         port_num,\r
439         IN              const   ib_mad_t                                        *p_mad_out )\r
440 {\r
441         if( p_mad_out->mgmt_class != IB_MCLASS_SUBN_DIR &&\r
442                 p_mad_out->mgmt_class != IB_MCLASS_SUBN_LID )\r
443         {\r
444                 return;\r
445         }\r
446 \r
447         /* Any successful response updates the cache. */\r
448         if( p_mad_out->status )\r
449                 return;\r
450 \r
451 \r
452         switch( p_mad_out->attr_id )\r
453         {\r
454         case IB_MAD_ATTR_GUID_INFO:\r
455                 mlnx_update_guid_info(\r
456                         &h_ca->cache[port_num-1], p_mad_out );\r
457                 break;\r
458 \r
459         case IB_MAD_ATTR_P_KEY_TABLE:\r
460                 mlnx_update_pkey_table(\r
461                         &h_ca->cache[port_num-1], p_mad_out );\r
462                 break;\r
463 \r
464         case IB_MAD_ATTR_SLVL_TABLE:\r
465                 mlnx_update_sl_vl_table(\r
466                         &h_ca->cache[port_num-1], p_mad_out );\r
467                 break;\r
468 \r
469         case IB_MAD_ATTR_VL_ARBITRATION:\r
470                 mlnx_update_vl_arb_table(\r
471                         &h_ca->cache[port_num-1], p_mad_out );\r
472                 break;\r
473 \r
474         case IB_MAD_ATTR_PORT_INFO:\r
475                 mlnx_update_port_info(\r
476                         &h_ca->cache[port_num-1], port_num, p_mad_out );\r
477                 break;\r
478 \r
479         default:\r
480                 break;\r
481         }\r
482 \r
483 }\r
484 \r
485 \r
486 /*\r
487  * Local MAD Support Verbs. For CAs that do not support\r
488  * agents in HW.\r
489  */\r
490 ib_api_status_t\r
491 mlnx_local_mad (\r
492         IN              const   ib_ca_handle_t                          h_ca,\r
493         IN              const   uint8_t                                         port_num,\r
494         IN              const   ib_av_attr_t                                    *p_av_src_attr,\r
495         IN              const   ib_mad_t                                        *p_mad_in,\r
496         OUT                     ib_mad_t                                        *p_mad_out )\r
497 {\r
498         ib_api_status_t         status;\r
499 \r
500         mlnx_hob_t                      *hob_p = (mlnx_hob_t *)h_ca;\r
501         u_int32_t                       hca_idx;\r
502         mlnx_hobul_t            *hobul_p;\r
503         HH_hca_dev_t            *hca_ul_info;\r
504 \r
505         CL_ENTER(MLNX_DBG_TRACE, g_mlnx_dbg_lvl);\r
506         UNUSED_PARAM(*p_av_src_attr);\r
507 \r
508         if (port_num > 2) {\r
509                 status = IB_INVALID_PARAMETER;\r
510                 goto cleanup;\r
511         }\r
512 \r
513         if (!hob_p || E_MARK_CA != hob_p->mark) {\r
514                 status = IB_INVALID_CA_HANDLE;\r
515                 goto cleanup;\r
516         }\r
517 \r
518         hca_idx = hob_p->index;\r
519         hobul_p = mlnx_hobul_array[hca_idx];\r
520         if (NULL == hobul_p) {\r
521                 status = IB_INVALID_CA_HANDLE;\r
522                 goto cleanup;\r
523         }\r
524 \r
525         hca_ul_info = (HH_hca_dev_t *)hobul_p->hh_hndl;\r
526         if (NULL == hca_ul_info) {\r
527                 status = IB_INVALID_CA_HANDLE;\r
528                 goto cleanup;\r
529         }\r
530 \r
531         if( !mlnx_cachable_mad( h_ca, port_num, p_mad_in, p_mad_out ) )\r
532         {\r
533                 if( HH_OK != THH_hob_process_local_mad( hobul_p->hh_hndl, port_num,\r
534                         0x0, 0, (void *)p_mad_in, p_mad_out ) )\r
535                 {\r
536                         HCA_TRACE( HCA_DBG_ERROR,\r
537                                 ("MAD failed:\n\tClass 0x%x\n\tMethod 0x%x\n\tAttr 0x%x",\r
538                                 p_mad_in->mgmt_class, p_mad_in->method, p_mad_in->attr_id ) );\r
539                         status = IB_ERROR;\r
540                         goto cleanup;\r
541                 }\r
542                 if( (p_mad_in->mgmt_class == IB_MCLASS_SUBN_DIR ||\r
543                         p_mad_in->mgmt_class == IB_MCLASS_SUBN_LID) &&\r
544                         p_mad_in->attr_id == IB_MAD_ATTR_PORT_INFO )\r
545                 {\r
546                         ib_port_info_t  *p_pi_in, *p_pi_out;\r
547 \r
548                         if( p_mad_in->mgmt_class == IB_MCLASS_SUBN_DIR )\r
549                         {\r
550                                 p_pi_in = (ib_port_info_t*)\r
551                                         ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_in );\r
552                                 p_pi_out = (ib_port_info_t*)\r
553                                         ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out );\r
554                         }\r
555                         else\r
556                         {\r
557                                 p_pi_in = (ib_port_info_t*)(p_mad_in + 1);\r
558                                 p_pi_out = (ib_port_info_t*)(p_mad_out + 1);\r
559                         }\r
560 \r
561                         /* Work around FW bug 33958 */\r
562                         p_pi_out->subnet_timeout &= 0x7F;\r
563                         if( p_mad_in->method == IB_MAD_METHOD_SET )\r
564                                 p_pi_out->subnet_timeout |= (p_pi_in->subnet_timeout & 0x80);\r
565                 }\r
566 \r
567                 mlnx_update_cache( h_ca, port_num, p_mad_out );\r
568         }\r
569 \r
570         /* Modify direction for Direct MAD */\r
571         if ( p_mad_in->mgmt_class == IB_MCLASS_SUBN_DIR )\r
572                 p_mad_out->status |= IB_SMP_DIRECTION;\r
573 \r
574         CL_EXIT(MLNX_DBG_TRACE, g_mlnx_dbg_lvl);\r
575         return IB_SUCCESS;\r
576 \r
577 cleanup:\r
578         CL_TRACE(CL_DBG_ERROR, g_mlnx_dbg_lvl, ("completes with ERROR status %d\n", status));\r
579         CL_EXIT(MLNX_DBG_TRACE, g_mlnx_dbg_lvl);\r
580         return status;\r
581 }\r