b24f58379b0c7358899f51b900d174661180c692
[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         )\r
90 {\r
91         ib_api_status_t                 status;\r
92         cl_status_t                             cl_status;\r
93         al_ci_ca_t                              *p_ci_ca;\r
94 \r
95         AL_ENTER( AL_DBG_CA );\r
96 \r
97         CL_ASSERT( p_ci );\r
98 \r
99         /* Allocate the CI CA. */\r
100         p_ci_ca = (al_ci_ca_t*)cl_zalloc( sizeof( al_ci_ca_t ) );\r
101         if( !p_ci_ca )\r
102         {\r
103                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
104                         ("cl_zalloc failed\n") );\r
105                 return  IB_INSUFFICIENT_MEMORY;\r
106         }\r
107 \r
108         /* Construct the CI CA. */\r
109         construct_al_obj( &p_ci_ca->obj, AL_OBJ_TYPE_CI_CA );\r
110         cl_spinlock_construct( &p_ci_ca->attr_lock );\r
111         cl_qlist_init( &p_ci_ca->ca_list );\r
112         cl_qlist_init( &p_ci_ca->shmid_list );\r
113         cl_qpool_construct( &p_ci_ca->event_pool );\r
114         p_ci_ca->verbs = *p_ci;\r
115         cl_event_construct( &p_ci_ca->event );\r
116         cl_event_init( &p_ci_ca->event, FALSE );\r
117 \r
118         cl_status = cl_spinlock_init( &p_ci_ca->attr_lock );\r
119         if( cl_status != CL_SUCCESS )\r
120         {\r
121                 free_ci_ca( &p_ci_ca->obj );\r
122                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
123                         ("cl_spinlock_init failed, status = 0x%x.\n",\r
124                         ib_convert_cl_status( cl_status ) ) );\r
125                 return ib_convert_cl_status( cl_status );\r
126         }\r
127 \r
128         /* Create a pool of items to report asynchronous events. */\r
129         cl_status = cl_qpool_init( &p_ci_ca->event_pool, EVENT_POOL_MIN,\r
130                 EVENT_POOL_MAX, EVENT_POOL_GROW, sizeof( event_item_t ), NULL,\r
131                 NULL, p_ci_ca );\r
132         if( cl_status != CL_SUCCESS )\r
133         {\r
134                 free_ci_ca( &p_ci_ca->obj );\r
135                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
136                         ("cl_qpool_init failed, status = 0x%x.\n", \r
137                         ib_convert_cl_status( cl_status ) ) );\r
138                 return ib_convert_cl_status( cl_status );\r
139         }\r
140 \r
141         status = init_al_obj( &p_ci_ca->obj, p_ci_ca, FALSE,\r
142                 destroying_ci_ca, cleanup_ci_ca, free_ci_ca );\r
143         if( status != IB_SUCCESS )\r
144         {\r
145                 free_ci_ca( &p_ci_ca->obj );\r
146                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
147                         ("init_al_obj failed, status = 0x%x.\n", status) );\r
148                 return status;\r
149         }\r
150         status = attach_al_obj( p_parent_obj, &p_ci_ca->obj );\r
151         if( status != IB_SUCCESS )\r
152         {\r
153                 p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL );\r
154                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
155                         ("attach_al_obj returned %s.\n", ib_get_err_str(status)) );\r
156                 return status;\r
157         }\r
158 \r
159         p_ci_ca->dereg_async_item.pfn_callback = ci_ca_async_proc_cb;\r
160 \r
161         /* Open the CI CA. */\r
162         status = p_ci_ca->verbs.open_ca( p_ci_ca->verbs.guid,\r
163                 ci_ca_async_event_cb, p_ci_ca, &p_ci_ca->h_ci_ca );\r
164         if( status != IB_SUCCESS )\r
165         {\r
166                 p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL );\r
167                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
168                         ("open_ca failed, status = 0x%x.\n", status) );\r
169                 return status;\r
170         }\r
171 \r
172         /* Increase the max timeout for the CI CA to handle driver unload. */\r
173         set_al_obj_timeout( &p_ci_ca->obj, AL_MAX_TIMEOUT_MS );\r
174 \r
175         /*\r
176          * Register ourselves with the AL manager, so that the open call below\r
177          * will succeed.\r
178          */\r
179         add_ci_ca( p_ci_ca );\r
180 \r
181         /* Open the AL CA. */\r
182         status = ib_open_ca( gh_al, p_ci_ca->verbs.guid, ca_event_cb, p_ci_ca,\r
183                 &p_ci_ca->h_ca );\r
184         if( status != IB_SUCCESS )\r
185         {\r
186                 p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL );\r
187                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
188                         ("ib_open_ca failed, status = 0x%x.\n", status) );\r
189                 return status;\r
190         }\r
191 \r
192         /* store HCA device object into CA object */\r
193         p_ci_ca->h_ca->p_hca_dev = p_hca_dev;\r
194         \r
195         /* Get a list of the port GUIDs on this CI CA. */\r
196         status = get_port_info( p_ci_ca );\r
197         if( status != IB_SUCCESS )\r
198         {\r
199                 p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL );\r
200                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
201                         ("get_port_guids failed, status = 0x%x.\n", status) );\r
202                 return status;\r
203         }\r
204 \r
205         /* Allocate a PD for use by AL itself.  */\r
206         status = ib_alloc_pd( p_ci_ca->h_ca, IB_PDT_SQP, p_ci_ca,\r
207                 &p_ci_ca->h_pd );\r
208         if( status != IB_SUCCESS )\r
209         {\r
210                 p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL );\r
211                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
212                         ("ib_alloc_pd failed, status = 0x%x.\n", status) );\r
213                 return status;\r
214         }\r
215 \r
216         /* Allocate a PD for use by AL itself.  */\r
217         status = ib_alloc_pd( p_ci_ca->h_ca, IB_PDT_ALIAS, p_ci_ca,\r
218                 &p_ci_ca->h_pd_alias );\r
219         if( status != IB_SUCCESS )\r
220         {\r
221                 p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL );\r
222                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
223                         ("ib_alloc_pd alias failed, status = 0x%x.\n", status) );\r
224                 return status;\r
225         }\r
226 \r
227         /* Register the global MAD pool on this CA. */\r
228         status = ib_reg_mad_pool( gh_mad_pool, p_ci_ca->h_pd, &p_ci_ca->pool_key );\r
229         if( status != IB_SUCCESS )\r
230         {\r
231                 p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL );\r
232                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
233                         ("ib_reg_mad_pool failed, status = 0x%x.\n", status) );\r
234                 return status;\r
235         }\r
236 \r
237         /*\r
238          * Notify the PnP manager that a CA has been added.\r
239          * NOTE: PnP Manager must increment the CA reference count.\r
240          */\r
241         status = pnp_ca_event( p_ci_ca, IB_PNP_CA_ADD );\r
242         if( status != IB_SUCCESS )\r
243         {\r
244                 /* Destroy the CA */\r
245                 p_ci_ca->obj.pfn_destroy( &p_ci_ca->obj, NULL );\r
246                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
247                         ("al_pnp_add_ca failed, status = 0x%x.\n", status) );\r
248                 return status;\r
249         }\r
250 \r
251         /* Release the reference taken in init_al_obj. */\r
252         deref_al_obj( &p_ci_ca->obj );\r
253 \r
254         AL_EXIT( AL_DBG_CA );\r
255         return IB_SUCCESS;\r
256 }\r
257 \r
258 \r
259 \r
260 void\r
261 destroying_ci_ca(\r
262         IN                              al_obj_t*                                       p_obj )\r
263 {\r
264         al_ci_ca_t                      *p_ci_ca;\r
265 \r
266         CL_ASSERT( p_obj );\r
267         p_ci_ca = PARENT_STRUCT( p_obj, al_ci_ca_t, obj );\r
268 \r
269         /*\r
270          * Notify the PnP manager that this CA is being removed.\r
271          * NOTE: PnP Manager must decrement the CA reference count.\r
272          */\r
273         pnp_ca_event( p_ci_ca, IB_PNP_CA_REMOVE );\r
274 \r
275         /*\r
276          * We queue a request to the asynchronous processing manager to close\r
277          * the CA after the PNP remove CA event has been delivered.  This avoids\r
278          * the ib_close_ca() call from immediately removing resouces (PDs, QPs)\r
279          * that are in use by clients waiting on the remove CA event.\r
280          */\r
281         if( p_ci_ca->h_ca )\r
282                 cl_async_proc_queue( gp_async_pnp_mgr, &p_ci_ca->dereg_async_item );\r
283 }\r
284 \r
285 \r
286 \r
287 void\r
288 ci_ca_async_proc_cb(\r
289         IN                              struct _cl_async_proc_item      *p_item )\r
290 {\r
291         al_ci_ca_t                      *p_ci_ca;\r
292 \r
293         p_ci_ca = PARENT_STRUCT( p_item, al_ci_ca_t, dereg_async_item );\r
294 \r
295         /* Release all AL resources acquired by the CI CA. */\r
296         ib_close_ca( p_ci_ca->h_ca, NULL );\r
297 }\r
298 \r
299 \r
300 \r
301 void\r
302 cleanup_ci_ca(\r
303         IN                              al_obj_t*                                       p_obj )\r
304 {\r
305         ib_api_status_t         status;\r
306         al_ci_ca_t                      *p_ci_ca;\r
307 \r
308         AL_ENTER( AL_DBG_CA );\r
309 \r
310         CL_ASSERT( p_obj );\r
311         p_ci_ca = PARENT_STRUCT( p_obj, al_ci_ca_t, obj );\r
312 \r
313         CL_ASSERT( cl_is_qlist_empty( &p_ci_ca->shmid_list ) );\r
314 \r
315         if( p_ci_ca->h_ci_ca )\r
316         {\r
317                 remove_ci_ca( p_ci_ca );\r
318                 status = p_ci_ca->verbs.close_ca( p_ci_ca->h_ci_ca );\r
319                 CL_ASSERT( status == IB_SUCCESS );\r
320         }\r
321 \r
322         AL_EXIT( AL_DBG_CA );\r
323 }\r
324 \r
325 \r
326 \r
327 void\r
328 ci_ca_comp_cb(\r
329         IN                              void                                            *cq_context )\r
330 {\r
331         ib_cq_handle_t                  h_cq = (ib_cq_handle_t)cq_context;\r
332 \r
333         if( h_cq->h_wait_obj )\r
334                 KeSetEvent( h_cq->h_wait_obj, IO_NETWORK_INCREMENT, FALSE );\r
335         else\r
336                 h_cq->pfn_user_comp_cb( h_cq, (void*)h_cq->obj.context );\r
337 }\r
338 \r
339 \r
340 \r
341 /*\r
342  * CI CA asynchronous event callback.\r
343  */\r
344 void\r
345 ci_ca_async_event_cb(\r
346         IN              ib_event_rec_t*         p_event_record )\r
347 {\r
348         ib_async_event_rec_t    event_rec;\r
349 \r
350         AL_ENTER( AL_DBG_CA );\r
351 \r
352         CL_ASSERT( p_event_record );\r
353 \r
354         event_rec.code = p_event_record->type;\r
355         event_rec.context = p_event_record->context;\r
356         event_rec.vendor_specific = p_event_record->vendor_specific;\r
357         event_rec.port_number = p_event_record->port_number;\r
358 \r
359         ci_ca_async_event( &event_rec );\r
360 \r
361         AL_EXIT( AL_DBG_CA );\r
362 }\r
363 \r
364 \r
365 \r
366 /*\r
367  * Insert a new shmid tracking structure into the CI CA's list.\r
368  */\r
369 void\r
370 add_shmid(\r
371         IN                              al_ci_ca_t* const                       p_ci_ca,\r
372         IN                              struct _al_shmid                        *p_shmid )\r
373 {\r
374         CL_ASSERT( p_ci_ca && p_shmid );\r
375 \r
376         p_shmid->obj.p_ci_ca = p_ci_ca;\r
377 \r
378         /* Insert the shmid structure into the shmid list. */\r
379         cl_spinlock_acquire( &p_ci_ca->obj.lock );\r
380         cl_qlist_insert_head( &p_ci_ca->shmid_list, &p_shmid->list_item );\r
381         cl_spinlock_release( &p_ci_ca->obj.lock );\r
382 }\r
383 \r
384 \r
385 \r
386 ib_api_status_t\r
387 acquire_shmid(\r
388         IN                              al_ci_ca_t* const                       p_ci_ca,\r
389         IN                              int                                                     shmid,\r
390                 OUT                     struct _al_shmid                        **pp_shmid )\r
391 {\r
392         al_shmid_t                      *p_shmid;\r
393         cl_list_item_t          *p_list_item;\r
394 \r
395         /* Try to find the shmid. */\r
396         cl_spinlock_acquire( &p_ci_ca->obj.lock );\r
397         for( p_list_item = cl_qlist_head( &p_ci_ca->shmid_list );\r
398                  p_list_item != cl_qlist_end( &p_ci_ca->shmid_list );\r
399                  p_list_item = cl_qlist_next( p_list_item ) )\r
400         {\r
401                 p_shmid = PARENT_STRUCT( p_list_item, al_shmid_t, list_item );\r
402                 if( p_shmid->id == shmid )\r
403                 {\r
404                         ref_al_obj( &p_shmid->obj );\r
405                         *pp_shmid = p_shmid;\r
406                         break;\r
407                 }\r
408         }\r
409         cl_spinlock_release( &p_ci_ca->obj.lock );\r
410 \r
411         if( p_list_item == cl_qlist_end( &p_ci_ca->shmid_list ) )\r
412                 return IB_NOT_FOUND;\r
413         else\r
414                 return IB_SUCCESS;\r
415 }\r
416 \r
417 \r
418 \r
419 void\r
420 release_shmid(\r
421         IN                              struct _al_shmid                        *p_shmid )\r
422 {\r
423         al_ci_ca_t                      *p_ci_ca;\r
424         int32_t                         ref_cnt;\r
425 \r
426         CL_ASSERT( p_shmid );\r
427 \r
428         p_ci_ca = p_shmid->obj.p_ci_ca;\r
429 \r
430         cl_spinlock_acquire( &p_ci_ca->obj.lock );\r
431 \r
432         /* Dereference the shmid. */\r
433         ref_cnt = deref_al_obj( &p_shmid->obj );\r
434 \r
435         /* If the shmid is no longer in active use, remove it. */\r
436         if( ref_cnt == 1 )\r
437                 cl_qlist_remove_item( &p_ci_ca->shmid_list, &p_shmid->list_item );\r
438 \r
439         cl_spinlock_release( &p_ci_ca->obj.lock );\r
440 \r
441         /* Destroy the shmid if it is not needed. */\r
442         if( ref_cnt == 1 )\r
443         {\r
444                 ref_al_obj( &p_shmid->obj );\r
445                 p_shmid->obj.pfn_destroy( &p_shmid->obj, NULL );\r
446         }\r
447 }\r
448 \r
449 \r
450 \r
451 ib_api_status_t\r
452 ib_ci_call(\r
453         IN                              ib_ca_handle_t                          h_ca,\r
454         IN              const   void**                          const   handle_array    OPTIONAL,\r
455         IN                              uint32_t                                        num_handles,\r
456         IN                              ib_ci_op_t*                     const   p_ci_op )\r
457 {\r
458         return ci_call( h_ca, handle_array, num_handles, p_ci_op, NULL );\r
459 }\r
460 \r
461 \r
462 \r
463 ib_api_status_t\r
464 ci_call(\r
465         IN                              ib_ca_handle_t                          h_ca,\r
466         IN              const   void**                          const   handle_array    OPTIONAL,\r
467         IN                              uint32_t                                        num_handles,\r
468         IN                              ib_ci_op_t*                     const   p_ci_op,\r
469         IN                              ci_umv_buf_t*           const   p_umv_buf OPTIONAL )\r
470 {\r
471         void**                  p_handle_array;\r
472         ib_api_status_t status;\r
473 \r
474         AL_ENTER( AL_DBG_CA );\r
475 \r
476         if( AL_OBJ_INVALID_HANDLE( h_ca, AL_OBJ_TYPE_H_CA ) )\r
477         {\r
478                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_CA_HANDLE\n") );\r
479                 return IB_INVALID_CA_HANDLE;\r
480         }\r
481         if( !p_ci_op )\r
482         {\r
483                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
484                 return IB_INVALID_PARAMETER;\r
485         }\r
486         p_handle_array = NULL;\r
487         if ( num_handles )\r
488         {\r
489                 p_handle_array = cl_zalloc( sizeof(void*) * num_handles );\r
490                 if( !p_handle_array )\r
491                         return IB_INSUFFICIENT_MEMORY;\r
492 \r
493                 status = al_convert_to_ci_handles( p_handle_array, handle_array,\r
494                         num_handles );\r
495 \r
496                 if( status != IB_SUCCESS )\r
497                 {\r
498                         cl_free( p_handle_array );\r
499                         return status;\r
500                 }\r
501         }\r
502 \r
503         if( h_ca->obj.p_ci_ca->verbs.vendor_call )\r
504         {\r
505                 status = verbs_ci_call(\r
506                         h_ca, p_handle_array, num_handles, p_ci_op, p_umv_buf );\r
507         }\r
508         else\r
509         {\r
510                 status = IB_UNSUPPORTED;\r
511         }\r
512 \r
513         if ( num_handles )\r
514                 cl_free( p_handle_array );\r
515 \r
516         AL_EXIT( AL_DBG_QUERY );\r
517         return status;\r
518 }\r
519 \r
520 \r
521 DEVICE_OBJECT*\r
522 get_ca_dev(\r
523         IN              const   ib_ca_handle_t                          h_ca )\r
524 {\r
525         ASSERT( h_ca );\r
526 \r
527         ObReferenceObject( h_ca->p_hca_dev );\r
528         return h_ca->p_hca_dev;\r
529 }\r