[IBAL] Fix race between user-mode PnP deregistration and PnP callbacks.
[mirror/winof/.git] / core / al / kernel / al_pnp.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 <iba/ib_al.h>\r
34 \r
35 #include "al.h"\r
36 #include "al_debug.h"\r
37 #include "al_mgr.h"\r
38 #include "al_pnp.h"\r
39 #include "ib_common.h"\r
40 #include "al_ioc_pnp.h"\r
41 \r
42 \r
43 #define PNP_CA_VECTOR_MIN               0\r
44 #define PNP_CA_VECTOR_GROW              10\r
45 \r
46 \r
47 /* ib_pnp_event_t values converted to text strings. */\r
48 char*   ib_pnp_event_str[] =\r
49 {\r
50         "IB_PNP_CA_ADD",\r
51         "IB_PNP_CA_REMOVE",\r
52         "IB_PNP_PORT_ADD",\r
53         "IB_PNP_PORT_REMOVE",\r
54         "IB_PNP_PORT_INIT",\r
55         "IB_PNP_PORT_ARMED",\r
56         "IB_PNP_PORT_ACTIVE",\r
57         "IB_PNP_PORT_DOWN",\r
58         "IB_PNP_PKEY_CHANGE",\r
59         "IB_PNP_SM_CHANGE",\r
60         "IB_PNP_GID_CHANGE",\r
61         "IB_PNP_LID_CHANGE",\r
62         "IB_PNP_SUBNET_TIMEOUT_CHANGE",\r
63         "IB_PNP_IOU_ADD",\r
64         "IB_PNP_IOU_REMOVE",\r
65         "IB_PNP_IOC_ADD",\r
66         "IB_PNP_IOC_REMOVE",\r
67         "IB_PNP_IOC_PATH_ADD",\r
68         "IB_PNP_IOC_PATH_REMOVE"\r
69 };\r
70 \r
71 \r
72 /*\r
73  * Declarations.\r
74  */\r
75 static void\r
76 __pnp_free(\r
77         IN                              al_obj_t                                        *p_obj );\r
78 \r
79 \r
80 /*\r
81  * Event structures for queuing to the async proc manager.\r
82  */\r
83 typedef struct _al_pnp_ca_change\r
84 {\r
85         cl_async_proc_item_t    async_item;\r
86         al_ci_ca_t                              *p_ci_ca;\r
87         ib_ca_attr_t                    *p_new_ca_attr;\r
88 \r
89 }       al_pnp_ca_change_t;\r
90 \r
91 \r
92 typedef struct _al_pnp_ca_event\r
93 {\r
94         cl_async_proc_item_t    async_item;\r
95         ib_pnp_event_t                  pnp_event;\r
96         al_ci_ca_t                              *p_ci_ca;\r
97         uint8_t                                 port_index;\r
98 \r
99 }       al_pnp_ca_event_t;\r
100 \r
101 \r
102 typedef struct _al_pnp_reg_event\r
103 {\r
104         cl_async_proc_item_t    async_item;\r
105         al_pnp_t                                *p_reg;\r
106 \r
107 }       al_pnp_reg_event_t;\r
108 \r
109 \r
110 /* PnP Manager structure. */\r
111 typedef struct _al_pnp_mgr\r
112 {\r
113         al_obj_t                                obj;\r
114 \r
115         cl_qlist_t                              ca_reg_list;\r
116         cl_qlist_t                              port_reg_list;\r
117 \r
118         cl_ptr_vector_t                 ca_vector;\r
119 \r
120         cl_async_proc_item_t    async_item;\r
121         boolean_t                               async_item_is_busy;\r
122 \r
123 }       al_pnp_mgr_t;\r
124 \r
125 \r
126 /*\r
127  * PnP Manager instance, creation, destruction.\r
128  */\r
129 \r
130 /* Global instance of the PnP manager. */\r
131 al_pnp_mgr_t    *gp_pnp = NULL;\r
132 \r
133 \r
134 static void\r
135 __pnp_check_events(\r
136         IN                              cl_async_proc_item_t*   p_item );\r
137 \r
138 static void\r
139 __al_pnp_process_dereg(\r
140         IN                              cl_async_proc_item_t*           p_item );\r
141 \r
142 \r
143 ib_api_status_t\r
144 create_pnp(\r
145         IN                              al_obj_t* const                 p_parent_obj )\r
146 {\r
147         ib_api_status_t         status;\r
148         cl_status_t                     cl_status;\r
149 \r
150         CL_ENTER( AL_DBG_PNP, g_al_dbg_lvl );\r
151 \r
152         CL_ASSERT( gp_pnp == NULL );\r
153 \r
154         gp_pnp = (al_pnp_mgr_t*)cl_zalloc( sizeof(al_pnp_mgr_t) );\r
155         if( !gp_pnp )\r
156         {\r
157                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
158                         ("Failed to allocate PnP manager.\n") );\r
159                 return IB_INSUFFICIENT_MEMORY;\r
160         }\r
161 \r
162         cl_qlist_init( &gp_pnp->ca_reg_list );\r
163         cl_qlist_init( &gp_pnp->port_reg_list );\r
164         construct_al_obj( &gp_pnp->obj, AL_OBJ_TYPE_PNP_MGR );\r
165         cl_ptr_vector_construct( &gp_pnp->ca_vector );\r
166 \r
167         cl_status = cl_ptr_vector_init( &gp_pnp->ca_vector, PNP_CA_VECTOR_MIN,\r
168                 PNP_CA_VECTOR_GROW );\r
169         if( cl_status != CL_SUCCESS )\r
170         {\r
171                 __pnp_free( &gp_pnp->obj );\r
172                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
173                         ("cl_ptr_vector_init failed with status %s.\n",\r
174                         CL_STATUS_MSG( cl_status )) );\r
175                 return IB_ERROR;\r
176         }\r
177 \r
178         gp_pnp->async_item.pfn_callback = __pnp_check_events;\r
179 \r
180         status = init_al_obj( &gp_pnp->obj, NULL, TRUE, NULL, NULL, __pnp_free );\r
181         if( status != IB_SUCCESS )\r
182         {\r
183                 __pnp_free( &gp_pnp->obj );\r
184                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
185                         ("init_al_obj() failed with status %s.\n", ib_get_err_str(status)) );\r
186                 return status;\r
187         }\r
188         status = attach_al_obj( p_parent_obj, &gp_pnp->obj );\r
189         if( status != IB_SUCCESS )\r
190         {\r
191                 gp_pnp->obj.pfn_destroy( &gp_pnp->obj, NULL );\r
192                 AL_TRACE_EXIT( AL_DBG_ERROR,\r
193                         ("attach_al_obj returned %s.\n", ib_get_err_str(status)) );\r
194                 return status;\r
195         }\r
196 \r
197         /* Release the reference taken in init_al_obj. */\r
198         deref_al_obj( &gp_pnp->obj );\r
199 \r
200         CL_EXIT( AL_DBG_PNP, g_al_dbg_lvl );\r
201         return( IB_SUCCESS );\r
202 }\r
203 \r
204 \r
205 static void\r
206 __pnp_free(\r
207         IN                              al_obj_t                                        *p_obj )\r
208 {\r
209         CL_ENTER( AL_DBG_PNP, g_al_dbg_lvl );\r
210 \r
211         CL_ASSERT( PARENT_STRUCT( p_obj, al_pnp_mgr_t, obj ) == gp_pnp );\r
212         CL_ASSERT( cl_is_qlist_empty( &gp_pnp->ca_reg_list ) );\r
213         CL_ASSERT( cl_is_qlist_empty( &gp_pnp->port_reg_list ) );\r
214         UNUSED_PARAM( p_obj );\r
215 \r
216         /* All CA's should have been removed by now. */\r
217         CL_ASSERT( !cl_ptr_vector_get_size( &gp_pnp->ca_vector ) );\r
218         cl_ptr_vector_destroy( &gp_pnp->ca_vector );\r
219 \r
220         destroy_al_obj( &gp_pnp->obj );\r
221         cl_free( gp_pnp );\r
222         gp_pnp = NULL;\r
223 \r
224         CL_EXIT( AL_DBG_PNP, g_al_dbg_lvl );\r
225 }\r
226 \r
227 \r
228 static void\r
229 __pnp_reg_destroying(\r
230         IN                              al_obj_t                                        *p_obj )\r
231 {\r
232         al_pnp_t                *p_reg;\r
233 \r
234         AL_ENTER( AL_DBG_PNP );\r
235 \r
236         p_reg = PARENT_STRUCT( p_obj, al_pnp_t, obj );\r
237 \r
238         /* Reference the registration entry while we queue it to our PnP thread. */\r
239         ref_al_obj( &p_reg->obj );\r
240 \r
241         /* Queue the registration for removal from the list. */\r
242         cl_async_proc_queue( gp_async_pnp_mgr, &p_reg->dereg_item );\r
243 \r
244         AL_EXIT( AL_DBG_PNP );\r
245 }\r
246 \r
247 \r
248 static void\r
249 __al_pnp_process_dereg(\r
250         IN                              cl_async_proc_item_t*           p_item )\r
251 {\r
252         al_pnp_t*               p_reg;\r
253 \r
254         CL_ENTER( AL_DBG_PNP, g_al_dbg_lvl );\r
255 \r
256         p_reg = PARENT_STRUCT( p_item, al_pnp_t, dereg_item );\r
257 \r
258         /* Remove the registration information from the list. */\r
259         switch( pnp_get_class( p_reg->pnp_class ) )\r
260         {\r
261         case IB_PNP_CA:\r
262                 cl_qlist_remove_item( &gp_pnp->ca_reg_list, &p_reg->list_item );\r
263                 break;\r
264 \r
265         case IB_PNP_PORT:\r
266                 cl_qlist_remove_item( &gp_pnp->port_reg_list, &p_reg->list_item );\r
267                 break;\r
268 \r
269         default:\r
270                 CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_CA ||\r
271                         pnp_get_class( p_reg->pnp_class ) == IB_PNP_PORT );\r
272                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
273                         ("Invalid PnP registartion type.\n") );\r
274         }\r
275 \r
276         /* Release the reference we took for processing the deregistration. */\r
277         deref_al_obj( &p_reg->obj );\r
278 \r
279         CL_EXIT( AL_DBG_PNP, g_al_dbg_lvl );\r
280 }\r
281 \r
282 \r
283 static void\r
284 __pnp_reg_cleanup(\r
285         IN                              al_obj_t                                        *p_obj )\r
286 {\r
287         al_pnp_t                *p_reg;\r
288         cl_map_item_t   *p_item;\r
289         IRP                             *p_irp;\r
290 \r
291         CL_ENTER( AL_DBG_PNP, g_al_dbg_lvl );\r
292 \r
293         p_reg = PARENT_STRUCT( p_obj, al_pnp_t, obj );\r
294 \r
295         /* Cleanup the context list. */\r
296         while( cl_qmap_count( &p_reg->context_map ) )\r
297         {\r
298                 p_item = cl_qmap_tail( &p_reg->context_map );\r
299                 cl_qmap_remove_item( &p_reg->context_map, p_item );\r
300                 cl_free( p_item );\r
301         }\r
302 \r
303         p_irp = InterlockedExchangePointer( &p_reg->p_rearm_irp, NULL );\r
304         if( p_irp )\r
305         {\r
306 #pragma warning(push, 3)\r
307                 IoSetCancelRoutine( p_irp, NULL );\r
308 #pragma warning(pop)\r
309                 /* Complete the IRP. */\r
310                 p_irp->IoStatus.Status = STATUS_CANCELLED;\r
311                 p_irp->IoStatus.Information = 0;\r
312                 IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
313         }\r
314 \r
315         if( p_reg->p_dereg_irp )\r
316         {\r
317                 p_reg->p_dereg_irp->IoStatus.Status = STATUS_SUCCESS;\r
318                 p_reg->p_dereg_irp->IoStatus.Information = 0;\r
319                 IoCompleteRequest( p_reg->p_dereg_irp, IO_NO_INCREMENT );\r
320                 p_reg->p_dereg_irp = NULL;\r
321         }\r
322 \r
323         /* Dereference the PnP manager. */\r
324         deref_al_obj( &gp_pnp->obj );\r
325 \r
326         CL_EXIT( AL_DBG_PNP, g_al_dbg_lvl );\r
327 }\r
328 \r
329 \r
330 static void\r
331 __pnp_reg_free(\r
332         IN                              al_obj_t                                        *p_obj )\r
333 {\r
334         al_pnp_t                *p_reg;\r
335         cl_map_item_t   *p_item;\r
336 \r
337         CL_ENTER( AL_DBG_PNP, g_al_dbg_lvl );\r
338 \r
339         p_reg = PARENT_STRUCT( p_obj, al_pnp_t, obj );\r
340 \r
341         /* Cleanup the context list. */\r
342         while( cl_qmap_count( &p_reg->context_map ) )\r
343         {\r
344                 p_item = cl_qmap_tail( &p_reg->context_map );\r
345                 cl_qmap_remove_item( &p_reg->context_map, p_item );\r
346                 cl_free( p_item );\r
347         }\r
348 \r
349         /* Free the registration structure. */\r
350         destroy_al_obj( &p_reg->obj );\r
351         cl_free( p_reg );\r
352 \r
353         CL_EXIT( AL_DBG_PNP, g_al_dbg_lvl );\r
354 }\r
355 \r
356 \r
357 /*\r
358  * Helper functions.\r
359  */\r
360 \r
361 \r
362 \r
363 /*\r
364  * Returns the context structure stored in a registration for\r
365  * a given CA or port GUID.\r
366  */\r
367 al_pnp_context_t*\r
368 pnp_get_context(\r
369         IN              const   al_pnp_t* const                         p_reg,\r
370         IN              const   ib_net64_t                                      guid )\r
371 {\r
372         cl_map_item_t           *p_context_item;\r
373 \r
374         AL_ENTER( AL_DBG_PNP );\r
375 \r
376         /* Search the context list for this CA. */\r
377         p_context_item = cl_qmap_get( &p_reg->context_map, guid );\r
378         if( p_context_item != cl_qmap_end( &p_reg->context_map ) )\r
379         {\r
380                 AL_EXIT( AL_DBG_PNP );\r
381                 return PARENT_STRUCT( p_context_item, al_pnp_context_t, map_item );\r
382         }\r
383 \r
384         AL_EXIT( AL_DBG_PNP );\r
385         return NULL;\r
386 }\r
387 \r
388 \r
389 void\r
390 pnp_reg_complete(\r
391         IN                              al_pnp_t* const                         p_reg )\r
392 {\r
393         ib_pnp_rec_t                    user_rec;\r
394 \r
395         AL_ENTER( AL_DBG_PNP );\r
396 \r
397         /* Notify the user that the registration is complete. */\r
398         if( (pnp_get_flag( p_reg->pnp_class ) & IB_PNP_FLAG_REG_COMPLETE) )\r
399         {\r
400                 /* Setup the PnP record for the callback. */\r
401                 cl_memclr( &user_rec, sizeof(user_rec) );\r
402                 user_rec.h_pnp = p_reg;\r
403                 user_rec.pnp_event = IB_PNP_REG_COMPLETE;\r
404                 user_rec.pnp_context = (void*)p_reg->obj.context;\r
405 \r
406                 /* Invoke the user callback. */\r
407                 p_reg->pfn_pnp_cb( &user_rec );\r
408         }\r
409 \r
410         if( pnp_get_flag( p_reg->pnp_class ) & IB_PNP_FLAG_REG_SYNC )\r
411         {\r
412                 KeSetEvent( p_reg->p_sync_event, 0, FALSE );\r
413                 /*\r
414                  * Proxy synchronizes PnP callbacks with registration, and thus can\r
415                  * safely set the UM_EXPORT subtype after al_reg_pnp returns.\r
416                  */\r
417                 if( p_reg->obj.type & AL_OBJ_SUBTYPE_UM_EXPORT )\r
418                         ObDereferenceObject( p_reg->p_sync_event );\r
419                 p_reg->p_sync_event = NULL;\r
420         }\r
421 \r
422         AL_EXIT( AL_DBG_PNP );\r
423 }\r
424 \r
425 /*\r
426  * User notification.  Formats the PnP record delivered by the\r
427  * callback, invokes the callback, and updates the contexts.\r
428  */\r
429 static ib_api_status_t\r
430 __pnp_notify_user(\r
431         IN                              al_pnp_t* const                         p_reg,\r
432         IN                              al_pnp_context_t* const         p_context,\r
433         IN              const   al_pnp_ca_event_t* const        p_event_rec )\r
434 {\r
435         ib_api_status_t                 status;\r
436         union\r
437         {\r
438                 ib_pnp_rec_t            user_rec;\r
439                 ib_pnp_ca_rec_t         ca_rec;\r
440                 ib_pnp_port_rec_t       port_rec;\r
441         }       u;\r
442 \r
443         CL_ENTER( AL_DBG_PNP, g_al_dbg_lvl );\r
444 \r
445         CL_ASSERT( p_reg );\r
446         CL_ASSERT( p_context );\r
447         CL_ASSERT( p_event_rec );\r
448 \r
449         /* Setup the PnP record for the callback. */\r
450         cl_memclr( &u, sizeof(u) );\r
451         u.user_rec.h_pnp = p_reg;\r
452         u.user_rec.pnp_event = p_event_rec->pnp_event;\r
453         u.user_rec.pnp_context = (void*)p_reg->obj.context;\r
454         u.user_rec.context = (void*)p_context->context;\r
455 \r
456         switch( p_event_rec->pnp_event )\r
457         {\r
458         case IB_PNP_CA_ADD:\r
459                 /* Copy the attributes for use in calling users back. */\r
460                 u.ca_rec.p_ca_attr = ib_copy_ca_attr(\r
461                         p_event_rec->p_ci_ca->p_user_attr,\r
462                         p_event_rec->p_ci_ca->p_pnp_attr );\r
463 \r
464                 /* Fall through */\r
465         case IB_PNP_CA_REMOVE:\r
466                 u.user_rec.guid = p_event_rec->p_ci_ca->p_pnp_attr->ca_guid;\r
467                 break;\r
468 \r
469         case IB_PNP_PORT_ADD:\r
470         case IB_PNP_PORT_INIT:\r
471         case IB_PNP_PORT_ARMED:\r
472         case IB_PNP_PORT_ACTIVE:\r
473         case IB_PNP_PORT_DOWN:\r
474         case IB_PNP_PKEY_CHANGE:\r
475         case IB_PNP_SM_CHANGE:\r
476         case IB_PNP_GID_CHANGE:\r
477         case IB_PNP_LID_CHANGE:\r
478         case IB_PNP_SUBNET_TIMEOUT_CHANGE:\r
479                 /* Copy the attributes for use in calling users back. */\r
480                 u.port_rec.p_ca_attr = ib_copy_ca_attr(\r
481                         p_event_rec->p_ci_ca->p_user_attr,\r
482                         p_event_rec->p_ci_ca->p_pnp_attr );\r
483 \r
484                 /* Setup the port attribute pointer. */\r
485                 u.port_rec.p_port_attr =\r
486                         &u.port_rec.p_ca_attr->p_port_attr[p_event_rec->port_index];\r
487 \r
488                 /* Fall through */\r
489         case IB_PNP_PORT_REMOVE:\r
490                 u.user_rec.guid = p_event_rec->p_ci_ca->p_pnp_attr->p_port_attr[ \r
491                         p_event_rec->port_index].port_guid;\r
492                 break;\r
493 \r
494         case IB_PNP_REG_COMPLETE:\r
495                 break;\r
496 \r
497         default:\r
498                 /* Invalid event type. */\r
499                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
500                         ("Invalid event type (%d).\n", p_event_rec->pnp_event) );\r
501                 CL_ASSERT( p_event_rec->pnp_event == IB_PNP_CA_ADD ||\r
502                         p_event_rec->pnp_event == IB_PNP_PORT_ADD ||\r
503                         p_event_rec->pnp_event == IB_PNP_PORT_INIT ||\r
504                         p_event_rec->pnp_event == IB_PNP_PORT_ACTIVE ||\r
505                         p_event_rec->pnp_event == IB_PNP_PORT_DOWN ||\r
506                         p_event_rec->pnp_event == IB_PNP_PKEY_CHANGE ||\r
507                         p_event_rec->pnp_event == IB_PNP_SM_CHANGE ||\r
508                         p_event_rec->pnp_event == IB_PNP_GID_CHANGE ||\r
509                         p_event_rec->pnp_event == IB_PNP_LID_CHANGE ||\r
510                         p_event_rec->pnp_event == IB_PNP_SUBNET_TIMEOUT_CHANGE ||\r
511                         p_event_rec->pnp_event == IB_PNP_CA_REMOVE ||\r
512                         p_event_rec->pnp_event == IB_PNP_PORT_REMOVE );\r
513                 return IB_SUCCESS;\r
514         }\r
515 \r
516         /* Invoke the user callback. */\r
517         status = p_reg->pfn_pnp_cb( &u.user_rec );\r
518 \r
519         if( status == IB_SUCCESS )\r
520         {\r
521                 /* Store the user's event context in the context block. */\r
522                 p_context->context = u.user_rec.context;\r
523         }\r
524         else\r
525         {\r
526                 cl_qmap_remove_item( &p_reg->context_map, &p_context->map_item );\r
527                 cl_free( p_context );\r
528         }\r
529 \r
530         CL_EXIT( AL_DBG_PNP, g_al_dbg_lvl );\r
531         return status;\r
532 }\r
533 \r
534 \r
535 \r
536 /*\r
537  * Context creation.\r
538  */\r
539 al_pnp_context_t*\r
540 pnp_create_context(\r
541         IN                              al_pnp_t* const                         p_reg,\r
542         IN              const   net64_t                                         guid )\r
543 {\r
544         al_pnp_context_t        *p_context;\r
545         cl_map_item_t           *p_item;\r
546 \r
547         CL_ENTER( AL_DBG_PNP, g_al_dbg_lvl );\r
548 \r
549         CL_ASSERT( p_reg );\r
550 \r
551         /* No context exists for this port.  Create one. */\r
552         p_context = (al_pnp_context_t*)cl_pzalloc( sizeof(al_pnp_context_t) );\r
553         if( !p_context )\r
554         {\r
555                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
556                         ("Failed to cl_zalloc al_pnp_context_t (%"PRIdSIZE_T" bytes).\n",\r
557                         sizeof(al_pnp_context_t)) );\r
558                 return NULL;\r
559         }\r
560 \r
561         /* Store the GUID in the context record. */\r
562         p_context->guid = guid;\r
563 \r
564         /* Add the context to the context list. */\r
565         p_item = cl_qmap_insert( &p_reg->context_map, p_context->guid,\r
566                 &p_context->map_item );\r
567 \r
568         CL_EXIT( AL_DBG_PNP, g_al_dbg_lvl );\r
569         return p_context;\r
570 }\r
571 \r
572 \r
573 \r
574 /*\r
575  * Report all local port information.  This notifies the user of PORT_ADD\r
576  * events, along with port state events (PORT_INIT, PORT_ACTIVE).\r
577  */\r
578 static void\r
579 __pnp_port_notify(\r
580         IN                              al_pnp_t                                        *p_reg,\r
581         IN                              al_ci_ca_t                                      *p_ci_ca )\r
582 {\r
583         ib_api_status_t                 status;\r
584         al_pnp_context_t                *p_context;\r
585         ib_port_attr_t                  *p_port_attr;\r
586         al_pnp_ca_event_t               event_rec;\r
587 \r
588         CL_ENTER( AL_DBG_PNP, g_al_dbg_lvl );\r
589 \r
590         event_rec.p_ci_ca = p_ci_ca;\r
591 \r
592         for( event_rec.port_index = 0;\r
593                  event_rec.port_index < p_ci_ca->num_ports;\r
594                  event_rec.port_index++ )\r
595         {\r
596                 p_port_attr = p_ci_ca->p_pnp_attr->p_port_attr;\r
597                 p_port_attr += event_rec.port_index;\r
598 \r
599                 /* Create a new context for user port information. */\r
600                 p_context = pnp_create_context( p_reg, p_port_attr->port_guid );\r
601                 if( !p_context )\r
602                         continue;\r
603 \r
604                 /* Notify the user of the port's existence. */\r
605                 event_rec.pnp_event = IB_PNP_PORT_ADD;\r
606                 status = __pnp_notify_user( p_reg, p_context, &event_rec );\r
607                 if( status != IB_SUCCESS )\r
608                         continue;\r
609 \r
610                 /* Generate a port down event if the port is currently down. */\r
611                 if( p_port_attr->link_state == IB_LINK_DOWN )\r
612                 {\r
613                         event_rec.pnp_event = IB_PNP_PORT_DOWN;\r
614                         __pnp_notify_user( p_reg, p_context, &event_rec );\r
615                 }\r
616                 else\r
617                 {\r
618                         /* Generate port init event. */\r
619                         if( p_port_attr->link_state >= IB_LINK_INIT )\r
620                         {\r
621                                 event_rec.pnp_event = IB_PNP_PORT_INIT;\r
622                                 status = __pnp_notify_user( p_reg, p_context, &event_rec );\r
623                                 if( status != IB_SUCCESS )\r
624                                         continue;\r
625                         }\r
626                         /* Generate port armed event. */\r
627                         if( p_port_attr->link_state >= IB_LINK_ARMED )\r
628                         {\r
629                                 event_rec.pnp_event = IB_PNP_PORT_ARMED;\r
630                                 status = __pnp_notify_user( p_reg, p_context, &event_rec );\r
631                                 if( status != IB_SUCCESS )\r
632                                         continue;\r
633                         }\r
634                         /* Generate port up event. */\r
635                         if( p_port_attr->link_state >= IB_LINK_ACTIVE )\r
636                         {\r
637                                 event_rec.pnp_event = IB_PNP_PORT_ACTIVE;\r
638                                 __pnp_notify_user( p_reg, p_context, &event_rec );\r
639                         }\r
640                 }\r
641         }\r
642         CL_EXIT( AL_DBG_PNP, g_al_dbg_lvl );\r
643 }\r
644 \r
645 \r
646 /*\r
647  * Registration and deregistration.\r
648  */\r
649 static void\r
650 __pnp_reg_notify(\r
651         IN                              al_pnp_t* const                         p_reg )\r
652 {\r
653         al_pnp_ca_event_t               event_rec;\r
654         size_t                                  i;\r
655         al_pnp_context_t                *p_context;\r
656 \r
657         CL_ENTER( AL_DBG_PNP, g_al_dbg_lvl );\r
658 \r
659         for( i = 0; i < cl_ptr_vector_get_size( &gp_pnp->ca_vector ); i++ )\r
660         {\r
661                 event_rec.p_ci_ca = (al_ci_ca_t*)\r
662                         cl_ptr_vector_get( &gp_pnp->ca_vector, i );\r
663                 if( !event_rec.p_ci_ca )\r
664                         continue;\r
665 \r
666                 switch( pnp_get_class( p_reg->pnp_class ) )\r
667                 {\r
668                 case IB_PNP_CA:\r
669                         event_rec.pnp_event = IB_PNP_CA_ADD;\r
670                         p_context = pnp_create_context( p_reg,\r
671                                 event_rec.p_ci_ca->p_pnp_attr->ca_guid );\r
672                         if( !p_context )\r
673                                 break;\r
674 \r
675                         __pnp_notify_user( p_reg, p_context, &event_rec );\r
676                         break;\r
677 \r
678                 case IB_PNP_PORT:\r
679                         __pnp_port_notify( p_reg, event_rec.p_ci_ca );\r
680                         break;\r
681 \r
682                 default:\r
683                         CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_CA ||\r
684                                 pnp_get_class( p_reg->pnp_class ) == IB_PNP_PORT );\r
685                         continue;\r
686                 }\r
687         }\r
688 \r
689         /* Notify the user that the registration is complete. */\r
690         pnp_reg_complete( p_reg );\r
691 \r
692         CL_EXIT( AL_DBG_PNP, g_al_dbg_lvl );\r
693 }\r
694 \r
695 \r
696 static void\r
697 __al_pnp_process_reg(\r
698         IN                              cl_async_proc_item_t*           p_item )\r
699 {\r
700         al_pnp_t*               p_reg;\r
701 \r
702         CL_ENTER( AL_DBG_PNP, g_al_dbg_lvl );\r
703 \r
704         p_reg = PARENT_STRUCT( p_item, al_pnp_t, async_item );\r
705 \r
706         /* Add the registrant to the list. */\r
707         switch( pnp_get_class( p_reg->pnp_class ) )\r
708         {\r
709         case IB_PNP_CA:\r
710                 cl_qlist_insert_tail( &gp_pnp->ca_reg_list, &p_reg->list_item );\r
711                 break;\r
712 \r
713         case IB_PNP_PORT:\r
714                 cl_qlist_insert_tail( &gp_pnp->port_reg_list, &p_reg->list_item );\r
715                 break;\r
716 \r
717         default:\r
718                 CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_CA ||\r
719                         pnp_get_class( p_reg->pnp_class ) == IB_PNP_PORT );\r
720         }\r
721 \r
722         /* Generate all relevant events for the registration. */\r
723         __pnp_reg_notify( p_reg );\r
724 \r
725         /* Release the reference taken in init_al_obj. */\r
726         deref_al_obj( &p_reg->obj );\r
727 \r
728         CL_EXIT( AL_DBG_PNP, g_al_dbg_lvl );\r
729 }\r
730 \r
731 \r
732 ib_api_status_t\r
733 ib_reg_pnp(\r
734         IN              const   ib_al_handle_t                          h_al,\r
735         IN              const   ib_pnp_req_t* const                     p_pnp_req,\r
736                 OUT                     ib_pnp_handle_t* const          ph_pnp )\r
737 {\r
738         ib_api_status_t         status;\r
739         KEVENT                          event;\r
740 \r
741         CL_ENTER( AL_DBG_PNP, g_al_dbg_lvl );\r
742 \r
743         if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) )\r
744         {\r
745                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl, ("IB_INVALID_AL_HANDLE\n") );\r
746                 return IB_INVALID_AL_HANDLE;\r
747         }\r
748         if( !p_pnp_req || !ph_pnp )\r
749         {\r
750                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl, ("IB_INVALID_PARAMETER\n") );\r
751                 return IB_INVALID_PARAMETER;\r
752         }\r
753 \r
754         if( pnp_get_flag( p_pnp_req->pnp_class ) & IB_PNP_FLAG_REG_SYNC )\r
755                 KeInitializeEvent( &event, SynchronizationEvent, FALSE );\r
756 \r
757         status = al_reg_pnp( h_al, p_pnp_req, &event, ph_pnp );\r
758         /* Release the reference taken in init_al_obj. */\r
759         if( status == IB_SUCCESS )\r
760         {\r
761                 deref_al_obj( &(*ph_pnp)->obj );\r
762                 \r
763                 /* Wait for registration to complete if synchronous. */\r
764                 if( pnp_get_flag( p_pnp_req->pnp_class ) & IB_PNP_FLAG_REG_SYNC )\r
765                 {\r
766                         KeWaitForSingleObject(\r
767                                 &event, Executive, KernelMode, TRUE, NULL );\r
768                 }\r
769         }\r
770 \r
771         AL_EXIT( AL_DBG_PNP );\r
772         return status;\r
773 }\r
774 \r
775 \r
776 ib_api_status_t\r
777 al_reg_pnp(\r
778         IN              const   ib_al_handle_t                          h_al,\r
779         IN              const   ib_pnp_req_t* const                     p_pnp_req,\r
780         IN                              KEVENT                                          *p_sync_event,\r
781                 OUT                     ib_pnp_handle_t* const          ph_pnp )\r
782 {\r
783         ib_api_status_t         status;\r
784         al_pnp_t*                       p_reg;\r
785 \r
786         CL_ENTER( AL_DBG_PNP, g_al_dbg_lvl );\r
787 \r
788         /* Allocate a new registration info structure. */\r
789         p_reg = (al_pnp_t*)cl_zalloc( sizeof(al_pnp_t) );\r
790         if( !p_reg )\r
791         {\r
792                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
793                         ("Failed to cl_zalloc al_pnp_t (%"PRIdSIZE_T" bytes).\n",\r
794                         sizeof(al_pnp_t)) );\r
795                 return( IB_INSUFFICIENT_MEMORY );\r
796         }\r
797 \r
798         /* Initialize the registration info. */\r
799         construct_al_obj( &p_reg->obj, AL_OBJ_TYPE_H_PNP );\r
800         cl_qmap_init( &p_reg->context_map );\r
801         status = init_al_obj( &p_reg->obj, p_pnp_req->pnp_context, TRUE,\r
802                 __pnp_reg_destroying, __pnp_reg_cleanup, __pnp_reg_free );\r
803         if( status != IB_SUCCESS )\r
804         {\r
805                 __pnp_reg_free( &p_reg->obj );\r
806                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
807                         ("init_al_obj() failed with status %s.\n", ib_get_err_str(status)) );\r
808                 return( status );\r
809         }\r
810         status = attach_al_obj( &h_al->obj, &p_reg->obj );\r
811         if( status != IB_SUCCESS )\r
812         {\r
813                 p_reg->obj.pfn_destroy( &p_reg->obj, NULL );\r
814                 AL_TRACE_EXIT( AL_DBG_ERROR,\r
815                         ("attach_al_obj returned %s.\n", ib_get_err_str(status)) );\r
816                 return status;\r
817         }\r
818 \r
819         /* Reference the PnP Manager. */\r
820         ref_al_obj( &gp_pnp->obj );\r
821 \r
822         /* Copy the request information. */\r
823         p_reg->pnp_class = p_pnp_req->pnp_class;\r
824         p_reg->pfn_pnp_cb = p_pnp_req->pfn_pnp_cb;\r
825 \r
826         p_reg->p_sync_event = p_sync_event;\r
827 \r
828         /* Send IOU/IOC registration to the IOC PnP manager. */\r
829         if( pnp_get_class(p_pnp_req->pnp_class) == IB_PNP_IOU ||\r
830                 pnp_get_class(p_pnp_req->pnp_class) == IB_PNP_IOC )\r
831         {\r
832                 p_reg->async_item.pfn_callback = ioc_pnp_process_reg;\r
833                 p_reg->dereg_item.pfn_callback = ioc_pnp_process_dereg;\r
834         }\r
835         else\r
836         {\r
837                 p_reg->async_item.pfn_callback = __al_pnp_process_reg;\r
838                 p_reg->dereg_item.pfn_callback = __al_pnp_process_dereg;\r
839         }\r
840 \r
841         /* Queue the registrant for addition to the list. */\r
842         ref_al_obj( &p_reg->obj );\r
843         cl_async_proc_queue( gp_async_pnp_mgr, &p_reg->async_item );\r
844 \r
845         /* Set the user handle. */\r
846         *ph_pnp = p_reg;\r
847 \r
848         CL_EXIT( AL_DBG_PNP, g_al_dbg_lvl );\r
849         return( IB_SUCCESS );\r
850 }\r
851 \r
852 \r
853 ib_api_status_t\r
854 ib_dereg_pnp(\r
855         IN              const   ib_pnp_handle_t                         h_pnp,\r
856         IN              const   ib_pfn_destroy_cb_t                     pfn_destroy_cb OPTIONAL )\r
857 {\r
858         CL_ENTER( AL_DBG_PNP, g_al_dbg_lvl );\r
859 \r
860         if( AL_OBJ_INVALID_HANDLE( h_pnp, AL_OBJ_TYPE_H_PNP ) )\r
861         {\r
862                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl, ("IB_INVALID_HANDLE\n") );\r
863                 return IB_INVALID_HANDLE;\r
864         }\r
865 \r
866         ref_al_obj( &h_pnp->obj );\r
867         h_pnp->obj.pfn_destroy( &h_pnp->obj, pfn_destroy_cb );\r
868 \r
869         CL_EXIT( AL_DBG_PNP, g_al_dbg_lvl );\r
870         return( IB_SUCCESS );\r
871 }\r
872 \r
873 \r
874 /*\r
875  * CA event handling.\r
876  */\r
877 static void\r
878 __pnp_process_add_ca(\r
879         IN                              cl_async_proc_item_t            *p_item )\r
880 {\r
881         al_pnp_t                        *p_reg;\r
882         al_pnp_ca_event_t       *p_event_rec;\r
883         cl_list_item_t          *p_reg_item;\r
884         al_pnp_context_t        *p_context;\r
885         cl_status_t                     cl_status;\r
886         size_t                          i;\r
887 \r
888         CL_ENTER( AL_DBG_PNP, g_al_dbg_lvl );\r
889 \r
890         p_event_rec = PARENT_STRUCT( p_item, al_pnp_ca_event_t, async_item );\r
891 \r
892         cl_spinlock_acquire( &gp_pnp->obj.lock );\r
893         /* Add the CA to the CA vector. */\r
894         for( i = 0; i < cl_ptr_vector_get_size( &gp_pnp->ca_vector ); i++ )\r
895         {\r
896                 if( !cl_ptr_vector_get( &gp_pnp->ca_vector, i ) )\r
897                 {\r
898                         cl_status = cl_ptr_vector_set( &gp_pnp->ca_vector, i,\r
899                                 p_event_rec->p_ci_ca );\r
900                         CL_ASSERT( cl_status == CL_SUCCESS );\r
901                         break;\r
902                 }\r
903         }\r
904         cl_spinlock_release( &gp_pnp->obj.lock );\r
905         CL_ASSERT( i < cl_ptr_vector_get_size( &gp_pnp->ca_vector ) );\r
906 \r
907         /* Walk the list of registrants for notification. */\r
908         for( p_reg_item = cl_qlist_head( &gp_pnp->ca_reg_list );\r
909                  p_reg_item != cl_qlist_end( &gp_pnp->ca_reg_list );\r
910                  p_reg_item = cl_qlist_next( p_reg_item ) )\r
911         {\r
912                 p_reg = PARENT_STRUCT( p_reg_item, al_pnp_t, list_item );\r
913                 CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_CA );\r
914 \r
915                 /* Allocate the user's context. */\r
916                 /*\r
917                  * Moving this allocation to the pnp_ca_event call is left as an\r
918                  * exercise to the open source community.\r
919                  */\r
920                 p_context = pnp_create_context( p_reg,\r
921                         p_event_rec->p_ci_ca->p_pnp_attr->ca_guid );\r
922                 if( !p_context )\r
923                         continue;\r
924 \r
925                 /* Notify the user. */\r
926                 __pnp_notify_user( p_reg, p_context, p_event_rec );\r
927         }\r
928 \r
929         /* Generate port add and state events. */\r
930         for( p_reg_item = cl_qlist_head( &gp_pnp->port_reg_list );\r
931                  p_reg_item != cl_qlist_end( &gp_pnp->port_reg_list );\r
932                  p_reg_item = cl_qlist_next( p_reg_item ) )\r
933         {\r
934                 p_reg = PARENT_STRUCT( p_reg_item, al_pnp_t, list_item );\r
935                 CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_PORT );\r
936                 __pnp_port_notify( p_reg, p_event_rec->p_ci_ca );\r
937         }\r
938 \r
939         /* Cleanup the event record. */\r
940         deref_al_obj( &gp_pnp->obj );\r
941         cl_free( p_event_rec );\r
942 \r
943         CL_EXIT( AL_DBG_PNP, g_al_dbg_lvl );\r
944 }\r
945 \r
946 \r
947 static void\r
948 __pnp_process_remove_port(\r
949         IN              const   al_pnp_ca_event_t* const        p_event_rec )\r
950 {\r
951         ib_api_status_t                 status;\r
952         al_pnp_t                                *p_reg;\r
953         cl_list_item_t                  *p_reg_item;\r
954         uint8_t                                 port_index;\r
955         al_pnp_context_t                *p_context;\r
956         al_pnp_ca_event_t               event_rec;\r
957         ib_port_attr_t                  *p_port_attr;\r
958 \r
959         CL_ENTER( AL_DBG_PNP, g_al_dbg_lvl );\r
960 \r
961         CL_ASSERT( p_event_rec->p_ci_ca->p_pnp_attr );\r
962         CL_ASSERT( p_event_rec->p_ci_ca->p_pnp_attr->p_port_attr );\r
963 \r
964         /* Notify the IOC PnP manager of the port down event. */\r
965         //***TODO: Make some call to the IOC PnP manager here, such as\r
966         //***TODO: al_ioc_pnp_process_port_down( p_event_rec->p_ci_ca,\r
967         //***TODO:              p_event_rec->port_index );\r
968 \r
969         cl_memclr( &event_rec, sizeof( al_pnp_ca_event_t ) );\r
970         event_rec = *p_event_rec;\r
971 \r
972         /* Walk the list of registrants for notification. */\r
973         for( p_reg_item = cl_qlist_tail( &gp_pnp->port_reg_list );\r
974                  p_reg_item != cl_qlist_end( &gp_pnp->port_reg_list );\r
975                  p_reg_item = cl_qlist_prev( p_reg_item ) )\r
976         {\r
977                 p_reg = PARENT_STRUCT( p_reg_item, al_pnp_t, list_item );\r
978 \r
979                 CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_PORT );\r
980 \r
981                 for( port_index = 0;\r
982                          port_index < p_event_rec->p_ci_ca->num_ports;\r
983                          port_index++ )\r
984                 {\r
985                         p_port_attr = p_event_rec->p_ci_ca->p_pnp_attr->p_port_attr;\r
986                         p_port_attr += port_index;\r
987                         p_context = pnp_get_context( p_reg, p_port_attr->port_guid );\r
988                         if( !p_context )\r
989                                 continue;\r
990 \r
991                         event_rec.port_index = port_index;\r
992 \r
993                         if( p_port_attr->link_state >= IB_LINK_INIT )\r
994                         {\r
995                                 /* Notify the user of the port down. */\r
996                                 event_rec.pnp_event = IB_PNP_PORT_DOWN;\r
997                                 status = __pnp_notify_user( p_reg, p_context, &event_rec );\r
998                                 if( status != IB_SUCCESS )\r
999                                         continue;\r
1000                         }\r
1001 \r
1002                         /* Notify the user of the port remove. */\r
1003                         event_rec.pnp_event = IB_PNP_PORT_REMOVE;\r
1004                         status = __pnp_notify_user( p_reg, p_context, &event_rec );\r
1005                         if( status == IB_SUCCESS )\r
1006                         {\r
1007                                 /*\r
1008                                  * Remove the port context from the registrant's\r
1009                                  * context list.\r
1010                                  */\r
1011                                 cl_qmap_remove_item( &p_reg->context_map,\r
1012                                         &p_context->map_item );\r
1013                                 /* Free the context. */\r
1014                                 cl_free( p_context );\r
1015                         }\r
1016                 }\r
1017         }\r
1018 \r
1019         CL_EXIT( AL_DBG_PNP, g_al_dbg_lvl );\r
1020 }\r
1021 \r
1022 \r
1023 static void\r
1024 __pnp_process_remove_ca(\r
1025         IN                              cl_async_proc_item_t            *p_item )\r
1026 {\r
1027         al_pnp_t                        *p_reg;\r
1028         al_pnp_ca_event_t       *p_event_rec;\r
1029         cl_list_item_t          *p_reg_item;\r
1030         al_pnp_context_t        *p_context = NULL;\r
1031         size_t                          i;\r
1032 \r
1033         CL_ENTER( AL_DBG_PNP, g_al_dbg_lvl );\r
1034 \r
1035         p_event_rec = PARENT_STRUCT( p_item, al_pnp_ca_event_t, async_item );\r
1036 \r
1037         /* Generate port remove events. */\r
1038         __pnp_process_remove_port( p_event_rec );\r
1039 \r
1040         /* Walk the list of registrants for notification. */\r
1041         for( p_reg_item = cl_qlist_tail( &gp_pnp->ca_reg_list );\r
1042                  p_reg_item != cl_qlist_end( &gp_pnp->ca_reg_list );\r
1043                  p_reg_item = cl_qlist_prev( p_reg_item ) )\r
1044         {\r
1045                 p_reg = PARENT_STRUCT( p_reg_item, al_pnp_t, list_item );\r
1046 \r
1047                 CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_CA );\r
1048 \r
1049                 /* Search the context list for this CA. */\r
1050                 p_context =\r
1051                         pnp_get_context( p_reg, p_event_rec->p_ci_ca->verbs.guid );\r
1052 \r
1053                 /* Make sure we found a context. */\r
1054                 if( !p_context )\r
1055                         continue;\r
1056 \r
1057                 /* Notify the user. */\r
1058                 if( __pnp_notify_user( p_reg, p_context, p_event_rec ) == IB_SUCCESS )\r
1059                 {\r
1060                         /* Remove the context from the context list. */\r
1061                         cl_qmap_remove_item( &p_reg->context_map, &p_context->map_item );\r
1062 \r
1063                         /* Deallocate the context block. */\r
1064                         cl_free( p_context );\r
1065                 }\r
1066         }\r
1067 \r
1068         /* Remove the CA from the CA vector. */\r
1069         for( i = 0; i < cl_ptr_vector_get_size( &gp_pnp->ca_vector ); i++ )\r
1070         {\r
1071                 if( cl_ptr_vector_get( &gp_pnp->ca_vector, i ) ==\r
1072                         p_event_rec->p_ci_ca )\r
1073                 {\r
1074                         cl_ptr_vector_remove( &gp_pnp->ca_vector, i );\r
1075                         break;\r
1076                 }\r
1077         }\r
1078 \r
1079         /* Release the reference to the CA. */\r
1080         deref_al_obj( &p_event_rec->p_ci_ca->obj );\r
1081 \r
1082         /* Cleanup the event record. */\r
1083         deref_al_obj( &gp_pnp->obj );\r
1084         cl_free( p_event_rec );\r
1085 \r
1086         CL_EXIT( AL_DBG_PNP, g_al_dbg_lvl );\r
1087 }\r
1088 \r
1089 \r
1090 ib_api_status_t\r
1091 pnp_ca_event(\r
1092         IN                              al_ci_ca_t* const                       p_ci_ca,\r
1093         IN              const   ib_pnp_event_t                          event )\r
1094 {\r
1095         ib_api_status_t         status;\r
1096         cl_status_t                     cl_status;\r
1097         al_pnp_ca_event_t       *p_event_rec;\r
1098         ib_ca_attr_t            *p_old_ca_attr;\r
1099 \r
1100         CL_ENTER( AL_DBG_PNP, g_al_dbg_lvl );\r
1101 \r
1102         /* Allocate an event record. */\r
1103         p_event_rec = (al_pnp_ca_event_t*)cl_zalloc( sizeof(al_pnp_ca_event_t) );\r
1104         if( !p_event_rec )\r
1105         {\r
1106                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
1107                         ("Failed to cl_zalloc al_pnp_ca_event_t (%"PRIdSIZE_T" bytes).\n",\r
1108                         sizeof(al_pnp_ca_event_t)) );\r
1109                 return IB_INSUFFICIENT_MEMORY;\r
1110         }\r
1111 \r
1112         /* Store the event type. */\r
1113         p_event_rec->pnp_event = event;\r
1114         /* Store a pointer to the ca. */\r
1115         p_event_rec->p_ci_ca = p_ci_ca;\r
1116 \r
1117         switch( event )\r
1118         {\r
1119         case IB_PNP_CA_ADD:\r
1120                 p_event_rec->async_item.pfn_callback = __pnp_process_add_ca;\r
1121 \r
1122                 /* Reserve space for the CA in the CA vector. */\r
1123                 cl_spinlock_acquire( &gp_pnp->obj.lock );\r
1124                 cl_status = cl_ptr_vector_set_size( &gp_pnp->ca_vector,\r
1125                                 cl_ptr_vector_get_size( &gp_pnp->ca_vector ) + 1 );\r
1126                 cl_spinlock_release( &gp_pnp->obj.lock );\r
1127 \r
1128                 if( cl_status != CL_SUCCESS )\r
1129                 {\r
1130                         cl_free( p_event_rec );\r
1131                         CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
1132                                 ("cl_ptr_vector_set_size failed with status %s.\n",\r
1133                                 CL_STATUS_MSG( cl_status )) );\r
1134                         return ib_convert_cl_status( cl_status );\r
1135                 }\r
1136 \r
1137                 /* Read the CA attributes required to process the event. */\r
1138                 status = ci_ca_update_attr( p_ci_ca, &p_old_ca_attr );\r
1139                 if( status != IB_SUCCESS )\r
1140                 {\r
1141                         cl_spinlock_acquire( &gp_pnp->obj.lock );\r
1142                         cl_status = cl_ptr_vector_set_size( &gp_pnp->ca_vector,\r
1143                                 cl_ptr_vector_get_size( &gp_pnp->ca_vector ) - 1 );\r
1144                         CL_ASSERT( cl_status == CL_SUCCESS );\r
1145                         cl_spinlock_release( &gp_pnp->obj.lock );\r
1146                         cl_free( p_event_rec );\r
1147                         CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
1148                                 ("ci_ca_update_attr failed.\n") );\r
1149                         return status;\r
1150                 }\r
1151 \r
1152                 /* Take out a reference to the CA until it is removed. */\r
1153                 ref_al_obj( &p_ci_ca->obj );\r
1154                 break;\r
1155 \r
1156         case IB_PNP_CA_REMOVE:\r
1157                 if( !p_event_rec->p_ci_ca->p_pnp_attr )\r
1158                 {\r
1159                         /* The CA was never added by the PNP manager. */\r
1160                         cl_free( p_event_rec );\r
1161                         CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
1162                                 ("Ignoring removal request for unknown CA.\n") );\r
1163                         return IB_NOT_FOUND;\r
1164                 }\r
1165 \r
1166                 p_event_rec->async_item.pfn_callback = __pnp_process_remove_ca;\r
1167                 break;\r
1168 \r
1169         default:\r
1170                 /* Invalid event for this function. */\r
1171                 CL_ASSERT( event == IB_PNP_CA_ADD || event == IB_PNP_CA_REMOVE );\r
1172                 cl_free( p_event_rec );\r
1173                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
1174                         ("Invalid event type.\n") );\r
1175                 return IB_ERROR;\r
1176         }\r
1177 \r
1178         /* Queue the event to the async processing manager. */\r
1179         ref_al_obj( &gp_pnp->obj );\r
1180         cl_async_proc_queue( gp_async_pnp_mgr, &p_event_rec->async_item );\r
1181 \r
1182         CL_EXIT( AL_DBG_PNP, g_al_dbg_lvl );\r
1183         return IB_SUCCESS;\r
1184 }\r
1185 \r
1186 \r
1187 /*\r
1188  * Port event handling.\r
1189  */\r
1190 \r
1191 /*\r
1192  * Processes a port event, reporting it to clients from the first\r
1193  * registrant to the last.\r
1194  */\r
1195 static void\r
1196 __pnp_process_port_forward(\r
1197         IN                              al_pnp_ca_event_t*                      p_event_rec )\r
1198 {\r
1199         al_pnp_t                                *p_reg;\r
1200         cl_list_item_t                  *p_reg_item;\r
1201         al_pnp_context_t                *p_context;\r
1202         ib_port_attr_t                  *p_port_attr;\r
1203 \r
1204         CL_ENTER( AL_DBG_PNP, g_al_dbg_lvl );\r
1205 \r
1206         /* Walk the list of registrants for notification. */\r
1207         for( p_reg_item = cl_qlist_head( &gp_pnp->port_reg_list );\r
1208                  p_reg_item != cl_qlist_end( &gp_pnp->port_reg_list );\r
1209                  p_reg_item = cl_qlist_next( p_reg_item ) )\r
1210         {\r
1211                 p_reg = PARENT_STRUCT( p_reg_item, al_pnp_t, list_item );\r
1212 \r
1213                 CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_PORT );\r
1214 \r
1215                 p_port_attr = p_event_rec->p_ci_ca->p_pnp_attr->p_port_attr;\r
1216                 p_port_attr += p_event_rec->port_index;\r
1217 \r
1218                 p_context = pnp_get_context( p_reg, p_port_attr->port_guid );\r
1219                 if( !p_context )\r
1220                         continue;\r
1221 \r
1222                 /* Notify the user. */\r
1223                 __pnp_notify_user( p_reg, p_context, p_event_rec );\r
1224         }\r
1225 \r
1226         CL_EXIT( AL_DBG_PNP, g_al_dbg_lvl );\r
1227 }\r
1228 \r
1229 \r
1230 /*\r
1231  * Processes a port event, reporting it to clients from the last\r
1232  * registrant to the first.\r
1233  */\r
1234 static void\r
1235 __pnp_process_port_backward(\r
1236         IN                              al_pnp_ca_event_t*                      p_event_rec )\r
1237 {\r
1238         al_pnp_t                                *p_reg;\r
1239         cl_list_item_t                  *p_reg_item;\r
1240         al_pnp_context_t                *p_context;\r
1241         ib_port_attr_t                  *p_port_attr;\r
1242 \r
1243         CL_ENTER( AL_DBG_PNP, g_al_dbg_lvl );\r
1244 \r
1245         /* Walk the list of registrants for notification. */\r
1246         for( p_reg_item = cl_qlist_tail( &gp_pnp->port_reg_list );\r
1247                  p_reg_item != cl_qlist_end( &gp_pnp->port_reg_list );\r
1248                  p_reg_item = cl_qlist_prev( p_reg_item ) )\r
1249         {\r
1250                 p_reg = PARENT_STRUCT( p_reg_item, al_pnp_t, list_item );\r
1251 \r
1252                 CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_PORT );\r
1253 \r
1254                 p_port_attr = p_event_rec->p_ci_ca->p_pnp_attr->p_port_attr;\r
1255                 p_port_attr += p_event_rec->port_index;\r
1256 \r
1257                 p_context = pnp_get_context( p_reg, p_port_attr->port_guid );\r
1258                 if( !p_context )\r
1259                         continue;\r
1260 \r
1261                 /* Notify the user. */\r
1262                 __pnp_notify_user( p_reg, p_context, p_event_rec );\r
1263         }\r
1264 \r
1265         CL_EXIT( AL_DBG_PNP, g_al_dbg_lvl );\r
1266 }\r
1267 \r
1268 \r
1269 \r
1270 /*\r
1271  * Check for port attribute changes.\r
1272  */\r
1273 static void\r
1274 __pnp_check_ports(\r
1275         IN                              al_ci_ca_t* const                       p_ci_ca,\r
1276         IN              const   ib_ca_attr_t* const                     p_old_ca_attr )\r
1277 {\r
1278         uint16_t                                index;\r
1279         al_pnp_ca_event_t               event_rec;\r
1280         ib_port_attr_t                  *p_old_port_attr, *p_new_port_attr;\r
1281 \r
1282         CL_ENTER( AL_DBG_PNP, g_al_dbg_lvl );\r
1283 \r
1284         /* Store the event information. */\r
1285         event_rec.p_ci_ca = p_ci_ca;\r
1286 \r
1287         for( event_rec.port_index = 0;\r
1288                  event_rec.port_index < p_ci_ca->p_pnp_attr->num_ports;\r
1289                  event_rec.port_index++ )\r
1290         {\r
1291                 p_old_port_attr = p_old_ca_attr->p_port_attr;\r
1292                 p_old_port_attr += event_rec.port_index;\r
1293                 p_new_port_attr = p_ci_ca->p_pnp_attr->p_port_attr;\r
1294                 p_new_port_attr += event_rec.port_index;\r
1295 \r
1296                 /* Check the link state. */\r
1297                 if( p_old_port_attr->link_state != p_new_port_attr->link_state )\r
1298                 {\r
1299                         switch( p_new_port_attr->link_state )\r
1300                         {\r
1301                         case IB_LINK_DOWN:\r
1302                                 event_rec.pnp_event = IB_PNP_PORT_DOWN;\r
1303                                 __pnp_process_port_backward( &event_rec );\r
1304                                 break;\r
1305 \r
1306                         case IB_LINK_INIT:\r
1307                                 if( p_old_port_attr->link_state > IB_LINK_INIT )\r
1308                                 {\r
1309                                         /* Missed the down event. */\r
1310                                         event_rec.pnp_event = IB_PNP_PORT_DOWN;\r
1311                                         __pnp_process_port_backward( &event_rec );\r
1312                                 }\r
1313                                 event_rec.pnp_event = IB_PNP_PORT_INIT;\r
1314                                 __pnp_process_port_forward( &event_rec );\r
1315                                 break;\r
1316 \r
1317                         case IB_LINK_ARMED:\r
1318                                 if( p_old_port_attr->link_state > IB_LINK_ARMED )\r
1319                                 {\r
1320                                         /* Missed the down and init events. */\r
1321                                         event_rec.pnp_event = IB_PNP_PORT_DOWN;\r
1322                                         __pnp_process_port_backward( &event_rec );\r
1323                                         event_rec.pnp_event = IB_PNP_PORT_INIT;\r
1324                                         __pnp_process_port_forward( &event_rec );\r
1325                                 }\r
1326                                 event_rec.pnp_event = IB_PNP_PORT_ARMED;\r
1327                                 __pnp_process_port_forward( &event_rec );\r
1328                                 break;\r
1329 \r
1330                         case IB_LINK_ACTIVE:\r
1331                         case IB_LINK_ACT_DEFER:\r
1332                                 if( p_old_port_attr->link_state == IB_LINK_DOWN )\r
1333                                 {\r
1334                                         /* Missed the init and armed event. */\r
1335                                         event_rec.pnp_event = IB_PNP_PORT_INIT;\r
1336                                         __pnp_process_port_forward( &event_rec );\r
1337                                         event_rec.pnp_event = IB_PNP_PORT_ARMED;\r
1338                                         __pnp_process_port_forward( &event_rec );\r
1339                                 }\r
1340                                 if( p_old_port_attr->link_state < IB_LINK_ACTIVE )\r
1341                                 {\r
1342                                         event_rec.pnp_event = IB_PNP_PORT_ACTIVE;\r
1343                                         __pnp_process_port_forward( &event_rec );\r
1344                                 }\r
1345                                 break;\r
1346 \r
1347                         default:\r
1348                                 break;\r
1349                         }\r
1350                 }\r
1351 \r
1352                 /*\r
1353                  * Check for P_Key and GID table changes.\r
1354                  * The tables are only valid in the armed or active states.\r
1355                  */\r
1356                 if( ( (p_old_port_attr->link_state == IB_LINK_ARMED) ||\r
1357                         (p_old_port_attr->link_state == IB_LINK_ACTIVE) )\r
1358                         &&\r
1359                         ( (p_new_port_attr->link_state == IB_LINK_ARMED) ||\r
1360                         (p_new_port_attr->link_state == IB_LINK_ACTIVE) ) )\r
1361                 {\r
1362                         /* A different number of P_Keys indicates a change.*/\r
1363                         if( p_old_port_attr->num_pkeys != p_new_port_attr->num_pkeys )\r
1364                         {\r
1365                                 event_rec.pnp_event = IB_PNP_PKEY_CHANGE;\r
1366                                 __pnp_process_port_forward( &event_rec );\r
1367                         }\r
1368                         else\r
1369                         {\r
1370                                 /* Same number of P_Keys - compare the table contents. */\r
1371                                 for( index = 0; index < p_old_port_attr->num_pkeys; index++ )\r
1372                                 {\r
1373                                         if( p_old_port_attr->p_pkey_table[index] !=\r
1374                                                 p_new_port_attr->p_pkey_table[index] )\r
1375                                         {\r
1376                                                 event_rec.pnp_event = IB_PNP_PKEY_CHANGE;\r
1377                                                 __pnp_process_port_forward( &event_rec );\r
1378                                                 break;\r
1379                                         }\r
1380                                 }\r
1381                         }\r
1382 \r
1383                         /* A different number of GIDs indicates a change.*/\r
1384                         if( p_old_port_attr->num_gids != p_new_port_attr->num_gids )\r
1385                         {\r
1386                                 event_rec.pnp_event = IB_PNP_GID_CHANGE;\r
1387                                 __pnp_process_port_forward( &event_rec );\r
1388                         }\r
1389                         else\r
1390                         {\r
1391                                 /* Same number of GIDs - compare the table contents. */\r
1392                                 for( index = 0; index < p_old_port_attr->num_gids; index++ )\r
1393                                 {\r
1394                                         if( cl_memcmp( p_old_port_attr->p_gid_table[index].raw,\r
1395                                                 p_new_port_attr->p_gid_table[index].raw,\r
1396                                                 sizeof( ib_gid_t ) ) )\r
1397                                         {\r
1398                                                 event_rec.pnp_event = IB_PNP_GID_CHANGE;\r
1399                                                 __pnp_process_port_forward( &event_rec );\r
1400                                                 break;\r
1401                                         }\r
1402                                 }\r
1403                         }\r
1404                 }\r
1405 \r
1406                 /* Check for LID change. */\r
1407                 if( (p_old_port_attr->lid != p_new_port_attr->lid) ||\r
1408                         (p_old_port_attr->lmc != p_new_port_attr->lmc) )\r
1409                 {\r
1410                         event_rec.pnp_event = IB_PNP_LID_CHANGE;\r
1411                         __pnp_process_port_forward( &event_rec );\r
1412                 }\r
1413                 /* Check for SM related changes. */\r
1414                 if( (p_old_port_attr->sm_lid != p_new_port_attr->sm_lid) ||\r
1415                         (p_old_port_attr->sm_sl != p_new_port_attr->sm_sl) )\r
1416                 {\r
1417                         event_rec.pnp_event = IB_PNP_SM_CHANGE;\r
1418                         __pnp_process_port_forward( &event_rec );\r
1419                 }\r
1420                 /* Check for subnet timeout change. */\r
1421                 if( p_old_port_attr->subnet_timeout !=\r
1422                         p_new_port_attr->subnet_timeout )\r
1423                 {\r
1424                         event_rec.pnp_event = IB_PNP_SUBNET_TIMEOUT_CHANGE;\r
1425                         __pnp_process_port_forward( &event_rec );\r
1426                 }\r
1427         }\r
1428 }\r
1429 \r
1430 \r
1431 \r
1432 static boolean_t\r
1433 __pnp_cmp_attr(\r
1434         IN                      ib_ca_attr_t                            *p_attr_1,\r
1435         IN                      ib_ca_attr_t                            *p_attr_2\r
1436         )\r
1437 {\r
1438         uint8_t                                 port_index;\r
1439         ib_port_attr_t*                 p_port_attr_1;\r
1440         ib_port_attr_t*                 p_port_attr_2;\r
1441 \r
1442         CL_ASSERT( p_attr_1 && p_attr_2 );\r
1443 \r
1444         for( port_index = 0;\r
1445                  port_index < p_attr_1->num_ports;\r
1446                  port_index++ )\r
1447         {\r
1448                 /* Initialize pointers to the port attributes. */\r
1449                 p_port_attr_1 = &p_attr_1->p_port_attr[port_index];\r
1450                 p_port_attr_2 = &p_attr_2->p_port_attr[port_index];\r
1451 \r
1452                 CL_ASSERT( p_port_attr_1->port_guid == p_port_attr_2->port_guid );\r
1453 \r
1454                 if( cl_memcmp( p_port_attr_1, p_port_attr_2,\r
1455                                 offsetof( ib_port_attr_t, p_gid_table ) ) != 0 )\r
1456                 {\r
1457                         return FALSE;\r
1458                 }\r
1459         }\r
1460 \r
1461         return TRUE;\r
1462 }\r
1463 \r
1464 \r
1465 \r
1466 static void\r
1467 __pnp_check_events(\r
1468         IN                              cl_async_proc_item_t*   p_item )\r
1469 {\r
1470         al_ci_ca_t                              *p_ci_ca;\r
1471         size_t                                  i;\r
1472         uint32_t                                attr_size;\r
1473         ib_ca_attr_t                    *p_old_ca_attr;\r
1474         ib_api_status_t                 status;\r
1475 \r
1476         CL_ENTER( AL_DBG_PNP, g_al_dbg_lvl );\r
1477 \r
1478         UNUSED_PARAM( p_item );\r
1479         CL_ASSERT( gp_pnp );\r
1480 \r
1481         /* Walk all known CAs. */\r
1482         for( i = 0; i < cl_ptr_vector_get_size( &gp_pnp->ca_vector ); i++ )\r
1483         {\r
1484                 p_ci_ca = (al_ci_ca_t*)cl_ptr_vector_get( &gp_pnp->ca_vector, i );\r
1485 \r
1486                 /* Check if the CA was just added to our list but is not ready. */\r
1487                 if( !p_ci_ca )\r
1488                         continue;\r
1489 \r
1490                 attr_size = p_ci_ca->p_pnp_attr->size;\r
1491                 status = ib_query_ca( p_ci_ca->h_ca, p_ci_ca->p_user_attr, &attr_size );\r
1492 \r
1493                 /* Report changes if there is an attribute size difference. */\r
1494                 if( ( attr_size != p_ci_ca->p_pnp_attr->size ) ||\r
1495                         !__pnp_cmp_attr( p_ci_ca->p_pnp_attr, p_ci_ca->p_user_attr ) )\r
1496                 {\r
1497                         status = ci_ca_update_attr( p_ci_ca, &p_old_ca_attr );\r
1498                         if( status == IB_SUCCESS )\r
1499                         {\r
1500                                 /* Check port attributes and report changes. */\r
1501                                 __pnp_check_ports( p_ci_ca, p_old_ca_attr );\r
1502 \r
1503                                 /* Free the old CA attributes. */\r
1504                                 cl_free( p_old_ca_attr );\r
1505                         }\r
1506                         else\r
1507                         {\r
1508                                 /*\r
1509                                  * Could not get new attribute buffers.\r
1510                                  * Skip this event - it should be picked up on the next check.\r
1511                                  */\r
1512                                 continue;\r
1513                         }\r
1514                 }\r
1515         }\r
1516 \r
1517         /* Dereference the PnP Manager. */\r
1518         deref_al_obj( &gp_pnp->obj );\r
1519         gp_pnp->async_item_is_busy = FALSE;\r
1520 \r
1521         CL_EXIT( AL_DBG_PNP, g_al_dbg_lvl );\r
1522 }\r
1523 \r
1524 \r
1525 \r
1526 /*\r
1527  * Check and report PnP events.\r
1528  */\r
1529 void\r
1530 pnp_poll(\r
1531         void )\r
1532 {\r
1533         CL_ENTER( AL_DBG_PNP, g_al_dbg_lvl );\r
1534 \r
1535         CL_ASSERT( gp_pnp );\r
1536 \r
1537         /* Determine if the PnP manager asynchronous processing item is busy. */\r
1538         cl_spinlock_acquire( &gp_pnp->obj.lock );\r
1539 \r
1540         if( gp_pnp->async_item_is_busy )\r
1541         {\r
1542                 cl_spinlock_release( &gp_pnp->obj.lock );\r
1543                 return;\r
1544         }\r
1545 \r
1546         gp_pnp->async_item_is_busy = TRUE;\r
1547 \r
1548         cl_spinlock_release( &gp_pnp->obj.lock );\r
1549 \r
1550         /* Reference the PnP Manager. */\r
1551         ref_al_obj( &gp_pnp->obj );\r
1552 \r
1553         /* Queue the request to check for PnP events. */\r
1554         cl_async_proc_queue( gp_async_pnp_mgr, &gp_pnp->async_item );\r
1555 \r
1556         CL_EXIT( AL_DBG_PNP, g_al_dbg_lvl );\r
1557 }\r
1558 \r
1559 \r
1560 \r
1561 static void\r
1562 __pnp_process_ca_change(\r
1563         IN                              cl_async_proc_item_t*   p_item )\r
1564 {\r
1565         al_pnp_ca_change_t              *p_pnp_ca_change;\r
1566         ib_ca_attr_t                    *p_old_ca_attr;\r
1567         al_ci_ca_t                              *p_ci_ca;\r
1568 \r
1569         CL_ENTER( AL_DBG_PNP, g_al_dbg_lvl );\r
1570 \r
1571         CL_ASSERT( p_item );\r
1572         CL_ASSERT( gp_pnp );\r
1573 \r
1574         p_pnp_ca_change = PARENT_STRUCT( p_item, al_pnp_ca_change_t, async_item );\r
1575 \r
1576         p_ci_ca = p_pnp_ca_change->p_ci_ca;\r
1577 \r
1578         /*\r
1579          * Prevent readers of the CA attributes from accessing them while\r
1580          * we are updating the pointers.\r
1581          */\r
1582         ci_ca_excl_lock_attr( p_ci_ca );\r
1583 \r
1584         /* Swap the old and new CA attributes. */\r
1585         p_old_ca_attr = p_ci_ca->p_pnp_attr;\r
1586         p_ci_ca->p_pnp_attr = p_pnp_ca_change->p_new_ca_attr;\r
1587         p_ci_ca->p_user_attr = (ib_ca_attr_t*)(((uint8_t*)p_ci_ca->p_pnp_attr) +\r
1588                 p_ci_ca->p_pnp_attr->size);\r
1589         ci_ca_unlock_attr( p_ci_ca );\r
1590 \r
1591         /* Report changes. */\r
1592         __pnp_check_ports( p_ci_ca, p_old_ca_attr );\r
1593 \r
1594         /* Free the old CA attributes. */\r
1595         cl_free( p_old_ca_attr );\r
1596 \r
1597         /* Dereference the PnP Manager. */\r
1598         deref_al_obj( &gp_pnp->obj );\r
1599 \r
1600         CL_EXIT( AL_DBG_PNP, g_al_dbg_lvl );\r
1601 }\r
1602 \r
1603 \r
1604 \r
1605 /*\r
1606  *      Called by user mode AL to report a CA attribute change.\r
1607  */\r
1608 ib_api_status_t\r
1609 pnp_ca_change(\r
1610         IN                              al_ci_ca_t* const               p_ci_ca,\r
1611         IN              const   ib_ca_attr_t*                   p_ca_attr )\r
1612 {\r
1613         ib_ca_attr_t*                   p_new_ca_attr;\r
1614         al_pnp_ca_change_t*             p_pnp_ca_change;\r
1615         size_t                                  size;\r
1616 \r
1617         CL_ENTER( AL_DBG_PNP, g_al_dbg_lvl );\r
1618 \r
1619         CL_ASSERT( p_ci_ca );\r
1620         CL_ASSERT( p_ca_attr );\r
1621 \r
1622         /*\r
1623          * Allocate the new CA attributes buffer.\r
1624          * Double the buffer size for PnP and user reporting halves.\r
1625          * Also include the CA change event structure in the allocation.\r
1626          */\r
1627         size = ( p_ca_attr->size * 2 ) + sizeof( al_pnp_ca_change_t );\r
1628         p_new_ca_attr = (ib_ca_attr_t*)cl_zalloc( size );\r
1629         if( !p_new_ca_attr )\r
1630         {\r
1631                 CL_TRACE_EXIT( AL_DBG_PNP, g_al_dbg_lvl,\r
1632                         ("Unable to allocate buffer for changed CA attributes\n") );\r
1633                 return IB_INSUFFICIENT_MEMORY;\r
1634         }\r
1635 \r
1636         /* Copy the attributes. */\r
1637         ib_copy_ca_attr( p_new_ca_attr, p_ca_attr );\r
1638 \r
1639         /* Initialize a pointer to the CA change event structure. */\r
1640         p_pnp_ca_change = (al_pnp_ca_change_t*)\r
1641                 (((uint8_t*)p_new_ca_attr) + ( p_ca_attr->size * 2 ));\r
1642 \r
1643         /* Initialize the CA change event strucuture. */\r
1644         p_pnp_ca_change->async_item.pfn_callback = __pnp_process_ca_change;\r
1645         p_pnp_ca_change->p_ci_ca = p_ci_ca;\r
1646         p_pnp_ca_change->p_new_ca_attr = p_new_ca_attr;\r
1647 \r
1648         /* Reference the PnP Manager. */\r
1649         ref_al_obj( &gp_pnp->obj );\r
1650 \r
1651         /* Queue the CA change event. */\r
1652         cl_async_proc_queue( gp_async_pnp_mgr, &p_pnp_ca_change->async_item );\r
1653 \r
1654         CL_EXIT( AL_DBG_PNP, g_al_dbg_lvl );\r
1655         return IB_SUCCESS;\r
1656 }\r
1657 \r
1658 \r
1659 \r
1660 ib_api_status_t\r
1661 ib_reject_ioc(\r
1662         IN              const   ib_al_handle_t                          h_al,\r
1663         IN              const   ib_pnp_handle_t                         h_event )\r
1664 {\r
1665         CL_ENTER( AL_DBG_PNP, g_al_dbg_lvl );\r
1666 \r
1667         if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) )\r
1668         {\r
1669                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl, ("IB_INVALID_AL_HANDLE\n") );\r
1670                 return IB_INVALID_AL_HANDLE;\r
1671         }\r
1672         if( !h_event )\r
1673         {\r
1674                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl, ("IB_INVALID_HANDLE\n") );\r
1675                 return IB_INVALID_HANDLE;\r
1676         }\r
1677 \r
1678         CL_EXIT( AL_DBG_PNP, g_al_dbg_lvl );\r
1679         return IB_UNSUPPORTED;\r
1680 }\r