ae992d77120a1fcfd5b01a440ca5cb590fb30a9b
[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                 }\r
318                 break;\r
319 #endif //CL_KERNEL\r
320 \r
321         case IB_AE_PORT_TRAP:\r
322         case IB_AE_PORT_DOWN:\r
323         case IB_AE_PORT_ACTIVE:\r
324         \r
325 #ifdef CL_KERNEL\r
326                 /* The SMI polling routine may report a PnP event. */\r
327                 force_smi_poll();\r
328 #endif\r
329                 /* Fall through next case. */\r
330 \r
331         case IB_AE_LOCAL_FATAL:\r
332                 ca_process_async_event_cb( &p_event_item->event_rec );\r
333                 break;\r
334 \r
335         /* Unhandled events - optional per IBA spec. */\r
336         case IB_AE_QKEY_TRAP:\r
337         case IB_AE_PKEY_TRAP:\r
338         case IB_AE_MKEY_TRAP:\r
339         case IB_AE_BKEY_TRAP:\r
340         case IB_AE_BUF_OVERRUN:\r
341         case IB_AE_LINK_INTEGRITY:\r
342         case IB_AE_FLOW_CTRL_ERROR:\r
343         case IB_AE_SYSIMG_GUID_TRAP:\r
344         default:\r
345                 break;\r
346         }\r
347 \r
348         /*\r
349          * Return the event item to the pool.  If an object is a child of\r
350          * a CA (e.g., CQ or QP) it will have valid p_ci_ca pointer.\r
351          * For CA's, the object is the actual p_ci_ca pointer itself.\r
352          */\r
353         if( p_obj->p_ci_ca )\r
354         {\r
355                 cl_spinlock_acquire( &p_obj->p_ci_ca->obj.lock );\r
356                 cl_qpool_put( &p_obj->p_ci_ca->event_pool,\r
357                         &p_event_item->async_item.pool_item );\r
358                 cl_spinlock_release( &p_obj->p_ci_ca->obj.lock );\r
359         }\r
360         else\r
361         {\r
362                 cl_spinlock_acquire( &p_obj->lock );\r
363                 cl_qpool_put( &((al_ci_ca_t*)p_obj)->event_pool,\r
364                         &p_event_item->async_item.pool_item );\r
365                 cl_spinlock_release( &p_obj->lock );\r
366         }\r
367 \r
368         /* Dereference the object. */\r
369         deref_al_obj( p_obj );\r
370 \r
371         AL_EXIT( AL_DBG_CA );\r
372 }\r
373 \r
374 \r
375 \r
376 /*\r
377  * Process an asynchronous event on a CA.  Notify all clients of the event.\r
378  */\r
379 void\r
380 ca_process_async_event_cb(\r
381         IN              const   ib_async_event_rec_t* const     p_event_rec )\r
382 {\r
383         al_ci_ca_t*                             p_ci_ca;\r
384         cl_list_item_t*                 p_list_item;\r
385         ib_ca_handle_t                  h_ca;\r
386         ib_async_event_rec_t    event_rec;\r
387 \r
388         CL_ASSERT( p_event_rec );\r
389         p_ci_ca = (al_ci_ca_t*)p_event_rec->context;\r
390 \r
391         /* Report the CA event to all clients. */\r
392         cl_spinlock_acquire( &p_ci_ca->obj.lock );\r
393         for( p_list_item = cl_qlist_head( &p_ci_ca->ca_list );\r
394                  p_list_item != cl_qlist_end( &p_ci_ca->ca_list );\r
395                  p_list_item = cl_qlist_next( p_list_item ) )\r
396         {\r
397                 cl_spinlock_release( &p_ci_ca->obj.lock );\r
398 \r
399                 h_ca = PARENT_STRUCT( p_list_item, ib_ca_t, list_item );\r
400 \r
401                 event_rec.handle.h_ca = h_ca;\r
402                 event_rec.code = p_event_rec->code;\r
403                 ca_async_event_cb( &event_rec );\r
404 \r
405                 cl_spinlock_acquire( &p_ci_ca->obj.lock );\r
406         }\r
407         cl_spinlock_release( &p_ci_ca->obj.lock );\r
408 }\r
409 \r
410 \r
411 \r
412 /*\r
413  * Process an asynchronous event on a CA.  Notify the user of the event.\r
414  */\r
415 void\r
416 ca_async_event_cb(\r
417         IN                              ib_async_event_rec_t* const     p_event_rec )\r
418 {\r
419         ib_ca_handle_t                  h_ca;\r
420 \r
421         CL_ASSERT( p_event_rec );\r
422         h_ca = p_event_rec->handle.h_ca;\r
423 \r
424         p_event_rec->context = (void*)h_ca->obj.context;\r
425         p_event_rec->handle.h_ca = h_ca;\r
426 \r
427         if( h_ca->pfn_event_cb )\r
428                 h_ca->pfn_event_cb( p_event_rec );\r
429 }\r
430 \r
431 \r
432 \r
433 void\r
434 ca_event_cb(\r
435         IN                              ib_async_event_rec_t            *p_event_rec )\r
436 {\r
437         UNUSED_PARAM( p_event_rec );\r
438 }\r
439 \r
440 \r
441 \r
442 /*\r
443  * Returns a port's index on its CA for the given port GUID.\r
444  */\r
445 ib_api_status_t\r
446 get_port_num(\r
447         IN                              al_ci_ca_t* const                       p_ci_ca,\r
448         IN              const   ib_net64_t                                      port_guid,\r
449                 OUT                     uint8_t                                         *p_port_num OPTIONAL )\r
450 {\r
451         uint8_t         i;\r
452 \r
453         /* Find a matching port GUID on this CI CA. */\r
454         for( i = 0; i < p_ci_ca->num_ports; i++ )\r
455         {\r
456                 if( p_ci_ca->port_array[i] == port_guid )\r
457                 {\r
458                         /* The port number is the index plus one. */\r
459                         if( p_port_num )\r
460                                 *p_port_num = (uint8_t)(i + 1);\r
461                         return IB_SUCCESS;\r
462                 }\r
463         }\r
464 \r
465         /* The port GUID was not found. */\r
466         return IB_INVALID_GUID;\r
467 }\r
468 \r
469 \r
470 \r
471 ib_port_attr_t*\r
472 get_port_attr(\r
473         IN                              ib_ca_attr_t * const            p_ca_attr,\r
474         IN                              ib_gid_t * const                        p_gid )\r
475 {\r
476         uintn_t                 port_index, gid_index;\r
477         ib_port_attr_t  *p_port_attr;\r
478 \r
479         AL_ENTER( AL_DBG_CA );\r
480 \r
481         if( !p_ca_attr || !p_gid )\r
482         {\r
483                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
484                         ("No p_ca_attr or p_gid.\n") );\r
485                 return NULL;\r
486         }\r
487 \r
488         /* Check all ports on this HCA for matching GID. */\r
489         for( port_index = 0; port_index < p_ca_attr->num_ports; port_index++ )\r
490         {\r
491                 p_port_attr = &p_ca_attr->p_port_attr[port_index];\r
492 \r
493                 for( gid_index = 0; gid_index < p_port_attr->num_gids; gid_index++ )\r
494                 {\r
495                         if( !cl_memcmp( &p_port_attr->p_gid_table[gid_index],\r
496                                 p_gid, sizeof(ib_gid_t) ) )\r
497                         {\r
498                                 AL_EXIT( AL_DBG_CA );\r
499                                 return p_port_attr;\r
500                         }\r
501                 }\r
502         }\r
503 \r
504         AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("No match found.\n") );\r
505         return NULL;\r
506 }\r
507 \r
508 \r
509 \r
510 uint16_t\r
511 get_pkey_index(\r
512         IN                              ib_port_attr_t * const          p_port_attr,\r
513         IN              const   ib_net16_t                                      pkey )\r
514 {\r
515         uint16_t                        pkey_index;\r
516 \r
517         if( !p_port_attr )\r
518                 return BAD_PKEY_INDEX;\r
519 \r
520         for( pkey_index = 0; pkey_index < p_port_attr->num_pkeys; pkey_index++ )\r
521         {\r
522                 if( p_port_attr->p_pkey_table[pkey_index] == pkey )\r
523                         return pkey_index;\r
524         }\r
525         return BAD_PKEY_INDEX;\r
526 }\r
527 \r
528 \r
529 /*\r
530  * Reads the CA attributes from verbs.\r
531  */\r
532 ib_api_status_t\r
533 ci_ca_update_attr(\r
534         IN                              al_ci_ca_t*                                     p_ci_ca,\r
535                 OUT                     ib_ca_attr_t**                          pp_old_pnp_attr )\r
536 {\r
537         ib_ca_attr_t            *p_pnp_attr;\r
538         uint32_t                        attr_size;\r
539         ib_api_status_t         status;\r
540 \r
541         AL_ENTER( AL_DBG_CA );\r
542 \r
543         /* Query to get the CA attributes size. */\r
544         attr_size = 0;\r
545         status = ib_query_ca( p_ci_ca->h_ca, NULL, &attr_size );\r
546         CL_ASSERT( status == IB_INSUFFICIENT_MEMORY );\r
547 \r
548         /*\r
549          * Allocate the new CA attributes buffer.\r
550          * Double the buffer size for PnP and user reporting halves.\r
551          */\r
552         p_pnp_attr = (ib_ca_attr_t*)cl_zalloc( attr_size * 2 );\r
553         if( !p_pnp_attr )\r
554         {\r
555                 AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_CA,\r
556                         ("Unable to allocate buffer for PnP attributes\n") );\r
557                 return IB_INSUFFICIENT_MEMORY;\r
558         }\r
559 \r
560         /* Read the attributes. */\r
561         status = ib_query_ca( p_ci_ca->h_ca, p_pnp_attr, &attr_size );\r
562         if( status != IB_SUCCESS )\r
563         {\r
564                 AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_CA,\r
565                         ("Unable to query attributes\n") );\r
566                 cl_free( p_pnp_attr );\r
567                 return status;\r
568         }\r
569 \r
570         ci_ca_excl_lock_attr( p_ci_ca );\r
571         if( pp_old_pnp_attr )\r
572                 *pp_old_pnp_attr = p_ci_ca->p_pnp_attr;\r
573         p_ci_ca->p_pnp_attr = p_pnp_attr;\r
574 \r
575         /*\r
576          * Initialize pointer to the user reporting half.\r
577          * This buffer is used to report this CAs attributes to users.\r
578          */\r
579         p_ci_ca->p_user_attr = (ib_ca_attr_t*)(((uint8_t*)p_pnp_attr) + attr_size);\r
580         ci_ca_unlock_attr( p_ci_ca );\r
581 \r
582         AL_EXIT( AL_DBG_CA );\r
583         return IB_SUCCESS;\r
584 }\r
585 \r
586 \r
587 \r
588 void\r
589 ci_ca_lock_attr(\r
590         IN                              al_ci_ca_t* const                       p_ci_ca )\r
591 {\r
592         CL_ASSERT( p_ci_ca );\r
593 \r
594         cl_spinlock_acquire( &p_ci_ca->attr_lock );\r
595 }\r
596 \r
597 \r
598 void\r
599 ci_ca_excl_lock_attr(\r
600         IN                              al_ci_ca_t* const                       p_ci_ca )\r
601 {\r
602         CL_ASSERT( p_ci_ca );\r
603 \r
604         cl_spinlock_acquire( &p_ci_ca->attr_lock );\r
605 }\r
606 \r
607 \r
608 void\r
609 ci_ca_unlock_attr(\r
610         IN                              al_ci_ca_t* const                       p_ci_ca )\r
611 {\r
612         CL_ASSERT( p_ci_ca );\r
613 \r
614         cl_spinlock_release( &p_ci_ca->attr_lock );\r
615 }\r