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