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