[IBAL] Set client reregister bit in port capabilities during CA addition.
[mirror/winof/.git] / core / al / al_ci_ca_shared.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  * Copyright (c) 1996-2003 Intel 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 #include "al_ci_ca.h"\r
34 #include "al_common.h"\r
35 #include "al_cq.h"\r
36 #include "al_debug.h"\r
37 #include "al_mgr.h"\r
38 #include "al_pnp.h"\r
39 #include "al_qp.h"\r
40 #include "ib_common.h"\r
41 \r
42 \r
43 void\r
44 ci_ca_process_event_cb(\r
45         IN                              cl_async_proc_item_t*           p_async_item );\r
46 \r
47 void\r
48 ca_process_async_event_cb(\r
49         IN              const   ib_async_event_rec_t* const     p_event_rec );\r
50 \r
51 void\r
52 ca_async_event_cb(\r
53         IN                              ib_async_event_rec_t* const     p_event_rec );\r
54 \r
55 \r
56 void\r
57 free_ci_ca(\r
58         IN                              al_obj_t*                                       p_obj )\r
59 {\r
60         al_ci_ca_t                              *p_ci_ca;\r
61 \r
62         CL_ASSERT( p_obj );\r
63         p_ci_ca = PARENT_STRUCT( p_obj, al_ci_ca_t, obj );\r
64 \r
65         cl_spinlock_destroy( &p_ci_ca->attr_lock );\r
66         cl_qpool_destroy( &p_ci_ca->event_pool );\r
67 \r
68         if( p_ci_ca->port_array )\r
69                 cl_free( p_ci_ca->port_array );\r
70 \r
71         /* Free the PnP attributes buffer. */\r
72         if( p_ci_ca->p_pnp_attr )\r
73                 cl_free( p_ci_ca->p_pnp_attr );\r
74 \r
75         destroy_al_obj( p_obj );\r
76         cl_free( p_ci_ca );\r
77 }\r
78 \r
79 void\r
80 add_ca(\r
81         IN                              al_ci_ca_t* const                       p_ci_ca,\r
82         IN              const   ib_ca_handle_t                          h_ca )\r
83 {\r
84         cl_spinlock_acquire( &p_ci_ca->obj.lock );\r
85         cl_qlist_insert_tail( &p_ci_ca->ca_list, &h_ca->list_item );\r
86         ref_al_obj( &p_ci_ca->obj );\r
87         cl_spinlock_release( &p_ci_ca->obj.lock );\r
88 }\r
89 \r
90 \r
91 \r
92 void\r
93 remove_ca(\r
94         IN              const   ib_ca_handle_t                          h_ca )\r
95 {\r
96         al_ci_ca_t                      *p_ci_ca;\r
97 \r
98         p_ci_ca = h_ca->obj.p_ci_ca;\r
99 \r
100         cl_spinlock_acquire( &p_ci_ca->obj.lock );\r
101         cl_qlist_remove_item( &p_ci_ca->ca_list, &h_ca->list_item );\r
102         cl_spinlock_release( &p_ci_ca->obj.lock );\r
103         deref_al_obj( &p_ci_ca->obj );\r
104 }\r
105 \r
106 \r
107 \r
108 ib_api_status_t\r
109 get_port_info(\r
110         IN                              al_ci_ca_t                                      *p_ci_ca )\r
111 {\r
112         ib_api_status_t         status;\r
113         ib_ca_attr_t            *p_ca_attr;\r
114         uint32_t                        attr_size;\r
115         uint8_t                         i;\r
116 \r
117         CL_ENTER( AL_DBG_CA, g_al_dbg_lvl );\r
118 \r
119         /* Get the size of the CA attribute structure. */\r
120         status = ib_query_ca( p_ci_ca->h_ca, NULL, &attr_size );\r
121         if( status != IB_INSUFFICIENT_MEMORY )\r
122         {\r
123                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
124                         ("ib_query_ca failed with status %s.\n", ib_get_err_str(status)) );\r
125                 return status;\r
126         }\r
127 \r
128         /* Allocate enough space to store the attribute structure. */\r
129         p_ca_attr = cl_malloc( attr_size );\r
130         if( !p_ca_attr )\r
131         {\r
132                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
133                         ("cl_malloc failed to allocate p_ca_attr!\n") );\r
134                 return IB_INSUFFICIENT_RESOURCES;\r
135         }\r
136 \r
137         /* Query the CA attributes. */\r
138         status = ib_query_ca( p_ci_ca->h_ca, p_ca_attr, &attr_size );\r
139         if( status != IB_SUCCESS )\r
140         {\r
141                 cl_free( p_ca_attr );\r
142 \r
143                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
144                         ("ib_query_ca failed with status %s.\n", ib_get_err_str(status)) );\r
145                 return status;\r
146         }\r
147 \r
148         /* Allocate the port GUID array. */\r
149         p_ci_ca->port_array = cl_malloc( sizeof( ib_net64_t ) *\r
150                 p_ca_attr->num_ports );\r
151         if( !p_ci_ca->port_array )\r
152         {\r
153                 cl_free( p_ca_attr );\r
154 \r
155                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
156                         ("cl_malloc failed to allocate port_array!\n") );\r
157                 return IB_INSUFFICIENT_RESOURCES;\r
158         }\r
159         p_ci_ca->num_ports = p_ca_attr->num_ports;\r
160 \r
161         /* Copy the necessary port information. */\r
162         for( i = 0; i < p_ca_attr->num_ports; i++ )\r
163         {\r
164                 p_ci_ca->port_array[i] = p_ca_attr->p_port_attr[i].port_guid;\r
165 \r
166 #ifdef CL_KERNEL\r
167                 /* Set the port's client reregister bit. */\r
168                 {\r
169                         ib_port_attr_mod_t attr;\r
170 \r
171                         attr.cap.client_reregister = TRUE;\r
172                         ib_modify_ca( p_ci_ca->h_ca, i + 1,\r
173                                 IB_CA_MOD_IS_CLIENT_REREGISTER_SUPPORTED, &attr );\r
174                 }\r
175 #endif\r
176         }\r
177 \r
178         cl_free( p_ca_attr );\r
179 \r
180         CL_EXIT( AL_DBG_CA, g_al_dbg_lvl );\r
181         return IB_SUCCESS;\r
182 }\r
183 \r
184 \r
185 \r
186 void\r
187 ci_ca_async_event(\r
188         IN              const   ib_async_event_rec_t* const     p_event_rec )\r
189 {\r
190         al_obj_t*                               p_obj;\r
191         cl_pool_item_t*                 p_item;\r
192         event_item_t*                   p_event_item;\r
193 \r
194         CL_ENTER( AL_DBG_CA, g_al_dbg_lvl );\r
195 \r
196         CL_ASSERT( p_event_rec );\r
197 \r
198         p_obj = (al_obj_t* __ptr64)p_event_rec->context;\r
199 \r
200         /* Block the destruction of the object until a reference is taken. */\r
201         cl_spinlock_acquire( &p_obj->lock );\r
202         if( p_obj->state == CL_DESTROYING )\r
203         {\r
204                 /* Ignore events if the object is being destroyed. */\r
205                 cl_spinlock_release( &p_obj->lock );\r
206                 CL_EXIT( AL_DBG_CA, g_al_dbg_lvl );\r
207                 return;\r
208         }\r
209 \r
210         /*\r
211          * Get an event item from the pool.  If an object is a child of\r
212          * a CA (e.g., CQ or QP) it will have valid p_ci_ca pointer.\r
213          * For CA's, the object is the actual p_ci_ca pointer itself.\r
214          */\r
215         if( p_obj->p_ci_ca )\r
216         {\r
217                 cl_spinlock_acquire( &p_obj->p_ci_ca->obj.lock );\r
218                 p_item = cl_qpool_get( &p_obj->p_ci_ca->event_pool );\r
219                 cl_spinlock_release( &p_obj->p_ci_ca->obj.lock );\r
220         }\r
221         else\r
222         {\r
223                 p_item = cl_qpool_get( &((al_ci_ca_t*)p_obj)->event_pool );\r
224         }\r
225         if( !p_item )\r
226         {\r
227                 /* Could not get an item.  This event will not be reported. */\r
228                 cl_spinlock_release( &p_obj->lock );\r
229                 CL_EXIT( AL_DBG_CA, g_al_dbg_lvl );\r
230                 return;\r
231         }\r
232 \r
233         /* Hold a reference to prevent destruction until the async_item runs. */\r
234         ref_al_obj( p_obj );\r
235 \r
236         cl_spinlock_release( &p_obj->lock );\r
237 \r
238         /* Initialize the item with the asynchronous event information. */\r
239         p_event_item = PARENT_STRUCT( p_item, event_item_t, async_item.pool_item );\r
240         p_event_item->event_rec.code = p_event_rec->code;\r
241         p_event_item->event_rec.context = p_event_rec->context;\r
242 \r
243         /* Queue the item on the asynchronous callback thread for processing. */\r
244         p_event_item->async_item.pfn_callback = ci_ca_process_event_cb;\r
245         cl_async_proc_queue( gp_async_proc_mgr, &p_event_item->async_item );\r
246 \r
247         CL_EXIT( AL_DBG_CA, g_al_dbg_lvl );\r
248 }\r
249 \r
250 \r
251 \r
252 void\r
253 ci_ca_process_event_cb(\r
254         IN                              cl_async_proc_item_t*           p_async_item )\r
255 {\r
256         event_item_t*                   p_event_item;\r
257         al_obj_t*                               p_obj;\r
258 \r
259         CL_ENTER( AL_DBG_CA, g_al_dbg_lvl );\r
260 \r
261         CL_ASSERT( p_async_item );\r
262 \r
263         p_event_item = PARENT_STRUCT( p_async_item, event_item_t,\r
264                 async_item.pool_item );\r
265 \r
266         p_obj = (al_obj_t* __ptr64)p_event_item->event_rec.context;\r
267 \r
268         switch( p_event_item->event_rec.code )\r
269         {\r
270         case IB_AE_QP_COMM:\r
271         case IB_AE_QP_APM:\r
272         case IB_AE_QP_APM_ERROR:\r
273         case IB_AE_QP_FATAL:\r
274         case IB_AE_RQ_ERROR:\r
275         case IB_AE_SQ_ERROR:\r
276         case IB_AE_SQ_DRAINED:\r
277         case IB_AE_WQ_REQ_ERROR:\r
278         case IB_AE_WQ_ACCESS_ERROR:\r
279                 qp_async_event_cb( &p_event_item->event_rec );\r
280                 break;\r
281 \r
282         case IB_AE_CQ_ERROR:\r
283                 cq_async_event_cb( &p_event_item->event_rec );\r
284                 break;\r
285 \r
286         case IB_AE_PORT_TRAP:\r
287         case IB_AE_PORT_DOWN:\r
288         case IB_AE_PORT_ACTIVE:\r
289         case IB_AE_CLIENT_REREGISTER:\r
290 #ifdef CL_KERNEL\r
291                 /* The SMI polling routine may report a PnP event. */\r
292                 force_smi_poll();\r
293 #endif\r
294                 /* Fall through next case. */\r
295 \r
296         case IB_AE_LOCAL_FATAL:\r
297                 ca_process_async_event_cb( &p_event_item->event_rec );\r
298                 break;\r
299 \r
300         /* Unhandled events - optional per IBA spec. */\r
301         case IB_AE_QKEY_TRAP:\r
302         case IB_AE_PKEY_TRAP:\r
303         case IB_AE_MKEY_TRAP:\r
304         case IB_AE_BKEY_TRAP:\r
305         case IB_AE_BUF_OVERRUN:\r
306         case IB_AE_LINK_INTEGRITY:\r
307         case IB_AE_FLOW_CTRL_ERROR:\r
308         case IB_AE_SYSIMG_GUID_TRAP:\r
309         default:\r
310                 break;\r
311         }\r
312 \r
313         /*\r
314          * Return the event item to the pool.  If an object is a child of\r
315          * a CA (e.g., CQ or QP) it will have valid p_ci_ca pointer.\r
316          * For CA's, the object is the actual p_ci_ca pointer itself.\r
317          */\r
318         if( p_obj->p_ci_ca )\r
319         {\r
320                 cl_spinlock_acquire( &p_obj->p_ci_ca->obj.lock );\r
321                 cl_qpool_put( &p_obj->p_ci_ca->event_pool,\r
322                         &p_event_item->async_item.pool_item );\r
323                 cl_spinlock_release( &p_obj->p_ci_ca->obj.lock );\r
324         }\r
325         else\r
326         {\r
327                 cl_spinlock_acquire( &p_obj->lock );\r
328                 cl_qpool_put( &((al_ci_ca_t*)p_obj)->event_pool,\r
329                         &p_event_item->async_item.pool_item );\r
330                 cl_spinlock_release( &p_obj->lock );\r
331         }\r
332 \r
333         /* Dereference the object. */\r
334         deref_al_obj( p_obj );\r
335 \r
336         CL_EXIT( AL_DBG_CA, g_al_dbg_lvl );\r
337 }\r
338 \r
339 \r
340 \r
341 /*\r
342  * Process an asynchronous event on a CA.  Notify all clients of the event.\r
343  */\r
344 void\r
345 ca_process_async_event_cb(\r
346         IN              const   ib_async_event_rec_t* const     p_event_rec )\r
347 {\r
348         al_ci_ca_t*                             p_ci_ca;\r
349         cl_list_item_t*                 p_list_item;\r
350         ib_ca_handle_t                  h_ca;\r
351         ib_async_event_rec_t    event_rec;\r
352 \r
353         CL_ASSERT( p_event_rec );\r
354         p_ci_ca = (al_ci_ca_t* __ptr64)p_event_rec->context;\r
355 \r
356         /* Report the CA event to all clients. */\r
357         cl_spinlock_acquire( &p_ci_ca->obj.lock );\r
358         for( p_list_item = cl_qlist_head( &p_ci_ca->ca_list );\r
359                  p_list_item != cl_qlist_end( &p_ci_ca->ca_list );\r
360                  p_list_item = cl_qlist_next( p_list_item ) )\r
361         {\r
362                 cl_spinlock_release( &p_ci_ca->obj.lock );\r
363 \r
364                 h_ca = PARENT_STRUCT( p_list_item, ib_ca_t, list_item );\r
365 \r
366                 event_rec.handle.h_ca = h_ca;\r
367                 event_rec.code = p_event_rec->code;\r
368                 ca_async_event_cb( &event_rec );\r
369 \r
370                 cl_spinlock_acquire( &p_ci_ca->obj.lock );\r
371         }\r
372         cl_spinlock_release( &p_ci_ca->obj.lock );\r
373 }\r
374 \r
375 \r
376 \r
377 /*\r
378  * Process an asynchronous event on a CA.  Notify the user of the event.\r
379  */\r
380 void\r
381 ca_async_event_cb(\r
382         IN                              ib_async_event_rec_t* const     p_event_rec )\r
383 {\r
384         ib_ca_handle_t                  h_ca;\r
385 \r
386         CL_ASSERT( p_event_rec );\r
387         h_ca = p_event_rec->handle.h_ca;\r
388 \r
389         p_event_rec->context = (void*)h_ca->obj.context;\r
390         p_event_rec->handle.h_ca = h_ca;\r
391 \r
392         if( h_ca->pfn_event_cb )\r
393                 h_ca->pfn_event_cb( p_event_rec );\r
394 }\r
395 \r
396 \r
397 \r
398 void\r
399 ca_event_cb(\r
400         IN                              ib_async_event_rec_t            *p_event_rec )\r
401 {\r
402         UNUSED_PARAM( p_event_rec );\r
403 }\r
404 \r
405 \r
406 \r
407 /*\r
408  * Returns a port's index on its CA for the given port GUID.\r
409  */\r
410 ib_api_status_t\r
411 get_port_num(\r
412         IN                              al_ci_ca_t* const                       p_ci_ca,\r
413         IN              const   ib_net64_t                                      port_guid,\r
414                 OUT                     uint8_t                                         *p_port_num OPTIONAL )\r
415 {\r
416         uint8_t         i;\r
417 \r
418         /* Find a matching port GUID on this CI CA. */\r
419         for( i = 0; i < p_ci_ca->num_ports; i++ )\r
420         {\r
421                 if( p_ci_ca->port_array[i] == port_guid )\r
422                 {\r
423                         /* The port number is the index plus one. */\r
424                         if( p_port_num )\r
425                                 *p_port_num = (uint8_t)(i + 1);\r
426                         return IB_SUCCESS;\r
427                 }\r
428         }\r
429 \r
430         /* The port GUID was not found. */\r
431         return IB_INVALID_GUID;\r
432 }\r
433 \r
434 \r
435 \r
436 ib_port_attr_t*\r
437 get_port_attr(\r
438         IN                              ib_ca_attr_t * const            p_ca_attr,\r
439         IN                              ib_gid_t * const                        p_gid )\r
440 {\r
441         uintn_t                 port_index, gid_index;\r
442         ib_port_attr_t  *p_port_attr;\r
443 \r
444         CL_ENTER( AL_DBG_CA, g_al_dbg_lvl );\r
445 \r
446         if( !p_ca_attr || !p_gid )\r
447         {\r
448                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
449                         ("No p_ca_attr or p_gid.\n") );\r
450                 return NULL;\r
451         }\r
452 \r
453         /* Check all ports on this HCA for matching GID. */\r
454         for( port_index = 0; port_index < p_ca_attr->num_ports; port_index++ )\r
455         {\r
456                 p_port_attr = &p_ca_attr->p_port_attr[port_index];\r
457 \r
458                 for( gid_index = 0; gid_index < p_port_attr->num_gids; gid_index++ )\r
459                 {\r
460                         if( !cl_memcmp( &p_port_attr->p_gid_table[gid_index],\r
461                                 p_gid, sizeof(ib_gid_t) ) )\r
462                         {\r
463                                 CL_EXIT( AL_DBG_CA, g_al_dbg_lvl );\r
464                                 return p_port_attr;\r
465                         }\r
466                 }\r
467         }\r
468 \r
469         CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl, ("No match found.\n") );\r
470         return NULL;\r
471 }\r
472 \r
473 \r
474 \r
475 uint16_t\r
476 get_pkey_index(\r
477         IN                              ib_port_attr_t * const          p_port_attr,\r
478         IN              const   uint16_t                                        pkey )\r
479 {\r
480         uint16_t                        pkey_index;\r
481 \r
482         if( !p_port_attr )\r
483                 return BAD_PKEY_INDEX;\r
484 \r
485         for( pkey_index = 0; pkey_index < p_port_attr->num_pkeys; pkey_index++ )\r
486         {\r
487                 if( p_port_attr->p_pkey_table[pkey_index] == pkey )\r
488                         return pkey_index;\r
489         }\r
490         return BAD_PKEY_INDEX;\r
491 }\r
492 \r
493 \r
494 /*\r
495  * Reads the CA attributes from verbs.\r
496  */\r
497 ib_api_status_t\r
498 ci_ca_update_attr(\r
499         IN                              al_ci_ca_t*                                     p_ci_ca,\r
500                 OUT                     ib_ca_attr_t**                          pp_old_pnp_attr )\r
501 {\r
502         ib_ca_attr_t            *p_pnp_attr;\r
503         uint32_t                        attr_size;\r
504         ib_api_status_t         status;\r
505 \r
506         CL_ENTER( AL_DBG_CA, g_al_dbg_lvl );\r
507 \r
508         /* Query to get the CA attributes size. */\r
509         attr_size = 0;\r
510         status = ib_query_ca( p_ci_ca->h_ca, NULL, &attr_size );\r
511         CL_ASSERT( status == IB_INSUFFICIENT_MEMORY );\r
512 \r
513         /*\r
514          * Allocate the new CA attributes buffer.\r
515          * Double the buffer size for PnP and user reporting halves.\r
516          */\r
517         p_pnp_attr = (ib_ca_attr_t*)cl_zalloc( attr_size * 2 );\r
518         if( !p_pnp_attr )\r
519         {\r
520                 CL_TRACE_EXIT( AL_DBG_CA, g_al_dbg_lvl,\r
521                         ("Unable to allocate buffer for PnP attributes\n") );\r
522                 return IB_INSUFFICIENT_MEMORY;\r
523         }\r
524 \r
525         /* Read the attributes. */\r
526         status = ib_query_ca( p_ci_ca->h_ca, p_pnp_attr, &attr_size );\r
527         if( status != IB_SUCCESS )\r
528         {\r
529                 CL_TRACE_EXIT( AL_DBG_CA, g_al_dbg_lvl,\r
530                         ("Unable to query attributes\n") );\r
531                 cl_free( p_pnp_attr );\r
532                 return status;\r
533         }\r
534 \r
535         ci_ca_excl_lock_attr( p_ci_ca );\r
536         if( pp_old_pnp_attr )\r
537                 *pp_old_pnp_attr = p_ci_ca->p_pnp_attr;\r
538         p_ci_ca->p_pnp_attr = p_pnp_attr;\r
539 \r
540         /*\r
541          * Initialize pointer to the user reporting half.\r
542          * This buffer is used to report this CAs attributes to users.\r
543          */\r
544         p_ci_ca->p_user_attr = (ib_ca_attr_t*)(((uint8_t*)p_pnp_attr) + attr_size);\r
545         ci_ca_unlock_attr( p_ci_ca );\r
546 \r
547         CL_EXIT( AL_DBG_CA, g_al_dbg_lvl );\r
548         return IB_SUCCESS;\r
549 }\r
550 \r
551 \r
552 \r
553 void\r
554 ci_ca_lock_attr(\r
555         IN                              al_ci_ca_t* const                       p_ci_ca )\r
556 {\r
557         CL_ASSERT( p_ci_ca );\r
558 \r
559         cl_spinlock_acquire( &p_ci_ca->attr_lock );\r
560 }\r
561 \r
562 \r
563 void\r
564 ci_ca_excl_lock_attr(\r
565         IN                              al_ci_ca_t* const                       p_ci_ca )\r
566 {\r
567         CL_ASSERT( p_ci_ca );\r
568 \r
569         cl_spinlock_acquire( &p_ci_ca->attr_lock );\r
570 }\r
571 \r
572 \r
573 void\r
574 ci_ca_unlock_attr(\r
575         IN                              al_ci_ca_t* const                       p_ci_ca )\r
576 {\r
577         CL_ASSERT( p_ci_ca );\r
578 \r
579         cl_spinlock_release( &p_ci_ca->attr_lock );\r
580 }\r