[IBAL] fix to 2226. cause an asynchronic event to be handled immediately (and not...
[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  * Portions Copyright (c) 2008 Microsoft Corporation.  All rights reserved.\r
5  *\r
6  * This software is available to you under the OpenIB.org BSD license\r
7  * below:\r
8  *\r
9  *     Redistribution and use in source and binary forms, with or\r
10  *     without modification, are permitted provided that the following\r
11  *     conditions are met:\r
12  *\r
13  *      - Redistributions of source code must retain the above\r
14  *        copyright notice, this list of conditions and the following\r
15  *        disclaimer.\r
16  *\r
17  *      - Redistributions in binary form must reproduce the above\r
18  *        copyright notice, this list of conditions and the following\r
19  *        disclaimer in the documentation and/or other materials\r
20  *        provided with the distribution.\r
21  *\r
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
23  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
25  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
26  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
27  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
28  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
29  * SOFTWARE.\r
30  *\r
31  * $Id$\r
32  */\r
33 \r
34 #include "al_ci_ca.h"\r
35 #include "al_common.h"\r
36 #include "al_cq.h"\r
37 #include "al_debug.h"\r
38 \r
39 #if defined(EVENT_TRACING)\r
40 #ifdef offsetof\r
41 #undef offsetof\r
42 #endif\r
43 #include "al_ci_ca_shared.tmh"\r
44 #endif\r
45 \r
46 #include "al_mgr.h"\r
47 #include "al_pnp.h"\r
48 #include "al_qp.h"\r
49 #include "al_srq.h"\r
50 #include "ib_common.h"\r
51 \r
52 \r
53 void\r
54 ci_ca_process_event_cb(\r
55         IN                              cl_async_proc_item_t*           p_async_item );\r
56 \r
57 void\r
58 ca_process_async_event_cb(\r
59         IN              const   ib_async_event_rec_t* const     p_event_rec );\r
60 \r
61 void\r
62 ca_async_event_cb(\r
63         IN                              ib_async_event_rec_t* const     p_event_rec );\r
64 \r
65 \r
66 void\r
67 free_ci_ca(\r
68         IN                              al_obj_t*                                       p_obj )\r
69 {\r
70         al_ci_ca_t                              *p_ci_ca;\r
71 \r
72         CL_ASSERT( p_obj );\r
73         p_ci_ca = PARENT_STRUCT( p_obj, al_ci_ca_t, obj );\r
74 \r
75         cl_spinlock_destroy( &p_ci_ca->attr_lock );\r
76         cl_qpool_destroy( &p_ci_ca->event_pool );\r
77         cl_event_destroy( &p_ci_ca->event );\r
78 \r
79         if( p_ci_ca->port_array )\r
80                 cl_free( p_ci_ca->port_array );\r
81 \r
82         /* Free the PnP attributes buffer. */\r
83         if( p_ci_ca->p_pnp_attr )\r
84                 cl_free( p_ci_ca->p_pnp_attr );\r
85 \r
86         destroy_al_obj( p_obj );\r
87         cl_free( p_ci_ca );\r
88 }\r
89 \r
90 void\r
91 add_ca(\r
92         IN                              al_ci_ca_t* const                       p_ci_ca,\r
93         IN              const   ib_ca_handle_t                          h_ca )\r
94 {\r
95         cl_spinlock_acquire( &p_ci_ca->obj.lock );\r
96         cl_qlist_insert_tail( &p_ci_ca->ca_list, &h_ca->list_item );\r
97         ref_al_obj( &p_ci_ca->obj );\r
98         cl_spinlock_release( &p_ci_ca->obj.lock );\r
99 }\r
100 \r
101 \r
102 \r
103 void\r
104 remove_ca(\r
105         IN              const   ib_ca_handle_t                          h_ca )\r
106 {\r
107         al_ci_ca_t                      *p_ci_ca;\r
108 \r
109         p_ci_ca = h_ca->obj.p_ci_ca;\r
110 \r
111         cl_spinlock_acquire( &p_ci_ca->obj.lock );\r
112         cl_qlist_remove_item( &p_ci_ca->ca_list, &h_ca->list_item );\r
113         cl_spinlock_release( &p_ci_ca->obj.lock );\r
114         deref_al_obj( &p_ci_ca->obj );\r
115 }\r
116 \r
117 \r
118 \r
119 ib_api_status_t\r
120 get_port_info(\r
121         IN                              al_ci_ca_t                                      *p_ci_ca )\r
122 {\r
123         ib_api_status_t         status;\r
124         ib_ca_attr_t            *p_ca_attr;\r
125         uint32_t                        attr_size;\r
126         uint8_t                         i;\r
127 \r
128         AL_ENTER( AL_DBG_CA );\r
129 \r
130         /* Get the size of the CA attribute structure. */\r
131         status = ib_query_ca( p_ci_ca->h_ca, NULL, &attr_size );\r
132         if( status != IB_INSUFFICIENT_MEMORY )\r
133         {\r
134                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
135                         ("ib_query_ca failed with status %s.\n", ib_get_err_str(status)) );\r
136                 return status;\r
137         }\r
138 \r
139         /* Allocate enough space to store the attribute structure. */\r
140         p_ca_attr = cl_malloc( attr_size );\r
141         if( !p_ca_attr )\r
142         {\r
143                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
144                         ("cl_malloc failed to allocate p_ca_attr!\n") );\r
145                 return IB_INSUFFICIENT_RESOURCES;\r
146         }\r
147 \r
148         /* Query the CA attributes. */\r
149         status = ib_query_ca( p_ci_ca->h_ca, p_ca_attr, &attr_size );\r
150         if( status != IB_SUCCESS )\r
151         {\r
152                 cl_free( p_ca_attr );\r
153 \r
154                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
155                         ("ib_query_ca failed with status %s.\n", ib_get_err_str(status)) );\r
156                 return status;\r
157         }\r
158 \r
159         /* Allocate the port GUID array. */\r
160         p_ci_ca->port_array = cl_malloc( sizeof( ib_net64_t ) *\r
161                 p_ca_attr->num_ports );\r
162         if( !p_ci_ca->port_array )\r
163         {\r
164                 cl_free( p_ca_attr );\r
165 \r
166                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
167                         ("cl_malloc failed to allocate port_array!\n") );\r
168                 return IB_INSUFFICIENT_RESOURCES;\r
169         }\r
170         p_ci_ca->num_ports = p_ca_attr->num_ports;\r
171 \r
172         /* Copy the necessary port information. */\r
173         for( i = 0; i < p_ca_attr->num_ports; i++ )\r
174         {\r
175                 p_ci_ca->port_array[i] = p_ca_attr->p_port_attr[i].port_guid;\r
176 \r
177 #ifdef CL_KERNEL\r
178                 /* Set the port's client reregister bit. */\r
179                 {\r
180                         ib_port_attr_mod_t attr;\r
181 \r
182                         attr.cap.client_reregister = TRUE;\r
183                         ib_modify_ca( p_ci_ca->h_ca, i + 1,\r
184                                 IB_CA_MOD_IS_CLIENT_REREGISTER_SUPPORTED, &attr );\r
185                 }\r
186 #endif\r
187         }\r
188 \r
189         cl_free( p_ca_attr );\r
190 \r
191         AL_EXIT( AL_DBG_CA );\r
192         return IB_SUCCESS;\r
193 }\r
194 \r
195 \r
196 \r
197 void\r
198 ci_ca_async_event(\r
199         IN              const   ib_async_event_rec_t* const     p_event_rec )\r
200 {\r
201         al_obj_t*                               p_obj;\r
202         cl_pool_item_t*                 p_item;\r
203         event_item_t*                   p_event_item;\r
204 \r
205         AL_ENTER( AL_DBG_CA );\r
206 \r
207         CL_ASSERT( p_event_rec );\r
208 \r
209         p_obj = (al_obj_t*)p_event_rec->context;\r
210 \r
211         /* Block the destruction of the object until a reference is taken. */\r
212         cl_spinlock_acquire( &p_obj->lock );\r
213         if( p_obj->state == CL_DESTROYING )\r
214         {\r
215                 /* Ignore events if the object is being destroyed. */\r
216                 cl_spinlock_release( &p_obj->lock );\r
217                 AL_EXIT( AL_DBG_CA );\r
218                 return;\r
219         }\r
220 \r
221         /*\r
222          * Get an event item from the pool.  If an object is a child of\r
223          * a CA (e.g., CQ or QP) it will have valid p_ci_ca pointer.\r
224          * For CA's, the object is the actual p_ci_ca pointer itself.\r
225          */\r
226         if( p_obj->p_ci_ca )\r
227         {\r
228                 cl_spinlock_acquire( &p_obj->p_ci_ca->obj.lock );\r
229                 p_item = cl_qpool_get( &p_obj->p_ci_ca->event_pool );\r
230                 cl_spinlock_release( &p_obj->p_ci_ca->obj.lock );\r
231         }\r
232         else\r
233         {\r
234                 p_item = cl_qpool_get( &((al_ci_ca_t*)p_obj)->event_pool );\r
235         }\r
236         if( !p_item )\r
237         {\r
238                 /* Could not get an item.  This event will not be reported. */\r
239                 cl_spinlock_release( &p_obj->lock );\r
240                 AL_EXIT( AL_DBG_CA );\r
241                 return;\r
242         }\r
243 \r
244         /* Hold a reference to prevent destruction until the async_item runs. */\r
245         ref_al_obj( p_obj );\r
246 \r
247         cl_spinlock_release( &p_obj->lock );\r
248 \r
249         /* Initialize the item with the asynchronous event information. */\r
250         p_event_item = PARENT_STRUCT( p_item, event_item_t, async_item.pool_item );\r
251         p_event_item->event_rec.code = p_event_rec->code;\r
252         p_event_item->event_rec.context = p_event_rec->context;\r
253         p_event_item->event_rec.port_number = p_event_rec->port_number;\r
254 \r
255         /* Queue the item on the asynchronous callback thread for processing. */\r
256         p_event_item->async_item.pfn_callback = ci_ca_process_event_cb;\r
257         cl_async_proc_queue( gp_async_proc_mgr, &p_event_item->async_item );\r
258 \r
259         AL_EXIT( AL_DBG_CA );\r
260 }\r
261 \r
262 \r
263 \r
264 void\r
265 ci_ca_process_event_cb(\r
266         IN                              cl_async_proc_item_t*           p_async_item )\r
267 {\r
268         event_item_t*                   p_event_item;\r
269         al_obj_t*                               p_obj;\r
270 \r
271         AL_ENTER( AL_DBG_CA );\r
272 \r
273         CL_ASSERT( p_async_item );\r
274 \r
275         p_event_item = PARENT_STRUCT( p_async_item, event_item_t,\r
276                 async_item.pool_item );\r
277 \r
278         p_obj = (al_obj_t*)p_event_item->event_rec.context;\r
279 \r
280         switch( p_event_item->event_rec.code )\r
281         {\r
282         case IB_AE_QP_COMM:\r
283         case IB_AE_QP_APM:\r
284         case IB_AE_QP_APM_ERROR:\r
285         case IB_AE_QP_FATAL:\r
286         case IB_AE_RQ_ERROR:\r
287         case IB_AE_SQ_ERROR:\r
288         case IB_AE_SQ_DRAINED:\r
289         case IB_AE_WQ_REQ_ERROR:\r
290         case IB_AE_WQ_ACCESS_ERROR:\r
291         case IB_AE_SRQ_QP_LAST_WQE_REACHED:\r
292                 qp_async_event_cb( &p_event_item->event_rec );\r
293                 break;\r
294 \r
295         case IB_AE_SRQ_LIMIT_REACHED:\r
296         case IB_AE_SRQ_CATAS_ERROR:\r
297                 srq_async_event_cb( &p_event_item->event_rec );\r
298                 break;\r
299 \r
300         case IB_AE_CQ_ERROR:\r
301                 cq_async_event_cb( &p_event_item->event_rec );\r
302                 break;\r
303 \r
304 #ifdef CL_KERNEL\r
305 \r
306         case IB_AE_LID_CHANGE:\r
307         case IB_AE_CLIENT_REREGISTER:\r
308                 // These AE events will be generated even in the case when\r
309                 // SM was restaretd but LID will not actually change.\r
310                 // It's important to propagate these event (via PnP mechanism)\r
311                 // up to subscribers. Otherwise, there will be no ping after\r
312                 // subnet manager restart\r
313                 //if (AL_OBJ_IS_TYPE(p_obj, AL_OBJ_TYPE_CI_CA)\r
314                 if (AL_BASE_TYPE( p_obj->type) == AL_OBJ_TYPE_CI_CA) {\r
315                                 pnp_force_event( (struct _al_ci_ca *) p_obj, IB_PNP_LID_CHANGE,\r
316                                         p_event_item->event_rec.port_number );\r
317                                 force_smi_poll();\r
318                 }\r
319                 break;\r
320 #endif //CL_KERNEL\r
321 \r
322         case IB_AE_PORT_TRAP:\r
323         case IB_AE_PORT_DOWN:\r
324         case IB_AE_PORT_ACTIVE:\r
325         \r
326 #ifdef CL_KERNEL\r
327                 /* The SMI polling routine may report a PnP event. */\r
328                 force_smi_poll();\r
329 #endif\r
330                 /* Fall through next case. */\r
331 \r
332         case IB_AE_LOCAL_FATAL:\r
333                 ca_process_async_event_cb( &p_event_item->event_rec );\r
334                 break;\r
335 \r
336         /* Unhandled events - optional per IBA spec. */\r
337         case IB_AE_QKEY_TRAP:\r
338         case IB_AE_PKEY_TRAP:\r
339         case IB_AE_MKEY_TRAP:\r
340         case IB_AE_BKEY_TRAP:\r
341         case IB_AE_BUF_OVERRUN:\r
342         case IB_AE_LINK_INTEGRITY:\r
343         case IB_AE_FLOW_CTRL_ERROR:\r
344         case IB_AE_SYSIMG_GUID_TRAP:\r
345         default:\r
346                 break;\r
347         }\r
348 \r
349         /*\r
350          * Return the event item to the pool.  If an object is a child of\r
351          * a CA (e.g., CQ or QP) it will have valid p_ci_ca pointer.\r
352          * For CA's, the object is the actual p_ci_ca pointer itself.\r
353          */\r
354         if( p_obj->p_ci_ca )\r
355         {\r
356                 cl_spinlock_acquire( &p_obj->p_ci_ca->obj.lock );\r
357                 cl_qpool_put( &p_obj->p_ci_ca->event_pool,\r
358                         &p_event_item->async_item.pool_item );\r
359                 cl_spinlock_release( &p_obj->p_ci_ca->obj.lock );\r
360         }\r
361         else\r
362         {\r
363                 cl_spinlock_acquire( &p_obj->lock );\r
364                 cl_qpool_put( &((al_ci_ca_t*)p_obj)->event_pool,\r
365                         &p_event_item->async_item.pool_item );\r
366                 cl_spinlock_release( &p_obj->lock );\r
367         }\r
368 \r
369         /* Dereference the object. */\r
370         deref_al_obj( p_obj );\r
371 \r
372         AL_EXIT( AL_DBG_CA );\r
373 }\r
374 \r
375 \r
376 \r
377 /*\r
378  * Process an asynchronous event on a CA.  Notify all clients of the event.\r
379  */\r
380 void\r
381 ca_process_async_event_cb(\r
382         IN              const   ib_async_event_rec_t* const     p_event_rec )\r
383 {\r
384         al_ci_ca_t*                             p_ci_ca;\r
385         cl_list_item_t*                 p_list_item;\r
386         ib_ca_handle_t                  h_ca;\r
387         ib_async_event_rec_t    event_rec;\r
388 \r
389         CL_ASSERT( p_event_rec );\r
390         p_ci_ca = (al_ci_ca_t*)p_event_rec->context;\r
391 \r
392         /* Report the CA event to all clients. */\r
393         cl_spinlock_acquire( &p_ci_ca->obj.lock );\r
394         for( p_list_item = cl_qlist_head( &p_ci_ca->ca_list );\r
395                  p_list_item != cl_qlist_end( &p_ci_ca->ca_list );\r
396                  p_list_item = cl_qlist_next( p_list_item ) )\r
397         {\r
398                 cl_spinlock_release( &p_ci_ca->obj.lock );\r
399 \r
400                 h_ca = PARENT_STRUCT( p_list_item, ib_ca_t, list_item );\r
401 \r
402                 event_rec.handle.h_ca = h_ca;\r
403                 event_rec.code = p_event_rec->code;\r
404                 ca_async_event_cb( &event_rec );\r
405 \r
406                 cl_spinlock_acquire( &p_ci_ca->obj.lock );\r
407         }\r
408         cl_spinlock_release( &p_ci_ca->obj.lock );\r
409 }\r
410 \r
411 \r
412 \r
413 /*\r
414  * Process an asynchronous event on a CA.  Notify the user of the event.\r
415  */\r
416 void\r
417 ca_async_event_cb(\r
418         IN                              ib_async_event_rec_t* const     p_event_rec )\r
419 {\r
420         ib_ca_handle_t                  h_ca;\r
421 \r
422         CL_ASSERT( p_event_rec );\r
423         h_ca = p_event_rec->handle.h_ca;\r
424 \r
425         p_event_rec->context = (void*)h_ca->obj.context;\r
426         p_event_rec->handle.h_ca = h_ca;\r
427 \r
428         if( h_ca->pfn_event_cb )\r
429                 h_ca->pfn_event_cb( p_event_rec );\r
430 }\r
431 \r
432 \r
433 \r
434 void\r
435 ca_event_cb(\r
436         IN                              ib_async_event_rec_t            *p_event_rec )\r
437 {\r
438         UNUSED_PARAM( p_event_rec );\r
439 }\r
440 \r
441 \r
442 \r
443 /*\r
444  * Returns a port's index on its CA for the given port GUID.\r
445  */\r
446 ib_api_status_t\r
447 get_port_num(\r
448         IN                              al_ci_ca_t* const                       p_ci_ca,\r
449         IN              const   ib_net64_t                                      port_guid,\r
450                 OUT                     uint8_t                                         *p_port_num OPTIONAL )\r
451 {\r
452         uint8_t         i;\r
453 \r
454         /* Find a matching port GUID on this CI CA. */\r
455         for( i = 0; i < p_ci_ca->num_ports; i++ )\r
456         {\r
457                 if( p_ci_ca->port_array[i] == port_guid )\r
458                 {\r
459                         /* The port number is the index plus one. */\r
460                         if( p_port_num )\r
461                                 *p_port_num = (uint8_t)(i + 1);\r
462                         return IB_SUCCESS;\r
463                 }\r
464         }\r
465 \r
466         /* The port GUID was not found. */\r
467         return IB_INVALID_GUID;\r
468 }\r
469 \r
470 \r
471 \r
472 ib_port_attr_t*\r
473 get_port_attr(\r
474         IN                              ib_ca_attr_t * const            p_ca_attr,\r
475         IN                              ib_gid_t * const                        p_gid )\r
476 {\r
477         uintn_t                 port_index, gid_index;\r
478         ib_port_attr_t  *p_port_attr;\r
479 \r
480         AL_ENTER( AL_DBG_CA );\r
481 \r
482         if( !p_ca_attr || !p_gid )\r
483         {\r
484                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
485                         ("No p_ca_attr or p_gid.\n") );\r
486                 return NULL;\r
487         }\r
488 \r
489         /* Check all ports on this HCA for matching GID. */\r
490         for( port_index = 0; port_index < p_ca_attr->num_ports; port_index++ )\r
491         {\r
492                 p_port_attr = &p_ca_attr->p_port_attr[port_index];\r
493 \r
494                 for( gid_index = 0; gid_index < p_port_attr->num_gids; gid_index++ )\r
495                 {\r
496                         if( !cl_memcmp( &p_port_attr->p_gid_table[gid_index],\r
497                                 p_gid, sizeof(ib_gid_t) ) )\r
498                         {\r
499                                 AL_EXIT( AL_DBG_CA );\r
500                                 return p_port_attr;\r
501                         }\r
502                 }\r
503         }\r
504 \r
505         AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("No match found.\n") );\r
506         return NULL;\r
507 }\r
508 \r
509 \r
510 \r
511 uint16_t\r
512 get_pkey_index(\r
513         IN                              ib_port_attr_t * const          p_port_attr,\r
514         IN              const   ib_net16_t                                      pkey )\r
515 {\r
516         uint16_t                        pkey_index;\r
517 \r
518         if( !p_port_attr )\r
519                 return BAD_PKEY_INDEX;\r
520 \r
521         for( pkey_index = 0; pkey_index < p_port_attr->num_pkeys; pkey_index++ )\r
522         {\r
523                 if( p_port_attr->p_pkey_table[pkey_index] == pkey )\r
524                         return pkey_index;\r
525         }\r
526         return BAD_PKEY_INDEX;\r
527 }\r
528 \r
529 \r
530 /*\r
531  * Reads the CA attributes from verbs.\r
532  */\r
533 ib_api_status_t\r
534 ci_ca_update_attr(\r
535         IN                              al_ci_ca_t*                                     p_ci_ca,\r
536                 OUT                     ib_ca_attr_t**                          pp_old_pnp_attr )\r
537 {\r
538         ib_ca_attr_t            *p_pnp_attr;\r
539         uint32_t                        attr_size;\r
540         ib_api_status_t         status;\r
541 \r
542         AL_ENTER( AL_DBG_CA );\r
543 \r
544         /* Query to get the CA attributes size. */\r
545         attr_size = 0;\r
546         status = ib_query_ca( p_ci_ca->h_ca, NULL, &attr_size );\r
547         CL_ASSERT( status == IB_INSUFFICIENT_MEMORY );\r
548 \r
549         /*\r
550          * Allocate the new CA attributes buffer.\r
551          * Double the buffer size for PnP and user reporting halves.\r
552          */\r
553         p_pnp_attr = (ib_ca_attr_t*)cl_zalloc( attr_size * 2 );\r
554         if( !p_pnp_attr )\r
555         {\r
556                 AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_CA,\r
557                         ("Unable to allocate buffer for PnP attributes\n") );\r
558                 return IB_INSUFFICIENT_MEMORY;\r
559         }\r
560 \r
561         /* Read the attributes. */\r
562         status = ib_query_ca( p_ci_ca->h_ca, p_pnp_attr, &attr_size );\r
563         if( status != IB_SUCCESS )\r
564         {\r
565                 AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_CA,\r
566                         ("Unable to query attributes\n") );\r
567                 cl_free( p_pnp_attr );\r
568                 return status;\r
569         }\r
570 \r
571         ci_ca_excl_lock_attr( p_ci_ca );\r
572         if( pp_old_pnp_attr )\r
573                 *pp_old_pnp_attr = p_ci_ca->p_pnp_attr;\r
574         p_ci_ca->p_pnp_attr = p_pnp_attr;\r
575 \r
576         /*\r
577          * Initialize pointer to the user reporting half.\r
578          * This buffer is used to report this CAs attributes to users.\r
579          */\r
580         p_ci_ca->p_user_attr = (ib_ca_attr_t*)(((uint8_t*)p_pnp_attr) + attr_size);\r
581         ci_ca_unlock_attr( p_ci_ca );\r
582 \r
583         AL_EXIT( AL_DBG_CA );\r
584         return IB_SUCCESS;\r
585 }\r
586 \r
587 \r
588 \r
589 void\r
590 ci_ca_lock_attr(\r
591         IN                              al_ci_ca_t* const                       p_ci_ca )\r
592 {\r
593         CL_ASSERT( p_ci_ca );\r
594 \r
595         cl_spinlock_acquire( &p_ci_ca->attr_lock );\r
596 }\r
597 \r
598 \r
599 void\r
600 ci_ca_excl_lock_attr(\r
601         IN                              al_ci_ca_t* const                       p_ci_ca )\r
602 {\r
603         CL_ASSERT( p_ci_ca );\r
604 \r
605         cl_spinlock_acquire( &p_ci_ca->attr_lock );\r
606 }\r
607 \r
608 \r
609 void\r
610 ci_ca_unlock_attr(\r
611         IN                              al_ci_ca_t* const                       p_ci_ca )\r
612 {\r
613         CL_ASSERT( p_ci_ca );\r
614 \r
615         cl_spinlock_release( &p_ci_ca->attr_lock );\r
616 }\r