c3026f297a6848647bb2348a9daaf638fc375361
[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                 cl_free( p_context );\r
609                 p_context = NULL;\r
610         }\r
611         \r
612         \r
613         AL_EXIT( AL_DBG_PNP );\r
614         return p_context;\r
615 }\r
616 \r
617 \r
618 \r
619 /*\r
620  * Report all local port information.  This notifies the user of PORT_ADD\r
621  * events, along with port state events (PORT_INIT, PORT_ACTIVE).\r
622  */\r
623 static void\r
624 __pnp_port_notify(\r
625         IN                              al_pnp_t                                        *p_reg,\r
626         IN                              al_ci_ca_t                                      *p_ci_ca )\r
627 {\r
628         ib_api_status_t                 status;\r
629         al_pnp_context_t                *p_context;\r
630         ib_port_attr_t                  *p_port_attr;\r
631         al_pnp_ca_event_t               event_rec;\r
632 \r
633         AL_ENTER( AL_DBG_PNP );\r
634 \r
635         event_rec.p_ci_ca = p_ci_ca;\r
636 \r
637         for( event_rec.port_index = 0;\r
638                  event_rec.port_index < p_ci_ca->num_ports;\r
639                  event_rec.port_index++ )\r
640         {\r
641                 p_port_attr = p_ci_ca->p_pnp_attr->p_port_attr;\r
642                 p_port_attr += event_rec.port_index;\r
643 \r
644                 /* Create a new context for user port information. */\r
645                 p_context = pnp_create_context( p_reg, &p_port_attr->port_guid);\r
646                 if( !p_context )\r
647                         continue;\r
648 \r
649                 /* Notify the user of the port's existence. */\r
650                 event_rec.pnp_event = IB_PNP_PORT_ADD;\r
651                 status = __pnp_notify_user( p_reg, p_context, &event_rec );\r
652                 if( status != IB_SUCCESS )\r
653                         continue;\r
654 \r
655                 /* Generate a port down event if the port is currently down. */\r
656                 if( p_port_attr->link_state == IB_LINK_DOWN )\r
657                 {\r
658                         event_rec.pnp_event = IB_PNP_PORT_DOWN;\r
659                         __pnp_notify_user( p_reg, p_context, &event_rec );\r
660                 }\r
661                 else\r
662                 {\r
663                         /* Generate port init event. */\r
664                         if( p_port_attr->link_state >= IB_LINK_INIT )\r
665                         {\r
666                                 event_rec.pnp_event = IB_PNP_PORT_INIT;\r
667                                 status = __pnp_notify_user( p_reg, p_context, &event_rec );\r
668                                 if( status != IB_SUCCESS )\r
669                                         continue;\r
670                         }\r
671                         /* Generate port armed event. */\r
672                         if( p_port_attr->link_state >= IB_LINK_ARMED )\r
673                         {\r
674                                 event_rec.pnp_event = IB_PNP_PORT_ARMED;\r
675                                 status = __pnp_notify_user( p_reg, p_context, &event_rec );\r
676                                 if( status != IB_SUCCESS )\r
677                                         continue;\r
678                         }\r
679                         /* Generate port up event. */\r
680                         if( p_port_attr->link_state >= IB_LINK_ACTIVE )\r
681                         {\r
682                                 event_rec.pnp_event = IB_PNP_PORT_ACTIVE;\r
683                                 __pnp_notify_user( p_reg, p_context, &event_rec );\r
684                         }\r
685                 }\r
686         }\r
687         AL_EXIT( AL_DBG_PNP );\r
688 }\r
689 \r
690 \r
691 /*\r
692  * Registration and deregistration.\r
693  */\r
694 static void\r
695 __pnp_reg_notify(\r
696         IN                              al_pnp_t* const                         p_reg )\r
697 {\r
698         al_pnp_ca_event_t               event_rec;\r
699         size_t                                  i;\r
700         al_pnp_context_t                *p_context;\r
701 \r
702         AL_ENTER( AL_DBG_PNP );\r
703 \r
704         for( i = 0; i < cl_ptr_vector_get_size( &gp_pnp->ca_vector ); i++ )\r
705         {\r
706                 event_rec.p_ci_ca = (al_ci_ca_t*)\r
707                         cl_ptr_vector_get( &gp_pnp->ca_vector, i );\r
708                 if( !event_rec.p_ci_ca )\r
709                         continue;\r
710 \r
711                 switch( pnp_get_class( p_reg->pnp_class ) )\r
712                 {\r
713                 case IB_PNP_CA:\r
714                         event_rec.pnp_event = IB_PNP_CA_ADD;\r
715                         p_context = pnp_create_context( p_reg,\r
716                                 &event_rec.p_ci_ca->p_pnp_attr->ca_guid);\r
717                         if( !p_context )\r
718                                 break;\r
719 \r
720                         __pnp_notify_user( p_reg, p_context, &event_rec );\r
721                         break;\r
722 \r
723                 case IB_PNP_PORT:\r
724                         __pnp_port_notify( p_reg, event_rec.p_ci_ca );\r
725                         break;\r
726 \r
727                 default:\r
728                         CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_CA ||\r
729                                 pnp_get_class( p_reg->pnp_class ) == IB_PNP_PORT );\r
730                         continue;\r
731                 }\r
732         }\r
733 \r
734         /* Notify the user that the registration is complete. */\r
735         pnp_reg_complete( p_reg );\r
736 \r
737         AL_EXIT( AL_DBG_PNP );\r
738 }\r
739 \r
740 \r
741 static void\r
742 __al_pnp_process_reg(\r
743         IN                              cl_async_proc_item_t*           p_item )\r
744 {\r
745         al_pnp_t*               p_reg;\r
746 \r
747         AL_ENTER( AL_DBG_PNP );\r
748 \r
749         p_reg = PARENT_STRUCT( p_item, al_pnp_t, async_item );\r
750 \r
751         /* Add the registrant to the list. */\r
752         switch( pnp_get_class( p_reg->pnp_class ) )\r
753         {\r
754         case IB_PNP_CA:\r
755                 cl_qlist_insert_tail( &gp_pnp->ca_reg_list, &p_reg->list_item );\r
756                 break;\r
757 \r
758         case IB_PNP_PORT:\r
759                 cl_qlist_insert_tail( &gp_pnp->port_reg_list, &p_reg->list_item );\r
760                 break;\r
761 \r
762         default:\r
763                 CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_CA ||\r
764                         pnp_get_class( p_reg->pnp_class ) == IB_PNP_PORT );\r
765         }\r
766 \r
767         /* Generate all relevant events for the registration. */\r
768         __pnp_reg_notify( p_reg );\r
769 \r
770         /* Release the reference taken in init_al_obj. */\r
771         deref_al_obj( &p_reg->obj );\r
772 \r
773         AL_EXIT( AL_DBG_PNP );\r
774 }\r
775 \r
776 \r
777 ib_api_status_t\r
778 ib_reg_pnp(\r
779         IN              const   ib_al_handle_t                          h_al,\r
780         IN              const   ib_pnp_req_t* const                     p_pnp_req,\r
781                 OUT                     ib_pnp_handle_t* const          ph_pnp )\r
782 {\r
783         ib_api_status_t         status;\r
784         KEVENT                          event;\r
785 \r
786         AL_ENTER( AL_DBG_PNP );\r
787 \r
788         if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) )\r
789         {\r
790                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AL_HANDLE\n") );\r
791                 return IB_INVALID_AL_HANDLE;\r
792         }\r
793         if( !p_pnp_req || !ph_pnp )\r
794         {\r
795                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
796                 return IB_INVALID_PARAMETER;\r
797         }\r
798 \r
799         if( pnp_get_flag( p_pnp_req->pnp_class ) & IB_PNP_FLAG_REG_SYNC )\r
800                 KeInitializeEvent( &event, SynchronizationEvent, FALSE );\r
801 \r
802         status = al_reg_pnp( h_al, p_pnp_req, &event, ph_pnp );\r
803         /* Release the reference taken in init_al_obj. */\r
804         if( status == IB_SUCCESS )\r
805         {\r
806                 deref_al_obj( &(*ph_pnp)->obj );\r
807                 \r
808                 /* Wait for registration to complete if synchronous. */\r
809                 if( pnp_get_flag( p_pnp_req->pnp_class ) & IB_PNP_FLAG_REG_SYNC )\r
810                 {\r
811                         KeWaitForSingleObject(\r
812                                 &event, Executive, KernelMode, TRUE, NULL );\r
813                 }\r
814         }\r
815 \r
816         AL_EXIT( AL_DBG_PNP );\r
817         return status;\r
818 }\r
819 \r
820 \r
821 ib_api_status_t\r
822 al_reg_pnp(\r
823         IN              const   ib_al_handle_t                          h_al,\r
824         IN              const   ib_pnp_req_t* const                     p_pnp_req,\r
825         IN                              KEVENT                                          *p_sync_event,\r
826                 OUT                     ib_pnp_handle_t* const          ph_pnp )\r
827 {\r
828         ib_api_status_t         status;\r
829         al_pnp_t*                       p_reg;\r
830 \r
831         AL_ENTER( AL_DBG_PNP );\r
832 \r
833         /* Allocate a new registration info structure. */\r
834         p_reg = (al_pnp_t*)cl_zalloc( sizeof(al_pnp_t) );\r
835         if( !p_reg )\r
836         {\r
837                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
838                         ("Failed to cl_zalloc al_pnp_t (%I64d bytes).\n",\r
839                         sizeof(al_pnp_t)) );\r
840                 return( IB_INSUFFICIENT_MEMORY );\r
841         }\r
842 \r
843         /* Initialize the registration info. */\r
844         construct_al_obj( &p_reg->obj, AL_OBJ_TYPE_H_PNP );\r
845         switch(pnp_get_class(p_pnp_req->pnp_class)){\r
846                 case IB_PNP_IOU:\r
847                 case IB_PNP_IOC:\r
848                         cl_fmap_init( &p_reg->context_map, __context_cmp128 );\r
849                         break;\r
850                 case IB_PNP_PORT:\r
851                 case IB_PNP_CA:\r
852                         cl_fmap_init( &p_reg->context_map, __context_cmp64 );\r
853                         break;\r
854                 default:\r
855                         AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
856                         ("unknown pnp_class 0x%x.\n", pnp_get_class(p_pnp_req->pnp_class)));\r
857         }\r
858         status = init_al_obj( &p_reg->obj, p_pnp_req->pnp_context, TRUE,\r
859                 __pnp_reg_destroying, __pnp_reg_cleanup, __pnp_reg_free );\r
860         if( status != IB_SUCCESS )\r
861         {\r
862                 __pnp_reg_free( &p_reg->obj );\r
863                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
864                         ("init_al_obj() failed with status %s.\n", ib_get_err_str(status)) );\r
865                 return( status );\r
866         }\r
867         status = attach_al_obj( &h_al->obj, &p_reg->obj );\r
868         if( status != IB_SUCCESS )\r
869         {\r
870                 p_reg->obj.pfn_destroy( &p_reg->obj, NULL );\r
871                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
872                         ("attach_al_obj returned %s.\n", ib_get_err_str(status)) );\r
873                 return status;\r
874         }\r
875 \r
876         /* Reference the PnP Manager. */\r
877         ref_al_obj( &gp_pnp->obj );\r
878 \r
879         /* Copy the request information. */\r
880         p_reg->pnp_class = p_pnp_req->pnp_class;\r
881         p_reg->pfn_pnp_cb = p_pnp_req->pfn_pnp_cb;\r
882 \r
883         p_reg->p_sync_event = p_sync_event;\r
884 \r
885         /* Send IOU/IOC registration to the IOC PnP manager. */\r
886         if( pnp_get_class(p_pnp_req->pnp_class) == IB_PNP_IOU ||\r
887                 pnp_get_class(p_pnp_req->pnp_class) == IB_PNP_IOC )\r
888         {\r
889                 p_reg->async_item.pfn_callback = ioc_pnp_process_reg;\r
890                 p_reg->dereg_item.pfn_callback = ioc_pnp_process_dereg;\r
891         }\r
892         else\r
893         {\r
894                 p_reg->async_item.pfn_callback = __al_pnp_process_reg;\r
895                 p_reg->dereg_item.pfn_callback = __al_pnp_process_dereg;\r
896         }\r
897 \r
898         /* Queue the registrant for addition to the list. */\r
899         ref_al_obj( &p_reg->obj );\r
900         cl_async_proc_queue( gp_async_pnp_mgr, &p_reg->async_item );\r
901 \r
902         /* Set the user handle. */\r
903         *ph_pnp = p_reg;\r
904 \r
905         AL_EXIT( AL_DBG_PNP );\r
906         return( IB_SUCCESS );\r
907 }\r
908 \r
909 \r
910 ib_api_status_t\r
911 ib_dereg_pnp(\r
912         IN              const   ib_pnp_handle_t                         h_pnp,\r
913         IN              const   ib_pfn_destroy_cb_t                     pfn_destroy_cb OPTIONAL )\r
914 {\r
915         AL_ENTER( AL_DBG_PNP );\r
916 \r
917         if( AL_OBJ_INVALID_HANDLE( h_pnp, AL_OBJ_TYPE_H_PNP ) )\r
918         {\r
919                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") );\r
920                 return IB_INVALID_HANDLE;\r
921         }\r
922 \r
923         ref_al_obj( &h_pnp->obj );\r
924         h_pnp->obj.pfn_destroy( &h_pnp->obj, pfn_destroy_cb );\r
925 \r
926         AL_EXIT( AL_DBG_PNP );\r
927         return( IB_SUCCESS );\r
928 }\r
929 \r
930 \r
931 /*\r
932  * CA event handling.\r
933  */\r
934 static void\r
935 __pnp_process_add_ca(\r
936         IN                              cl_async_proc_item_t            *p_item )\r
937 {\r
938         al_pnp_t                        *p_reg;\r
939         al_pnp_ca_event_t       *p_event_rec;\r
940         cl_list_item_t          *p_reg_item;\r
941         al_pnp_context_t        *p_context;\r
942         cl_status_t                     cl_status;\r
943         size_t                          i;\r
944 \r
945         AL_ENTER( AL_DBG_PNP );\r
946 \r
947         p_event_rec = PARENT_STRUCT( p_item, al_pnp_ca_event_t, async_item );\r
948 \r
949         cl_spinlock_acquire( &gp_pnp->obj.lock );\r
950         /* Add the CA to the CA vector. */\r
951         for( i = 0; i < cl_ptr_vector_get_size( &gp_pnp->ca_vector ); i++ )\r
952         {\r
953                 if( !cl_ptr_vector_get( &gp_pnp->ca_vector, i ) )\r
954                 {\r
955                         cl_status = cl_ptr_vector_set( &gp_pnp->ca_vector, i,\r
956                                 p_event_rec->p_ci_ca );\r
957                         CL_ASSERT( cl_status == CL_SUCCESS );\r
958                         break;\r
959                 }\r
960         }\r
961         cl_spinlock_release( &gp_pnp->obj.lock );\r
962         CL_ASSERT( i < cl_ptr_vector_get_size( &gp_pnp->ca_vector ) );\r
963 \r
964         /* Walk the list of registrants for notification. */\r
965         for( p_reg_item = cl_qlist_head( &gp_pnp->ca_reg_list );\r
966                  p_reg_item != cl_qlist_end( &gp_pnp->ca_reg_list );\r
967                  p_reg_item = cl_qlist_next( p_reg_item ) )\r
968         {\r
969                 p_reg = PARENT_STRUCT( p_reg_item, al_pnp_t, list_item );\r
970                 CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_CA );\r
971 \r
972                 /* Allocate the user's context. */\r
973                 /*\r
974                  * Moving this allocation to the pnp_ca_event call is left as an\r
975                  * exercise to the open source community.\r
976                  */\r
977                 p_context = pnp_create_context( p_reg,\r
978                         &p_event_rec->p_ci_ca->p_pnp_attr->ca_guid);\r
979                 if( !p_context )\r
980                         continue;\r
981 \r
982                 /* Notify the user. */\r
983                 __pnp_notify_user( p_reg, p_context, p_event_rec );\r
984         }\r
985 \r
986         /* Generate port add and state events. */\r
987         for( p_reg_item = cl_qlist_head( &gp_pnp->port_reg_list );\r
988                  p_reg_item != cl_qlist_end( &gp_pnp->port_reg_list );\r
989                  p_reg_item = cl_qlist_next( p_reg_item ) )\r
990         {\r
991                 p_reg = PARENT_STRUCT( p_reg_item, al_pnp_t, list_item );\r
992                 CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_PORT );\r
993                 __pnp_port_notify( p_reg, p_event_rec->p_ci_ca );\r
994         }\r
995 \r
996         /* Cleanup the event record. */\r
997         deref_al_obj( &gp_pnp->obj );\r
998         cl_event_signal( &p_event_rec->p_ci_ca->event );\r
999         cl_free( p_event_rec );\r
1000 \r
1001         AL_EXIT( AL_DBG_PNP );\r
1002 }\r
1003 \r
1004 \r
1005 static void\r
1006 __pnp_process_remove_port(\r
1007         IN              const   al_pnp_ca_event_t* const        p_event_rec )\r
1008 {\r
1009         ib_api_status_t                 status;\r
1010         al_pnp_t                                *p_reg;\r
1011         cl_list_item_t                  *p_reg_item;\r
1012         uint8_t                                 port_index;\r
1013         al_pnp_context_t                *p_context;\r
1014         al_pnp_ca_event_t               event_rec;\r
1015         ib_port_attr_t                  *p_port_attr;\r
1016 \r
1017         AL_ENTER( AL_DBG_PNP );\r
1018 \r
1019         CL_ASSERT( p_event_rec->p_ci_ca->p_pnp_attr );\r
1020         CL_ASSERT( p_event_rec->p_ci_ca->p_pnp_attr->p_port_attr );\r
1021 \r
1022         /* Notify the IOC PnP manager of the port down event. */\r
1023         //***TODO: Make some call to the IOC PnP manager here, such as\r
1024         //***TODO: al_ioc_pnp_process_port_down( p_event_rec->p_ci_ca,\r
1025         //***TODO:              p_event_rec->port_index );\r
1026 \r
1027         cl_memclr( &event_rec, sizeof( al_pnp_ca_event_t ) );\r
1028         event_rec = *p_event_rec;\r
1029 \r
1030         /* Walk the list of registrants for notification. */\r
1031         for( p_reg_item = cl_qlist_tail( &gp_pnp->port_reg_list );\r
1032                  p_reg_item != cl_qlist_end( &gp_pnp->port_reg_list );\r
1033                  p_reg_item = cl_qlist_prev( p_reg_item ) )\r
1034         {\r
1035                 p_reg = PARENT_STRUCT( p_reg_item, al_pnp_t, list_item );\r
1036 \r
1037                 CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_PORT );\r
1038 \r
1039                 for( port_index = 0;\r
1040                          port_index < p_event_rec->p_ci_ca->num_ports;\r
1041                          port_index++ )\r
1042                 {\r
1043                         p_port_attr = p_event_rec->p_ci_ca->p_pnp_attr->p_port_attr;\r
1044                         p_port_attr += port_index;\r
1045                         p_context = pnp_get_context( p_reg, &p_port_attr->port_guid );\r
1046                         if( !p_context )\r
1047                                 continue;\r
1048 \r
1049                         event_rec.port_index = port_index;\r
1050 \r
1051                         if( p_port_attr->link_state >= IB_LINK_INIT )\r
1052                         {\r
1053                                 /* Notify the user of the port down. */\r
1054                                 event_rec.pnp_event = IB_PNP_PORT_DOWN;\r
1055                                 status = __pnp_notify_user( p_reg, p_context, &event_rec );\r
1056                                 if( status != IB_SUCCESS )\r
1057                                         continue;\r
1058                         }\r
1059 \r
1060                         /* Notify the user of the port remove. */\r
1061                         event_rec.pnp_event = IB_PNP_PORT_REMOVE;\r
1062                         status = __pnp_notify_user( p_reg, p_context, &event_rec );\r
1063                         if( status == IB_SUCCESS )\r
1064                         {\r
1065                                 /*\r
1066                                  * Remove the port context from the registrant's\r
1067                                  * context list.\r
1068                                  */\r
1069                                 cl_fmap_remove_item( &p_reg->context_map,\r
1070                                         &p_context->map_item );\r
1071                                 /* Free the context. */\r
1072                                 cl_free( p_context );\r
1073                         }\r
1074                 }\r
1075         }\r
1076 \r
1077         AL_EXIT( AL_DBG_PNP );\r
1078 }\r
1079 \r
1080 \r
1081 static void\r
1082 __pnp_process_remove_ca(\r
1083         IN                              cl_async_proc_item_t            *p_item )\r
1084 {\r
1085         al_pnp_t                        *p_reg;\r
1086         al_pnp_ca_event_t       *p_event_rec;\r
1087         cl_list_item_t          *p_reg_item;\r
1088         al_pnp_context_t        *p_context = NULL;\r
1089         size_t                          i;\r
1090 \r
1091         AL_ENTER( AL_DBG_PNP );\r
1092 \r
1093         p_event_rec = PARENT_STRUCT( p_item, al_pnp_ca_event_t, async_item );\r
1094 \r
1095         /* Generate port remove events. */\r
1096         __pnp_process_remove_port( p_event_rec );\r
1097 \r
1098         /* Walk the list of registrants for notification. */\r
1099         for( p_reg_item = cl_qlist_tail( &gp_pnp->ca_reg_list );\r
1100                  p_reg_item != cl_qlist_end( &gp_pnp->ca_reg_list );\r
1101                  p_reg_item = cl_qlist_prev( p_reg_item ) )\r
1102         {\r
1103                 p_reg = PARENT_STRUCT( p_reg_item, al_pnp_t, list_item );\r
1104 \r
1105                 CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_CA );\r
1106 \r
1107                 /* Search the context list for this CA. */\r
1108                 p_context =\r
1109                         pnp_get_context( p_reg, &p_event_rec->p_ci_ca->p_pnp_attr->ca_guid);\r
1110 \r
1111                 /* Make sure we found a context. */\r
1112                 if( !p_context )\r
1113                         continue;\r
1114 \r
1115                 /* Notify the user. */\r
1116                 if( __pnp_notify_user( p_reg, p_context, p_event_rec ) == IB_SUCCESS )\r
1117                 {\r
1118                         /* Remove the context from the context list. */\r
1119                         cl_fmap_remove_item( &p_reg->context_map, &p_context->map_item );\r
1120 \r
1121                         /* Deallocate the context block. */\r
1122                         cl_free( p_context );\r
1123                 }\r
1124         }\r
1125 \r
1126         /* Remove the CA from the CA vector. */\r
1127         for( i = 0; i < cl_ptr_vector_get_size( &gp_pnp->ca_vector ); i++ )\r
1128         {\r
1129                 if( cl_ptr_vector_get( &gp_pnp->ca_vector, i ) ==\r
1130                         p_event_rec->p_ci_ca )\r
1131                 {\r
1132                         cl_ptr_vector_remove( &gp_pnp->ca_vector, i );\r
1133                         break;\r
1134                 }\r
1135         }\r
1136 \r
1137         /* Release the reference to the CA. */\r
1138         deref_al_obj( &p_event_rec->p_ci_ca->obj );\r
1139 \r
1140         /* Cleanup the event record. */\r
1141         deref_al_obj( &gp_pnp->obj );\r
1142         cl_event_signal( &p_event_rec->p_ci_ca->event );\r
1143         cl_free( p_event_rec );\r
1144 \r
1145         AL_EXIT( AL_DBG_PNP );\r
1146 }\r
1147 \r
1148 \r
1149 ib_api_status_t\r
1150 pnp_ca_event(\r
1151         IN                              al_ci_ca_t* const                       p_ci_ca,\r
1152         IN              const   ib_pnp_event_t                          event )\r
1153 {\r
1154         ib_api_status_t         status;\r
1155         cl_status_t                     cl_status;\r
1156         al_pnp_ca_event_t       *p_event_rec;\r
1157         ib_ca_attr_t            *p_old_ca_attr;\r
1158 \r
1159         AL_ENTER( AL_DBG_PNP );\r
1160 \r
1161         /* Allocate an event record. */\r
1162         p_event_rec = (al_pnp_ca_event_t*)cl_zalloc( sizeof(al_pnp_ca_event_t) );\r
1163         if( !p_event_rec )\r
1164         {\r
1165                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1166                         ("Failed to cl_zalloc al_pnp_ca_event_t (%I64d bytes).\n",\r
1167                         sizeof(al_pnp_ca_event_t)) );\r
1168                 return IB_INSUFFICIENT_MEMORY;\r
1169         }\r
1170 \r
1171         /* Store the event type. */\r
1172         p_event_rec->pnp_event = event;\r
1173         /* Store a pointer to the ca. */\r
1174         p_event_rec->p_ci_ca = p_ci_ca;\r
1175 \r
1176         switch( event )\r
1177         {\r
1178         case IB_PNP_CA_ADD:\r
1179                 p_event_rec->async_item.pfn_callback = __pnp_process_add_ca;\r
1180 \r
1181                 /* Reserve space for the CA in the CA vector. */\r
1182                 cl_spinlock_acquire( &gp_pnp->obj.lock );\r
1183                 cl_status = cl_ptr_vector_set_size( &gp_pnp->ca_vector,\r
1184                                 cl_ptr_vector_get_size( &gp_pnp->ca_vector ) + 1 );\r
1185                 cl_spinlock_release( &gp_pnp->obj.lock );\r
1186 \r
1187                 if( cl_status != CL_SUCCESS )\r
1188                 {\r
1189                         cl_free( p_event_rec );\r
1190                         AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1191                                 ("cl_ptr_vector_set_size failed with status %#x.\n",\r
1192                                 cl_status) );\r
1193                         return ib_convert_cl_status( cl_status );\r
1194                 }\r
1195 \r
1196                 /* Read the CA attributes required to process the event. */\r
1197                 status = ci_ca_update_attr( p_ci_ca, &p_old_ca_attr );\r
1198                 if( status != IB_SUCCESS )\r
1199                 {\r
1200                         cl_spinlock_acquire( &gp_pnp->obj.lock );\r
1201                         cl_status = cl_ptr_vector_set_size( &gp_pnp->ca_vector,\r
1202                                 cl_ptr_vector_get_size( &gp_pnp->ca_vector ) - 1 );\r
1203                         CL_ASSERT( cl_status == CL_SUCCESS );\r
1204                         cl_spinlock_release( &gp_pnp->obj.lock );\r
1205                         cl_free( p_event_rec );\r
1206                         AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1207                                 ("ci_ca_update_attr failed.\n") );\r
1208                         return status;\r
1209                 }\r
1210 \r
1211                 /* Take out a reference to the CA until it is removed. */\r
1212                 ref_al_obj( &p_ci_ca->obj );\r
1213                 break;\r
1214 \r
1215         case IB_PNP_CA_REMOVE:\r
1216                 if( !p_event_rec->p_ci_ca->p_pnp_attr )\r
1217                 {\r
1218                         /* The CA was never added by the PNP manager. */\r
1219                         cl_free( p_event_rec );\r
1220                         AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1221                                 ("Ignoring removal request for unknown CA.\n") );\r
1222                         return IB_NOT_FOUND;\r
1223                 }\r
1224 \r
1225                 p_event_rec->async_item.pfn_callback = __pnp_process_remove_ca;\r
1226                 break;\r
1227 \r
1228         default:\r
1229                 /* Invalid event for this function. */\r
1230                 CL_ASSERT( event == IB_PNP_CA_ADD || event == IB_PNP_CA_REMOVE );\r
1231                 cl_free( p_event_rec );\r
1232                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1233                         ("Invalid event type.\n") );\r
1234                 return IB_ERROR;\r
1235         }\r
1236 \r
1237         /* Queue the event to the async processing manager. */\r
1238         ref_al_obj( &gp_pnp->obj );\r
1239         cl_async_proc_queue( gp_async_pnp_mgr, &p_event_rec->async_item );\r
1240 \r
1241         /* wait for the end of event propagation \r
1242         It is needed for enabling quick HCA disable/enable scenarios. */\r
1243         cl_status = cl_event_wait_on( &p_ci_ca->event, \r
1244                 EVENT_NO_TIMEOUT, AL_WAIT_ALERTABLE );\r
1245         if (cl_status != CL_SUCCESS)\r
1246                 return IB_ERROR;\r
1247 \r
1248         AL_EXIT( AL_DBG_PNP );\r
1249         return IB_SUCCESS;\r
1250 }\r
1251 \r
1252 \r
1253 /*\r
1254  * Port event handling.\r
1255  */\r
1256 \r
1257 /*\r
1258  * Processes a port event, reporting it to clients from the first\r
1259  * registrant to the last.\r
1260  */\r
1261 static void\r
1262 __pnp_process_port_forward(\r
1263         IN                              al_pnp_ca_event_t*                      p_event_rec )\r
1264 {\r
1265         al_pnp_t                                *p_reg;\r
1266         cl_list_item_t                  *p_reg_item;\r
1267         al_pnp_context_t                *p_context;\r
1268         ib_port_attr_t                  *p_port_attr;\r
1269 \r
1270         AL_ENTER( AL_DBG_PNP );\r
1271 \r
1272         /* Walk the list of registrants for notification. */\r
1273         for( p_reg_item = cl_qlist_head( &gp_pnp->port_reg_list );\r
1274                  p_reg_item != cl_qlist_end( &gp_pnp->port_reg_list );\r
1275                  p_reg_item = cl_qlist_next( p_reg_item ) )\r
1276         {\r
1277                 p_reg = PARENT_STRUCT( p_reg_item, al_pnp_t, list_item );\r
1278 \r
1279                 CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_PORT );\r
1280 \r
1281                 p_port_attr = p_event_rec->p_ci_ca->p_pnp_attr->p_port_attr;\r
1282                 p_port_attr += p_event_rec->port_index;\r
1283 \r
1284                 p_context = pnp_get_context( p_reg, &p_port_attr->port_guid );\r
1285                 if( !p_context )\r
1286                         continue;\r
1287 \r
1288                 /* Notify the user. */\r
1289                 __pnp_notify_user( p_reg, p_context, p_event_rec );\r
1290         }\r
1291 \r
1292         AL_EXIT( AL_DBG_PNP );\r
1293 }\r
1294 \r
1295 \r
1296 /*\r
1297  * Processes a port event, reporting it to clients from the last\r
1298  * registrant to the first.\r
1299  */\r
1300 static void\r
1301 __pnp_process_port_backward(\r
1302         IN                              al_pnp_ca_event_t*                      p_event_rec )\r
1303 {\r
1304         al_pnp_t                                *p_reg;\r
1305         cl_list_item_t                  *p_reg_item;\r
1306         al_pnp_context_t                *p_context;\r
1307         ib_port_attr_t                  *p_port_attr;\r
1308 \r
1309         AL_ENTER( AL_DBG_PNP );\r
1310 \r
1311         /* Walk the list of registrants for notification. */\r
1312         for( p_reg_item = cl_qlist_tail( &gp_pnp->port_reg_list );\r
1313                  p_reg_item != cl_qlist_end( &gp_pnp->port_reg_list );\r
1314                  p_reg_item = cl_qlist_prev( p_reg_item ) )\r
1315         {\r
1316                 p_reg = PARENT_STRUCT( p_reg_item, al_pnp_t, list_item );\r
1317 \r
1318                 CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_PORT );\r
1319 \r
1320                 p_port_attr = p_event_rec->p_ci_ca->p_pnp_attr->p_port_attr;\r
1321                 p_port_attr += p_event_rec->port_index;\r
1322 \r
1323                 p_context = pnp_get_context( p_reg, &p_port_attr->port_guid );\r
1324                 if( !p_context )\r
1325                         continue;\r
1326 \r
1327                 /* Notify the user. */\r
1328                 __pnp_notify_user( p_reg, p_context, p_event_rec );\r
1329         }\r
1330 \r
1331         AL_EXIT( AL_DBG_PNP );\r
1332 }\r
1333 \r
1334 \r
1335 \r
1336 /*\r
1337  * Check for port attribute changes.\r
1338  */\r
1339 static void\r
1340 __pnp_check_ports(\r
1341         IN                              al_ci_ca_t* const                       p_ci_ca,\r
1342         IN              const   ib_ca_attr_t* const                     p_old_ca_attr )\r
1343 {\r
1344         uint16_t                                index;\r
1345         al_pnp_ca_event_t               event_rec;\r
1346         ib_port_attr_t                  *p_old_port_attr, *p_new_port_attr;\r
1347 \r
1348         AL_ENTER( AL_DBG_PNP );\r
1349 \r
1350         /* Store the event information. */\r
1351         event_rec.p_ci_ca = p_ci_ca;\r
1352 \r
1353         for( event_rec.port_index = 0;\r
1354                  event_rec.port_index < p_ci_ca->p_pnp_attr->num_ports;\r
1355                  event_rec.port_index++ )\r
1356         {\r
1357                 p_old_port_attr = p_old_ca_attr->p_port_attr;\r
1358                 p_old_port_attr += event_rec.port_index;\r
1359                 p_new_port_attr = p_ci_ca->p_pnp_attr->p_port_attr;\r
1360                 p_new_port_attr += event_rec.port_index;\r
1361 \r
1362                 /* Check the link state. */\r
1363                 if( p_old_port_attr->link_state != p_new_port_attr->link_state )\r
1364                 {\r
1365                         switch( p_new_port_attr->link_state )\r
1366                         {\r
1367                         case IB_LINK_DOWN:\r
1368                                 event_rec.pnp_event = IB_PNP_PORT_DOWN;\r
1369                                 __pnp_process_port_backward( &event_rec );\r
1370                                 break;\r
1371 \r
1372                         case IB_LINK_INIT:\r
1373                                 if( p_old_port_attr->link_state > IB_LINK_INIT )\r
1374                                 {\r
1375                                         /* Missed the down event. */\r
1376                                         event_rec.pnp_event = IB_PNP_PORT_DOWN;\r
1377                                         __pnp_process_port_backward( &event_rec );\r
1378                                 }\r
1379                                 event_rec.pnp_event = IB_PNP_PORT_INIT;\r
1380                                 __pnp_process_port_forward( &event_rec );\r
1381                                 break;\r
1382 \r
1383                         case IB_LINK_ARMED:\r
1384                                 if( p_old_port_attr->link_state > IB_LINK_ARMED )\r
1385                                 {\r
1386                                         /* Missed the down and init events. */\r
1387                                         event_rec.pnp_event = IB_PNP_PORT_DOWN;\r
1388                                         __pnp_process_port_backward( &event_rec );\r
1389                                         event_rec.pnp_event = IB_PNP_PORT_INIT;\r
1390                                         __pnp_process_port_forward( &event_rec );\r
1391                                 }\r
1392                                 event_rec.pnp_event = IB_PNP_PORT_ARMED;\r
1393                                 __pnp_process_port_forward( &event_rec );\r
1394                                 break;\r
1395 \r
1396                         case IB_LINK_ACTIVE:\r
1397                         case IB_LINK_ACT_DEFER:\r
1398                                 if( p_old_port_attr->link_state == IB_LINK_DOWN )\r
1399                                 {\r
1400                                         /* Missed the init and armed event. */\r
1401                                         event_rec.pnp_event = IB_PNP_PORT_INIT;\r
1402                                         __pnp_process_port_forward( &event_rec );\r
1403                                         event_rec.pnp_event = IB_PNP_PORT_ARMED;\r
1404                                         __pnp_process_port_forward( &event_rec );\r
1405                                 }\r
1406                                 if( p_old_port_attr->link_state < IB_LINK_ACTIVE )\r
1407                                 {\r
1408                                         event_rec.pnp_event = IB_PNP_PORT_ACTIVE;\r
1409                                         __pnp_process_port_forward( &event_rec );\r
1410                                 }\r
1411                                 break;\r
1412 \r
1413                         default:\r
1414                                 break;\r
1415                         }\r
1416                 }\r
1417 \r
1418                 /*\r
1419                  * Check for P_Key and GID table changes.\r
1420                  * The tables are only valid in the armed or active states.\r
1421                  */\r
1422                 if( ( (p_old_port_attr->link_state == IB_LINK_ARMED) ||\r
1423                         (p_old_port_attr->link_state == IB_LINK_ACTIVE) )\r
1424                         &&\r
1425                         ( (p_new_port_attr->link_state == IB_LINK_ARMED) ||\r
1426                         (p_new_port_attr->link_state == IB_LINK_ACTIVE) ) )\r
1427                 {\r
1428                         /* A different number of P_Keys indicates a change.*/\r
1429                         if( p_old_port_attr->num_pkeys != p_new_port_attr->num_pkeys )\r
1430                         {\r
1431                                 event_rec.pnp_event = IB_PNP_PKEY_CHANGE;\r
1432                                 __pnp_process_port_forward( &event_rec );\r
1433                         }\r
1434                         else\r
1435                         {\r
1436                                 /* Same number of P_Keys - compare the table contents. */\r
1437                                 for( index = 0; index < p_old_port_attr->num_pkeys; index++ )\r
1438                                 {\r
1439                                         if( p_old_port_attr->p_pkey_table[index] !=\r
1440                                                 p_new_port_attr->p_pkey_table[index] )\r
1441                                         {\r
1442                                                 event_rec.pnp_event = IB_PNP_PKEY_CHANGE;\r
1443                                                 __pnp_process_port_forward( &event_rec );\r
1444                                                 break;\r
1445                                         }\r
1446                                 }\r
1447                         }\r
1448 \r
1449                         /* A different number of GIDs indicates a change.*/\r
1450                         if( p_old_port_attr->num_gids != p_new_port_attr->num_gids )\r
1451                         {\r
1452                                 event_rec.pnp_event = IB_PNP_GID_CHANGE;\r
1453                                 __pnp_process_port_forward( &event_rec );\r
1454                         }\r
1455                         else\r
1456                         {\r
1457                                 /* Same number of GIDs - compare the table contents. */\r
1458                                 for( index = 0; index < p_old_port_attr->num_gids; index++ )\r
1459                                 {\r
1460                                         if( cl_memcmp( p_old_port_attr->p_gid_table[index].raw,\r
1461                                                 p_new_port_attr->p_gid_table[index].raw,\r
1462                                                 sizeof( ib_gid_t ) ) )\r
1463                                         {\r
1464                                                 event_rec.pnp_event = IB_PNP_GID_CHANGE;\r
1465                                                 __pnp_process_port_forward( &event_rec );\r
1466                                                 break;\r
1467                                         }\r
1468                                 }\r
1469                         }\r
1470                 }\r
1471 \r
1472                 /* Check for LID change. */\r
1473                 if( (p_old_port_attr->lid != p_new_port_attr->lid) ||\r
1474                         (p_old_port_attr->lmc != p_new_port_attr->lmc) )\r
1475                 {\r
1476                         event_rec.pnp_event = IB_PNP_LID_CHANGE;\r
1477                         __pnp_process_port_forward( &event_rec );\r
1478                 }\r
1479                 /* Check for SM related changes. */\r
1480                 if( (p_old_port_attr->sm_lid != p_new_port_attr->sm_lid) ||\r
1481                         (p_old_port_attr->sm_sl != p_new_port_attr->sm_sl) )\r
1482                 {\r
1483                         event_rec.pnp_event = IB_PNP_SM_CHANGE;\r
1484                         __pnp_process_port_forward( &event_rec );\r
1485                 }\r
1486                 /* Check for subnet timeout change. */\r
1487                 if( p_old_port_attr->subnet_timeout !=\r
1488                         p_new_port_attr->subnet_timeout )\r
1489                 {\r
1490                         event_rec.pnp_event = IB_PNP_SUBNET_TIMEOUT_CHANGE;\r
1491                         __pnp_process_port_forward( &event_rec );\r
1492                 }\r
1493         }\r
1494 \r
1495         /* send asynchronous events */\r
1496         {\r
1497                 int ci, cnt, i;\r
1498                 al_ae_info_t ae[MAX_AE]; /* pending Asynchronic Events */               \r
1499 \r
1500                 if (!p_ci_ca->cnt)\r
1501                         return;\r
1502                 \r
1503                 /* copy events in temp array */\r
1504                 ci_ca_lock_attr( p_ci_ca );\r
1505                 cnt = p_ci_ca->cnt;\r
1506                 ci = p_ci_ca->ci;\r
1507                 for (i=0; i<cnt; ++i)\r
1508                 {\r
1509                         ae[i] = p_ci_ca->ae[ci];\r
1510                         if ( ++ci >= MAX_AE )\r
1511                                 ci = 0;\r
1512                 }\r
1513                 cnt = p_ci_ca->cnt;\r
1514                 p_ci_ca->cnt = 0;\r
1515                 p_ci_ca->ci = ci;\r
1516                 ci_ca_unlock_attr( p_ci_ca );\r
1517 \r
1518                 for (i=0; i<cnt; ++i)\r
1519                 {\r
1520                         event_rec.pnp_event = ae[i].pnp_event;\r
1521                         event_rec.port_index = ae[i].port_index;\r
1522                         __pnp_process_port_forward( &event_rec );\r
1523                 }\r
1524         } \r
1525 \r
1526 }\r
1527 \r
1528 \r
1529 \r
1530 static boolean_t\r
1531 __pnp_cmp_attr(\r
1532         IN                      ib_ca_attr_t                            *p_attr_1,\r
1533         IN                      ib_ca_attr_t                            *p_attr_2\r
1534         )\r
1535 {\r
1536         uint8_t                                 port_index;\r
1537         ib_port_attr_t*                 p_port_attr_1;\r
1538         ib_port_attr_t*                 p_port_attr_2;\r
1539 \r
1540         CL_ASSERT( p_attr_1 && p_attr_2 );\r
1541 \r
1542         for( port_index = 0;\r
1543                  port_index < p_attr_1->num_ports;\r
1544                  port_index++ )\r
1545         {\r
1546                 /* Initialize pointers to the port attributes. */\r
1547                 p_port_attr_1 = &p_attr_1->p_port_attr[port_index];\r
1548                 p_port_attr_2 = &p_attr_2->p_port_attr[port_index];\r
1549 \r
1550                 CL_ASSERT( p_port_attr_1->port_guid == p_port_attr_2->port_guid );\r
1551 \r
1552                 if( (cl_memcmp( p_port_attr_1, p_port_attr_2,\r
1553                                 offsetof( ib_port_attr_t, p_gid_table ) ) != 0 ) ||\r
1554                         (cl_memcmp(p_port_attr_1->p_gid_table,p_port_attr_2->p_gid_table,\r
1555                                            p_port_attr_1->num_gids*sizeof(p_port_attr_1->p_gid_table[0]))) ||\r
1556                         (cl_memcmp(p_port_attr_1->p_pkey_table,p_port_attr_2->p_pkey_table,\r
1557                                            p_port_attr_1->num_pkeys*sizeof(p_port_attr_1->p_pkey_table[0]))) \r
1558                         )\r
1559 \r
1560                 {\r
1561                         return FALSE;\r
1562                 }\r
1563         }\r
1564 \r
1565         return TRUE;\r
1566 }\r
1567 \r
1568 \r
1569 \r
1570 static void\r
1571 __pnp_check_events(\r
1572         IN                              cl_async_proc_item_t*   p_item )\r
1573 {\r
1574         al_ci_ca_t                              *p_ci_ca;\r
1575         size_t                                  i;\r
1576         uint32_t                                attr_size;\r
1577         ib_ca_attr_t                    *p_old_ca_attr;\r
1578         ib_api_status_t                 status;\r
1579 \r
1580         AL_ENTER( AL_DBG_PNP );\r
1581 \r
1582         UNUSED_PARAM( p_item );\r
1583         CL_ASSERT( gp_pnp );\r
1584 \r
1585         /* Walk all known CAs. */\r
1586         for( i = 0; i < cl_ptr_vector_get_size( &gp_pnp->ca_vector ); i++ )\r
1587         {\r
1588                 p_ci_ca = (al_ci_ca_t*)cl_ptr_vector_get( &gp_pnp->ca_vector, i );\r
1589 \r
1590                 /* Check if the CA was just added to our list but is not ready. */\r
1591                 if( !p_ci_ca )\r
1592                         continue;\r
1593 \r
1594                 attr_size = p_ci_ca->p_pnp_attr->size;\r
1595                 status = ib_query_ca( p_ci_ca->h_ca, p_ci_ca->p_user_attr, &attr_size );\r
1596 \r
1597                 /* Report changes if there is an attribute size difference. */\r
1598                 if( ( attr_size != p_ci_ca->p_pnp_attr->size ) ||\r
1599                         !__pnp_cmp_attr( p_ci_ca->p_pnp_attr, p_ci_ca->p_user_attr ) )\r
1600                 {\r
1601                         status = ci_ca_update_attr( p_ci_ca, &p_old_ca_attr );\r
1602                         if( status == IB_SUCCESS )\r
1603                         {\r
1604                                 /* Check port attributes and report changes. */\r
1605                                 __pnp_check_ports( p_ci_ca, p_old_ca_attr );\r
1606 \r
1607                                 /* Free the old CA attributes. */\r
1608                                 cl_free( p_old_ca_attr );\r
1609                         }\r
1610                         else\r
1611                         {\r
1612                                 /*\r
1613                                  * Could not get new attribute buffers.\r
1614                                  * Skip this event - it should be picked up on the next check.\r
1615                                  */\r
1616                                 continue;\r
1617                         }\r
1618                 }\r
1619         }\r
1620 \r
1621         /* Dereference the PnP Manager. */\r
1622         deref_al_obj( &gp_pnp->obj );\r
1623         gp_pnp->async_item_is_busy = FALSE;\r
1624 \r
1625         AL_EXIT( AL_DBG_PNP );\r
1626 }\r
1627 \r
1628 \r
1629 \r
1630 /*\r
1631  * Check and report PnP events.\r
1632  */\r
1633 void\r
1634 pnp_poll(\r
1635         void )\r
1636 {\r
1637         AL_ENTER( AL_DBG_PNP );\r
1638 \r
1639         CL_ASSERT( gp_pnp );\r
1640 \r
1641         /* Determine if the PnP manager asynchronous processing item is busy. */\r
1642         cl_spinlock_acquire( &gp_pnp->obj.lock );\r
1643 \r
1644         if( gp_pnp->async_item_is_busy )\r
1645         {\r
1646                 cl_spinlock_release( &gp_pnp->obj.lock );\r
1647                 return;\r
1648         }\r
1649 \r
1650         gp_pnp->async_item_is_busy = TRUE;\r
1651 \r
1652         cl_spinlock_release( &gp_pnp->obj.lock );\r
1653 \r
1654         /* Reference the PnP Manager. */\r
1655         ref_al_obj( &gp_pnp->obj );\r
1656 \r
1657         /* Queue the request to check for PnP events. */\r
1658         cl_async_proc_queue( gp_async_pnp_mgr, &gp_pnp->async_item );\r
1659 \r
1660         AL_EXIT( AL_DBG_PNP );\r
1661 }\r
1662 \r
1663 \r
1664 \r
1665 static void\r
1666 __pnp_process_ca_change(\r
1667         IN                              cl_async_proc_item_t*   p_item )\r
1668 {\r
1669         al_pnp_ca_change_t              *p_pnp_ca_change;\r
1670         ib_ca_attr_t                    *p_old_ca_attr;\r
1671         al_ci_ca_t                              *p_ci_ca;\r
1672 \r
1673         AL_ENTER( AL_DBG_PNP );\r
1674 \r
1675         CL_ASSERT( p_item );\r
1676         CL_ASSERT( gp_pnp );\r
1677 \r
1678         p_pnp_ca_change = PARENT_STRUCT( p_item, al_pnp_ca_change_t, async_item );\r
1679 \r
1680         p_ci_ca = p_pnp_ca_change->p_ci_ca;\r
1681 \r
1682         /*\r
1683          * Prevent readers of the CA attributes from accessing them while\r
1684          * we are updating the pointers.\r
1685          */\r
1686         ci_ca_excl_lock_attr( p_ci_ca );\r
1687 \r
1688         /* Swap the old and new CA attributes. */\r
1689         p_old_ca_attr = p_ci_ca->p_pnp_attr;\r
1690         p_ci_ca->p_pnp_attr = p_pnp_ca_change->p_new_ca_attr;\r
1691         p_ci_ca->p_user_attr = (ib_ca_attr_t*)(((uint8_t*)p_ci_ca->p_pnp_attr) +\r
1692                 p_ci_ca->p_pnp_attr->size);\r
1693         ci_ca_unlock_attr( p_ci_ca );\r
1694 \r
1695         /* Report changes. */\r
1696         __pnp_check_ports( p_ci_ca, p_old_ca_attr );\r
1697 \r
1698         /* Free the old CA attributes. */\r
1699         cl_free( p_old_ca_attr );\r
1700 \r
1701         /* Dereference the PnP Manager. */\r
1702         deref_al_obj( &gp_pnp->obj );\r
1703 \r
1704         AL_EXIT( AL_DBG_PNP );\r
1705 }\r
1706 \r
1707 \r
1708 \r
1709 /*\r
1710  *      Called by user mode AL to report a CA attribute change.\r
1711  */\r
1712 ib_api_status_t\r
1713 pnp_ca_change(\r
1714         IN                              al_ci_ca_t* const               p_ci_ca,\r
1715         IN              const   ib_ca_attr_t*                   p_ca_attr )\r
1716 {\r
1717         ib_ca_attr_t*                   p_new_ca_attr;\r
1718         al_pnp_ca_change_t*             p_pnp_ca_change;\r
1719         size_t                                  size;\r
1720 \r
1721         AL_ENTER( AL_DBG_PNP );\r
1722 \r
1723         CL_ASSERT( p_ci_ca );\r
1724         CL_ASSERT( p_ca_attr );\r
1725 \r
1726         /*\r
1727          * Allocate the new CA attributes buffer.\r
1728          * Double the buffer size for PnP and user reporting halves.\r
1729          * Also include the CA change event structure in the allocation.\r
1730          */\r
1731         size = ( p_ca_attr->size * 2 ) + sizeof( al_pnp_ca_change_t );\r
1732         p_new_ca_attr = (ib_ca_attr_t*)cl_zalloc( size );\r
1733         if( !p_new_ca_attr )\r
1734         {\r
1735                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR,AL_DBG_PNP,\r
1736                         ("Unable to allocate buffer for changed CA attributes\n") );\r
1737                 return IB_INSUFFICIENT_MEMORY;\r
1738         }\r
1739 \r
1740         /* Copy the attributes. */\r
1741         ib_copy_ca_attr( p_new_ca_attr, p_ca_attr );\r
1742 \r
1743         /* Initialize a pointer to the CA change event structure. */\r
1744         p_pnp_ca_change = (al_pnp_ca_change_t*)\r
1745                 (((uint8_t*)p_new_ca_attr) + ( p_ca_attr->size * 2 ));\r
1746 \r
1747         /* Initialize the CA change event strucuture. */\r
1748         p_pnp_ca_change->async_item.pfn_callback = __pnp_process_ca_change;\r
1749         p_pnp_ca_change->p_ci_ca = p_ci_ca;\r
1750         p_pnp_ca_change->p_new_ca_attr = p_new_ca_attr;\r
1751 \r
1752         /* Reference the PnP Manager. */\r
1753         ref_al_obj( &gp_pnp->obj );\r
1754 \r
1755         /* Queue the CA change event. */\r
1756         cl_async_proc_queue( gp_async_pnp_mgr, &p_pnp_ca_change->async_item );\r
1757 \r
1758         AL_EXIT( AL_DBG_PNP );\r
1759         return IB_SUCCESS;\r
1760 }\r
1761 \r
1762 \r
1763 \r
1764 ib_api_status_t\r
1765 ib_reject_ioc(\r
1766         IN              const   ib_al_handle_t                          h_al,\r
1767         IN              const   ib_pnp_handle_t                         h_event )\r
1768 {\r
1769         AL_ENTER( AL_DBG_PNP );\r
1770 \r
1771         if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) )\r
1772         {\r
1773                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AL_HANDLE\n") );\r
1774                 return IB_INVALID_AL_HANDLE;\r
1775         }\r
1776         if( !h_event )\r
1777         {\r
1778                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") );\r
1779                 return IB_INVALID_HANDLE;\r
1780         }\r
1781 \r
1782         AL_EXIT( AL_DBG_PNP );\r
1783         return IB_UNSUPPORTED;\r
1784 }\r
1785 \r
1786 void\r
1787 pnp_force_event(\r
1788         IN              struct _al_ci_ca         * p_ci_ca,\r
1789         IN              ib_pnp_event_t pnp_event,\r
1790         IN              uint8_t port_num)\r
1791 {\r
1792 #define PORT_INDEX_OFFSET 1\r
1793 \r
1794         ASSERT(p_ci_ca);\r
1795         \r
1796         if (!p_ci_ca)\r
1797                 return;\r
1798         \r
1799         p_ci_ca->ae[p_ci_ca->pi].pnp_event = pnp_event;\r
1800         p_ci_ca->ae[p_ci_ca->pi].port_index = port_num - PORT_INDEX_OFFSET;\r
1801         ci_ca_lock_attr( p_ci_ca );\r
1802         if ( ++p_ci_ca->pi >= MAX_AE )\r
1803                 p_ci_ca->pi = 0;\r
1804         ASSERT(p_ci_ca->cnt < MAX_AE);\r
1805         if ( ++p_ci_ca->cnt > MAX_AE )\r
1806         {\r
1807                 p_ci_ca->cnt = MAX_AE;\r
1808                 p_ci_ca->ci =p_ci_ca->pi;\r
1809         }\r
1810         ci_ca_unlock_attr( p_ci_ca );\r
1811 }\r
1812 \r
1813 \r