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