initial implementation
[mirror/winof/.git] / core / al / user / al_mad_pool.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 \r
34 #include "al.h"\r
35 #include "al_ci_ca.h"\r
36 #include "al_debug.h"\r
37 #include "al_mad_pool.h"\r
38 #include "al_pd.h"\r
39 #include "al_verbs.h"\r
40 #include "ib_common.h"\r
41 \r
42 \r
43 typedef struct _mad_reg\r
44 {\r
45         al_obj_t                                obj;                    /* Child of al_pool_key_t */\r
46         ib_mr_handle_t                  h_mr;\r
47         net32_t                                 lkey;\r
48         net32_t                                 rkey;\r
49         mad_array_t*                    p_mad_array;\r
50 \r
51 }       mad_reg_t;\r
52 \r
53 \r
54 \r
55 typedef struct _mad_send\r
56 {\r
57         al_mad_send_t                   mad_send;\r
58         ib_pool_handle_t                h_pool;\r
59 \r
60 }       mad_send_t;\r
61 \r
62 \r
63 \r
64 \r
65 typedef struct _mad_rmpp\r
66 {\r
67         al_mad_rmpp_t                   mad_rmpp;\r
68         ib_pool_handle_t                h_pool;\r
69 \r
70 }       mad_rmpp_t;\r
71 \r
72 \r
73 \r
74 /*\r
75  * Function prototypes.\r
76  */\r
77 static void\r
78 __destroying_pool(\r
79         IN                              al_obj_t*                                       p_obj );\r
80 \r
81 static void\r
82 __free_pool(\r
83         IN                              al_obj_t*                                       p_obj );\r
84 \r
85 static void\r
86 __cleanup_pool_key(\r
87         IN                              al_obj_t*                                       p_obj );\r
88 \r
89 static void\r
90 __free_pool_key(\r
91         IN                              al_obj_t*                                       p_obj );\r
92 \r
93 static ib_api_status_t\r
94 __reg_mad_array(\r
95         IN                              al_pool_key_t*  const   p_pool_key,\r
96         IN                              mad_array_t*    const   p_mad_array );\r
97 \r
98 static void\r
99 __free_mad_reg(\r
100         IN                              al_obj_t*                                       p_obj );\r
101 \r
102 static ib_api_status_t\r
103 __init_mad_element(\r
104         IN              const   al_pool_key_t*                          p_pool_key,\r
105         IN      OUT                     mad_item_t*                                     p_mad_item );\r
106 \r
107 static cl_status_t\r
108 __locate_reg_cb(\r
109         IN              const   cl_list_item_t* const           p_list_item,\r
110         IN                              void*                                           context );\r
111 \r
112 static ib_api_status_t\r
113 __grow_mad_pool(\r
114         IN              const   ib_pool_handle_t                        h_pool,\r
115                 OUT                     mad_item_t**                            pp_mad_item OPTIONAL );\r
116 \r
117 static void\r
118 __free_mad_array(\r
119         IN                              al_obj_t*                                       p_obj );\r
120 \r
121 static cl_status_t\r
122 __mad_send_init(\r
123         IN                              void* const                                     p_object,\r
124         IN                              void*                                           context,\r
125                 OUT                     cl_pool_item_t** const          pp_pool_item );\r
126 \r
127 static cl_status_t\r
128 __mad_rmpp_init(\r
129         IN                              void* const                                     p_object,\r
130         IN                              void*                                           context,\r
131                 OUT                     cl_pool_item_t** const          pp_pool_item );\r
132 \r
133 \r
134 \r
135 /*\r
136  * Create a MAD pool.\r
137  */\r
138 ib_api_status_t\r
139 ib_create_mad_pool(\r
140         IN              const   ib_al_handle_t                          h_al,\r
141         IN              const   size_t                                          min,\r
142         IN              const   size_t                                          max,\r
143         IN              const   size_t                                          grow_size,\r
144                 OUT                     ib_pool_handle_t* const         ph_pool )\r
145 {\r
146         ib_pool_handle_t                h_pool;\r
147         ib_api_status_t                 status;\r
148         cl_status_t                             cl_status;\r
149 \r
150         CL_ENTER( AL_DBG_MAD_POOL, g_al_dbg_lvl );\r
151 \r
152         if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) )\r
153         {\r
154                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl, ("IB_INVALID_AL_HANDLE\n") );\r
155                 return IB_INVALID_AL_HANDLE;\r
156         }\r
157         if( !ph_pool )\r
158         {\r
159                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl, ("IB_INVALID_PARAMETER\n") );\r
160                 return IB_INVALID_PARAMETER;\r
161         }\r
162 \r
163         /* Validate the min and max parameters. */\r
164         if( (min > 0) && (max > 0) && (min > max) )\r
165                 return IB_INVALID_SETTING;\r
166 \r
167         h_pool = cl_zalloc( sizeof( al_pool_t ) );\r
168         if( !h_pool )\r
169                 return IB_INSUFFICIENT_MEMORY;\r
170 \r
171         /* Initialize the pool lists. */\r
172         cl_qlist_init( &h_pool->mad_stack );\r
173         cl_qlist_init( &h_pool->key_list );\r
174         cl_qpool_construct( &h_pool->mad_send_pool );\r
175         cl_qpool_construct( &h_pool->mad_rmpp_pool );\r
176 \r
177         /* Initialize the pool object. */\r
178         construct_al_obj( &h_pool->obj, AL_OBJ_TYPE_H_MAD_POOL );\r
179         status = init_al_obj( &h_pool->obj, h_pool, TRUE,\r
180                 __destroying_pool, NULL, __free_pool );\r
181         if( status != IB_SUCCESS )\r
182         {\r
183                 __free_pool( &h_pool->obj );\r
184                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
185                         ("init_al_obj failed with status %s.\n", ib_get_err_str(status)) );\r
186                 return status;\r
187         }\r
188 \r
189         /* Attach the pool to the AL object. */\r
190         attach_al_obj( &h_al->obj, &h_pool->obj );\r
191 \r
192         /* Save the pool parameters.  Set grow_size to min for initialization. */\r
193         h_pool->max = max;\r
194         h_pool->grow_size = min;\r
195 \r
196         /* Grow the pool to the minimum size. */\r
197         status = __grow_mad_pool( h_pool, NULL );\r
198         if( status != IB_SUCCESS )\r
199         {\r
200                 h_pool->obj.pfn_destroy( &h_pool->obj, NULL );\r
201                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
202                         ("grow_mad_pool failed with status %s.\n", ib_get_err_str(status)) );\r
203                 return status;\r
204         }\r
205 \r
206         /* Save the grow_size for subsequent allocations. */\r
207         h_pool->grow_size = grow_size;\r
208 \r
209         /* Initialize the pool of mad send tracking structures. */\r
210         cl_status = cl_qpool_init( &h_pool->mad_send_pool,\r
211                 min, max, grow_size, sizeof( mad_send_t ),\r
212                 __mad_send_init, NULL, h_pool );\r
213         if( cl_status != CL_SUCCESS )\r
214         {\r
215                 h_pool->obj.pfn_destroy( &h_pool->obj, NULL );\r
216                 status = ib_convert_cl_status( cl_status );\r
217                 h_pool->obj.pfn_destroy( &h_pool->obj, NULL );\r
218 \r
219                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
220                         ("cl_qpool_init failed with status %s.\n", ib_get_err_str(status)) );\r
221                 return status;\r
222         }\r
223 \r
224         /* Initialize the pool of mad send tracking structures. */\r
225         cl_status = cl_qpool_init( &h_pool->mad_rmpp_pool,\r
226                 min, max, grow_size, sizeof( mad_rmpp_t ),\r
227                 __mad_rmpp_init, NULL, h_pool );\r
228         if( cl_status != CL_SUCCESS )\r
229         {\r
230                 h_pool->obj.pfn_destroy( &h_pool->obj, NULL );\r
231                 status = ib_convert_cl_status( cl_status );\r
232                 h_pool->obj.pfn_destroy( &h_pool->obj, NULL );\r
233 \r
234                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
235                         ("cl_qpool_init failed with status %s.\n", ib_get_err_str(status)) );\r
236                 return status;\r
237         }\r
238 \r
239         /* Return the pool handle. */\r
240         *ph_pool = h_pool;\r
241 \r
242         /* Release the reference taken in init_al_obj. */\r
243         deref_al_obj( &h_pool->obj );\r
244 \r
245         CL_EXIT( AL_DBG_MAD_POOL, g_al_dbg_lvl );\r
246         return IB_SUCCESS;\r
247 }\r
248 \r
249 \r
250 \r
251 /*\r
252  * Pre-destory the pool.\r
253  */\r
254 static void\r
255 __destroying_pool(\r
256         IN                              al_obj_t*                                       p_obj )\r
257 {\r
258         ib_pool_handle_t                h_pool;\r
259         ib_al_handle_t                  h_al;\r
260 \r
261         CL_ENTER( AL_DBG_MAD_POOL, g_al_dbg_lvl );\r
262 \r
263         CL_ASSERT( p_obj );\r
264         h_pool = PARENT_STRUCT( p_obj, al_pool_t, obj );\r
265 \r
266         /* Get the AL instance of this MAD pool. */\r
267         p_obj = h_pool->obj.p_parent_obj;\r
268         h_al = PARENT_STRUCT( p_obj, ib_al_t, obj );\r
269 \r
270         /* Deregister this MAD pool from all protection domains. */\r
271         al_dereg_pool( h_al, h_pool );\r
272 \r
273         CL_EXIT( AL_DBG_MAD_POOL, g_al_dbg_lvl );\r
274 }\r
275 \r
276 \r
277 \r
278 /*\r
279  * Free the pool.\r
280  */\r
281 static void\r
282 __free_pool(\r
283         IN                              al_obj_t*                                       p_obj )\r
284 {\r
285         ib_pool_handle_t                h_pool;\r
286 \r
287         CL_ASSERT( p_obj );\r
288         h_pool = PARENT_STRUCT( p_obj, al_pool_t, obj );\r
289 \r
290         cl_qpool_destroy( &h_pool->mad_send_pool );\r
291         cl_qpool_destroy( &h_pool->mad_rmpp_pool );\r
292         destroy_al_obj( &h_pool->obj );\r
293         cl_free( h_pool );\r
294 }\r
295 \r
296 \r
297 \r
298 /*\r
299  * Destory a MAD pool.\r
300  */\r
301 ib_api_status_t\r
302 ib_destroy_mad_pool(\r
303         IN              const   ib_pool_handle_t                        h_pool )\r
304 {\r
305         cl_list_item_t*                 p_array_item;\r
306         al_obj_t*                               p_obj;\r
307         boolean_t                               busy;\r
308 \r
309         CL_ENTER( AL_DBG_MAD_POOL, g_al_dbg_lvl );\r
310 \r
311         if( AL_OBJ_INVALID_HANDLE( h_pool, AL_OBJ_TYPE_H_MAD_POOL ) )\r
312         {\r
313                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl, ("IB_INVALID_HANDLE\n") );\r
314                 return IB_INVALID_HANDLE;\r
315         }\r
316 \r
317         /* Verify that all send handles and MAD elements are in pool. */\r
318         cl_spinlock_acquire( &h_pool->obj.lock );\r
319         busy = ( h_pool->obj.ref_cnt > 1 );\r
320         for( p_array_item = cl_qlist_head( &h_pool->obj.obj_list );\r
321                  p_array_item != cl_qlist_end( &h_pool->obj.obj_list ) && !busy;\r
322                  p_array_item = cl_qlist_next( p_array_item ) )\r
323         {\r
324                 p_obj = PARENT_STRUCT( p_array_item, al_obj_t, pool_item );\r
325                 busy = ( p_obj->ref_cnt > 1 );\r
326         }\r
327         cl_spinlock_release( &h_pool->obj.lock );\r
328 \r
329         /* Return an error if the pool is busy. */\r
330         if( busy )\r
331         {\r
332                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
333                         ("h_pool (0x%p) is busy!.\n", h_pool) );\r
334                 return IB_RESOURCE_BUSY;\r
335         }\r
336 \r
337         ref_al_obj( &h_pool->obj );\r
338         h_pool->obj.pfn_destroy( &h_pool->obj, NULL );\r
339 \r
340         CL_EXIT( AL_DBG_MAD_POOL, g_al_dbg_lvl );\r
341         return IB_SUCCESS;\r
342 }\r
343 \r
344 \r
345 \r
346 /*\r
347  * Register a MAD pool with a protection domain.\r
348  */\r
349 ib_api_status_t\r
350 ib_reg_mad_pool(\r
351         IN              const   ib_pool_handle_t                        h_pool,\r
352         IN              const   ib_pd_handle_t                          h_pd,\r
353                 OUT                     ib_pool_key_t* const            pp_pool_key )\r
354 {\r
355         al_pool_key_t*                  p_pool_key;\r
356         cl_list_item_t*                 p_array_item;\r
357         al_obj_t*                               p_obj;\r
358         ib_al_handle_t                  h_al;\r
359         mad_array_t*                    p_mad_array;\r
360         ib_api_status_t                 status;\r
361         al_key_type_t                   key_type;\r
362 \r
363         CL_ENTER( AL_DBG_MAD_POOL, g_al_dbg_lvl );\r
364 \r
365         if( AL_OBJ_INVALID_HANDLE( h_pool, AL_OBJ_TYPE_H_MAD_POOL ) )\r
366         {\r
367                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl, ("IB_INVALID_HANDLE\n") );\r
368                 return IB_INVALID_HANDLE;\r
369         }\r
370         /* Alias keys require an alias PD. */\r
371         if( AL_OBJ_INVALID_HANDLE( h_pd, AL_OBJ_TYPE_H_PD ) )\r
372         {\r
373                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl, ("IB_INVALID_PD_HANDLE\n") );\r
374                 return IB_INVALID_PD_HANDLE;\r
375         }\r
376         if( !pp_pool_key )\r
377         {\r
378                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl, ("IB_INVALID_PARAMETER\n") );\r
379                 return IB_INVALID_PARAMETER;\r
380         }\r
381 \r
382         /* Set the type of key to create. */\r
383         if( h_pd->type != IB_PDT_ALIAS )\r
384                 key_type = AL_KEY_NORMAL;\r
385         else\r
386                 key_type = AL_KEY_ALIAS;\r
387 \r
388         /* Allocate a pool key structure. */\r
389         p_pool_key = cl_zalloc( sizeof( al_pool_key_t ) );\r
390         if( !p_pool_key )\r
391                 return IB_INSUFFICIENT_MEMORY;\r
392 \r
393         /* Initialize the pool key. */\r
394         construct_al_obj( &p_pool_key->obj, AL_OBJ_TYPE_H_POOL_KEY );\r
395         p_pool_key->type = key_type;\r
396         p_pool_key->h_pool = h_pool;\r
397         p_pool_key->h_pd = h_pd;\r
398 \r
399         /* Initialize the pool key object. */\r
400         status = init_al_obj( &p_pool_key->obj, p_pool_key, TRUE,\r
401                 NULL, __cleanup_pool_key, __free_pool_key );\r
402         if( status != IB_SUCCESS )\r
403         {\r
404                 __free_pool_key( &p_pool_key->obj );\r
405 \r
406                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
407                         ("init_al_obj failed with status %s.\n", ib_get_err_str(status)) );\r
408                 return status;\r
409         }\r
410 \r
411         status = attach_al_obj( &h_pd->obj, &p_pool_key->obj );\r
412         if( status != IB_SUCCESS )\r
413         {\r
414                 p_pool_key->obj.pfn_destroy( &p_pool_key->obj, NULL );\r
415                 AL_TRACE_EXIT( AL_DBG_ERROR,\r
416                         ("attach_al_obj returned %s.\n", ib_get_err_str(status)) );\r
417                 return status;\r
418         }\r
419 \r
420         /* From the PD, get the AL handle of the pool_key. */\r
421         p_obj = h_pd->obj.p_parent_obj->p_parent_obj;\r
422         h_al = PARENT_STRUCT( p_obj, ib_al_t, obj );\r
423 \r
424         /* Add this pool_key to the AL instance. */\r
425         al_insert_key( h_al, p_pool_key );\r
426 \r
427         ref_al_obj( &h_pd->obj );\r
428         ref_al_obj( &h_pool->obj );\r
429 \r
430         /*\r
431          * Take a reference on the global pool_key for this CA, if it exists.\r
432          * Note that the pool_key does not exist for the global MAD pool in\r
433          * user-mode, as that MAD pool never registers memory on a PD.\r
434          */\r
435         if( key_type == AL_KEY_ALIAS && h_pd->obj.p_ci_ca->pool_key )\r
436         {\r
437                 ref_al_obj( &h_pd->obj.p_ci_ca->pool_key->obj );\r
438                 p_pool_key->pool_key = h_pd->obj.p_ci_ca->pool_key;\r
439         }\r
440 \r
441         /* Register the pool on the protection domain. */\r
442         if( key_type == AL_KEY_NORMAL )\r
443         {\r
444                 /* Chain the pool key onto the pool. */\r
445                 cl_spinlock_acquire( &h_pool->obj.lock );\r
446                 cl_qlist_insert_tail( &h_pool->key_list, &p_pool_key->pool_item );\r
447 \r
448                 /* Synchronize with growing the MAD pool. */\r
449                 for( p_array_item = cl_qlist_head( &h_pool->obj.obj_list );\r
450                          p_array_item != cl_qlist_end( &h_pool->obj.obj_list );\r
451                          p_array_item = cl_qlist_next( p_array_item ) )\r
452                 {\r
453                         p_obj = PARENT_STRUCT( p_array_item, al_obj_t, pool_item );\r
454                         p_mad_array = PARENT_STRUCT( p_obj, mad_array_t, obj );\r
455 \r
456                         status = __reg_mad_array( p_pool_key, p_mad_array );\r
457                         \r
458                         if( status != IB_SUCCESS )\r
459                         {\r
460                                 cl_spinlock_release( &h_pool->obj.lock );\r
461                                 p_pool_key->obj.pfn_destroy( &p_pool_key->obj, NULL );\r
462 \r
463                                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
464                                         ("reg_mad_array failed with status %s.\n",\r
465                                         ib_get_err_str(status)) );\r
466                                 return status;\r
467                         }\r
468                 }\r
469                 cl_spinlock_release( &h_pool->obj.lock );\r
470         }\r
471 \r
472         /*\r
473          * If the PD is of alias type, then we need to create/register an\r
474          * equivalent pool key in the kernel.\r
475          */\r
476         if( h_pd->type == IB_PDT_ALIAS )\r
477         {\r
478                 status = create_reg_mad_pool( h_pool, h_pd, p_pool_key );\r
479                 if( status != IB_SUCCESS )\r
480                 {\r
481                         p_pool_key->obj.pfn_destroy( &p_pool_key->obj, NULL );\r
482                         return status;\r
483                 }\r
484         }\r
485 \r
486         /* Return the pool key. */\r
487         *pp_pool_key = (ib_pool_key_t)p_pool_key;\r
488 \r
489         /* Release the reference taken in init_al_obj. */\r
490         deref_al_obj( &p_pool_key->obj );\r
491 \r
492         CL_EXIT( AL_DBG_MAD_POOL, g_al_dbg_lvl );\r
493         return IB_SUCCESS;\r
494 }\r
495 \r
496 \r
497 \r
498 /*\r
499  * Release all references on objects that were needed by the pool key.\r
500  */\r
501 static void\r
502 __cleanup_pool_key(\r
503         IN                              al_obj_t*                                       p_obj )\r
504 {\r
505         cl_list_item_t                  *p_list_item, *p_next_item;\r
506         ib_mad_element_t                *p_mad_element_list, *p_last_mad_element;\r
507         al_mad_element_t                *p_mad;\r
508         ib_api_status_t                 status;\r
509         al_pool_key_t*                  p_pool_key;\r
510 \r
511         CL_ASSERT( p_obj );\r
512         p_pool_key = PARENT_STRUCT( p_obj, al_pool_key_t, obj );\r
513 \r
514         /* Search for any outstanding MADs associated with the given pool key. */\r
515         if( p_pool_key->mad_cnt )\r
516         {\r
517                 p_mad_element_list = p_last_mad_element = NULL;\r
518 \r
519                 cl_spinlock_acquire( &p_pool_key->h_al->obj.lock );\r
520                 for( p_list_item = cl_qlist_head( &p_pool_key->h_al->mad_list );\r
521                          p_list_item != cl_qlist_end( &p_pool_key->h_al->mad_list );\r
522                          p_list_item = p_next_item )\r
523                 {\r
524                         p_next_item = cl_qlist_next( p_list_item );\r
525                         p_mad = PARENT_STRUCT( p_list_item, al_mad_element_t, al_item );\r
526 \r
527                         if( p_mad->pool_key != p_pool_key ) continue;\r
528 \r
529                         /* Build the list of MADs to be returned to pool. */\r
530                         if( p_last_mad_element )\r
531                                 p_last_mad_element->p_next = &p_mad->element;\r
532                         else\r
533                                 p_mad_element_list = &p_mad->element;\r
534 \r
535                         p_last_mad_element = &p_mad->element;\r
536                         p_last_mad_element->p_next = NULL;\r
537                 }\r
538                 cl_spinlock_release( &p_pool_key->h_al->obj.lock );\r
539 \r
540                 /* Return any outstanding MADs to the pool. */\r
541                 if( p_mad_element_list )\r
542                 {\r
543                         status = ib_put_mad( p_mad_element_list );\r
544                         if( status != IB_SUCCESS )\r
545                         {\r
546                                 CL_TRACE( AL_DBG_ERROR, g_al_dbg_lvl,\r
547                                         ("ib_put_mad failed with status %s, continuing.\n",\r
548                                         ib_get_err_str(status)) );\r
549                         }\r
550                 }\r
551         }\r
552 \r
553         /*\r
554          * Remove the pool key from the pool to prevent further registrations\r
555          * against this pool.\r
556          *\r
557          * Warning: There is a small window where a pool key can be destroyed\r
558          * while its associated pool is growing.  In this case, the pool key\r
559          * will receive a new registration after it has been destroyed.  This\r
560          * is a result of having to register memory with the HCA without holding\r
561          * a lock, making correct synchronization impossible.  One solution to\r
562          * this problem is to register all of physical memory, which avoids\r
563          * having to register more memory as a MAD pool grows.\r
564          */\r
565         if( p_pool_key->type == AL_KEY_NORMAL )\r
566         {\r
567                 cl_spinlock_acquire( &p_pool_key->h_pool->obj.lock );\r
568                 cl_qlist_remove_item( &p_pool_key->h_pool->key_list,\r
569                         &p_pool_key->pool_item );\r
570                 cl_spinlock_release( &p_pool_key->h_pool->obj.lock );\r
571         }\r
572 \r
573         /* Remove this pool_key from the AL instance. */\r
574         al_remove_key( p_pool_key );\r
575 \r
576         /* User-mode only: cleanup kernel resources. */\r
577         dereg_destroy_mad_pool( p_pool_key );\r
578 \r
579         deref_al_obj( &p_pool_key->h_pool->obj );\r
580         p_pool_key->h_pool = NULL;\r
581         deref_al_obj( &p_pool_key->h_pd->obj );\r
582         p_pool_key->h_pd = NULL;\r
583         if( p_pool_key->pool_key )\r
584                 deref_al_obj( &p_pool_key->pool_key->obj );\r
585 }\r
586 \r
587 \r
588 \r
589 /*\r
590  * Free a pool key.\r
591  */\r
592 static void\r
593 __free_pool_key(\r
594         IN                              al_obj_t*                                       p_obj )\r
595 {\r
596         al_pool_key_t*                  p_pool_key;\r
597 \r
598         CL_ASSERT( p_obj );\r
599         p_pool_key = PARENT_STRUCT( p_obj, al_pool_key_t, obj );\r
600 \r
601         destroy_al_obj( &p_pool_key->obj );\r
602         cl_free( p_pool_key );\r
603 }\r
604 \r
605 \r
606 \r
607 /*\r
608  * Register a MAD array with a protection domain.\r
609  */\r
610 static ib_api_status_t\r
611 __reg_mad_array(\r
612         IN                              al_pool_key_t*  const   p_pool_key,\r
613         IN                              mad_array_t*    const   p_mad_array )\r
614 {\r
615         mad_reg_t*                              p_reg;\r
616         ib_mr_create_t                  mr_create;\r
617         ib_api_status_t                 status;\r
618 \r
619         CL_ASSERT( p_pool_key );\r
620         CL_ASSERT( p_mad_array );\r
621 \r
622         /* Determine if there is memory to register. */\r
623         if( p_mad_array->sizeof_array == 0 )\r
624                 return IB_SUCCESS;\r
625 \r
626         p_reg = cl_zalloc( sizeof( mad_reg_t ) );\r
627         if( p_reg == NULL )\r
628                 return IB_INSUFFICIENT_MEMORY;\r
629 \r
630         /*\r
631          * Initialize the registration object.  We use synchronous\r
632          * destruction to deregister memory immediately.  Otherwise, the\r
633          * memory will be automatically deregistered when destroying the\r
634          * PD, which can lead to trying to deregister the memory twice.\r
635          */\r
636         construct_al_obj( &p_reg->obj, AL_OBJ_TYPE_MAD_POOL );\r
637         status = init_al_obj( &p_reg->obj, p_reg, FALSE,\r
638                 NULL, NULL, __free_mad_reg );\r
639         if( status != IB_SUCCESS )\r
640         {\r
641                 __free_mad_reg( &p_reg->obj );\r
642                 return status;\r
643         }\r
644 \r
645         /* Attach the registration to the pool key. */\r
646         attach_al_obj( &p_pool_key->obj, &p_reg->obj );\r
647 \r
648         if( p_pool_key->h_pd->type != IB_PDT_ALIAS )\r
649         {\r
650                 /* Register the MAD array on the protection domain. */\r
651                 cl_memclr( &mr_create, sizeof( ib_mr_create_t ) );\r
652                 mr_create.vaddr = p_mad_array->p_data;\r
653                 mr_create.length = p_mad_array->sizeof_array;\r
654                 mr_create.access_ctrl = IB_AC_LOCAL_WRITE;\r
655 \r
656                 status = ib_reg_mem( p_pool_key->h_pd, &mr_create, &p_reg->lkey,\r
657                         &p_reg->rkey, &p_reg->h_mr );\r
658         }\r
659 \r
660         if( status != IB_SUCCESS )\r
661         {\r
662                 p_reg->obj.pfn_destroy( &p_reg->obj, NULL );\r
663                 return status;\r
664         }\r
665 \r
666         /* Save p_mad_array to match the registration with the array. */\r
667         p_reg->p_mad_array = p_mad_array;\r
668 \r
669         /* Release the reference taken in init_al_obj. */\r
670         deref_al_obj( &p_reg->obj );\r
671 \r
672         return IB_SUCCESS;\r
673 }\r
674 \r
675 \r
676 \r
677 /*\r
678  * Free a MAD registration.\r
679  */\r
680 static void\r
681 __free_mad_reg(\r
682         IN                              al_obj_t*                                       p_obj )\r
683 {\r
684         mad_reg_t*                              p_reg;\r
685         ib_api_status_t                 status;\r
686 \r
687         CL_ASSERT( p_obj );\r
688         p_reg = PARENT_STRUCT( p_obj, mad_reg_t, obj );\r
689 \r
690         /* Deregister the MAD array if it was registered. */\r
691         if( p_reg->h_mr )\r
692         {\r
693                 status = ib_dereg_mr( p_reg->h_mr );\r
694                 CL_ASSERT( status == IB_SUCCESS );\r
695         }\r
696 \r
697         destroy_al_obj( &p_reg->obj );\r
698         cl_free( p_reg );\r
699 }\r
700 \r
701 \r
702 \r
703 /*\r
704  * Deregister a MAD pool from a protection domain.  Only normal pool_keys\r
705  * can be destroyed using this routine.\r
706  */\r
707 ib_api_status_t\r
708 ib_dereg_mad_pool(\r
709         IN              const   ib_pool_key_t                           pool_key )\r
710 {\r
711         ib_api_status_t         status;\r
712 \r
713         CL_ENTER( AL_DBG_MAD_POOL, g_al_dbg_lvl );\r
714 \r
715         if( AL_OBJ_INVALID_HANDLE( pool_key, AL_OBJ_TYPE_H_POOL_KEY ) )\r
716         {\r
717                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl, ("IB_INVALID_PARAMETER\n") );\r
718                 return IB_INVALID_PARAMETER;\r
719         }\r
720 \r
721         ref_al_obj( &pool_key->obj );\r
722         status = dereg_mad_pool( pool_key, AL_KEY_NORMAL );\r
723 \r
724         if( status != IB_SUCCESS )\r
725                 deref_al_obj( &pool_key->obj );\r
726 \r
727         CL_EXIT( AL_DBG_MAD_POOL, g_al_dbg_lvl );\r
728         return status;\r
729 }\r
730 \r
731 \r
732 \r
733 /*\r
734  * Deregister a MAD pool from a protection domain.\r
735  */\r
736 ib_api_status_t\r
737 dereg_mad_pool(\r
738         IN              const   ib_pool_key_t                           pool_key ,\r
739         IN              const   al_key_type_t                           expected_type )\r
740 {\r
741         CL_ENTER( AL_DBG_MAD_POOL, g_al_dbg_lvl );\r
742 \r
743         if( pool_key->type != expected_type )\r
744         {\r
745                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl, ("IB_INVALID_PARAMETER\n") );\r
746                 return IB_INVALID_PARAMETER;\r
747         }\r
748 \r
749         ///* Check mad_cnt to see if MADs are still outstanding. */\r
750         //if( pool_key->mad_cnt )\r
751         //{\r
752         //      CL_TRACE_EXIT( AL_DBG_MAD_POOL, g_al_dbg_lvl, ("IB_RESOURCE_BUSY\n") );\r
753         //      return IB_RESOURCE_BUSY;\r
754         //}\r
755 \r
756         pool_key->obj.pfn_destroy( &pool_key->obj, NULL );\r
757 \r
758         CL_EXIT( AL_DBG_MAD_POOL, g_al_dbg_lvl );\r
759         return IB_SUCCESS;\r
760 }\r
761 \r
762 \r
763 \r
764 /*\r
765  * Obtain a MAD element from the pool.\r
766  */\r
767 static ib_api_status_t\r
768 __get_mad_element(\r
769         IN              const   ib_pool_key_t                           pool_key,\r
770                 OUT                     al_mad_element_t**                      pp_mad_element )\r
771 {\r
772         al_pool_key_t*                  p_pool_key;\r
773         ib_pool_handle_t                h_pool;\r
774         cl_list_item_t*                 p_mad_item;\r
775         al_mad_element_t*               p_mad_element;\r
776         mad_item_t*                             p_mad;\r
777         ib_api_status_t                 status;\r
778 \r
779         CL_ENTER( AL_DBG_MAD_POOL, g_al_dbg_lvl );\r
780 \r
781         CL_ASSERT( pool_key );\r
782         CL_ASSERT( pp_mad_element );\r
783 \r
784         p_pool_key = (al_pool_key_t*)pool_key;\r
785         h_pool = p_pool_key->h_pool;\r
786 \r
787         /* Obtain a MAD item from the stack. */\r
788         cl_spinlock_acquire( &h_pool->obj.lock );\r
789         p_mad_item = cl_qlist_remove_head( &h_pool->mad_stack );\r
790         p_mad_element = PARENT_STRUCT( p_mad_item, al_mad_element_t, list_item );\r
791         p_mad = PARENT_STRUCT( p_mad_element, mad_item_t, al_mad_element );\r
792         if( p_mad_item == cl_qlist_end( &h_pool->mad_stack ) )\r
793         {\r
794                 /* The stack was empty.  Grow the pool and obtain a new item. */\r
795                 cl_spinlock_release( &h_pool->obj.lock );\r
796                 status = __grow_mad_pool( h_pool, &p_mad );\r
797                 if( status != IB_SUCCESS )\r
798                 {\r
799                         CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
800                                 ("grow_mad_pool failed with status %s.\n",\r
801                                 ib_get_err_str(status)) );\r
802                         return status;\r
803                 }\r
804         }\r
805         else\r
806         {\r
807                 cl_spinlock_release( &h_pool->obj.lock );\r
808         }\r
809 \r
810         if( p_mad == NULL )\r
811                 return IB_INSUFFICIENT_RESOURCES;\r
812 \r
813         /* Get the local data segment information for this pool key. */\r
814         status = __init_mad_element( p_pool_key, p_mad );\r
815         if( status != IB_SUCCESS )\r
816         {\r
817                 cl_spinlock_acquire( &h_pool->obj.lock );\r
818                 cl_qlist_insert_head( &h_pool->mad_stack,\r
819                         &p_mad_element->list_item );\r
820                 cl_spinlock_release( &h_pool->obj.lock );\r
821 \r
822                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
823                         ("init_mad_element failed with status %s.\n",\r
824                         ib_get_err_str(status)) );\r
825                 return status;\r
826         }\r
827 \r
828         /* Hold a reference on the array while a MAD element is removed. */\r
829         ref_al_obj( &p_mad->p_mad_array->obj );\r
830 \r
831         p_mad->al_mad_element.pool_key = (ib_pool_key_t)pool_key;\r
832         /* Return the MAD element. */\r
833         *pp_mad_element = &p_mad->al_mad_element;\r
834 \r
835         CL_EXIT( AL_DBG_MAD_POOL, g_al_dbg_lvl );\r
836         return IB_SUCCESS;\r
837 }\r
838 \r
839 \r
840 \r
841 static void\r
842 __setup_mad_element(\r
843         IN      OUT                     al_mad_element_t* const         p_al_mad_element,\r
844         IN              const   uint32_t                                        lkey )\r
845 {\r
846         /* Clear the MAD element. */\r
847         cl_memclr( &p_al_mad_element->element, sizeof( ib_mad_element_t ) );\r
848 \r
849         /* Initialize the receive data segment information. */\r
850         p_al_mad_element->grh_ds.lkey = lkey;\r
851 \r
852         /* Initialize the send data segment information. */\r
853         p_al_mad_element->mad_ds.lkey = lkey;\r
854 \r
855         /* Initialize grh */\r
856         p_al_mad_element->element.p_grh =\r
857                 (ib_grh_t*)(uintn_t)p_al_mad_element->mad_ds.vaddr;\r
858 }\r
859 \r
860 \r
861 \r
862 /*\r
863  * Initialize the MAD element local data segment for this pool key.\r
864  */\r
865 static ib_api_status_t\r
866 __init_mad_element(\r
867         IN              const   al_pool_key_t*                          p_pool_key,\r
868         IN      OUT                     mad_item_t*                                     p_mad_item )\r
869 {\r
870         cl_list_item_t                  *p_item;\r
871         cl_qlist_t                              *p_list;\r
872         al_obj_t                                *p_obj;\r
873         mad_reg_t                               *p_reg;\r
874         ib_pool_handle_t                h_pool;\r
875 \r
876         CL_ASSERT( p_pool_key );\r
877         CL_ASSERT( p_mad_item != NULL );\r
878 \r
879         /* Find the MAD array registration entry. */\r
880         if( p_pool_key->type == AL_KEY_NORMAL )\r
881         {\r
882                 p_list = (cl_qlist_t*)&p_pool_key->obj.obj_list;\r
883         }\r
884         else\r
885         {\r
886 #if defined( CL_KERNEL )\r
887                 /* Search the registrations on the actual pool key, not the alias. */\r
888                 p_list = (cl_qlist_t*)&p_pool_key->pool_key->obj.obj_list;\r
889 #else\r
890                 /*\r
891                  * Note that MAD elements used by user-mode clients on special QPs\r
892                  * are not registered on a user-mode PD.  The user-mode MAD elements\r
893                  * must be copied into a kernel-mode MAD element before being sent.\r
894                  */\r
895                 __setup_mad_element( &p_mad_item->al_mad_element, 0 );\r
896                 return IB_SUCCESS;\r
897 #endif\r
898         }\r
899 \r
900         /* Prevent MAD array registrations. */\r
901         h_pool = p_pool_key->h_pool;\r
902         cl_spinlock_acquire( &h_pool->obj.lock );\r
903 \r
904         /* Search for the registration entry. */\r
905         p_item = cl_qlist_find_from_head( p_list, __locate_reg_cb,\r
906                 p_mad_item->p_mad_array );\r
907         if( p_item == cl_qlist_end( p_list ) )\r
908         {\r
909                 cl_spinlock_release( &h_pool->obj.lock );\r
910                 return IB_NOT_FOUND;\r
911         }\r
912 \r
913         /* Allow MAD array registrations. */\r
914         cl_spinlock_release( &h_pool->obj.lock );\r
915 \r
916         /* Get a pointer to the registration. */\r
917         p_obj = PARENT_STRUCT( p_item, al_obj_t, pool_item );\r
918         p_reg = PARENT_STRUCT( p_obj, mad_reg_t, obj );\r
919         __setup_mad_element( &p_mad_item->al_mad_element, p_reg->lkey );\r
920 \r
921         return IB_SUCCESS;\r
922 }\r
923 \r
924 \r
925 \r
926 /*\r
927  * Determine if a registration is for a given array.\r
928  */\r
929 static cl_status_t\r
930 __locate_reg_cb(\r
931         IN              const   cl_list_item_t* const           p_list_item,\r
932         IN                              void*                                           context )\r
933 {\r
934         al_obj_t*                               p_obj;\r
935         mad_reg_t*                              p_reg;\r
936         mad_array_t*                    p_mad_array;\r
937 \r
938         CL_ASSERT( p_list_item );\r
939         CL_ASSERT( context );\r
940 \r
941         p_obj = PARENT_STRUCT( p_list_item,     al_obj_t, pool_item );\r
942         p_reg = PARENT_STRUCT( p_obj, mad_reg_t, obj );\r
943         p_mad_array = context;\r
944 \r
945         return ( p_reg->p_mad_array == p_mad_array ) ? CL_SUCCESS : CL_NOT_FOUND;\r
946 }\r
947 \r
948 \r
949 \r
950 /*\r
951  * Return a MAD element to the pool.\r
952  */\r
953 static void\r
954 __put_mad_element(\r
955         IN                              al_mad_element_t*                       p_mad_element )\r
956 {\r
957         mad_item_t*                             p_mad_item;\r
958         ib_pool_handle_t                h_pool;\r
959 \r
960         CL_ASSERT( p_mad_element );\r
961         p_mad_item = PARENT_STRUCT( p_mad_element, mad_item_t, al_mad_element );\r
962 \r
963         /* Get a handle to the pool. */\r
964         h_pool = p_mad_item->p_mad_array->h_pool;\r
965 \r
966         /* Clear the MAD buffer. */\r
967         cl_memclr(\r
968                 (uint8_t*)(uintn_t)p_mad_element->grh_ds.vaddr, MAD_BLOCK_GRH_SIZE );\r
969         p_mad_element->element.p_next = NULL;\r
970 \r
971         /* Return the MAD element to the pool. */\r
972         cl_spinlock_acquire( &h_pool->obj.lock );\r
973         cl_qlist_insert_head( &h_pool->mad_stack,\r
974                 &p_mad_item->al_mad_element.list_item );\r
975         cl_spinlock_release( &h_pool->obj.lock );\r
976 \r
977         /* Dereference the array when a MAD element is returned. */\r
978         deref_al_obj( &p_mad_item->p_mad_array->obj );\r
979 }\r
980 \r
981 \r
982 \r
983 /*\r
984  * Grow a MAD pool.\r
985  */\r
986 static ib_api_status_t\r
987 __grow_mad_pool(\r
988         IN              const   ib_pool_handle_t                        h_pool,\r
989                 OUT                     mad_item_t**                            pp_mad_item OPTIONAL )\r
990 {\r
991         size_t                                  i;\r
992         size_t                                  alloc_size;\r
993         uint8_t*                                p_data;\r
994         mad_array_t*                    p_mad_array;\r
995         mad_item_t*                             p_mad_item;\r
996         mad_item_t*                             p_mad_items;\r
997         cl_list_item_t*                 p_key_item;\r
998         al_pool_key_t*                  p_pool_key;\r
999         ib_api_status_t                 status;\r
1000 \r
1001         CL_ENTER( AL_DBG_MAD_POOL, g_al_dbg_lvl );\r
1002 \r
1003         CL_ASSERT( h_pool );\r
1004 \r
1005         /* Determine if the pool is allowed to grow. */\r
1006         if( h_pool->grow_size == 0 )\r
1007         {\r
1008                 /* Cannot grow the pool.  Clear the p_mad_item if one was provided. */\r
1009                 if( pp_mad_item != NULL) *pp_mad_item = NULL;\r
1010                 return IB_SUCCESS;\r
1011         }\r
1012 \r
1013         /* Lock the pool. */\r
1014         cl_spinlock_acquire( &h_pool->obj.lock );\r
1015 \r
1016         /* Determine if the pool has a maximum. */\r
1017         if( h_pool->max != 0 )\r
1018         {\r
1019                 /* Determine if the pool maximum has been reached. */\r
1020                 if( h_pool->actual >= h_pool->max )\r
1021                 {\r
1022                         cl_spinlock_release( &h_pool->obj.lock );\r
1023 \r
1024                         CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
1025                                 ("h_pool's (0x%p) maximum has been reached.\n", h_pool) );\r
1026                         return IB_INSUFFICIENT_RESOURCES;\r
1027                 }\r
1028 \r
1029                 /* Determine if growing the pool will exceed the maximum. */\r
1030                 if( (h_pool->actual + h_pool->grow_size) > h_pool->max )\r
1031                 {\r
1032                         cl_spinlock_release( &h_pool->obj.lock );\r
1033 \r
1034                         CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
1035                                 ("h_pool's (0x%p) will exceed maximum on grow.\n", h_pool) );\r
1036                         return IB_INSUFFICIENT_RESOURCES;\r
1037                 }\r
1038         }\r
1039 \r
1040         /* Calculate the allocation size. */\r
1041         alloc_size = sizeof( mad_item_t );\r
1042         alloc_size += MAD_BLOCK_GRH_SIZE;\r
1043         alloc_size *= h_pool->grow_size;\r
1044         alloc_size += sizeof( mad_array_t );\r
1045 \r
1046         /* Allocate a MAD data array and item structures. */\r
1047         p_data = cl_zalloc( alloc_size );\r
1048         if( p_data == NULL )\r
1049         {\r
1050                 cl_spinlock_release( &h_pool->obj.lock );\r
1051                 return IB_INSUFFICIENT_MEMORY;\r
1052         }\r
1053 \r
1054         /* Offset to the MAD array structure. */\r
1055         alloc_size -= sizeof( mad_array_t );\r
1056         p_mad_array = (mad_array_t*)(p_data + alloc_size);\r
1057 \r
1058         /* Offset to the array of MAD item structures. */\r
1059         alloc_size -= sizeof( mad_item_t ) * h_pool->grow_size;\r
1060         p_mad_items = (mad_item_t*)(p_data + alloc_size);\r
1061 \r
1062         /* Initialize the MAD array structure. */\r
1063         p_mad_array->h_pool = h_pool;\r
1064         p_mad_array->p_data = p_data;\r
1065         p_mad_array->sizeof_array = alloc_size;\r
1066 \r
1067         /* Initialize the MAD array object. */\r
1068         construct_al_obj( &p_mad_array->obj, AL_OBJ_TYPE_MAD_POOL );\r
1069         status = init_al_obj( &p_mad_array->obj, p_mad_array, TRUE,\r
1070                 NULL, NULL, __free_mad_array );\r
1071         if( status != IB_SUCCESS )\r
1072         {\r
1073                 cl_spinlock_release( &h_pool->obj.lock );\r
1074                 __free_mad_array( &p_mad_array->obj );\r
1075 \r
1076                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
1077                         ("init_al_obj failed with status %s.\n", ib_get_err_str(status)) );\r
1078                 return status;\r
1079         }\r
1080 \r
1081         /* Register the MAD array on the existing pool protection domains. */\r
1082         for( p_key_item = cl_qlist_head( &h_pool->key_list );\r
1083                  p_key_item != cl_qlist_end( &h_pool->key_list );\r
1084                  p_key_item = cl_qlist_next( p_key_item ) )\r
1085         {\r
1086                 p_pool_key = PARENT_STRUCT( p_key_item, al_pool_key_t, pool_item );\r
1087                 ref_al_obj( &p_pool_key->obj );\r
1088                 status = __reg_mad_array( p_pool_key, p_mad_array );\r
1089                 deref_al_obj( &p_pool_key->obj );\r
1090                 if( status != IB_SUCCESS )\r
1091                         break;\r
1092         }\r
1093 \r
1094         if( status != IB_SUCCESS )\r
1095         {\r
1096                 cl_spinlock_release( &h_pool->obj.lock );\r
1097                 p_mad_array->obj.pfn_destroy( &p_mad_array->obj, NULL );\r
1098                 return status;\r
1099         }\r
1100 \r
1101         /* The pool has been successfully grown.  Update the actual size. */\r
1102         h_pool->actual += h_pool->grow_size;\r
1103 \r
1104         /* Intialize the MAD stack item structures. */\r
1105         p_mad_item = p_mad_items;\r
1106         for( i = 0; i < h_pool->grow_size; i++ )\r
1107         {\r
1108                 p_mad_item->p_mad_array = p_mad_array;\r
1109 \r
1110                 p_mad_item->al_mad_element.grh_ds.vaddr = (uintn_t)p_data;\r
1111                 p_mad_item->al_mad_element.grh_ds.length = MAD_BLOCK_GRH_SIZE;\r
1112 \r
1113                 p_mad_item->al_mad_element.mad_ds.vaddr =\r
1114                         (uintn_t)(p_data + sizeof( ib_grh_t ));\r
1115                 p_mad_item->al_mad_element.mad_ds.length = MAD_BLOCK_SIZE;\r
1116                 p_data += MAD_BLOCK_GRH_SIZE;\r
1117                 p_mad_item++;\r
1118         }\r
1119 \r
1120         /* Return a MAD item to the caller if one was requested. */\r
1121         if( pp_mad_item != NULL )\r
1122         {\r
1123                 *pp_mad_item = p_mad_items;\r
1124                 p_mad_items++;\r
1125                 i--;\r
1126         }\r
1127 \r
1128         /* Append the remaining MAD items to the existing stack. */\r
1129         cl_qlist_insert_array_tail( &h_pool->mad_stack,\r
1130                 &p_mad_items->al_mad_element.list_item, i, sizeof( mad_item_t ) );\r
1131 \r
1132         /* Unlock the pool. */\r
1133         cl_spinlock_release( &h_pool->obj.lock );\r
1134 \r
1135         /* Attach the array object to the pool. */\r
1136         attach_al_obj( &h_pool->obj, &p_mad_array->obj );\r
1137 \r
1138         /* Release the reference taken in init_al_obj. */\r
1139         deref_al_obj( &p_mad_array->obj );\r
1140 \r
1141         CL_EXIT( AL_DBG_MAD_POOL, g_al_dbg_lvl );\r
1142         return IB_SUCCESS;\r
1143 }\r
1144 \r
1145 \r
1146 \r
1147 /*\r
1148  * Free the MAD array structure.\r
1149  */\r
1150 static void\r
1151 __free_mad_array(\r
1152         IN                              al_obj_t*                                       p_obj )\r
1153 {\r
1154         mad_array_t*                    p_mad_array;\r
1155         ib_pool_handle_t                h_pool;\r
1156         cl_list_item_t*                 p_key_item;\r
1157         al_pool_key_t*                  p_pool_key;\r
1158         cl_list_item_t*                 p_reg_item;\r
1159         cl_list_item_t*                 p_next_item;\r
1160         mad_reg_t*                              p_reg;\r
1161 \r
1162         CL_ENTER( AL_DBG_MAD_POOL, g_al_dbg_lvl );\r
1163 \r
1164         CL_ASSERT( p_obj );\r
1165         p_mad_array = PARENT_STRUCT( p_obj, mad_array_t, obj );\r
1166 \r
1167         /* Destroy any registrations for this MAD array. */\r
1168         h_pool = p_mad_array->h_pool;\r
1169         cl_spinlock_acquire( &h_pool->obj.lock );\r
1170 \r
1171         /* Walk the pool key list. */\r
1172         p_key_item = cl_qlist_head( &h_pool->key_list );\r
1173         while( p_key_item != cl_qlist_end( &h_pool->key_list ) )\r
1174         {\r
1175                 p_pool_key = PARENT_STRUCT( p_key_item, al_pool_key_t, pool_item );\r
1176 \r
1177                 /* Walk the pool key registrations. */\r
1178                 for( p_reg_item = cl_qlist_head( &p_pool_key->obj.obj_list );\r
1179                          p_reg_item != cl_qlist_end( &p_pool_key->obj.obj_list );\r
1180                          p_reg_item = p_next_item )\r
1181                 {\r
1182                         p_next_item = cl_qlist_next( p_reg_item );\r
1183 \r
1184                         p_obj = PARENT_STRUCT( p_reg_item, al_obj_t, pool_item );\r
1185                         p_reg = PARENT_STRUCT( p_obj, mad_reg_t, obj );\r
1186 \r
1187                         /* Destroy registrations for this MAD array. */\r
1188                         if( p_reg->p_mad_array == p_mad_array )\r
1189                         {\r
1190                                 ref_al_obj( &p_reg->obj );\r
1191                                 p_reg->obj.pfn_destroy( &p_reg->obj, NULL );\r
1192                         }\r
1193                 }\r
1194 \r
1195                 p_key_item = cl_qlist_next( p_key_item );\r
1196         }\r
1197         cl_spinlock_release( &h_pool->obj.lock );\r
1198 \r
1199         destroy_al_obj( &p_mad_array->obj );\r
1200         cl_free( p_mad_array->p_data );\r
1201 \r
1202         CL_EXIT( AL_DBG_MAD_POOL, g_al_dbg_lvl );\r
1203 }\r
1204 \r
1205 \r
1206 \r
1207 /*\r
1208  * Initialize a MAD send tracking structure to reference the pool from\r
1209  * whence it came.\r
1210  */\r
1211 static cl_status_t\r
1212 __mad_send_init(\r
1213         IN                              void* const                                     p_object,\r
1214         IN                              void*                                           context,\r
1215                 OUT                     cl_pool_item_t** const          pp_pool_item )\r
1216 {\r
1217         mad_send_t                              *p_mad_send;\r
1218 \r
1219         p_mad_send = (mad_send_t*)p_object;\r
1220         p_mad_send->h_pool = context;\r
1221         *pp_pool_item = &p_mad_send->mad_send.pool_item;\r
1222         return CL_SUCCESS;\r
1223 }\r
1224 \r
1225 \r
1226 \r
1227 ib_mad_send_handle_t\r
1228 get_mad_send(\r
1229         IN              const   al_mad_element_t                        *p_mad_element )\r
1230 {\r
1231         mad_item_t*                             p_mad_item;\r
1232         ib_pool_handle_t                h_pool;\r
1233         cl_pool_item_t                  *p_pool_item;\r
1234         ib_mad_send_handle_t    h_send;\r
1235 \r
1236         CL_ASSERT( p_mad_element );\r
1237 \r
1238         /* Get a handle to the pool. */\r
1239         p_mad_item = PARENT_STRUCT( p_mad_element, mad_item_t, al_mad_element );\r
1240         h_pool = p_mad_item->p_mad_array->h_pool;\r
1241 \r
1242         cl_spinlock_acquire( &h_pool->obj.lock );\r
1243         p_pool_item = cl_qpool_get( &h_pool->mad_send_pool );\r
1244         cl_spinlock_release( &h_pool->obj.lock );\r
1245 \r
1246         if( !p_pool_item )\r
1247                 return NULL;\r
1248 \r
1249         ref_al_obj( &h_pool->obj );\r
1250         h_send = PARENT_STRUCT( p_pool_item, al_mad_send_t, pool_item );\r
1251         h_send->canceled = FALSE;\r
1252         h_send->p_send_mad = NULL;\r
1253         h_send->p_resp_mad = NULL;\r
1254         h_send->h_av = NULL;\r
1255         h_send->retry_cnt = 0;\r
1256         h_send->retry_time = 0;\r
1257 \r
1258         return h_send;\r
1259 }\r
1260 \r
1261 \r
1262 \r
1263 void\r
1264 put_mad_send(\r
1265         IN                              ib_mad_send_handle_t            h_mad_send )\r
1266 {\r
1267         mad_send_t                      *p_mad_send;\r
1268 \r
1269         p_mad_send = PARENT_STRUCT( h_mad_send, mad_send_t, mad_send );\r
1270 \r
1271         cl_spinlock_acquire( &p_mad_send->h_pool->obj.lock );\r
1272         cl_qpool_put( &p_mad_send->h_pool->mad_send_pool, &h_mad_send->pool_item );\r
1273         cl_spinlock_release( &p_mad_send->h_pool->obj.lock );\r
1274         deref_al_obj( &p_mad_send->h_pool->obj );\r
1275 }\r
1276 \r
1277 \r
1278 \r
1279 /*\r
1280  * Initialize a MAD RMPP tracking structure to reference the pool from\r
1281  * whence it came.\r
1282  */\r
1283 static cl_status_t\r
1284 __mad_rmpp_init(\r
1285         IN                              void* const                                     p_object,\r
1286         IN                              void*                                           context,\r
1287                 OUT                     cl_pool_item_t** const          pp_pool_item )\r
1288 {\r
1289         mad_rmpp_t                              *p_mad_rmpp;\r
1290 \r
1291         p_mad_rmpp = (mad_rmpp_t*)p_object;\r
1292         p_mad_rmpp->h_pool = context;\r
1293         *pp_pool_item = &p_mad_rmpp->mad_rmpp.pool_item;\r
1294         return CL_SUCCESS;\r
1295 }\r
1296 \r
1297 \r
1298 \r
1299 al_mad_rmpp_t*\r
1300 get_mad_rmpp(\r
1301         IN              const   al_mad_element_t                        *p_mad_element )\r
1302 {\r
1303         mad_item_t*                             p_mad_item;\r
1304         ib_pool_handle_t                h_pool;\r
1305         cl_pool_item_t                  *p_pool_item;\r
1306 \r
1307         CL_ASSERT( p_mad_element );\r
1308 \r
1309         /* Get a handle to the pool. */\r
1310         p_mad_item = PARENT_STRUCT( p_mad_element, mad_item_t, al_mad_element );\r
1311         h_pool = p_mad_item->p_mad_array->h_pool;\r
1312 \r
1313         cl_spinlock_acquire( &h_pool->obj.lock );\r
1314         p_pool_item = cl_qpool_get( &h_pool->mad_rmpp_pool );\r
1315         cl_spinlock_release( &h_pool->obj.lock );\r
1316 \r
1317         if( !p_pool_item )\r
1318                 return NULL;\r
1319 \r
1320         ref_al_obj( &h_pool->obj );\r
1321         return PARENT_STRUCT( p_pool_item, al_mad_rmpp_t, pool_item );\r
1322 }\r
1323 \r
1324 \r
1325 \r
1326 void\r
1327 put_mad_rmpp(\r
1328         IN                              al_mad_rmpp_t*                          h_mad_rmpp )\r
1329 {\r
1330         mad_rmpp_t                      *p_mad_rmpp;\r
1331 \r
1332         p_mad_rmpp = PARENT_STRUCT( h_mad_rmpp, mad_rmpp_t, mad_rmpp );\r
1333 \r
1334         cl_spinlock_acquire( &p_mad_rmpp->h_pool->obj.lock );\r
1335         cl_qpool_put( &p_mad_rmpp->h_pool->mad_rmpp_pool, &h_mad_rmpp->pool_item );\r
1336         cl_spinlock_release( &p_mad_rmpp->h_pool->obj.lock );\r
1337         deref_al_obj( &p_mad_rmpp->h_pool->obj );\r
1338 }\r
1339 \r
1340 \r
1341 \r
1342 ib_api_status_t\r
1343 ib_get_mad(\r
1344         IN              const   ib_pool_key_t                           pool_key,\r
1345         IN              const   size_t                                          buf_size,\r
1346                 OUT                     ib_mad_element_t                        **pp_mad_element )\r
1347 {\r
1348         al_pool_key_t*                  p_pool_key;\r
1349         al_mad_element_t*               p_mad;\r
1350         ib_api_status_t                 status;\r
1351 \r
1352         CL_ENTER( AL_DBG_MAD_POOL, g_al_dbg_lvl );\r
1353 \r
1354         if( AL_OBJ_INVALID_HANDLE( pool_key, AL_OBJ_TYPE_H_POOL_KEY ) )\r
1355         {\r
1356                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl, ("IB_INVALID_PARAMETER\n") );\r
1357                 return IB_INVALID_PARAMETER;\r
1358         }\r
1359         if( !buf_size || !pp_mad_element )\r
1360         {\r
1361                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl, ("IB_INVALID_PARAMETER\n") );\r
1362                 return IB_INVALID_PARAMETER;\r
1363         }\r
1364 \r
1365         p_pool_key = (al_pool_key_t*)pool_key;\r
1366 \r
1367         status = __get_mad_element( pool_key, &p_mad );\r
1368         if( status != IB_SUCCESS )\r
1369         {\r
1370                 CL_EXIT( AL_DBG_MAD_POOL, g_al_dbg_lvl );\r
1371                 return status;\r
1372         }\r
1373 \r
1374         /* Set the user accessible buffer. */\r
1375         if( buf_size <= MAD_BLOCK_SIZE )\r
1376         {\r
1377                 /* Use the send buffer for 256 byte MADs. */\r
1378                 p_mad->element.p_mad_buf = (ib_mad_t*)(uintn_t)p_mad->mad_ds.vaddr;\r
1379         }\r
1380         else if( buf_size >= 0xFFFFFFFF )\r
1381         {\r
1382                 __put_mad_element( p_mad );\r
1383                 return IB_INVALID_SETTING;\r
1384         }\r
1385         else\r
1386         {\r
1387                 /* Allocate a new buffer for the MAD. */\r
1388                 p_mad->p_al_mad_buf = cl_zalloc( buf_size );\r
1389                 if( !p_mad->p_al_mad_buf )\r
1390                 {\r
1391                         __put_mad_element( p_mad );\r
1392                         CL_EXIT( AL_DBG_MAD_POOL, g_al_dbg_lvl );\r
1393                         return IB_INSUFFICIENT_MEMORY;\r
1394                 }\r
1395                 p_mad->element.p_mad_buf = p_mad->p_al_mad_buf;\r
1396         }\r
1397         p_mad->element.size = (uint32_t)buf_size;\r
1398 \r
1399         /* Track the MAD element with the requesting AL instance. */\r
1400         al_insert_mad( p_pool_key->h_al, p_mad );\r
1401 \r
1402         ref_al_obj( &p_pool_key->obj );\r
1403         cl_atomic_inc( &p_pool_key->mad_cnt );\r
1404 \r
1405         /* Return the MAD element to the client. */\r
1406         *pp_mad_element = &p_mad->element;\r
1407 \r
1408         CL_EXIT( AL_DBG_MAD_POOL, g_al_dbg_lvl );\r
1409         return IB_SUCCESS;\r
1410 }\r
1411 \r
1412 \r
1413 \r
1414 ib_api_status_t\r
1415 ib_put_mad(\r
1416         IN              const   ib_mad_element_t*                       p_mad_element_list )\r
1417 {\r
1418         al_mad_element_t*               p_mad;\r
1419 \r
1420         if( !p_mad_element_list )\r
1421         {\r
1422                 CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl, ("IB_INVALID_PARAMETER\n") );\r
1423                 return IB_INVALID_PARAMETER;\r
1424         }\r
1425 \r
1426         while( p_mad_element_list )\r
1427         {\r
1428                 p_mad = PARENT_STRUCT( p_mad_element_list, al_mad_element_t, element );\r
1429                 p_mad_element_list = p_mad_element_list->p_next;\r
1430 \r
1431                 /* Deallocate any buffers allocated for the user. */\r
1432                 if( p_mad->p_al_mad_buf )\r
1433                 {\r
1434                         cl_free( p_mad->p_al_mad_buf );\r
1435                         p_mad->p_al_mad_buf = NULL;\r
1436                 }\r
1437 \r
1438                 /* See if the MAD has already been returned to the MAD pool. */\r
1439                 if( p_mad->h_al )\r
1440                 {\r
1441                         /* Remove the MAD element from the owning AL instance. */\r
1442                         al_remove_mad( p_mad );\r
1443 \r
1444                         /* Return the MAD element to the pool. */\r
1445                         cl_atomic_dec( &p_mad->pool_key->mad_cnt );\r
1446                         deref_al_obj( &p_mad->pool_key->obj );\r
1447                         __put_mad_element( p_mad );\r
1448                 }\r
1449                 else\r
1450                 {\r
1451                         CL_TRACE_EXIT( AL_DBG_ERROR, g_al_dbg_lvl,\r
1452                                 ("MAD has already been returned to MAD pool.\n") );\r
1453                 }\r
1454         }\r
1455 \r
1456         return IB_SUCCESS;\r
1457 }\r
1458 \r
1459 \r
1460 \r
1461 /*\r
1462  * Resize the data buffer associated with a MAD element.\r
1463  */\r
1464 ib_api_status_t\r
1465 al_resize_mad(\r
1466                 OUT                     ib_mad_element_t                        *p_mad_element,\r
1467         IN              const   size_t                                          buf_size )\r
1468 {\r
1469         al_mad_element_t                *p_al_element;\r
1470         ib_mad_t                                *p_new_buf;\r
1471 \r
1472         CL_ASSERT( p_mad_element );\r
1473 \r
1474         /* We only support growing the buffer for now. */\r
1475         CL_ASSERT( buf_size > p_mad_element->size );\r
1476 \r
1477         /* Cap the size. */\r
1478         if( buf_size >= 0xFFFFFFFF )\r
1479                 return IB_INVALID_SETTING;\r
1480 \r
1481         p_al_element = PARENT_STRUCT( p_mad_element, al_mad_element_t, element );\r
1482 \r
1483         /* Allocate a new buffer. */\r
1484         p_new_buf = cl_malloc( buf_size );\r
1485         if( !p_new_buf )\r
1486                 return IB_INSUFFICIENT_MEMORY;\r
1487 \r
1488         /* Copy the existing buffer's data into the new buffer. */\r
1489         cl_memcpy( p_new_buf, p_mad_element->p_mad_buf, p_mad_element->size );\r
1490         cl_memclr( (uint8_t*)p_new_buf + p_mad_element->size,\r
1491                 buf_size - p_mad_element->size );\r
1492 \r
1493         /* Update the MAD element to use the new buffer. */\r
1494         p_mad_element->p_mad_buf = p_new_buf;\r
1495         p_mad_element->size = (uint32_t)buf_size;\r
1496 \r
1497         /* Free any old buffer. */\r
1498         if( p_al_element->p_al_mad_buf )\r
1499                 cl_free( p_al_element->p_al_mad_buf );\r
1500         p_al_element->p_al_mad_buf = p_new_buf;\r
1501 \r
1502         return IB_SUCCESS;\r
1503 }\r
1504 \r