[MT23108] Removed linker dependency on IBAL.
[mirror/winof/.git] / hw / mt23108 / kernel / hca_smp.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  *\r
4  * This software is available to you under the OpenIB.org BSD license\r
5  * below:\r
6  *\r
7  *     Redistribution and use in source and binary forms, with or\r
8  *     without modification, are permitted provided that the following\r
9  *     conditions are met:\r
10  *\r
11  *      - Redistributions of source code must retain the above\r
12  *        copyright notice, this list of conditions and the following\r
13  *        disclaimer.\r
14  *\r
15  *      - Redistributions in binary form must reproduce the above\r
16  *        copyright notice, this list of conditions and the following\r
17  *        disclaimer in the documentation and/or other materials\r
18  *        provided with the distribution.\r
19  *\r
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
23  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
24  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
25  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
27  * SOFTWARE.\r
28  *\r
29  * $Id$\r
30  */\r
31 \r
32 \r
33 /*\r
34  * SMP handling of IB Access Layer VPD for Mellanox MT23108 HCA\r
35  */\r
36 \r
37 \r
38 #include "hca_data.h"\r
39 #include "hca_debug.h"\r
40 \r
41 \r
42 boolean_t\r
43 mlnx_cachable_guid_info(\r
44         IN              const   mlnx_cache_t* const                     p_cache,\r
45         IN              const   ib_mad_t                                        *p_mad_in,\r
46                 OUT                     ib_mad_t                                        *p_mad_out )\r
47 {\r
48         uint32_t                        idx;\r
49 \r
50         /* Get the table selector from the attribute */\r
51         idx = cl_ntoh32( p_mad_in->attr_mod );\r
52 \r
53         /*\r
54          * TODO: Setup the response to fail the MAD instead of sending\r
55          * it down to the HCA.\r
56          */\r
57         if( idx > 31 )\r
58                 return FALSE;\r
59 \r
60         if( !p_cache->guid_block[idx].valid )\r
61                 return FALSE;\r
62 \r
63         /*\r
64          * If a SET, see if the set is identical to the cache,\r
65          * in which case it's a no-op.\r
66          */\r
67         if( p_mad_in->method == IB_MAD_METHOD_SET )\r
68         {\r
69                 if( !cl_memcmp( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_in ),\r
70                         &p_cache->guid_block[idx].tbl, sizeof(ib_guid_info_t) ) )\r
71                 {\r
72                         /* The set is requesting a change. */\r
73                         return FALSE;\r
74                 }\r
75         }\r
76         CL_ASSERT( p_mad_in->method == IB_MAD_METHOD_GET );\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;\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         CL_ASSERT( p_mad_in->method == IB_MAD_METHOD_GET );\r
129 \r
130         /* Setup the response mad. */\r
131         cl_memcpy( p_mad_out, p_mad_in, MAD_BLOCK_SIZE );\r
132         p_mad_out->method |= IB_MAD_METHOD_RESP_MASK;\r
133         if( p_mad_out->mgmt_class == IB_MCLASS_SUBN_DIR )\r
134                 p_mad_out->status = IB_SMP_DIRECTION;\r
135         else\r
136                 p_mad_out->status = 0;\r
137 \r
138         /* Copy the cached data. */\r
139         cl_memcpy( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out ),\r
140                 &p_cache->pkey_tbl[idx].tbl, sizeof(ib_pkey_table_info_t) );\r
141 \r
142         return TRUE;\r
143 }\r
144 \r
145 \r
146 boolean_t\r
147 mlnx_cachable_sl_vl_table(\r
148         IN              const   mlnx_cache_t* const                     p_cache,\r
149         IN              const   ib_mad_t                                        *p_mad_in,\r
150                 OUT                     ib_mad_t                                        *p_mad_out )\r
151 {\r
152         if( !p_cache->sl_vl.valid )\r
153                 return FALSE;\r
154 \r
155         /*\r
156          * If a SET, see if the set is identical to the cache,\r
157          * in which case it's a no-op.\r
158          */\r
159         if( p_mad_in->method == IB_MAD_METHOD_SET )\r
160         {\r
161                 if( !cl_memcmp( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_in ),\r
162                         &p_cache->sl_vl.tbl, sizeof(ib_slvl_table_t) ) )\r
163                 {\r
164                         /* The set is requesting a change. */\r
165                         return FALSE;\r
166                 }\r
167         }\r
168         CL_ASSERT( p_mad_in->method == IB_MAD_METHOD_GET );\r
169 \r
170         /* Setup the response mad. */\r
171         cl_memcpy( p_mad_out, p_mad_in, MAD_BLOCK_SIZE );\r
172         p_mad_out->method |= IB_MAD_METHOD_RESP_MASK;\r
173         if( p_mad_out->mgmt_class == IB_MCLASS_SUBN_DIR )\r
174                 p_mad_out->status = IB_SMP_DIRECTION;\r
175         else\r
176                 p_mad_out->status = 0;\r
177 \r
178         /* Copy the cached data. */\r
179         cl_memcpy( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out ),\r
180                 &p_cache->sl_vl.tbl, sizeof(ib_slvl_table_t) );\r
181 \r
182         return TRUE;\r
183 }\r
184 \r
185 \r
186 boolean_t\r
187 mlnx_cachable_vl_arb_table(\r
188         IN              const   mlnx_cache_t* const                     p_cache,\r
189         IN              const   ib_mad_t                                        *p_mad_in,\r
190                 OUT                     ib_mad_t                                        *p_mad_out )\r
191 {\r
192         uint16_t                        idx;\r
193 \r
194         /* Get the table selector from the attribute */\r
195         idx = ((uint16_t)(cl_ntoh32( p_mad_in->attr_mod ) >> 16)) - 1;\r
196 \r
197         /*\r
198          * TODO: Setup the response to fail the MAD instead of sending\r
199          * it down to the HCA.\r
200          */\r
201         if( idx > 3 )\r
202                 return FALSE;\r
203 \r
204         if( !p_cache->vl_arb[idx].valid )\r
205                 return FALSE;\r
206 \r
207         /*\r
208          * If a SET, see if the set is identical to the cache,\r
209          * in which case it's a no-op.\r
210          */\r
211         if( p_mad_in->method == IB_MAD_METHOD_SET )\r
212         {\r
213                 if( !cl_memcmp( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_in ),\r
214                         &p_cache->vl_arb[idx].tbl, sizeof(ib_vl_arb_table_t) ) )\r
215                 {\r
216                         /* The set is requesting a change. */\r
217                         return FALSE;\r
218                 }\r
219         }\r
220         CL_ASSERT( p_mad_in->method == IB_MAD_METHOD_GET );\r
221 \r
222         /* Setup the response mad. */\r
223         cl_memcpy( p_mad_out, p_mad_in, MAD_BLOCK_SIZE );\r
224         p_mad_out->method |= IB_MAD_METHOD_RESP_MASK;\r
225         if( p_mad_out->mgmt_class == IB_MCLASS_SUBN_DIR )\r
226                 p_mad_out->status = IB_SMP_DIRECTION;\r
227         else\r
228                 p_mad_out->status = 0;\r
229 \r
230         /* Copy the cached data. */\r
231         cl_memcpy( ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out ),\r
232                 &p_cache->vl_arb[idx].tbl, sizeof(ib_vl_arb_table_t) );\r
233 \r
234         return TRUE;\r
235 }\r
236 \r
237 \r
238 boolean_t\r
239 mlnx_cachable_port_info(\r
240         IN              const   mlnx_cache_t* const                     p_cache,\r
241         IN              const   uint8_t                                         port_num,\r
242         IN              const   ib_mad_t                                        *p_mad_in,\r
243                 OUT                     ib_mad_t                                        *p_mad_out )\r
244 {\r
245         ib_port_info_t          *p_port_info;\r
246 \r
247         UNUSED_PARAM( p_mad_out );\r
248 \r
249         if( !p_cache->port_info.valid )\r
250                 return FALSE;\r
251 \r
252         if( p_mad_in->method == IB_MAD_METHOD_GET )\r
253                 return FALSE;\r
254 \r
255         /*\r
256          * NOTE: Even though the input MAD is const, we modify it to change\r
257          * some parameters to no-ops to compensate for problems in the HCA chip.\r
258          */\r
259         p_port_info =\r
260                 (ib_port_info_t*)ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_in );\r
261 \r
262         /* We can only cache requests for the same port that the SMP came in on. */\r
263         if( p_mad_in->attr_mod != 0 &&\r
264                 cl_ntoh32( p_mad_in->attr_mod ) != port_num )\r
265         {\r
266                 return FALSE;\r
267         }\r
268 \r
269         /*\r
270          * to avoid unnecessary glitches in port state, we translate these\r
271          * fields to NOP when there is no change.  Note these fields cannot\r
272          * change within the hardware without a Set going through here.\r
273          */\r
274         if( p_port_info->link_width_enabled ==\r
275                 p_cache->port_info.info.link_width_enabled )\r
276         {\r
277                 p_port_info->link_width_enabled = 0;\r
278         }\r
279         if( (p_port_info->state_info2 & 0x0F) ==\r
280                 (p_cache->port_info.info.state_info2 & 0x0F) )\r
281         {\r
282                 p_port_info->state_info2 &= 0xF0;\r
283         }\r
284         if( (p_port_info->link_speed & 0x0F) ==\r
285                 (p_cache->port_info.info.link_speed & 0x0F) )\r
286         {\r
287                 p_port_info->link_speed &= 0xF0;\r
288         }\r
289         if( (p_port_info->vl_enforce & 0xF0) ==\r
290                 (p_cache->port_info.info.vl_enforce & 0xF0) )\r
291         {\r
292                 p_port_info->vl_enforce &= 0x0F;\r
293         }\r
294 \r
295         /*\r
296          * We modified the input MAD to change things to no-ops, but\r
297          * we can't actually fulfill the MAD with cached data.\r
298          */\r
299         return FALSE;\r
300 }\r
301 \r
302 \r
303 boolean_t\r
304 mlnx_cachable_mad(\r
305         IN              const   ib_ca_handle_t                          h_ca,\r
306         IN              const   uint8_t                                         port_num,\r
307         IN              const   ib_mad_t                                        *p_mad_in,\r
308                 OUT                     ib_mad_t                                        *p_mad_out )\r
309 {\r
310         if( p_mad_in->method != IB_MCLASS_SUBN_DIR &&\r
311                 p_mad_in->method != IB_MCLASS_SUBN_LID )\r
312         {\r
313                 return FALSE;\r
314         }\r
315 \r
316         switch( p_mad_in->attr_id )\r
317         {\r
318         case IB_MAD_ATTR_GUID_INFO:\r
319                 return mlnx_cachable_guid_info(\r
320                         &h_ca->cache[port_num-1], p_mad_in, p_mad_out );\r
321 \r
322         case IB_MAD_ATTR_P_KEY_TABLE:\r
323                 return mlnx_cachable_pkey_table(\r
324                         &h_ca->cache[port_num-1], p_mad_in, p_mad_out );\r
325 \r
326         case IB_MAD_ATTR_SLVL_TABLE:\r
327                 return mlnx_cachable_sl_vl_table(\r
328                         &h_ca->cache[port_num-1], p_mad_in, p_mad_out );\r
329 \r
330         case IB_MAD_ATTR_VL_ARBITRATION:\r
331                 return mlnx_cachable_vl_arb_table(\r
332                         &h_ca->cache[port_num-1], p_mad_in, p_mad_out );\r
333 \r
334         case IB_MAD_ATTR_PORT_INFO:\r
335                 return mlnx_cachable_port_info(\r
336                         &h_ca->cache[port_num-1], port_num, p_mad_in, p_mad_out );\r
337 \r
338         default:\r
339                 break;\r
340         }\r
341         return FALSE;\r
342 }\r
343 \r
344 \r
345 void\r
346 mlnx_update_guid_info(\r
347         IN                              mlnx_cache_t* const                     p_cache,\r
348         IN              const   ib_mad_t* const                         p_mad_out )\r
349 {\r
350         uint32_t                        idx;\r
351 \r
352         /* Get the table selector from the attribute */\r
353         idx = cl_ntoh32( p_mad_out->attr_mod );\r
354 \r
355         /*\r
356          * We only get successful MADs here, so invalid settings\r
357          * shouldn't happen.\r
358          */\r
359         CL_ASSERT( idx <= 31 );\r
360 \r
361         cl_memcpy( &p_cache->guid_block[idx].tbl,\r
362                 ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out ),\r
363                 sizeof(ib_guid_info_t) );\r
364         p_cache->guid_block[idx].valid = TRUE;\r
365 }\r
366 \r
367 \r
368 void\r
369 mlnx_update_pkey_table(\r
370         IN                              mlnx_cache_t* const                     p_cache,\r
371         IN              const   ib_mad_t* const                         p_mad_out )\r
372 {\r
373         uint16_t                        idx;\r
374 \r
375         /* Get the table selector from the attribute */\r
376         idx = ((uint16_t)cl_ntoh32( p_mad_out->attr_mod ));\r
377 \r
378         ASSERT( idx <= 2047 );\r
379 \r
380         cl_memcpy( &p_cache->pkey_tbl[idx].tbl,\r
381                 ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out ),\r
382                 sizeof(ib_pkey_table_info_t) );\r
383         p_cache->pkey_tbl[idx].valid = TRUE;\r
384 }\r
385 \r
386 \r
387 void\r
388 mlnx_update_sl_vl_table(\r
389         IN                              mlnx_cache_t* const                     p_cache,\r
390         IN              const   ib_mad_t* const                         p_mad_out )\r
391 {\r
392         cl_memcpy( &p_cache->sl_vl.tbl,\r
393                 ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out ),\r
394                 sizeof(ib_slvl_table_t) );\r
395         p_cache->sl_vl.valid = TRUE;\r
396 }\r
397 \r
398 \r
399 void\r
400 mlnx_update_vl_arb_table(\r
401         IN                              mlnx_cache_t* const                     p_cache,\r
402         IN              const   ib_mad_t* const                         p_mad_out )\r
403 {\r
404         uint16_t                        idx;\r
405 \r
406         /* Get the table selector from the attribute */\r
407         idx = ((uint16_t)(cl_ntoh32( p_mad_out->attr_mod ) >> 16)) - 1;\r
408 \r
409         CL_ASSERT( idx <= 3 );\r
410 \r
411         cl_memcpy( &p_cache->vl_arb[idx].tbl,\r
412                 ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out ),\r
413                 sizeof(ib_vl_arb_table_t) );\r
414         p_cache->vl_arb[idx].valid = TRUE;\r
415 }\r
416 \r
417 \r
418 void\r
419 mlnx_update_port_info(\r
420         IN              const   mlnx_cache_t* const                     p_cache,\r
421         IN              const   uint8_t                                         port_num,\r
422         IN              const   ib_mad_t* const                         p_mad_out )\r
423 {\r
424         UNUSED_PARAM( p_cache );\r
425 \r
426         /* We can only cache requests for the same port that the SMP came in on. */\r
427         /* TODO: Add synchronization to support getting data from other ports. */\r
428         if( p_mad_out->attr_mod != 0 &&\r
429                 cl_ntoh32( p_mad_out->attr_mod ) != port_num )\r
430         {\r
431                 return;\r
432         }\r
433 \r
434         /* TODO: Setup the capabilites mask properly. */\r
435 }\r
436 \r
437 \r
438 void\r
439 mlnx_update_cache(\r
440         IN              const   ib_ca_handle_t                          h_ca,\r
441         IN              const   uint8_t                                         port_num,\r
442         IN              const   ib_mad_t                                        *p_mad_out )\r
443 {\r
444         if( p_mad_out->method != IB_MCLASS_SUBN_DIR &&\r
445                 p_mad_out->method != IB_MCLASS_SUBN_LID )\r
446         {\r
447                 return;\r
448         }\r
449 \r
450         /* Any successful response updates the cache. */\r
451         if( p_mad_out->status )\r
452                 return;\r
453 \r
454 \r
455         switch( p_mad_out->attr_id )\r
456         {\r
457         case IB_MAD_ATTR_GUID_INFO:\r
458                 mlnx_update_guid_info(\r
459                         &h_ca->cache[port_num-1], p_mad_out );\r
460                 break;\r
461 \r
462         case IB_MAD_ATTR_P_KEY_TABLE:\r
463                 mlnx_update_pkey_table(\r
464                         &h_ca->cache[port_num-1], p_mad_out );\r
465                 break;\r
466 \r
467         case IB_MAD_ATTR_SLVL_TABLE:\r
468                 mlnx_update_sl_vl_table(\r
469                         &h_ca->cache[port_num-1], p_mad_out );\r
470                 break;\r
471 \r
472         case IB_MAD_ATTR_VL_ARBITRATION:\r
473                 mlnx_update_vl_arb_table(\r
474                         &h_ca->cache[port_num-1], p_mad_out );\r
475                 break;\r
476 \r
477         case IB_MAD_ATTR_PORT_INFO:\r
478                 mlnx_update_port_info(\r
479                         &h_ca->cache[port_num-1], port_num, p_mad_out );\r
480                 break;\r
481 \r
482         default:\r
483                 break;\r
484         }\r
485 \r
486 }\r
487 \r
488 \r
489 /*\r
490  * Local MAD Support Verbs. For CAs that do not support\r
491  * agents in HW.\r
492  */\r
493 ib_api_status_t\r
494 mlnx_local_mad (\r
495         IN              const   ib_ca_handle_t                          h_ca,\r
496         IN              const   uint8_t                                         port_num,\r
497         IN              const   ib_mad_t                                        *p_mad_in,\r
498                 OUT                     ib_mad_t                                        *p_mad_out )\r
499 {\r
500         ib_api_status_t         status;\r
501 \r
502         mlnx_hob_t                      *hob_p = (mlnx_hob_t *)h_ca;\r
503         u_int32_t                       hca_idx;\r
504         mlnx_hobul_t            *hobul_p;\r
505         HH_hca_dev_t            *hca_ul_info;\r
506 \r
507         CL_ENTER(MLNX_DBG_TRACE, g_mlnx_dbg_lvl);\r
508 \r
509         if (port_num > 2) {\r
510                 status = IB_INVALID_PARAMETER;\r
511                 goto cleanup;\r
512         }\r
513 \r
514         if (!hob_p || E_MARK_CA != hob_p->mark) {\r
515                 status = IB_INVALID_CA_HANDLE;\r
516                 goto cleanup;\r
517         }\r
518 \r
519         hca_idx = hob_p->index;\r
520         hobul_p = mlnx_hobul_array[hca_idx];\r
521         if (NULL == hobul_p) {\r
522                 status = IB_INVALID_CA_HANDLE;\r
523                 goto cleanup;\r
524         }\r
525 \r
526         hca_ul_info = (HH_hca_dev_t *)hobul_p->hh_hndl;\r
527         if (NULL == hca_ul_info) {\r
528                 status = IB_INVALID_CA_HANDLE;\r
529                 goto cleanup;\r
530         }\r
531 \r
532         if( !mlnx_cachable_mad( h_ca, port_num, p_mad_in, p_mad_out ) )\r
533         {\r
534                 if( HH_OK != THH_hob_process_local_mad( hobul_p->hh_hndl, port_num,\r
535                         0x0, 0, (void *)p_mad_in, p_mad_out ) )\r
536                 {\r
537                         HCA_TRACE( HCA_DBG_ERROR,\r
538                                 ("MAD failed:\n\tClass 0x%x\n\tMethod 0x%x\n\tAttr 0x%x",\r
539                                 p_mad_in->mgmt_class, p_mad_in->method, p_mad_in->attr_id ) );\r
540                         status = IB_ERROR;\r
541                         goto cleanup;\r
542                 }\r
543 \r
544                 mlnx_update_cache( h_ca, port_num, p_mad_out );\r
545         }\r
546 \r
547         /* Modify direction for Direct MAD */\r
548         if ( p_mad_in->mgmt_class == IB_MCLASS_SUBN_DIR )\r
549                 p_mad_out->status |= IB_SMP_DIRECTION;\r
550 \r
551         CL_EXIT(MLNX_DBG_TRACE, g_mlnx_dbg_lvl);\r
552         return IB_SUCCESS;\r
553 \r
554 cleanup:\r
555         CL_TRACE(CL_DBG_ERROR, g_mlnx_dbg_lvl, ("completes with ERROR status %d\n", status));\r
556         CL_EXIT(MLNX_DBG_TRACE, g_mlnx_dbg_lvl);\r
557         return status;\r
558 }\r