[IBBUS] added support to logging to System Event Log.
[mirror/winof/.git] / core / al / kernel / al_ci_ca.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. \r
4  * Portions Copyright (c) 2008 Microsoft Corporation.  All rights reserved.\r
5  *\r
6  * This software is available to you under the OpenIB.org BSD license\r
7  * below:\r
8  *\r
9  *     Redistribution and use in source and binary forms, with or\r
10  *     without modification, are permitted provided that the following\r
11  *     conditions are met:\r
12  *\r
13  *      - Redistributions of source code must retain the above\r
14  *        copyright notice, this list of conditions and the following\r
15  *        disclaimer.\r
16  *\r
17  *      - Redistributions in binary form must reproduce the above\r
18  *        copyright notice, this list of conditions and the following\r
19  *        disclaimer in the documentation and/or other materials\r
20  *        provided with the distribution.\r
21  *\r
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
23  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
25  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
26  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
27  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
28  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
29  * SOFTWARE.\r
30  *\r
31  * $Id$\r
32  */\r
33 \r
34 #include "al_ci_ca.h"\r
35 #include "al_verbs.h"\r
36 #include "al_cq.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_ci_ca.tmh"\r
43 #endif\r
44 #include "al_mad_pool.h"\r
45 #include "al_mgr.h"\r
46 #include "al_mr.h"\r
47 #include "al_pnp.h"\r
48 #include "al_mad_pool.h"\r
49 \r
50 #include "ib_common.h"\r
51 \r
52 \r
53 #define EVENT_POOL_MIN                  4\r
54 #define EVENT_POOL_MAX                  0\r
55 #define EVENT_POOL_GROW                 1\r
56 \r
57 \r
58 void\r
59 destroying_ci_ca(\r
60         IN                              al_obj_t*                                       p_obj );\r
61 \r
62 void\r
63 cleanup_ci_ca(\r
64         IN                              al_obj_t*                                       p_obj );\r
65 \r
66 void\r
67 free_ci_ca(\r
68         IN                              al_obj_t*                                       p_obj );\r
69 \r
70 void\r
71 ci_ca_comp_cb(\r
72         IN                              void                                            *cq_context );\r
73 \r
74 void\r
75 ci_ca_async_proc_cb(\r
76         IN                              struct _cl_async_proc_item      *p_item );\r
77 \r
78 void\r
79 ci_ca_async_event_cb(\r
80         IN                              ib_event_rec_t*                         p_event_record );\r
81 \r
82 \r
83 \r
84 ib_api_status_t\r
85 create_ci_ca(\r
86         IN                              al_obj_t                                        *p_parent_obj,\r
87         IN              const   ci_interface_t*                         p_ci,\r
88         IN              const   PDEVICE_OBJECT                          p_hca_dev,\r
89         IN              const   PDEVICE_OBJECT                          p_fdo\r
90         )\r
91 {\r
92         ib_api_status_t                 status;\r
93         cl_status_t                             cl_status;\r
94         al_ci_ca_t                              *p_ci_ca;\r
95 \r
96         AL_ENTER( AL_DBG_CA );\r
97 \r
98         CL_ASSERT( p_ci );\r
99 \r
100         /* Allocate the CI CA. */\r
101         p_ci_ca = (al_ci_ca_t*)cl_zalloc( sizeof( al_ci_ca_t ) );\r
102         if( !p_ci_ca )\r
103         {\r
104                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
105                         ("cl_zalloc failed\n") );\r
106                 return  IB_INSUFFICIENT_MEMORY;\r
107         }\r
108 \r
109         /* Construct the CI CA. */\r
110         construct_al_obj( &p_ci_ca->obj, AL_OBJ_TYPE_CI_CA );\r
111         cl_spinlock_construct( &p_ci_ca->attr_lock );\r
112         cl_qlist_init( &p_ci_ca->ca_list );\r
113         cl_qlist_init( &p_ci_ca->shmid_list );\r
114         cl_qpool_construct( &p_ci_ca->event_pool );\r
115         p_ci_ca->verbs = *p_ci;\r
116         cl_event_construct( &p_ci_ca->event );\r
117         cl_event_init( &p_ci_ca->event, FALSE );\r
118 \r
119         cl_status = cl_spinlock_init( &p_ci_ca->attr_lock );\r
120         if( cl_status != CL_SUCCESS )\r
121         {\r
122                 free_ci_ca( &p_ci_ca->obj );\r
123                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
124                         ("cl_spinlock_init failed, status = 0x%x.\n",\r
125                         ib_convert_cl_status( cl_status ) ) );\r
126                 return ib_convert_cl_status( cl_status );\r
127         }\r
128 \r
129         /* Create a pool of items to report asynchronous events. */\r
130         cl_status = cl_qpool_init( &p_ci_ca->event_pool, EVENT_POOL_MIN,\r
131                 EVENT_POOL_MAX, EVENT_POOL_GROW, sizeof( event_item_t ), NULL,\r
132                 NULL, p_ci_ca );\r
133         if( cl_status != CL_SUCCESS )\r
134         {\r
135                 free_ci_ca( &p_ci_ca->obj );\r
136                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
137                         ("cl_qpool_init failed, status = 0x%x.\n", \r
138                         ib_convert_cl_status( cl_status ) ) );\r
139                 return ib_convert_cl_status( cl_status );\r
140         }\r
141 \r
142         status = init_al_obj( &p_ci_ca->obj, p_ci_ca, FALSE,\r
143                 destroying_ci_ca, cleanup_ci_ca, free_ci_ca );\r
144         if( status != IB_SUCCESS )\r
145         {\r
146                 free_ci_ca( &p_ci_ca->obj );\r
147                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
148                         ("init_al_obj failed, status = 0x%x.\n", status) );\r
149                 return status;\r
150         }\r
151         status = attach_al_obj( p_parent_obj, &p_ci_ca->obj );\r
152         if( status != IB_SUCCESS )\r
153         {\r
154                 p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL );\r
155                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
156                         ("attach_al_obj returned %s.\n", ib_get_err_str(status)) );\r
157                 return status;\r
158         }\r
159 \r
160         p_ci_ca->dereg_async_item.pfn_callback = ci_ca_async_proc_cb;\r
161 \r
162         /* Open the CI CA. */\r
163         status = p_ci_ca->verbs.open_ca( p_ci_ca->verbs.guid,\r
164                 ci_ca_async_event_cb, p_ci_ca, &p_ci_ca->h_ci_ca );\r
165         if( status != IB_SUCCESS )\r
166         {\r
167                 p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL );\r
168                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
169                         ("open_ca failed, status = 0x%x.\n", status) );\r
170                 return status;\r
171         }\r
172 \r
173         /* Increase the max timeout for the CI CA to handle driver unload. */\r
174         set_al_obj_timeout( &p_ci_ca->obj, AL_MAX_TIMEOUT_MS );\r
175 \r
176         /*\r
177          * Register ourselves with the AL manager, so that the open call below\r
178          * will succeed.\r
179          */\r
180         add_ci_ca( p_ci_ca );\r
181 \r
182         /* Open the AL CA. */\r
183         status = ib_open_ca( gh_al, p_ci_ca->verbs.guid, ca_event_cb, p_ci_ca,\r
184                 &p_ci_ca->h_ca );\r
185         if( status != IB_SUCCESS )\r
186         {\r
187                 p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL );\r
188                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
189                         ("ib_open_ca failed, status = 0x%x.\n", status) );\r
190                 return status;\r
191         }\r
192 \r
193 \r
194         /* store HCA device object into CA object */\r
195         p_ci_ca->h_ca->p_hca_dev = p_hca_dev;\r
196         p_ci_ca->h_ca->p_fdo = p_fdo;\r
197         \r
198         /* Get a list of the port GUIDs on this CI CA. */\r
199         status = get_port_info( p_ci_ca );\r
200         if( status != IB_SUCCESS )\r
201         {\r
202                 p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL );\r
203                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
204                         ("get_port_guids failed, status = 0x%x.\n", status) );\r
205                 return status;\r
206         }\r
207 \r
208         /* Allocate a PD for use by AL itself.  */\r
209         status = ib_alloc_pd( p_ci_ca->h_ca, IB_PDT_SQP, p_ci_ca,\r
210                 &p_ci_ca->h_pd );\r
211         if( status != IB_SUCCESS )\r
212         {\r
213                 p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL );\r
214                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
215                         ("ib_alloc_pd failed, status = 0x%x.\n", status) );\r
216                 return status;\r
217         }\r
218 \r
219         /* Allocate a PD for use by AL itself.  */\r
220         status = ib_alloc_pd( p_ci_ca->h_ca, IB_PDT_ALIAS, p_ci_ca,\r
221                 &p_ci_ca->h_pd_alias );\r
222         if( status != IB_SUCCESS )\r
223         {\r
224                 p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL );\r
225                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
226                         ("ib_alloc_pd alias failed, status = 0x%x.\n", status) );\r
227                 return status;\r
228         }\r
229 \r
230         /* Register the global MAD pool on this CA. */\r
231         status = ib_reg_mad_pool( gh_mad_pool, p_ci_ca->h_pd, &p_ci_ca->pool_key );\r
232         if( status != IB_SUCCESS )\r
233         {\r
234                 p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL );\r
235                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
236                         ("ib_reg_mad_pool failed, status = 0x%x.\n", status) );\r
237                 return status;\r
238         }\r
239 \r
240         /*\r
241          * Notify the PnP manager that a CA has been added.\r
242          * NOTE: PnP Manager must increment the CA reference count.\r
243          */\r
244         status = pnp_ca_event( p_ci_ca, IB_PNP_CA_ADD );\r
245         if( status != IB_SUCCESS )\r
246         {\r
247                 /* Destroy the CA */\r
248                 p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL );\r
249                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
250                         ("al_pnp_add_ca failed, status = 0x%x.\n", status) );\r
251                 return status;\r
252         }\r
253 \r
254         /* Release the reference taken in init_al_obj. */\r
255         deref_al_obj( &p_ci_ca->obj );\r
256 \r
257         AL_EXIT( AL_DBG_CA );\r
258         return IB_SUCCESS;\r
259 }\r
260 \r
261 \r
262 \r
263 void\r
264 destroying_ci_ca(\r
265         IN                              al_obj_t*                                       p_obj )\r
266 {\r
267         al_ci_ca_t                      *p_ci_ca;\r
268 \r
269         CL_ASSERT( p_obj );\r
270         p_ci_ca = PARENT_STRUCT( p_obj, al_ci_ca_t, obj );\r
271 \r
272         /*\r
273          * Notify the PnP manager that this CA is being removed.\r
274          * NOTE: PnP Manager must decrement the CA reference count.\r
275          */\r
276         pnp_ca_event( p_ci_ca, IB_PNP_CA_REMOVE );\r
277 \r
278         /*\r
279          * We queue a request to the asynchronous processing manager to close\r
280          * the CA after the PNP remove CA event has been delivered.  This avoids\r
281          * the ib_close_ca() call from immediately removing resouces (PDs, QPs)\r
282          * that are in use by clients waiting on the remove CA event.\r
283          */\r
284         if( p_ci_ca->h_ca )\r
285                 cl_async_proc_queue( gp_async_pnp_mgr, &p_ci_ca->dereg_async_item );\r
286 }\r
287 \r
288 \r
289 \r
290 void\r
291 ci_ca_async_proc_cb(\r
292         IN                              struct _cl_async_proc_item      *p_item )\r
293 {\r
294         al_ci_ca_t                      *p_ci_ca;\r
295 \r
296         p_ci_ca = PARENT_STRUCT( p_item, al_ci_ca_t, dereg_async_item );\r
297 \r
298         /* Release all AL resources acquired by the CI CA. */\r
299         ib_close_ca( p_ci_ca->h_ca, NULL );\r
300 }\r
301 \r
302 \r
303 \r
304 void\r
305 cleanup_ci_ca(\r
306         IN                              al_obj_t*                                       p_obj )\r
307 {\r
308         ib_api_status_t         status;\r
309         al_ci_ca_t                      *p_ci_ca;\r
310 \r
311         AL_ENTER( AL_DBG_CA );\r
312 \r
313         CL_ASSERT( p_obj );\r
314         p_ci_ca = PARENT_STRUCT( p_obj, al_ci_ca_t, obj );\r
315 \r
316         CL_ASSERT( cl_is_qlist_empty( &p_ci_ca->shmid_list ) );\r
317 \r
318         if( p_ci_ca->h_ci_ca )\r
319         {\r
320                 remove_ci_ca( p_ci_ca );\r
321                 status = p_ci_ca->verbs.close_ca( p_ci_ca->h_ci_ca );\r
322                 CL_ASSERT( status == IB_SUCCESS );\r
323         }\r
324 \r
325         AL_EXIT( AL_DBG_CA );\r
326 }\r
327 \r
328 \r
329 \r
330 void\r
331 ci_ca_comp_cb(\r
332         IN                              void                                            *cq_context )\r
333 {\r
334         ib_cq_handle_t                  h_cq = (ib_cq_handle_t)cq_context;\r
335 \r
336         if( h_cq->h_wait_obj )\r
337                 KeSetEvent( h_cq->h_wait_obj, IO_NETWORK_INCREMENT, FALSE );\r
338         else\r
339                 h_cq->pfn_user_comp_cb( h_cq, (void*)h_cq->obj.context );\r
340 }\r
341 \r
342 \r
343 \r
344 /*\r
345  * CI CA asynchronous event callback.\r
346  */\r
347 void\r
348 ci_ca_async_event_cb(\r
349         IN              ib_event_rec_t*         p_event_record )\r
350 {\r
351         ib_async_event_rec_t    event_rec;\r
352 \r
353         AL_ENTER( AL_DBG_CA );\r
354 \r
355         CL_ASSERT( p_event_record );\r
356 \r
357         event_rec.code = p_event_record->type;\r
358         event_rec.context = p_event_record->context;\r
359         event_rec.vendor_specific = p_event_record->vendor_specific;\r
360         event_rec.port_number = p_event_record->port_number;\r
361 \r
362         ci_ca_async_event( &event_rec );\r
363 \r
364         AL_EXIT( AL_DBG_CA );\r
365 }\r
366 \r
367 \r
368 \r
369 /*\r
370  * Insert a new shmid tracking structure into the CI CA's list.\r
371  */\r
372 void\r
373 add_shmid(\r
374         IN                              al_ci_ca_t* const                       p_ci_ca,\r
375         IN                              struct _al_shmid                        *p_shmid )\r
376 {\r
377         CL_ASSERT( p_ci_ca && p_shmid );\r
378 \r
379         p_shmid->obj.p_ci_ca = p_ci_ca;\r
380 \r
381         /* Insert the shmid structure into the shmid list. */\r
382         cl_spinlock_acquire( &p_ci_ca->obj.lock );\r
383         cl_qlist_insert_head( &p_ci_ca->shmid_list, &p_shmid->list_item );\r
384         cl_spinlock_release( &p_ci_ca->obj.lock );\r
385 }\r
386 \r
387 \r
388 \r
389 ib_api_status_t\r
390 acquire_shmid(\r
391         IN                              al_ci_ca_t* const                       p_ci_ca,\r
392         IN                              int                                                     shmid,\r
393                 OUT                     struct _al_shmid                        **pp_shmid )\r
394 {\r
395         al_shmid_t                      *p_shmid;\r
396         cl_list_item_t          *p_list_item;\r
397 \r
398         /* Try to find the shmid. */\r
399         cl_spinlock_acquire( &p_ci_ca->obj.lock );\r
400         for( p_list_item = cl_qlist_head( &p_ci_ca->shmid_list );\r
401                  p_list_item != cl_qlist_end( &p_ci_ca->shmid_list );\r
402                  p_list_item = cl_qlist_next( p_list_item ) )\r
403         {\r
404                 p_shmid = PARENT_STRUCT( p_list_item, al_shmid_t, list_item );\r
405                 if( p_shmid->id == shmid )\r
406                 {\r
407                         ref_al_obj( &p_shmid->obj );\r
408                         *pp_shmid = p_shmid;\r
409                         break;\r
410                 }\r
411         }\r
412         cl_spinlock_release( &p_ci_ca->obj.lock );\r
413 \r
414         if( p_list_item == cl_qlist_end( &p_ci_ca->shmid_list ) )\r
415                 return IB_NOT_FOUND;\r
416         else\r
417                 return IB_SUCCESS;\r
418 }\r
419 \r
420 \r
421 \r
422 void\r
423 release_shmid(\r
424         IN                              struct _al_shmid                        *p_shmid )\r
425 {\r
426         al_ci_ca_t                      *p_ci_ca;\r
427         int32_t                         ref_cnt;\r
428 \r
429         CL_ASSERT( p_shmid );\r
430 \r
431         p_ci_ca = p_shmid->obj.p_ci_ca;\r
432 \r
433         cl_spinlock_acquire( &p_ci_ca->obj.lock );\r
434 \r
435         /* Dereference the shmid. */\r
436         ref_cnt = deref_al_obj( &p_shmid->obj );\r
437 \r
438         /* If the shmid is no longer in active use, remove it. */\r
439         if( ref_cnt == 1 )\r
440                 cl_qlist_remove_item( &p_ci_ca->shmid_list, &p_shmid->list_item );\r
441 \r
442         cl_spinlock_release( &p_ci_ca->obj.lock );\r
443 \r
444         /* Destroy the shmid if it is not needed. */\r
445         if( ref_cnt == 1 )\r
446         {\r
447                 ref_al_obj( &p_shmid->obj );\r
448                 p_shmid->obj.pfn_destroy( &p_shmid->obj, NULL );\r
449         }\r
450 }\r
451 \r
452 \r
453 \r
454 ib_api_status_t\r
455 ib_ci_call(\r
456         IN                              ib_ca_handle_t                          h_ca,\r
457         IN              const   void**                          const   handle_array    OPTIONAL,\r
458         IN                              uint32_t                                        num_handles,\r
459         IN                              ib_ci_op_t*                     const   p_ci_op )\r
460 {\r
461         return ci_call( h_ca, handle_array, num_handles, p_ci_op, NULL );\r
462 }\r
463 \r
464 \r
465 \r
466 ib_api_status_t\r
467 ci_call(\r
468         IN                              ib_ca_handle_t                          h_ca,\r
469         IN              const   void**                          const   handle_array    OPTIONAL,\r
470         IN                              uint32_t                                        num_handles,\r
471         IN                              ib_ci_op_t*                     const   p_ci_op,\r
472         IN                              ci_umv_buf_t*           const   p_umv_buf OPTIONAL )\r
473 {\r
474         void**                  p_handle_array;\r
475         ib_api_status_t status;\r
476 \r
477         AL_ENTER( AL_DBG_CA );\r
478 \r
479         if( AL_OBJ_INVALID_HANDLE( h_ca, AL_OBJ_TYPE_H_CA ) )\r
480         {\r
481                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_CA_HANDLE\n") );\r
482                 return IB_INVALID_CA_HANDLE;\r
483         }\r
484         if( !p_ci_op )\r
485         {\r
486                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
487                 return IB_INVALID_PARAMETER;\r
488         }\r
489         p_handle_array = NULL;\r
490         if ( num_handles )\r
491         {\r
492                 p_handle_array = cl_zalloc( sizeof(void*) * num_handles );\r
493                 if( !p_handle_array )\r
494                         return IB_INSUFFICIENT_MEMORY;\r
495 \r
496                 status = al_convert_to_ci_handles( p_handle_array, handle_array,\r
497                         num_handles );\r
498 \r
499                 if( status != IB_SUCCESS )\r
500                 {\r
501                         cl_free( p_handle_array );\r
502                         return status;\r
503                 }\r
504         }\r
505 \r
506         if( h_ca->obj.p_ci_ca->verbs.vendor_call )\r
507         {\r
508                 status = verbs_ci_call(\r
509                         h_ca, p_handle_array, num_handles, p_ci_op, p_umv_buf );\r
510         }\r
511         else\r
512         {\r
513                 status = IB_UNSUPPORTED;\r
514         }\r
515 \r
516         if ( num_handles )\r
517                 cl_free( p_handle_array );\r
518 \r
519         AL_EXIT( AL_DBG_QUERY );\r
520         return status;\r
521 }\r
522 \r
523 \r
524 DEVICE_OBJECT*\r
525 get_ca_dev(\r
526         IN              const   ib_ca_handle_t                          h_ca )\r
527 {\r
528         ASSERT( h_ca );\r
529 \r
530         ObReferenceObject( h_ca->p_hca_dev );\r
531         return h_ca->p_hca_dev;\r
532 }\r