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