[IBAL] bugfix: QP has to increment the reference on the pool key upon creation and...
[mirror/winof/.git] / core / al / al_qp.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 <complib/cl_async_proc.h>\r
34 #include <complib/cl_memory.h>\r
35 #include <complib/cl_timer.h>\r
36 \r
37 #include "al.h"\r
38 #include "al_av.h"\r
39 #include "al_ca.h"\r
40 #include "al_cm_cep.h"\r
41 #include "al_cq.h"\r
42 #include "al_debug.h"\r
43 #if defined(EVENT_TRACING)\r
44 #ifdef offsetof\r
45 #undef offsetof\r
46 #endif\r
47 #include "al_qp.tmh"\r
48 #endif\r
49 #include "al_mad.h"\r
50 #include "al_mad_pool.h"\r
51 #include "al_mcast.h"\r
52 #include "al_mgr.h"\r
53 #include "al_mr.h"\r
54 #include "al_mw.h"\r
55 #include "al_pd.h"\r
56 #include "al_qp.h"\r
57 #include "al_query.h"\r
58 #ifdef CL_KERNEL\r
59 #include "al_smi.h"\r
60 #endif  /* CL_KERNEL */\r
61 #include "al_verbs.h"\r
62 \r
63 #include "ib_common.h"\r
64 \r
65 \r
66 #define UNBOUND_PORT_GUID               0\r
67 \r
68 \r
69 extern ib_pool_handle_t                 gh_mad_pool;\r
70 \r
71 \r
72 /*\r
73  * Function prototypes.\r
74  */\r
75 void\r
76 destroying_qp(\r
77         IN                              al_obj_t                                        *p_obj );\r
78 \r
79 void\r
80 cleanup_qp(\r
81         IN                              al_obj_t                                        *p_obj );\r
82 \r
83 void\r
84 free_qp(\r
85         IN                              al_obj_t                                        *p_obj );\r
86 \r
87 \r
88 \r
89 ib_api_status_t\r
90 init_base_qp(\r
91         IN                              ib_qp_t* const                          p_qp,\r
92         IN              const   void* const                                     qp_context,\r
93         IN              const   ib_pfn_event_cb_t                       pfn_qp_event_cb,\r
94         IN      OUT                     ci_umv_buf_t* const                     p_umv_buf );\r
95 \r
96 ib_api_status_t\r
97 init_raw_qp(\r
98         IN              const   ib_qp_handle_t                          h_qp,\r
99         IN              const   ib_pd_handle_t                          h_pd,\r
100         IN              const   ib_net64_t                                      port_guid OPTIONAL,\r
101         IN              const   ib_qp_create_t* const           p_qp_create,\r
102         IN      OUT                     ci_umv_buf_t* const                     p_umv_buf );\r
103 \r
104 ib_api_status_t\r
105 init_conn_qp(\r
106         IN                              al_conn_qp_t* const                     p_conn_qp,\r
107         IN              const   ib_pd_handle_t                          h_pd,\r
108         IN              const   ib_qp_create_t* const           p_qp_create,\r
109         IN      OUT                     ci_umv_buf_t* const                     p_umv_buf );\r
110 \r
111 ib_api_status_t\r
112 init_dgrm_qp(\r
113         IN                              al_dgrm_qp_t* const                     p_dgrm_qp,\r
114         IN              const   ib_pd_handle_t                          h_pd,\r
115         IN              const   ib_qp_create_t* const           p_qp_create,\r
116         IN      OUT                     ci_umv_buf_t* const                     p_umv_buf );\r
117 \r
118 ib_api_status_t\r
119 init_special_qp(\r
120         IN                              al_special_qp_t* const          p_special_qp,\r
121         IN              const   ib_pd_handle_t                          h_pd,\r
122         IN              const   ib_net64_t                                      port_guid,\r
123         IN              const   ib_qp_create_t* const           p_qp_create );\r
124 \r
125 ib_api_status_t\r
126 init_qp_alias(\r
127         IN                              al_qp_alias_t* const            p_qp_alias,\r
128         IN              const   ib_pd_handle_t                          h_pd,\r
129         IN              const   ib_net64_t                                      port_guid,\r
130         IN              const   ib_qp_create_t* const           p_qp_create );\r
131 \r
132 ib_api_status_t\r
133 init_mad_qp(\r
134         IN                              al_mad_qp_t* const                      p_mad_qp,\r
135         IN              const   ib_pd_handle_t                          h_pd,\r
136         IN              const   ib_qp_create_t* const           p_qp_create,\r
137         IN              const   ib_pfn_event_cb_t                       pfn_qp_event_cb );\r
138 \r
139 ib_api_status_t\r
140 init_mad_dgrm_svc(\r
141         IN              const   ib_qp_handle_t                          h_qp,\r
142         IN              const   ib_dgrm_info_t* const           p_dgrm_info );\r
143 \r
144 \r
145 ib_api_status_t\r
146 al_modify_qp(\r
147         IN              const   ib_qp_handle_t                          h_qp,\r
148         IN              const   ib_qp_mod_t* const                      p_qp_mod,\r
149         IN      OUT                     ci_umv_buf_t* const                     p_umv_buf );\r
150 \r
151 \r
152 ib_api_status_t\r
153 init_dgrm_svc(\r
154         IN              const   ib_qp_handle_t                          h_qp,\r
155         IN              const   ib_dgrm_info_t* const           p_dgrm_info );\r
156 \r
157 ib_api_status_t\r
158 mad_qp_post_recvs(\r
159         IN                              al_mad_qp_t*    const           p_mad_qp );\r
160 \r
161 ib_api_status_t\r
162 ud_post_send(\r
163         IN              const   ib_qp_handle_t                          h_qp,\r
164         IN                              ib_send_wr_t* const                     p_send_wr,\r
165                 OUT                     ib_send_wr_t                            **pp_send_failure );\r
166 \r
167 ib_api_status_t\r
168 special_qp_post_send(\r
169         IN              const   ib_qp_handle_t                          h_qp,\r
170         IN                              ib_send_wr_t* const                     p_send_wr,\r
171                 OUT                     ib_send_wr_t                            **pp_send_failure );\r
172 \r
173 void\r
174 mad_qp_queue_mad(\r
175         IN              const   ib_qp_handle_t                          h_qp,\r
176         IN                              al_mad_wr_t* const                      p_mad_wr );\r
177 \r
178 void\r
179 mad_qp_resume_sends(\r
180         IN                              ib_qp_handle_t                          h_qp );\r
181 \r
182 void\r
183 mad_qp_flush_send(\r
184         IN                              al_mad_qp_t*                            p_mad_qp,\r
185         IN                              al_mad_wr_t* const                      p_mad_wr );\r
186 \r
187 void\r
188 mad_recv_comp_cb(\r
189         IN              const   ib_cq_handle_t                          h_cq,\r
190         IN                              void                                            *cq_context );\r
191 \r
192 void\r
193 mad_send_comp_cb(\r
194         IN              const   ib_cq_handle_t                          h_cq,\r
195         IN                              void                                            *cq_context );\r
196 \r
197 void\r
198 mad_qp_comp(\r
199         IN                              al_mad_qp_t*                            p_mad_qp,\r
200         IN              const   ib_cq_handle_t                          h_cq,\r
201         IN                              ib_wc_type_t                            wc_type );\r
202 \r
203 void\r
204 mad_qp_cq_event_cb(\r
205         IN                              ib_async_event_rec_t            *p_event_rec );\r
206 \r
207 \r
208 \r
209 /*\r
210  * Allocates a structure to store QP information.\r
211  */\r
212 ib_api_status_t\r
213 alloc_qp(\r
214         IN              const   ib_qp_type_t                            qp_type,\r
215                 OUT                     ib_qp_handle_t* const           ph_qp )\r
216 {\r
217         ib_qp_handle_t                          h_qp;\r
218 \r
219         switch( qp_type )\r
220         {\r
221         case IB_QPT_RELIABLE_CONN:\r
222         case IB_QPT_UNRELIABLE_CONN:\r
223                 h_qp = (ib_qp_handle_t)cl_zalloc( sizeof( al_conn_qp_t ) );\r
224                 break;\r
225 \r
226         case IB_QPT_UNRELIABLE_DGRM:\r
227                 h_qp = (ib_qp_handle_t)cl_zalloc( sizeof( al_dgrm_qp_t ) );\r
228                 break;\r
229 \r
230         case IB_QPT_QP0:\r
231         case IB_QPT_QP1:\r
232                 h_qp = (ib_qp_handle_t)cl_zalloc( sizeof( al_special_qp_t ) );\r
233                 break;\r
234 \r
235         case IB_QPT_RAW_IPV6:\r
236         case IB_QPT_RAW_ETHER:\r
237                 h_qp = (ib_qp_handle_t)cl_zalloc( sizeof( ib_qp_t ) );\r
238                 break;\r
239 \r
240         case IB_QPT_MAD:\r
241                 h_qp = (ib_qp_handle_t)cl_zalloc( sizeof( al_mad_qp_t ) );\r
242                 break;\r
243 \r
244         case IB_QPT_QP0_ALIAS:\r
245         case IB_QPT_QP1_ALIAS:\r
246                 h_qp = (ib_qp_handle_t)cl_zalloc( sizeof( al_qp_alias_t ) );\r
247                 break;\r
248 \r
249         default:\r
250                 CL_ASSERT( qp_type == IB_QPT_RELIABLE_CONN ||\r
251                         qp_type == IB_QPT_UNRELIABLE_CONN ||\r
252                         qp_type == IB_QPT_UNRELIABLE_DGRM ||\r
253                         qp_type == IB_QPT_QP0 ||\r
254                         qp_type == IB_QPT_QP1 ||\r
255                         qp_type == IB_QPT_RAW_IPV6 ||\r
256                         qp_type == IB_QPT_RAW_ETHER ||\r
257                         qp_type == IB_QPT_MAD ||\r
258                         qp_type == IB_QPT_QP0_ALIAS ||\r
259                         qp_type == IB_QPT_QP1_ALIAS );\r
260                 return IB_INVALID_SETTING;\r
261         }\r
262 \r
263         if( !h_qp )\r
264         {\r
265                 return IB_INSUFFICIENT_MEMORY;\r
266         }\r
267 \r
268         h_qp->type = qp_type;\r
269 \r
270         *ph_qp = h_qp;\r
271         return IB_SUCCESS;\r
272 }\r
273 \r
274 \r
275 \r
276 /*\r
277  * Initializes the QP information structure.\r
278  */\r
279 ib_api_status_t\r
280 create_qp(\r
281         IN              const   ib_pd_handle_t                          h_pd,\r
282         IN              const   ib_qp_create_t* const           p_qp_create,\r
283         IN              const   void* const                                     qp_context,\r
284         IN              const   ib_pfn_event_cb_t                       pfn_qp_event_cb,\r
285                 OUT                     ib_qp_handle_t* const           ph_qp,\r
286         IN      OUT                     ci_umv_buf_t* const                     p_umv_buf )\r
287 {\r
288         ib_api_status_t                 status;\r
289         ib_qp_handle_t                  h_qp;\r
290 \r
291         if( !p_qp_create || !ph_qp )\r
292         {\r
293                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
294                 return IB_INVALID_PARAMETER;\r
295         }\r
296 \r
297         /* Allocate a QP. */\r
298         status = alloc_qp( p_qp_create->qp_type, &h_qp );\r
299         if( status != IB_SUCCESS )\r
300         {\r
301                 return status;\r
302         }\r
303 \r
304         /* Init the base QP first. */\r
305         status = init_base_qp( h_qp, qp_context, pfn_qp_event_cb, p_umv_buf );\r
306         if( status != IB_SUCCESS )\r
307                 return status;\r
308 \r
309         /* Initialize the QP based on its type. */\r
310         switch( h_qp->type )\r
311         {\r
312         case IB_QPT_RELIABLE_CONN:\r
313         case IB_QPT_UNRELIABLE_CONN:\r
314                 if( AL_OBJ_INVALID_HANDLE( p_qp_create->h_sq_cq, AL_OBJ_TYPE_H_CQ ) ||\r
315                         AL_OBJ_INVALID_HANDLE( p_qp_create->h_rq_cq, AL_OBJ_TYPE_H_CQ ) )\r
316                 {\r
317                         status = IB_INVALID_CQ_HANDLE;\r
318                         break;\r
319                 }\r
320                 status = init_conn_qp( (al_conn_qp_t*)h_qp, h_pd, p_qp_create, p_umv_buf );\r
321                 break;\r
322 \r
323         case IB_QPT_UNRELIABLE_DGRM:\r
324                 if( AL_OBJ_INVALID_HANDLE( p_qp_create->h_sq_cq, AL_OBJ_TYPE_H_CQ ) ||\r
325                         AL_OBJ_INVALID_HANDLE( p_qp_create->h_rq_cq, AL_OBJ_TYPE_H_CQ ) )\r
326                 {\r
327                         status = IB_INVALID_CQ_HANDLE;\r
328                         break;\r
329                 }\r
330                 status = init_dgrm_qp( (al_dgrm_qp_t*)h_qp, h_pd, p_qp_create, p_umv_buf );\r
331                 break;\r
332 \r
333         case IB_QPT_MAD:\r
334                 if( p_qp_create->h_sq_cq || p_qp_create->h_rq_cq )\r
335                 {\r
336                         status = IB_INVALID_CQ_HANDLE;\r
337                         break;\r
338                 }\r
339                 status = init_mad_qp( (al_mad_qp_t*)h_qp, h_pd, p_qp_create,\r
340                         pfn_qp_event_cb );\r
341                 break;\r
342 \r
343         default:\r
344                 CL_ASSERT( h_qp->type == IB_QPT_RELIABLE_CONN ||\r
345                         h_qp->type == IB_QPT_UNRELIABLE_CONN ||\r
346                         h_qp->type == IB_QPT_UNRELIABLE_DGRM ||\r
347                         h_qp->type == IB_QPT_MAD );\r
348                 status = IB_INVALID_SETTING;\r
349                 break;\r
350         }\r
351 \r
352         if( status != IB_SUCCESS )\r
353         {\r
354                 h_qp->obj.pfn_destroy( &h_qp->obj, NULL );\r
355                 return status;\r
356         }\r
357 \r
358         *ph_qp = h_qp;\r
359 \r
360         /*\r
361          * Note that we don't release the reference taken in init_al_obj here.\r
362          * For kernel clients, it is release in ib_create_qp.  For user-mode\r
363          * clients is is released by the proxy after the handle is extracted.\r
364          */\r
365         return IB_SUCCESS;\r
366 }\r
367 \r
368 \r
369 \r
370 ib_api_status_t\r
371 get_spl_qp(\r
372         IN              const   ib_pd_handle_t                          h_pd,\r
373         IN              const   ib_net64_t                                      port_guid,\r
374         IN              const   ib_qp_create_t* const           p_qp_create,\r
375         IN              const   void* const                                     qp_context,\r
376         IN              const   ib_pfn_event_cb_t                       pfn_qp_event_cb,\r
377                 OUT                     ib_pool_key_t* const            p_pool_key OPTIONAL,\r
378                 OUT                     ib_qp_handle_t* const           ph_qp,\r
379         IN      OUT                     ci_umv_buf_t* const                     p_umv_buf )\r
380 {\r
381         ib_api_status_t                 status;\r
382         ib_qp_handle_t                  h_qp;\r
383 \r
384         if( !p_qp_create || !ph_qp )\r
385         {\r
386                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
387                 return IB_INVALID_PARAMETER;\r
388         }\r
389 \r
390         /* Only allow creation of the special QP types. */\r
391         switch( p_qp_create->qp_type )\r
392         {\r
393 #ifdef CL_KERNEL\r
394         case IB_QPT_QP0:\r
395         case IB_QPT_QP1:\r
396 #endif\r
397         case IB_QPT_QP0_ALIAS:\r
398         case IB_QPT_QP1_ALIAS:\r
399         case IB_QPT_RAW_IPV6:\r
400         case IB_QPT_RAW_ETHER:\r
401                 break;                          /* The QP type is valid. */\r
402 \r
403         default:\r
404                 return IB_INVALID_SETTING;\r
405         }\r
406 \r
407         /* Allocate a QP. */\r
408         status = alloc_qp( p_qp_create->qp_type, &h_qp );\r
409         if( status != IB_SUCCESS )\r
410         {\r
411                 return status;\r
412         }\r
413 \r
414         /* Init the base QP first. */\r
415         status = init_base_qp( h_qp, qp_context, pfn_qp_event_cb, p_umv_buf );\r
416         if( status != IB_SUCCESS )\r
417                 return status;\r
418 \r
419         /* Initialize the QP based on its type. */\r
420         switch( h_qp->type )\r
421         {\r
422 #ifdef CL_KERNEL\r
423         case IB_QPT_QP0:\r
424         case IB_QPT_QP1:\r
425                 if( AL_OBJ_INVALID_HANDLE( p_qp_create->h_sq_cq, AL_OBJ_TYPE_H_CQ ) ||\r
426                         AL_OBJ_INVALID_HANDLE( p_qp_create->h_rq_cq, AL_OBJ_TYPE_H_CQ ) )\r
427                 {\r
428                         status = IB_INVALID_CQ_HANDLE;\r
429                         break;\r
430                 }\r
431                 status = init_special_qp( (al_special_qp_t*)h_qp, h_pd, port_guid,\r
432                         p_qp_create );\r
433                 break;\r
434 #endif  /* CL_KERNEL */\r
435 \r
436         case IB_QPT_QP0_ALIAS:\r
437         case IB_QPT_QP1_ALIAS:\r
438                 if( p_qp_create->h_sq_cq || p_qp_create->h_rq_cq )\r
439                 {\r
440                         status = IB_INVALID_CQ_HANDLE;\r
441                         break;\r
442                 }\r
443                 status = init_alias_qp( (al_qp_alias_t*)h_qp, h_pd, port_guid,\r
444                         p_qp_create );\r
445                 if( status == IB_SUCCESS && p_pool_key )\r
446                 {\r
447                         /* Create a pool_key to access to the global MAD pool. */\r
448                         status = ib_reg_mad_pool( gh_mad_pool, h_pd,\r
449                                 &((al_qp_alias_t*)h_qp)->pool_key );\r
450                         if( status == IB_SUCCESS )\r
451                         {\r
452                                 /*\r
453                                  * Take a reference on the pool key since we don't have a\r
454                                  * mechanism for the pool key to clear the QP's pointer to it.\r
455                                  */\r
456                                 ref_al_obj( &((al_qp_alias_t*)h_qp)->pool_key->obj );\r
457                                 *p_pool_key = ((al_qp_alias_t*)h_qp)->pool_key;\r
458                         }\r
459                 }\r
460                 break;\r
461 \r
462         case IB_QPT_RAW_IPV6:\r
463         case IB_QPT_RAW_ETHER:\r
464                 if( AL_OBJ_INVALID_HANDLE( p_qp_create->h_sq_cq, AL_OBJ_TYPE_H_CQ ) ||\r
465                         AL_OBJ_INVALID_HANDLE( p_qp_create->h_rq_cq, AL_OBJ_TYPE_H_CQ ) )\r
466                 {\r
467                         status = IB_INVALID_CQ_HANDLE;\r
468                         break;\r
469                 }\r
470                 status = init_raw_qp( h_qp, h_pd, port_guid, p_qp_create, p_umv_buf );\r
471                 break;\r
472 \r
473         default:\r
474                 CL_ASSERT( h_qp->type == IB_QPT_QP0 ||\r
475                         h_qp->type == IB_QPT_QP1 ||\r
476                         h_qp->type == IB_QPT_QP0_ALIAS ||\r
477                         h_qp->type == IB_QPT_QP1_ALIAS ||\r
478                         h_qp->type == IB_QPT_RAW_IPV6 ||\r
479                         h_qp->type == IB_QPT_RAW_ETHER );\r
480 \r
481                 status = IB_INVALID_SETTING;\r
482                 break;\r
483         }\r
484 \r
485         if( status != IB_SUCCESS )\r
486         {\r
487                 h_qp->obj.pfn_destroy( &h_qp->obj, NULL );\r
488                 return status;\r
489         }\r
490 \r
491         *ph_qp = h_qp;\r
492 \r
493         return IB_SUCCESS;\r
494 }\r
495 \r
496 \r
497 static ib_api_status_t\r
498 al_bad_modify_qp(\r
499         IN              const   ib_qp_handle_t                          h_qp,\r
500         IN              const   ib_qp_mod_t* const                      p_qp_mod,\r
501         IN      OUT                     ci_umv_buf_t* const                     p_umv_buf )\r
502 {\r
503         UNUSED_PARAM( h_qp );\r
504         UNUSED_PARAM( p_qp_mod );\r
505         UNUSED_PARAM( p_umv_buf );\r
506         return IB_INVALID_PARAMETER;\r
507 }\r
508 \r
509 \r
510 static ib_api_status_t\r
511 al_bad_post_send(\r
512         IN              const   ib_qp_handle_t                          h_qp,\r
513         IN                              ib_send_wr_t* const                     p_send_wr,\r
514         IN                              ib_send_wr_t                            **pp_send_failure OPTIONAL )\r
515 {\r
516         UNUSED_PARAM( h_qp );\r
517         UNUSED_PARAM( p_send_wr );\r
518         UNUSED_PARAM( pp_send_failure );\r
519         return IB_INVALID_PARAMETER;\r
520 }\r
521 \r
522 \r
523 static ib_api_status_t\r
524 al_bad_post_recv(\r
525         IN              const   ib_qp_handle_t                          h_qp,\r
526         IN                              ib_recv_wr_t* const                     p_recv_wr,\r
527         IN                              ib_recv_wr_t                            **p_recv_failure OPTIONAL )\r
528 {\r
529         UNUSED_PARAM( h_qp );\r
530         UNUSED_PARAM( p_recv_wr );\r
531         UNUSED_PARAM( p_recv_failure );\r
532         return IB_INVALID_PARAMETER;\r
533 }\r
534 \r
535 \r
536 static ib_api_status_t\r
537 al_bad_init_dgrm_svc(\r
538         IN              const   ib_qp_handle_t                          h_qp,\r
539         IN              const   ib_dgrm_info_t* const           p_dgrm_info )\r
540 {\r
541         UNUSED_PARAM( h_qp );\r
542         UNUSED_PARAM( p_dgrm_info );\r
543         return IB_INVALID_PARAMETER;\r
544 }\r
545 \r
546 \r
547 static ib_api_status_t\r
548 al_bad_reg_mad_svc(\r
549         IN              const   ib_qp_handle_t                          h_qp,\r
550         IN              const   ib_mad_svc_t* const                     p_mad_svc,\r
551                 OUT                     ib_mad_svc_handle_t* const      ph_mad_svc )\r
552 {\r
553         UNUSED_PARAM( h_qp );\r
554         UNUSED_PARAM( p_mad_svc );\r
555         UNUSED_PARAM( ph_mad_svc );\r
556         return IB_INVALID_PARAMETER;\r
557 }\r
558 \r
559 \r
560 static ib_api_status_t\r
561 al_bad_dereg_mad_svc(\r
562         IN              const   ib_mad_svc_handle_t                     h_mad_svc )\r
563 {\r
564         UNUSED_PARAM( h_mad_svc );\r
565         return IB_INVALID_PARAMETER;\r
566 }\r
567 \r
568 \r
569 static void\r
570 al_bad_queue_mad(\r
571         IN              const   ib_qp_handle_t                          h_qp,\r
572         IN                              al_mad_wr_t* const                      p_mad_wr )\r
573 {\r
574         UNUSED_PARAM( h_qp );\r
575         UNUSED_PARAM( p_mad_wr );\r
576 }\r
577 \r
578 \r
579 static void\r
580 al_bad_resume_mad(\r
581         IN              const   ib_qp_handle_t                          h_qp )\r
582 {\r
583         UNUSED_PARAM( h_qp );\r
584         return;\r
585 }\r
586 \r
587 \r
588 static ib_api_status_t\r
589 al_bad_join_mcast(\r
590         IN              const   ib_qp_handle_t                          h_qp,\r
591         IN              const   ib_mcast_req_t* const           p_mcast_req )\r
592 {\r
593         UNUSED_PARAM( h_qp );\r
594         UNUSED_PARAM( p_mcast_req );\r
595         return IB_INVALID_PARAMETER;\r
596 }\r
597 \r
598 \r
599 ib_api_status_t\r
600 init_base_qp(\r
601         IN                              ib_qp_t* const                          p_qp,\r
602         IN              const   void* const                                     qp_context,\r
603         IN              const   ib_pfn_event_cb_t                       pfn_qp_event_cb,\r
604         IN      OUT                     ci_umv_buf_t* const                     p_umv_buf )\r
605 {\r
606         ib_api_status_t                 status;\r
607         al_obj_type_t                   obj_type = AL_OBJ_TYPE_H_QP;\r
608 \r
609         CL_ASSERT( p_qp );\r
610 \r
611         if( p_umv_buf )\r
612                 obj_type |= AL_OBJ_SUBTYPE_UM_EXPORT;\r
613 \r
614         construct_al_obj( &p_qp->obj, obj_type );\r
615         status = init_al_obj( &p_qp->obj, qp_context, TRUE,\r
616                 destroying_qp, cleanup_qp, free_qp );\r
617         if( status != IB_SUCCESS )\r
618         {\r
619                 free_qp( &p_qp->obj );\r
620                 return status;\r
621         }\r
622 \r
623         p_qp->pfn_event_cb = pfn_qp_event_cb;\r
624 \r
625         /*\r
626          * All function pointers should be invalid.  They will be set by\r
627          * derived QP types where appropriate.\r
628          */\r
629         p_qp->pfn_modify_qp = al_bad_modify_qp;\r
630         p_qp->pfn_post_recv = al_bad_post_recv;\r
631         p_qp->pfn_post_send = al_bad_post_send;\r
632         p_qp->pfn_reg_mad_svc = al_bad_reg_mad_svc;\r
633         p_qp->pfn_dereg_mad_svc = al_bad_dereg_mad_svc;\r
634         p_qp->pfn_queue_mad = al_bad_queue_mad;\r
635         p_qp->pfn_resume_mad = al_bad_resume_mad;\r
636         p_qp->pfn_init_dgrm_svc = al_bad_init_dgrm_svc;\r
637         p_qp->pfn_join_mcast = al_bad_join_mcast;\r
638 \r
639         if( p_qp->type == IB_QPT_RELIABLE_CONN ||\r
640                 p_qp->type == IB_QPT_UNRELIABLE_CONN )\r
641         {\r
642                 ((al_conn_qp_t*)p_qp)->cid = AL_INVALID_CID;\r
643         }\r
644 \r
645         return status;\r
646 }\r
647 \r
648 \r
649 \r
650 ib_api_status_t\r
651 init_raw_qp(\r
652         IN              const   ib_qp_handle_t                          h_qp,\r
653         IN              const   ib_pd_handle_t                          h_pd,\r
654         IN              const   ib_net64_t                                      port_guid OPTIONAL,\r
655         IN              const   ib_qp_create_t* const           p_qp_create,\r
656         IN      OUT                     ci_umv_buf_t* const                     p_umv_buf )\r
657 {\r
658         ib_api_status_t                         status;\r
659         ib_qp_create_t                          qp_create;\r
660         ib_qp_attr_t                            qp_attr;\r
661         uint8_t                                         port_num;\r
662 \r
663         status = attach_al_obj( &h_pd->obj, &h_qp->obj );\r
664         if( status != IB_SUCCESS )\r
665                 return status;\r
666 \r
667         /* Convert AL handles to CI handles. */\r
668         qp_create = *p_qp_create;\r
669         convert_qp_handle( qp_create );\r
670 \r
671         /* Clear the QP attributes to ensure non-set values are 0. */\r
672         cl_memclr( &qp_attr, sizeof( ib_qp_attr_t ) );\r
673 \r
674         h_qp->port_guid = port_guid;\r
675 \r
676         /*\r
677          * Allocate a QP from the channel adapter.  Note that these calls\r
678          * set the send and receive pointers appropriately for posting\r
679          * work requests.\r
680          */\r
681         if( port_guid == UNBOUND_PORT_GUID )\r
682         {\r
683                 status =\r
684                         verbs_create_qp( h_pd, h_qp, &qp_create, &qp_attr, p_umv_buf );\r
685         }\r
686         else\r
687         {\r
688                 status = get_port_num( h_pd->obj.p_ci_ca, port_guid, &port_num );\r
689                 if( status == IB_SUCCESS )\r
690                 {\r
691                         status = verbs_get_spl_qp( h_pd, port_num, h_qp,\r
692                                 &qp_create, &qp_attr );\r
693                 }\r
694         }\r
695         if( status != IB_SUCCESS )\r
696         {\r
697                 return status;\r
698         }\r
699 \r
700         /* Override function pointers. */\r
701         h_qp->pfn_modify_qp = al_modify_qp;\r
702 \r
703         if( h_qp->type == IB_QPT_UNRELIABLE_DGRM ||\r
704                 h_qp->type == IB_QPT_QP0 ||\r
705                 h_qp->type == IB_QPT_QP1 )\r
706         {\r
707                 /* We have to mess with the AV handles. */\r
708                 h_qp->pfn_ud_post_send = h_qp->pfn_post_send;\r
709                 h_qp->h_ud_send_qp = h_qp->h_send_qp;\r
710 \r
711                 h_qp->pfn_post_send = ud_post_send;\r
712                 h_qp->h_send_qp = h_qp;\r
713         }\r
714 \r
715         h_qp->h_recv_cq = p_qp_create->h_rq_cq;\r
716         h_qp->h_send_cq = p_qp_create->h_sq_cq;\r
717 \r
718         h_qp->recv_cq_rel.p_child_obj = (cl_obj_t*)h_qp;\r
719         h_qp->send_cq_rel.p_child_obj = (cl_obj_t*)h_qp;\r
720 \r
721         cq_attach_qp( h_qp->h_recv_cq, &h_qp->recv_cq_rel );\r
722         cq_attach_qp( h_qp->h_send_cq, &h_qp->send_cq_rel );\r
723 \r
724         h_qp->num = qp_attr.num;\r
725 \r
726         return IB_SUCCESS;\r
727 }\r
728 \r
729 \r
730 \r
731 ib_api_status_t\r
732 init_conn_qp(\r
733         IN                              al_conn_qp_t* const                     p_conn_qp,\r
734         IN              const   ib_pd_handle_t                          h_pd,\r
735         IN              const   ib_qp_create_t* const           p_qp_create,\r
736         IN      OUT                     ci_umv_buf_t* const                     p_umv_buf )\r
737 {\r
738         ib_api_status_t                         status;\r
739         CL_ASSERT( p_conn_qp );\r
740 \r
741         /* Initialize the inherited QP first. */\r
742         status = init_raw_qp( &p_conn_qp->qp, h_pd, UNBOUND_PORT_GUID,\r
743                 p_qp_create, p_umv_buf );\r
744 \r
745 \r
746         return status;\r
747 }\r
748 \r
749 \r
750 \r
751 ib_api_status_t\r
752 init_dgrm_qp(\r
753         IN                              al_dgrm_qp_t* const                     p_dgrm_qp,\r
754         IN              const   ib_pd_handle_t                          h_pd,\r
755         IN              const   ib_qp_create_t* const           p_qp_create,\r
756         IN      OUT                     ci_umv_buf_t* const                     p_umv_buf )\r
757 {\r
758         ib_api_status_t                         status;\r
759         CL_ASSERT( p_dgrm_qp );\r
760 \r
761         /* Initialize the inherited QP first. */\r
762         status = init_raw_qp( p_dgrm_qp, h_pd, UNBOUND_PORT_GUID,\r
763                 p_qp_create, p_umv_buf );\r
764         if( status != IB_SUCCESS )\r
765         {\r
766                 return status;\r
767         }\r
768 \r
769         /* Override function pointers. */\r
770         p_dgrm_qp->pfn_init_dgrm_svc = init_dgrm_svc;\r
771         p_dgrm_qp->pfn_join_mcast = al_join_mcast;\r
772 \r
773         return IB_SUCCESS;\r
774 }\r
775 \r
776 \r
777 #ifdef CL_KERNEL\r
778 ib_api_status_t\r
779 init_special_qp(\r
780         IN                              al_special_qp_t* const          p_special_qp,\r
781         IN              const   ib_pd_handle_t                          h_pd,\r
782         IN              const   ib_net64_t                                      port_guid,\r
783         IN              const   ib_qp_create_t* const           p_qp_create )\r
784 {\r
785         ib_api_status_t                         status;\r
786         CL_ASSERT( p_special_qp );\r
787 \r
788         /* Construct the special QP. */\r
789         cl_qlist_init( &p_special_qp->to_send_queue );\r
790 \r
791         /* Initialize the inherited QP first. */\r
792         status =\r
793                 init_raw_qp( &p_special_qp->qp, h_pd, port_guid, p_qp_create, NULL );\r
794         if( status != IB_SUCCESS )\r
795         {\r
796                 return status;\r
797         }\r
798 \r
799         /* Override function pointers. */\r
800         p_special_qp->qp.pfn_init_dgrm_svc = init_dgrm_svc;\r
801         p_special_qp->qp.pfn_queue_mad = special_qp_queue_mad;\r
802         p_special_qp->qp.pfn_resume_mad = special_qp_resume_sends;\r
803 \r
804         return IB_SUCCESS;\r
805 }\r
806 \r
807 \r
808 ib_api_status_t\r
809 init_qp_alias(\r
810         IN                              al_qp_alias_t* const            p_qp_alias,\r
811         IN              const   ib_pd_handle_t                          h_pd,\r
812         IN              const   ib_net64_t                                      port_guid,\r
813         IN              const   ib_qp_create_t* const           p_qp_create )\r
814 {\r
815         ib_api_status_t                         status;\r
816 \r
817         CL_ASSERT( p_qp_alias );\r
818         UNUSED_PARAM( p_qp_create );\r
819 \r
820         if( h_pd->type != IB_PDT_ALIAS )\r
821         {\r
822                 return IB_INVALID_PD_HANDLE;\r
823         }\r
824 \r
825         status = attach_al_obj( &h_pd->obj, &p_qp_alias->qp.obj );\r
826         if( status != IB_SUCCESS )\r
827                 return status;\r
828 \r
829         switch( p_qp_alias->qp.type )\r
830         {\r
831         case IB_QPT_QP0_ALIAS:\r
832                 status = acquire_smi_disp( port_guid, &p_qp_alias->h_mad_disp );\r
833                 break;\r
834 \r
835         case IB_QPT_QP1_ALIAS:\r
836                 status = acquire_gsi_disp( port_guid, &p_qp_alias->h_mad_disp );\r
837                 break;\r
838 \r
839         default:\r
840                 CL_ASSERT( p_qp_alias->qp.type == IB_QPT_QP0_ALIAS ||\r
841                         p_qp_alias->qp.type == IB_QPT_QP1_ALIAS );\r
842                 return IB_ERROR;\r
843         }\r
844 \r
845         if( status != IB_SUCCESS )\r
846                 return status;\r
847 \r
848         /* Get a copy of the QP used by the MAD dispatcher. */\r
849         ref_al_obj( &p_qp_alias->h_mad_disp->h_qp->obj );\r
850         p_qp_alias->qp.h_ci_qp = p_qp_alias->h_mad_disp->h_qp->h_ci_qp;\r
851 \r
852         /* Override function pointers. */\r
853         p_qp_alias->qp.pfn_reg_mad_svc = reg_mad_svc;\r
854 \r
855         return IB_SUCCESS;\r
856 }\r
857 #endif  /* CL_KERNEL */\r
858 \r
859 \r
860 \r
861 ib_api_status_t\r
862 init_mad_qp(\r
863         IN                              al_mad_qp_t* const                      p_mad_qp,\r
864         IN              const   ib_pd_handle_t                          h_pd,\r
865         IN              const   ib_qp_create_t* const           p_qp_create,\r
866         IN              const   ib_pfn_event_cb_t                       pfn_qp_event_cb )\r
867 {\r
868         ib_cq_create_t                          cq_create;\r
869         ib_qp_create_t                          qp_create;\r
870         ib_al_handle_t                          h_al;\r
871         ib_ca_handle_t                          h_ca;\r
872         ib_api_status_t                         status;\r
873 \r
874         CL_ASSERT( p_mad_qp );\r
875 \r
876         /* Initialize the send and receive tracking queues. */\r
877         cl_qlist_init( &p_mad_qp->to_send_queue );\r
878         cl_qlist_init( &p_mad_qp->send_queue );\r
879         cl_qlist_init( &p_mad_qp->recv_queue );\r
880 \r
881         /* The CQ handles must be NULL when creating a MAD queue pair. */\r
882         if( p_qp_create->h_sq_cq || p_qp_create->h_rq_cq )\r
883         {\r
884                 return IB_INVALID_SETTING;\r
885         }\r
886 \r
887         /* Initialize the CQs used with the MAD QP. */\r
888         cl_memclr( &cq_create, sizeof( ib_cq_create_t ) );\r
889 \r
890         /* Create the send CQ. */\r
891         cq_create.size = p_qp_create->sq_depth;\r
892         cq_create.pfn_comp_cb = mad_send_comp_cb;\r
893 \r
894         status = ib_create_cq( h_pd->obj.p_ci_ca->h_ca, &cq_create,\r
895                 p_mad_qp, mad_qp_cq_event_cb, &p_mad_qp->h_send_cq );\r
896 \r
897         if( status != IB_SUCCESS )\r
898         {\r
899                 return status;\r
900         }\r
901 \r
902         /* Reference the MAD QP on behalf of ib_create_cq. */\r
903         ref_al_obj( &p_mad_qp->qp.obj );\r
904 \r
905         /* Create the receive CQ. */\r
906         cq_create.size = p_qp_create->rq_depth;\r
907         cq_create.pfn_comp_cb = mad_recv_comp_cb;\r
908 \r
909         h_ca = PARENT_STRUCT( h_pd->obj.p_parent_obj, ib_ca_t, obj );\r
910         status = ib_create_cq( h_ca, &cq_create, p_mad_qp, mad_qp_cq_event_cb,\r
911                 &p_mad_qp->h_recv_cq );\r
912 \r
913         if( status != IB_SUCCESS )\r
914         {\r
915                 return status;\r
916         }\r
917 \r
918         /* Reference the MAD QP on behalf of ib_create_cq. */\r
919         ref_al_obj( &p_mad_qp->qp.obj );\r
920 \r
921         /* Save the requested receive queue depth.  This is used to post MADs. */\r
922         p_mad_qp->max_rq_depth = p_qp_create->rq_depth;\r
923 \r
924         /* Allocate a datagram QP for the MAD QP. */\r
925         qp_create = *p_qp_create;\r
926         qp_create.qp_type = IB_QPT_UNRELIABLE_DGRM;\r
927         qp_create.sq_sge = 1;\r
928         qp_create.rq_sge = 1;\r
929         qp_create.h_rq_cq = p_mad_qp->h_recv_cq;\r
930         qp_create.h_sq_cq = p_mad_qp->h_send_cq;\r
931 \r
932         status = ib_create_qp( h_pd, &qp_create, p_mad_qp, pfn_qp_event_cb,\r
933                 &p_mad_qp->h_dgrm_qp );\r
934 \r
935         if( status != IB_SUCCESS )\r
936         {\r
937                 return status;\r
938         }\r
939 \r
940         /* Reference the MAD QP on behalf of ib_create_qp. */\r
941         ref_al_obj( &p_mad_qp->qp.obj );\r
942 \r
943         /* Create the MAD dispatch service. */\r
944         status = create_mad_disp( &p_mad_qp->qp.obj, &p_mad_qp->qp,\r
945                 &p_mad_qp->h_mad_disp );\r
946         if( status != IB_SUCCESS )\r
947         {\r
948                 return status;\r
949         }\r
950 \r
951         /* Override function pointers. */\r
952         p_mad_qp->qp.pfn_init_dgrm_svc = init_mad_dgrm_svc;\r
953         p_mad_qp->qp.pfn_queue_mad = mad_qp_queue_mad;\r
954         p_mad_qp->qp.pfn_resume_mad = mad_qp_resume_sends;\r
955         p_mad_qp->qp.pfn_reg_mad_svc = reg_mad_svc;\r
956 \r
957         /* The client's AL handle is the grandparent of the PD. */\r
958         h_al = PARENT_STRUCT( h_pd->obj.p_parent_obj->p_parent_obj, ib_al_t, obj );\r
959 \r
960         /* Create a receive MAD pool. */\r
961         status = ib_create_mad_pool( h_al, p_mad_qp->max_rq_depth + 16, 0, 16,\r
962                 &p_mad_qp->h_pool );\r
963 \r
964         if (status != IB_SUCCESS)\r
965         {\r
966                 return status;\r
967         }\r
968 \r
969         /*\r
970          * The MAD pool is a child of the client's AL instance.  If the client\r
971          * closes AL, the MAD pool will be destroyed before the MAD queue pair.\r
972          * Therefore, we hold a reference on the MAD pool to keep it from being\r
973          * destroyed until the MAD queue pair is destroyed.  Refer to the MAD\r
974          * queue pair cleanup code.\r
975          */\r
976         ref_al_obj( &p_mad_qp->h_pool->obj );\r
977 \r
978         /* Register the MAD pool with the PD. */\r
979         status = ib_reg_mad_pool( p_mad_qp->h_pool, h_pd, &p_mad_qp->pool_key );\r
980 \r
981         if (status != IB_SUCCESS)\r
982         {\r
983                 return status;\r
984         }\r
985 \r
986         /*\r
987          * Attach the MAD queue pair to the protection domain.  This must be\r
988          * done after creating the datagram queue pair and the MAD pool to set\r
989          * the correct order of object destruction.\r
990          */\r
991         status = attach_al_obj( &h_pd->obj, &p_mad_qp->qp.obj );\r
992         \r
993         /* Get a copy of the CI datagram QP for ib_query_qp. */\r
994         p_mad_qp->qp.h_ci_qp = p_mad_qp->h_dgrm_qp->h_ci_qp;\r
995 \r
996         return status;\r
997 }\r
998 \r
999 \r
1000 \r
1001 ib_api_status_t\r
1002 ib_destroy_qp(\r
1003         IN              const   ib_qp_handle_t                          h_qp,\r
1004         IN              const   ib_pfn_destroy_cb_t                     pfn_destroy_cb OPTIONAL )\r
1005 {\r
1006         AL_ENTER( AL_DBG_QP );\r
1007 \r
1008         if( AL_OBJ_INVALID_HANDLE( h_qp, AL_OBJ_TYPE_H_QP ) )\r
1009         {\r
1010                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );\r
1011                 return IB_INVALID_QP_HANDLE;\r
1012         }\r
1013 \r
1014         ref_al_obj( &h_qp->obj );\r
1015         h_qp->obj.pfn_destroy( &h_qp->obj, pfn_destroy_cb );\r
1016 \r
1017         AL_EXIT( AL_DBG_QP );\r
1018         return IB_SUCCESS;\r
1019 }\r
1020 \r
1021 \r
1022 \r
1023 /*\r
1024  * Release any resources that must be cleaned up immediately, such as\r
1025  * any AL resources acquired by calling through the main API.\r
1026  */\r
1027 void\r
1028 destroying_qp(\r
1029         IN                              al_obj_t                                        *p_obj )\r
1030 {\r
1031         ib_qp_handle_t                  h_qp;\r
1032         al_mad_qp_t                             *p_mad_qp;\r
1033         al_qp_alias_t                   *p_qp_alias;\r
1034         net32_t                                 cid;\r
1035 \r
1036         CL_ASSERT( p_obj );\r
1037         h_qp = PARENT_STRUCT( p_obj, ib_qp_t, obj );\r
1038 \r
1039         switch( h_qp->type )\r
1040         {\r
1041         case IB_QPT_MAD:\r
1042                 /* Destroy QP and CQ services required for MAD QP support. */\r
1043                 p_mad_qp = PARENT_STRUCT( h_qp, al_mad_qp_t, qp );\r
1044 \r
1045                 if( p_mad_qp->h_dgrm_qp )\r
1046                 {\r
1047                         ib_destroy_qp( p_mad_qp->h_dgrm_qp,\r
1048                                 (ib_pfn_destroy_cb_t)deref_al_obj );\r
1049                         p_mad_qp->qp.h_ci_qp = NULL;\r
1050                 }\r
1051 \r
1052                 if( p_mad_qp->h_recv_cq )\r
1053                 {\r
1054                         ib_destroy_cq( p_mad_qp->h_recv_cq,\r
1055                                 (ib_pfn_destroy_cb_t)deref_al_obj );\r
1056                 }\r
1057 \r
1058                 if( p_mad_qp->h_send_cq )\r
1059                 {\r
1060                         ib_destroy_cq( p_mad_qp->h_send_cq,\r
1061                                 (ib_pfn_destroy_cb_t)deref_al_obj );\r
1062                 }\r
1063                 break;\r
1064 \r
1065         case IB_QPT_QP0_ALIAS:\r
1066         case IB_QPT_QP1_ALIAS:\r
1067                 p_qp_alias = PARENT_STRUCT( h_qp, al_qp_alias_t, qp );\r
1068 \r
1069                 if( p_qp_alias->pool_key )\r
1070                 {\r
1071                         ib_api_status_t         status;\r
1072                         /* Deregister the pool_key. */\r
1073                         status = dereg_mad_pool( p_qp_alias->pool_key, AL_KEY_ALIAS );\r
1074                         if( status != IB_SUCCESS )\r
1075                         {\r
1076                                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1077                                         ("dereg_mad_pool returned %s.\n",\r
1078                                         ib_get_err_str(status)) );\r
1079                                 /* Release the reference taken when we created the pool key. */\r
1080                                 deref_al_obj( &p_qp_alias->pool_key->obj );\r
1081                         }\r
1082                         p_qp_alias->pool_key = NULL;\r
1083                 }\r
1084 \r
1085                 if( p_qp_alias->qp.h_ci_qp )\r
1086                 {\r
1087                         deref_al_obj( &p_qp_alias->h_mad_disp->h_qp->obj );\r
1088                         p_qp_alias->qp.h_ci_qp = NULL;\r
1089                 }\r
1090 \r
1091                 /*\r
1092                  * If the pool_key still exists here, then the QP is being destroyed\r
1093                  * by destroying its parent (the PD).  Destruction of the PD will also\r
1094                  * destroy the pool_key.\r
1095                  */\r
1096 \r
1097                 if( p_qp_alias->h_mad_disp )\r
1098                         deref_al_obj( &p_qp_alias->h_mad_disp->obj );\r
1099                 break;\r
1100 \r
1101         case IB_QPT_RELIABLE_CONN:\r
1102         case IB_QPT_UNRELIABLE_CONN:\r
1103                 cid = cl_atomic_xchg(\r
1104                         &((al_conn_qp_t*)h_qp)->cid, AL_INVALID_CID );\r
1105                 if( cid != AL_INVALID_CID )\r
1106                 {\r
1107                         ref_al_obj( &h_qp->obj );\r
1108                         if( al_destroy_cep(\r
1109                                 h_qp->obj.h_al, cid, deref_al_obj ) != IB_SUCCESS )\r
1110                         {\r
1111                                 deref_al_obj( &h_qp->obj );\r
1112                         }\r
1113                 }\r
1114 \r
1115                 /* Fall through. */\r
1116         case IB_QPT_UNRELIABLE_DGRM:\r
1117         default:\r
1118                 /* Multicast membership gets cleaned up by object hierarchy. */\r
1119                 cq_detach_qp( h_qp->h_recv_cq, &h_qp->recv_cq_rel );\r
1120                 cq_detach_qp( h_qp->h_send_cq, &h_qp->send_cq_rel );\r
1121         }\r
1122 }\r
1123 \r
1124 \r
1125 \r
1126 /*\r
1127  * Release any HW resources.\r
1128  */\r
1129 void\r
1130 cleanup_qp(\r
1131         IN                              al_obj_t                                        *p_obj )\r
1132 {\r
1133         ib_qp_handle_t                  h_qp;\r
1134         al_mad_qp_t*                    p_mad_qp;\r
1135         al_mad_wr_t*                    p_mad_wr;\r
1136         cl_list_item_t*                 p_list_item;\r
1137         al_mad_element_t*               p_al_mad;\r
1138         ib_api_status_t                 status;\r
1139 \r
1140         CL_ASSERT( p_obj );\r
1141         h_qp = PARENT_STRUCT( p_obj, ib_qp_t, obj );\r
1142 \r
1143         if( verbs_check_qp( h_qp ) )\r
1144         {\r
1145                 status = verbs_destroy_qp( h_qp );\r
1146                 if( status != IB_SUCCESS )\r
1147                 {\r
1148                         AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1149                                 ("verbs_destroy_qp failed with status %s.\n",\r
1150                                 ib_get_err_str(status)) );\r
1151                 }\r
1152                 h_qp->h_ci_qp = NULL;\r
1153         }\r
1154 \r
1155         if( h_qp->type == IB_QPT_MAD )\r
1156         {\r
1157                 /* All MAD queue pair operations are complete. */\r
1158                 p_mad_qp = PARENT_STRUCT( h_qp, al_mad_qp_t, qp );\r
1159 \r
1160                 /* Append the pending MAD send queue to the posted MAD send queue. */\r
1161                 cl_qlist_insert_list_tail( &p_mad_qp->send_queue,\r
1162                         &p_mad_qp->to_send_queue );\r
1163 \r
1164                 /* Complete all MAD sends as "flushed". */\r
1165                 for( p_list_item = cl_qlist_remove_head( &p_mad_qp->send_queue );\r
1166                          p_list_item != cl_qlist_end( &p_mad_qp->send_queue );\r
1167                          p_list_item = cl_qlist_remove_head( &p_mad_qp->send_queue ) )\r
1168                 {\r
1169                         p_mad_wr = PARENT_STRUCT( p_list_item, al_mad_wr_t, list_item );\r
1170                         mad_qp_flush_send( p_mad_qp, p_mad_wr );\r
1171                 }\r
1172 \r
1173                 /* Return any posted receive MAD elements to the pool. */\r
1174                 for( p_list_item = cl_qlist_remove_head( &p_mad_qp->recv_queue );\r
1175                          p_list_item != cl_qlist_end( &p_mad_qp->recv_queue );\r
1176                          p_list_item = cl_qlist_remove_head( &p_mad_qp->recv_queue ) )\r
1177                 {\r
1178                         p_al_mad = PARENT_STRUCT( p_list_item, al_mad_element_t,\r
1179                                 list_item );\r
1180 \r
1181                         status = ib_put_mad( &p_al_mad->element );\r
1182                         CL_ASSERT( status == IB_SUCCESS );\r
1183                 }\r
1184 \r
1185                 if( p_mad_qp->h_pool )\r
1186                 {\r
1187                         /*\r
1188                          * Destroy the receive MAD pool.  If the client has closed the\r
1189                          * AL instance, the MAD pool should already be destroying.  In\r
1190                          * this case, we simply release our reference on the pool to\r
1191                          * allow it to cleanup and deallocate.  Otherwise, we initiate\r
1192                          * the destruction of the MAD pool and release our reference.\r
1193                          */\r
1194                         cl_spinlock_acquire( &p_mad_qp->h_pool->obj.lock );\r
1195                         if( p_mad_qp->h_pool->obj.state == CL_DESTROYING )\r
1196                         {\r
1197                                 cl_spinlock_release( &p_mad_qp->h_pool->obj.lock );\r
1198                         }\r
1199                         else\r
1200                         {\r
1201                                 cl_spinlock_release( &p_mad_qp->h_pool->obj.lock );\r
1202                                 ib_destroy_mad_pool( p_mad_qp->h_pool );\r
1203                         }\r
1204                         deref_al_obj( &p_mad_qp->h_pool->obj );\r
1205                 }\r
1206         }\r
1207         else\r
1208         {\r
1209                 if( h_qp->h_recv_cq )\r
1210                         deref_al_obj( &h_qp->h_recv_cq->obj );\r
1211                 if( h_qp->h_send_cq )\r
1212                         deref_al_obj( &h_qp->h_send_cq->obj );\r
1213         }\r
1214 }\r
1215 \r
1216 \r
1217 \r
1218 void\r
1219 free_qp(\r
1220         IN                              al_obj_t                                        *p_obj )\r
1221 {\r
1222         ib_qp_handle_t                  h_qp;\r
1223 \r
1224         CL_ASSERT( p_obj );\r
1225         h_qp = PARENT_STRUCT( p_obj, ib_qp_t, obj );\r
1226 \r
1227         destroy_al_obj( p_obj );\r
1228         cl_free( h_qp );\r
1229 }\r
1230 \r
1231 \r
1232 \r
1233 ib_api_status_t\r
1234 ib_query_qp(\r
1235         IN              const   ib_qp_handle_t                          h_qp,\r
1236                 OUT                     ib_qp_attr_t* const                     p_qp_attr )\r
1237 {\r
1238         return query_qp( h_qp, p_qp_attr, NULL );\r
1239 }\r
1240 \r
1241 \r
1242 ib_api_status_t\r
1243 query_qp(\r
1244         IN              const   ib_qp_handle_t                          h_qp,\r
1245                 OUT                     ib_qp_attr_t* const                     p_qp_attr,\r
1246         IN      OUT                     ci_umv_buf_t* const                     p_umv_buf )\r
1247 {\r
1248         ib_api_status_t                 status;\r
1249 \r
1250         AL_ENTER( AL_DBG_QP );\r
1251 \r
1252         if( AL_OBJ_INVALID_HANDLE( h_qp, AL_OBJ_TYPE_H_QP ) )\r
1253         {\r
1254                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );\r
1255                 return IB_INVALID_QP_HANDLE;\r
1256         }\r
1257         if( !p_qp_attr )\r
1258         {\r
1259                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
1260                 return IB_INVALID_PARAMETER;\r
1261         }\r
1262 \r
1263         status = verbs_query_qp( h_qp, p_qp_attr );\r
1264         if( status != IB_SUCCESS )\r
1265         {\r
1266                 AL_EXIT( AL_DBG_QP );\r
1267                 return status;\r
1268         }\r
1269 \r
1270         /* Convert to using AL's handles. */\r
1271         p_qp_attr->h_pd = PARENT_STRUCT( h_qp->obj.p_parent_obj, ib_pd_t, obj );\r
1272         p_qp_attr->h_rq_cq = h_qp->h_recv_cq;\r
1273         p_qp_attr->h_sq_cq = h_qp->h_send_cq;\r
1274         p_qp_attr->qp_type = h_qp->type;\r
1275 \r
1276         AL_EXIT( AL_DBG_QP );\r
1277         return IB_SUCCESS;\r
1278 }\r
1279 \r
1280 \r
1281 \r
1282 ib_api_status_t\r
1283 ib_modify_qp(\r
1284         IN              const   ib_qp_handle_t                          h_qp,\r
1285         IN              const   ib_qp_mod_t* const                      p_qp_mod )\r
1286 {\r
1287         return modify_qp( h_qp, p_qp_mod, NULL );\r
1288 }\r
1289 \r
1290 \r
1291 \r
1292 ib_api_status_t\r
1293 modify_qp(\r
1294         IN              const   ib_qp_handle_t                          h_qp,\r
1295         IN              const   ib_qp_mod_t* const                      p_qp_mod,\r
1296         IN      OUT                     ci_umv_buf_t* const                     p_umv_buf )\r
1297 {\r
1298         ib_api_status_t                 status;\r
1299 \r
1300         AL_ENTER( AL_DBG_QP );\r
1301 \r
1302         if( AL_OBJ_INVALID_HANDLE( h_qp, AL_OBJ_TYPE_H_QP ) )\r
1303         {\r
1304                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );\r
1305                 return IB_INVALID_QP_HANDLE;\r
1306         }\r
1307         if( !p_qp_mod )\r
1308         {\r
1309                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
1310                 return IB_INVALID_PARAMETER;\r
1311         }\r
1312 \r
1313         status = h_qp->pfn_modify_qp( h_qp, p_qp_mod, p_umv_buf );\r
1314 \r
1315         AL_EXIT( AL_DBG_QP );\r
1316         return status;\r
1317 }\r
1318 \r
1319 \r
1320 \r
1321 ib_api_status_t\r
1322 al_modify_qp(\r
1323         IN              const   ib_qp_handle_t                          h_qp,\r
1324         IN              const   ib_qp_mod_t* const                      p_qp_mod,\r
1325         IN      OUT                     ci_umv_buf_t* const                     p_umv_buf )\r
1326 {\r
1327         ib_api_status_t                 status;\r
1328         ib_qp_attr_t                    qp_attr;\r
1329 \r
1330         CL_ASSERT( h_qp );\r
1331 \r
1332 #ifdef CL_KERNEL\r
1333         /* Only allow ERROR and RESET state changes during timewait. */\r
1334         if( (h_qp->type == IB_QPT_RELIABLE_CONN ||\r
1335                 h_qp->type == IB_QPT_UNRELIABLE_CONN) &&\r
1336                 p_qp_mod->req_state != IB_QPS_ERROR &&\r
1337                 p_qp_mod->req_state != IB_QPS_RESET &&\r
1338                 p_qp_mod->req_state != IB_QPS_INIT &&\r
1339                 cl_get_time_stamp() < h_qp->timewait )\r
1340         {\r
1341                 return IB_QP_IN_TIMEWAIT;\r
1342         }\r
1343 #endif  /* CL_KERNEL */\r
1344 \r
1345         /* Modify the actual QP attributes. */\r
1346         status = verbs_modify_qp( h_qp, p_qp_mod, qp_attr );\r
1347 \r
1348         /* Record the QP state if the modify was successful. */\r
1349         if( status == IB_SUCCESS )\r
1350                 h_qp->state = p_qp_mod->req_state;\r
1351 \r
1352         return status;\r
1353 }\r
1354 \r
1355 \r
1356 \r
1357 ib_api_status_t\r
1358 ib_init_dgrm_svc(\r
1359         IN              const   ib_qp_handle_t                          h_qp,\r
1360         IN              const   ib_dgrm_info_t* const           p_dgrm_info OPTIONAL )\r
1361 {\r
1362         ib_api_status_t                 status;\r
1363 \r
1364         AL_ENTER( AL_DBG_QP );\r
1365 \r
1366         if( AL_OBJ_INVALID_HANDLE( h_qp, AL_OBJ_TYPE_H_QP ) )\r
1367         {\r
1368                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );\r
1369                 return IB_INVALID_QP_HANDLE;\r
1370         }\r
1371 \r
1372         switch( h_qp->type )\r
1373         {\r
1374         case IB_QPT_QP0:\r
1375         case IB_QPT_QP1:\r
1376         case IB_QPT_RAW_IPV6:\r
1377         case IB_QPT_RAW_ETHER:\r
1378                 break;\r
1379 \r
1380         case IB_QPT_UNRELIABLE_DGRM:\r
1381         case IB_QPT_MAD:\r
1382                 if( !p_dgrm_info )\r
1383                 {\r
1384                         AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1385                                 ("IB_INVALID_PARAMETER\n") );\r
1386                         return IB_INVALID_PARAMETER;\r
1387                 }\r
1388                 break;\r
1389 \r
1390         default:\r
1391                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
1392                 return IB_INVALID_PARAMETER;\r
1393         }\r
1394 \r
1395         status = h_qp->pfn_init_dgrm_svc( h_qp, p_dgrm_info );\r
1396 \r
1397         AL_EXIT( AL_DBG_QP );\r
1398         return status;\r
1399 }\r
1400 \r
1401 \r
1402 \r
1403 /*\r
1404  * Initialize a datagram QP to send and receive datagrams.\r
1405  */\r
1406 ib_api_status_t\r
1407 init_dgrm_svc(\r
1408         IN              const   ib_qp_handle_t                          h_qp,\r
1409         IN              const   ib_dgrm_info_t* const           p_dgrm_info OPTIONAL )\r
1410 {\r
1411         al_dgrm_qp_t                    *p_dgrm_qp;\r
1412         ib_qp_mod_t                             qp_mod;\r
1413         ib_api_status_t                 status;\r
1414 \r
1415         CL_ASSERT( h_qp );\r
1416 \r
1417         p_dgrm_qp = (al_dgrm_qp_t*)h_qp;\r
1418 \r
1419         /* Change to the RESET state. */\r
1420         cl_memclr( &qp_mod, sizeof( ib_qp_mod_t ) );\r
1421         qp_mod.req_state = IB_QPS_RESET;\r
1422 \r
1423         status = ib_modify_qp( h_qp, &qp_mod );\r
1424         if( status != IB_SUCCESS )\r
1425         {\r
1426                 return status;\r
1427         }\r
1428 \r
1429         /* Change to the INIT state. */\r
1430         cl_memclr( &qp_mod, sizeof( ib_qp_mod_t ) );\r
1431         qp_mod.req_state = IB_QPS_INIT;\r
1432         if( p_dgrm_info )\r
1433         {\r
1434                 qp_mod.state.init.qkey = p_dgrm_info->qkey;\r
1435                 qp_mod.state.init.pkey_index = p_dgrm_info->pkey_index;\r
1436                 status = get_port_num( h_qp->obj.p_ci_ca, p_dgrm_info->port_guid,\r
1437                         &qp_mod.state.init.primary_port );\r
1438         }\r
1439         else\r
1440         {\r
1441                 if( h_qp->type == IB_QPT_QP0 )\r
1442                         qp_mod.state.init.qkey = 0;\r
1443                 else\r
1444                         qp_mod.state.init.qkey = IB_QP1_WELL_KNOWN_Q_KEY;\r
1445                 status = get_port_num( h_qp->obj.p_ci_ca, h_qp->port_guid,\r
1446                         &qp_mod.state.init.primary_port );\r
1447         }\r
1448         if( status != IB_SUCCESS )\r
1449         {\r
1450                 return status;\r
1451         }\r
1452 \r
1453         status = ib_modify_qp( h_qp, &qp_mod );\r
1454         if( status != IB_SUCCESS )\r
1455         {\r
1456                 return status;\r
1457         }\r
1458 \r
1459         /* Change to the RTR state. */\r
1460         cl_memclr( &qp_mod, sizeof( ib_qp_mod_t ) );\r
1461         qp_mod.req_state = IB_QPS_RTR;\r
1462 \r
1463         status = ib_modify_qp( h_qp, &qp_mod );\r
1464         if( status != IB_SUCCESS )\r
1465         {\r
1466                 return status;\r
1467         }\r
1468 \r
1469         /* Change to the RTS state. */\r
1470         cl_memclr( &qp_mod, sizeof( ib_qp_mod_t ) );\r
1471         qp_mod.req_state = IB_QPS_RTS;\r
1472         qp_mod.state.rts.sq_psn = CL_HTON32(cl_get_time_stamp_sec() & 0x00ffffff);\r
1473         status = ib_modify_qp( h_qp, &qp_mod );\r
1474 \r
1475         return status;\r
1476 }\r
1477 \r
1478 \r
1479 \r
1480 ib_api_status_t\r
1481 init_mad_dgrm_svc(\r
1482         IN              const   ib_qp_handle_t                          h_qp,\r
1483         IN              const   ib_dgrm_info_t* const           p_dgrm_info )\r
1484 {\r
1485         al_mad_qp_t                             *p_mad_qp;\r
1486         ib_api_status_t                 status;\r
1487 \r
1488         CL_ASSERT( h_qp );\r
1489 \r
1490         p_mad_qp = (al_mad_qp_t*)h_qp;\r
1491         status = ib_init_dgrm_svc( p_mad_qp->h_dgrm_qp, p_dgrm_info );\r
1492         if( status != IB_SUCCESS )\r
1493         {\r
1494                 return status;\r
1495         }\r
1496 \r
1497         /* Post receive buffers. */\r
1498         status = mad_qp_post_recvs( p_mad_qp );\r
1499         if (status != IB_SUCCESS)\r
1500         {\r
1501                 return status;\r
1502         }\r
1503 \r
1504         /* Force a completion callback to rearm the CQs. */\r
1505         mad_send_comp_cb( p_mad_qp->h_send_cq, p_mad_qp );\r
1506         mad_recv_comp_cb( p_mad_qp->h_recv_cq, p_mad_qp );\r
1507 \r
1508         return status;\r
1509 }\r
1510 \r
1511 \r
1512 \r
1513 ib_api_status_t\r
1514 ib_reg_mad_svc(\r
1515         IN              const   ib_qp_handle_t                          h_qp,\r
1516         IN              const   ib_mad_svc_t* const                     p_mad_svc,\r
1517                 OUT                     ib_mad_svc_handle_t* const      ph_mad_svc )\r
1518 {\r
1519         ib_api_status_t                 status;\r
1520 \r
1521         AL_ENTER( AL_DBG_MAD_SVC );\r
1522 \r
1523         if( AL_OBJ_INVALID_HANDLE( h_qp, AL_OBJ_TYPE_H_QP ) )\r
1524         {\r
1525                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );\r
1526                 return IB_INVALID_QP_HANDLE;\r
1527         }\r
1528 \r
1529         status = h_qp->pfn_reg_mad_svc( h_qp, p_mad_svc, ph_mad_svc );\r
1530 \r
1531         /* Release the reference taken in init_al_obj. */\r
1532         if( status == IB_SUCCESS )\r
1533                 deref_al_obj( &(*ph_mad_svc)->obj );\r
1534 \r
1535         AL_EXIT( AL_DBG_MAD_SVC );\r
1536         return status;\r
1537 }\r
1538 \r
1539 \r
1540 ib_api_status_t\r
1541 ib_join_mcast(\r
1542         IN              const   ib_qp_handle_t                          h_qp,\r
1543         IN              const   ib_mcast_req_t* const           p_mcast_req )\r
1544 {\r
1545         ib_api_status_t                 status;\r
1546 \r
1547         AL_ENTER( AL_DBG_MCAST );\r
1548 \r
1549         if( AL_OBJ_INVALID_HANDLE( h_qp, AL_OBJ_TYPE_H_QP ) )\r
1550         {\r
1551                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );\r
1552                 return IB_INVALID_QP_HANDLE;\r
1553         }\r
1554         if( !p_mcast_req )\r
1555         {\r
1556                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
1557                 return IB_INVALID_PARAMETER;\r
1558         }\r
1559 \r
1560         status = h_qp->pfn_join_mcast( h_qp, p_mcast_req );\r
1561 \r
1562         AL_EXIT( AL_DBG_MCAST );\r
1563         return status;\r
1564 }\r
1565 \r
1566 \r
1567 \r
1568 /*\r
1569  * Post a work request to the send queue of the QP.\r
1570  */\r
1571 ib_api_status_t\r
1572 ib_post_send(\r
1573         IN              const   ib_qp_handle_t                          h_qp,\r
1574         IN                              ib_send_wr_t* const                     p_send_wr,\r
1575                 OUT                     ib_send_wr_t                            **pp_send_failure OPTIONAL )\r
1576 {\r
1577         ib_api_status_t                 status;\r
1578         PERF_DECLARE( IbPostSend );\r
1579         PERF_DECLARE( PostSend );\r
1580 \r
1581         cl_perf_start( IbPostSend );\r
1582         AL_ENTER( AL_DBG_QP );\r
1583 \r
1584         if( AL_OBJ_INVALID_HANDLE( h_qp, AL_OBJ_TYPE_H_QP ) )\r
1585         {\r
1586                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );\r
1587                 return IB_INVALID_QP_HANDLE;\r
1588         }\r
1589         if( !p_send_wr || ( p_send_wr->p_next && !pp_send_failure ) )\r
1590         {\r
1591                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
1592                 return IB_INVALID_PARAMETER;\r
1593         }\r
1594 \r
1595         cl_perf_start( PostSend );\r
1596         status =\r
1597                 h_qp->pfn_post_send( h_qp->h_send_qp, p_send_wr, pp_send_failure );\r
1598         cl_perf_stop( &g_perf, PostSend );\r
1599 \r
1600         AL_EXIT( AL_DBG_QP );\r
1601         cl_perf_stop( &g_perf, IbPostSend );\r
1602         return status;\r
1603 }\r
1604 \r
1605 \r
1606 \r
1607 ib_api_status_t\r
1608 ud_post_send(\r
1609         IN              const   ib_qp_handle_t                          h_qp,\r
1610         IN                              ib_send_wr_t* const                     p_send_wr,\r
1611                 OUT                     ib_send_wr_t                            **pp_send_failure )\r
1612 {\r
1613         ib_api_status_t                 status;\r
1614         ib_send_wr_t                    *p_wr;\r
1615 \r
1616         CL_ASSERT( h_qp );\r
1617 \r
1618         /* Convert all AV handles for verb provider usage. */\r
1619         for( p_wr = p_send_wr; p_wr; p_wr = p_wr->p_next )\r
1620         {\r
1621                 CL_ASSERT( p_wr->dgrm.ud.h_av );\r
1622                 p_wr->dgrm.ud.rsvd = p_wr->dgrm.ud.h_av;\r
1623                 p_wr->dgrm.ud.h_av = convert_av_handle( h_qp, p_wr->dgrm.ud.h_av );\r
1624         }\r
1625 \r
1626         status = h_qp->pfn_ud_post_send(\r
1627                 h_qp->h_ud_send_qp, p_send_wr, pp_send_failure );\r
1628 \r
1629         /* Restore all AV handles. */\r
1630         for( p_wr = p_send_wr; p_wr; p_wr = p_wr->p_next )\r
1631                 p_wr->dgrm.ud.h_av = (ib_av_handle_t)p_wr->dgrm.ud.rsvd;\r
1632 \r
1633         return status;\r
1634 }\r
1635 \r
1636 \r
1637 \r
1638 #ifdef CL_KERNEL\r
1639 /*\r
1640  * Post a work request to the send queue of a special QP.\r
1641  * The special QP is owned by the GSA or SMA, so care must be taken to prevent\r
1642  * overruning the QP by multiple owners.\r
1643  */\r
1644 void\r
1645 special_qp_queue_mad(\r
1646         IN              const   ib_qp_handle_t                          h_qp,\r
1647         IN                              al_mad_wr_t* const                      p_mad_wr )\r
1648 {\r
1649         al_special_qp_t*                p_special_qp;\r
1650 \r
1651         CL_ASSERT( h_qp );\r
1652         CL_ASSERT( p_mad_wr );\r
1653 \r
1654         p_special_qp = (al_special_qp_t*)h_qp;\r
1655 \r
1656         /* Queue the send work request. */\r
1657         cl_spinlock_acquire( &h_qp->obj.lock );\r
1658         cl_qlist_insert_tail( &p_special_qp->to_send_queue, &p_mad_wr->list_item );\r
1659         cl_spinlock_release( &h_qp->obj.lock );\r
1660 }\r
1661 \r
1662 \r
1663 \r
1664 void\r
1665 special_qp_resume_sends(\r
1666         IN              const   ib_qp_handle_t                          h_qp )\r
1667 {\r
1668         al_special_qp_t*                p_special_qp;\r
1669         cl_list_item_t*                 p_list_item;\r
1670         al_mad_wr_t*                    p_mad_wr;\r
1671         ib_api_status_t                 status;\r
1672 \r
1673         CL_ASSERT( h_qp );\r
1674         p_special_qp = (al_special_qp_t*)h_qp;\r
1675 \r
1676         cl_spinlock_acquire( &p_special_qp->qp.obj.lock );\r
1677 \r
1678         for( p_list_item = cl_qlist_remove_head( &p_special_qp->to_send_queue );\r
1679                  p_list_item != cl_qlist_end( &p_special_qp->to_send_queue );\r
1680                  p_list_item = cl_qlist_remove_head( &p_special_qp->to_send_queue ) )\r
1681         {\r
1682                 p_mad_wr = PARENT_STRUCT( p_list_item, al_mad_wr_t, list_item );\r
1683 \r
1684                 cl_spinlock_release( &p_special_qp->qp.obj.lock );\r
1685                 status = spl_qp_svc_send( &p_special_qp->qp, &p_mad_wr->send_wr );\r
1686                 cl_spinlock_acquire( &p_special_qp->qp.obj.lock );\r
1687 \r
1688                 if( status != IB_SUCCESS )\r
1689                 {\r
1690                         cl_qlist_insert_head( &p_special_qp->to_send_queue, p_list_item );\r
1691                         break;\r
1692                 }\r
1693         }\r
1694 \r
1695         cl_spinlock_release( &p_special_qp->qp.obj.lock );\r
1696 }\r
1697 #endif  /* CL_KERNEL */\r
1698 \r
1699 \r
1700 void\r
1701 mad_qp_queue_mad(\r
1702         IN              const   ib_qp_handle_t                          h_qp,\r
1703         IN                              al_mad_wr_t* const                      p_mad_wr )\r
1704 {\r
1705         al_mad_qp_t                             *p_mad_qp;\r
1706 \r
1707         CL_ASSERT( h_qp );\r
1708         p_mad_qp = (al_mad_qp_t*)h_qp;\r
1709 \r
1710         /* Queue the send work request on the to_send_queue. */\r
1711         cl_spinlock_acquire( &p_mad_qp->qp.obj.lock );\r
1712         cl_qlist_insert_tail( &p_mad_qp->to_send_queue, &p_mad_wr->list_item );\r
1713         cl_spinlock_release( &p_mad_qp->qp.obj.lock );\r
1714 }\r
1715 \r
1716 \r
1717 \r
1718 void\r
1719 mad_qp_resume_sends(\r
1720         IN                              ib_qp_handle_t                          h_qp )\r
1721 {\r
1722         al_mad_qp_t                             *p_mad_qp;\r
1723         cl_list_item_t*                 p_list_item;\r
1724         al_mad_wr_t*                    p_mad_wr;\r
1725         ib_api_status_t                 status;\r
1726 \r
1727         CL_ASSERT( h_qp );\r
1728 \r
1729         p_mad_qp = (al_mad_qp_t*)h_qp;\r
1730 \r
1731         cl_spinlock_acquire( &p_mad_qp->qp.obj.lock );\r
1732 \r
1733         /* Do not post sends if the MAD queue pair is being destroyed. */\r
1734         if( p_mad_qp->qp.obj.state == CL_DESTROYING )\r
1735         {\r
1736                 cl_spinlock_release( &p_mad_qp->qp.obj.lock );\r
1737                 return;\r
1738         }\r
1739 \r
1740         for( p_list_item = cl_qlist_remove_head( &p_mad_qp->to_send_queue );\r
1741                  p_list_item != cl_qlist_end( &p_mad_qp->to_send_queue );\r
1742                  p_list_item = cl_qlist_remove_head( &p_mad_qp->to_send_queue ) )\r
1743         {\r
1744                 p_mad_wr = PARENT_STRUCT( p_list_item, al_mad_wr_t, list_item );\r
1745 \r
1746                 /* Always generate send completions. */\r
1747                 p_mad_wr->send_wr.send_opt |= IB_SEND_OPT_SIGNALED;\r
1748 \r
1749                 status = ib_post_send( p_mad_qp->h_dgrm_qp, &p_mad_wr->send_wr, NULL );\r
1750 \r
1751                 if( status == IB_SUCCESS )\r
1752                 {\r
1753                         /* Queue the MAD work request on the send tracking queue. */\r
1754                         cl_qlist_insert_tail( &p_mad_qp->send_queue, &p_mad_wr->list_item );\r
1755                 }\r
1756                 else\r
1757                 {\r
1758                         /* Re-queue the send work request on the to_send_queue. */\r
1759                         cl_qlist_insert_head( &p_mad_qp->to_send_queue, p_list_item );\r
1760                         break;\r
1761                 }\r
1762         }\r
1763 \r
1764         cl_spinlock_release( &p_mad_qp->qp.obj.lock );\r
1765 }\r
1766 \r
1767 \r
1768 \r
1769 void\r
1770 mad_qp_flush_send(\r
1771         IN                              al_mad_qp_t*                            p_mad_qp,\r
1772         IN                              al_mad_wr_t* const                      p_mad_wr )\r
1773 {\r
1774         ib_wc_t                                 wc;\r
1775 \r
1776         cl_memclr( &wc, sizeof( ib_wc_t ) );\r
1777         wc.wr_id = p_mad_wr->send_wr.wr_id;\r
1778         wc.wc_type = IB_WC_SEND;\r
1779         wc.status = IB_WCS_WR_FLUSHED_ERR;\r
1780 \r
1781         mad_disp_send_done( p_mad_qp->h_mad_disp, p_mad_wr, &wc );\r
1782 }\r
1783 \r
1784 \r
1785 \r
1786 ib_api_status_t\r
1787 ib_post_recv(\r
1788         IN              const   ib_qp_handle_t                          h_qp,\r
1789         IN                              ib_recv_wr_t* const                     p_recv_wr,\r
1790                 OUT                     ib_recv_wr_t                            **pp_recv_failure OPTIONAL )\r
1791 {\r
1792         ib_api_status_t                 status;\r
1793 \r
1794         AL_ENTER( AL_DBG_QP );\r
1795 \r
1796         if( AL_OBJ_INVALID_HANDLE( h_qp, AL_OBJ_TYPE_H_QP ) )\r
1797         {\r
1798                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );\r
1799                 return IB_INVALID_QP_HANDLE;\r
1800         }\r
1801         if( !p_recv_wr || ( p_recv_wr->p_next && !pp_recv_failure ) )\r
1802         {\r
1803                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
1804                 return IB_INVALID_PARAMETER;\r
1805         }\r
1806 \r
1807         status =\r
1808                 h_qp->pfn_post_recv( h_qp->h_recv_qp, p_recv_wr, pp_recv_failure );\r
1809 \r
1810         AL_EXIT( AL_DBG_QP );\r
1811         return status;\r
1812 }\r
1813 \r
1814 \r
1815 \r
1816 /*\r
1817  * Post receive buffers to a MAD QP.\r
1818  */\r
1819 ib_api_status_t\r
1820 mad_qp_post_recvs(\r
1821         IN                              al_mad_qp_t*    const           p_mad_qp )\r
1822 {\r
1823         ib_mad_element_t*               p_mad_element;\r
1824         al_mad_element_t*               p_al_element;\r
1825         ib_recv_wr_t                    recv_wr;\r
1826         ib_api_status_t                 status = IB_SUCCESS;\r
1827 \r
1828         CL_ASSERT( p_mad_qp );\r
1829 \r
1830         /* Attempt to post receive buffers up to the max_rq_depth limit. */\r
1831         cl_spinlock_acquire( &p_mad_qp->qp.obj.lock );\r
1832         while( p_mad_qp->cur_rq_depth < (int32_t)p_mad_qp->max_rq_depth )\r
1833         {\r
1834                 /* Get a MAD element from the pool. */\r
1835                 status = ib_get_mad( p_mad_qp->pool_key, MAD_BLOCK_SIZE,\r
1836                         &p_mad_element );\r
1837 \r
1838                 if( status != IB_SUCCESS ) break;\r
1839 \r
1840                 p_al_element = PARENT_STRUCT( p_mad_element, al_mad_element_t,\r
1841                         element );\r
1842 \r
1843                 /* Build the receive work request. */\r
1844                 recv_wr.p_next   = NULL;\r
1845                 recv_wr.wr_id    = (uintn_t)p_al_element;\r
1846                 recv_wr.num_ds = 1;\r
1847                 recv_wr.ds_array = &p_al_element->grh_ds;\r
1848 \r
1849                 /* Queue the receive on the service tracking list. */\r
1850                 cl_qlist_insert_tail( &p_mad_qp->recv_queue, &p_al_element->list_item );\r
1851 \r
1852                 /* Post the receive. */\r
1853                 status = ib_post_recv( p_mad_qp->h_dgrm_qp, &recv_wr, NULL );\r
1854 \r
1855                 if( status != IB_SUCCESS )\r
1856                 {\r
1857                         cl_qlist_remove_item( &p_mad_qp->recv_queue,\r
1858                                 &p_al_element->list_item );\r
1859 \r
1860                         ib_put_mad( p_mad_element );\r
1861                         break;\r
1862                 }\r
1863 \r
1864                 cl_atomic_inc( &p_mad_qp->cur_rq_depth );\r
1865         }\r
1866         cl_spinlock_release( &p_mad_qp->qp.obj.lock );\r
1867 \r
1868         return status;\r
1869 }\r
1870 \r
1871 \r
1872 \r
1873 void\r
1874 mad_recv_comp_cb(\r
1875         IN              const   ib_cq_handle_t                          h_cq,\r
1876         IN                              void                                            *cq_context )\r
1877 {\r
1878         al_mad_qp_t                             *p_mad_qp;\r
1879 \r
1880         CL_ASSERT( cq_context );\r
1881         p_mad_qp = (al_mad_qp_t*)cq_context;\r
1882 \r
1883         CL_ASSERT( h_cq == p_mad_qp->h_recv_cq );\r
1884         mad_qp_comp( p_mad_qp, h_cq, IB_WC_RECV );\r
1885 }\r
1886 \r
1887 \r
1888 \r
1889 void\r
1890 mad_send_comp_cb(\r
1891         IN              const   ib_cq_handle_t                          h_cq,\r
1892         IN                              void                                            *cq_context )\r
1893 {\r
1894         al_mad_qp_t                             *p_mad_qp;\r
1895 \r
1896         CL_ASSERT( cq_context );\r
1897         p_mad_qp = (al_mad_qp_t*)cq_context;\r
1898 \r
1899         CL_ASSERT( h_cq == p_mad_qp->h_send_cq );\r
1900         mad_qp_comp( p_mad_qp, h_cq, IB_WC_SEND );\r
1901 \r
1902         /* Continue processing any queued MADs on the QP. */\r
1903         mad_qp_resume_sends( &p_mad_qp->qp );\r
1904 }\r
1905 \r
1906 \r
1907 \r
1908 void\r
1909 mad_qp_comp(\r
1910         IN                              al_mad_qp_t*                            p_mad_qp,\r
1911         IN              const   ib_cq_handle_t                          h_cq,\r
1912         IN                              ib_wc_type_t                            wc_type )\r
1913 {\r
1914         ib_wc_t                                 wc;\r
1915         ib_wc_t*                                p_free_wc = &wc;\r
1916         ib_wc_t*                                p_done_wc;\r
1917         al_mad_wr_t*                    p_mad_wr;\r
1918         al_mad_element_t*               p_al_mad;\r
1919         ib_mad_element_t*               p_mad_element;\r
1920         ib_api_status_t                 status;\r
1921 \r
1922         CL_ASSERT( p_mad_qp );\r
1923         CL_ASSERT( h_cq );\r
1924 \r
1925         /* Rearm the CQ before polling to avoid missing completions. */\r
1926         status = ib_rearm_cq( h_cq, FALSE );\r
1927         CL_ASSERT( status == IB_SUCCESS );\r
1928 \r
1929         wc.p_next = NULL;\r
1930         /* Process work completions. */\r
1931         while( ib_poll_cq( h_cq, &p_free_wc, &p_done_wc ) == IB_SUCCESS )\r
1932         {\r
1933                 /* Process completions one at a time. */\r
1934 \r
1935                 /*\r
1936                  * Process the work completion.  Per IBA specification, the\r
1937                  * wc.wc_type is undefined if wc.status is not IB_WCS_SUCCESS.\r
1938                  * Use the wc_type function parameter instead of wc.wc_type.\r
1939                  */\r
1940                 switch( wc_type )\r
1941                 {\r
1942                 case IB_WC_SEND:\r
1943                         /* Get a pointer to the MAD work request. */\r
1944                         p_mad_wr = (al_mad_wr_t*)((uintn_t)wc.wr_id);\r
1945 \r
1946                         /* Remove the MAD work request from the send tracking queue. */\r
1947                         cl_spinlock_acquire( &p_mad_qp->qp.obj.lock );\r
1948                         cl_qlist_remove_item( &p_mad_qp->send_queue, &p_mad_wr->list_item );\r
1949                         cl_spinlock_release( &p_mad_qp->qp.obj.lock );\r
1950 \r
1951                         /* Report the send completion to the dispatcher. */\r
1952                         mad_disp_send_done( p_mad_qp->h_mad_disp, p_mad_wr, &wc );\r
1953                         break;\r
1954 \r
1955                 case IB_WC_RECV:\r
1956                         /* A receive buffer was consumed. */\r
1957                         cl_atomic_dec( &p_mad_qp->cur_rq_depth );\r
1958 \r
1959                         /* Replenish the receive buffer. */\r
1960                         mad_qp_post_recvs( p_mad_qp );\r
1961 \r
1962                         /* Initialize pointers to the MAD element. */\r
1963                         p_al_mad = (al_mad_element_t*)((uintn_t)wc.wr_id);\r
1964                         p_mad_element = &p_al_mad->element;\r
1965 \r
1966                         /* Remove the AL MAD element from the receive tracking queue. */\r
1967                         cl_spinlock_acquire( &p_mad_qp->qp.obj.lock );\r
1968                         cl_qlist_remove_item( &p_mad_qp->recv_queue, &p_al_mad->list_item );\r
1969                         cl_spinlock_release( &p_mad_qp->qp.obj.lock );\r
1970 \r
1971                         /* Construct the MAD element from the receive work completion. */\r
1972                         build_mad_recv( p_mad_element, &wc );\r
1973 \r
1974                         /* Process the received MAD. */\r
1975                         status = mad_disp_recv_done( p_mad_qp->h_mad_disp,\r
1976                                 p_mad_element );\r
1977 \r
1978                         /* Discard this MAD on error. */\r
1979                         if( status != IB_SUCCESS )\r
1980                         {\r
1981                                 status = ib_put_mad( p_mad_element );\r
1982                                 CL_ASSERT( status == IB_SUCCESS );\r
1983                         }\r
1984                         break;\r
1985 \r
1986                 default:\r
1987                         CL_ASSERT( wc_type == IB_WC_SEND || wc_type == IB_WC_RECV );\r
1988                         break;\r
1989                 }\r
1990                 p_free_wc = &wc;\r
1991         }\r
1992 }\r
1993 \r
1994 \r
1995 \r
1996 /*\r
1997  * Process an event on a CQ associated with a MAD QP.\r
1998  */\r
1999 void\r
2000 mad_qp_cq_event_cb(\r
2001         IN                              ib_async_event_rec_t            *p_event_rec )\r
2002 {\r
2003         al_mad_qp_t                             *p_mad_qp;\r
2004 \r
2005         CL_ASSERT( p_event_rec );\r
2006         CL_ASSERT( p_event_rec->context );\r
2007 \r
2008         if( p_event_rec->code == IB_AE_SQ_DRAINED )\r
2009                 return;\r
2010 \r
2011         p_mad_qp = (al_mad_qp_t* __ptr64)p_event_rec->context;\r
2012 \r
2013         /* Nothing to do here. */\r
2014 }\r
2015 \r
2016 \r
2017 \r
2018 /*\r
2019  * Process an asynchronous event on the QP.  Notify the user of the event.\r
2020  */\r
2021 void\r
2022 qp_async_event_cb(\r
2023         IN                              ib_async_event_rec_t* const     p_event_rec )\r
2024 {\r
2025         ib_qp_handle_t                  h_qp;\r
2026 \r
2027         CL_ASSERT( p_event_rec );\r
2028         h_qp = (ib_qp_handle_t)p_event_rec->context;\r
2029 \r
2030 #if defined(CL_KERNEL)\r
2031         switch( p_event_rec->code )\r
2032         {\r
2033         case IB_AE_QP_COMM:\r
2034                 al_cep_established( h_qp->obj.h_al, ((al_conn_qp_t*)h_qp)->cid );\r
2035                 break;\r
2036 \r
2037         case IB_AE_QP_APM:\r
2038                 al_cep_migrate( h_qp->obj.h_al, ((al_conn_qp_t*)h_qp)->cid );\r
2039                 break;\r
2040 \r
2041         case IB_AE_QP_APM_ERROR:\r
2042                 //***TODO: Figure out how to handle these errors.\r
2043                 break;\r
2044 \r
2045         default:\r
2046                 break;\r
2047         }\r
2048 #endif\r
2049 \r
2050         p_event_rec->context = (void*)h_qp->obj.context;\r
2051         p_event_rec->handle.h_qp = h_qp;\r
2052 \r
2053         if( h_qp->pfn_event_cb )\r
2054                 h_qp->pfn_event_cb( p_event_rec );\r
2055 }\r
2056 \r
2057 \r
2058 \r
2059 ib_api_status_t\r
2060 ib_bind_mw(\r
2061         IN              const   ib_mw_handle_t                          h_mw,\r
2062         IN              const   ib_qp_handle_t                          h_qp,\r
2063         IN                              ib_bind_wr_t * const            p_mw_bind,\r
2064                 OUT                     net32_t * const                         p_rkey )\r
2065 {\r
2066         ib_mr_handle_t                  h_mr;\r
2067         ib_api_status_t                 status;\r
2068 \r
2069         AL_ENTER( AL_DBG_MW );\r
2070 \r
2071         if( AL_OBJ_INVALID_HANDLE( h_mw, AL_OBJ_TYPE_H_MW ) )\r
2072         {\r
2073                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_MW_HANDLE\n") );\r
2074                 return IB_INVALID_MW_HANDLE;\r
2075         }\r
2076         if( AL_OBJ_INVALID_HANDLE( h_qp, AL_OBJ_TYPE_H_QP ) )\r
2077         {\r
2078                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );\r
2079                 return IB_INVALID_QP_HANDLE;\r
2080         }\r
2081         if( !p_mw_bind || !p_rkey )\r
2082         {\r
2083                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
2084                 return IB_INVALID_PARAMETER;\r
2085         }\r
2086 \r
2087         /* Convert to the CI handles. */\r
2088         h_mr = p_mw_bind->h_mr;\r
2089         p_mw_bind->h_mr = convert_mr_handle( h_mr );\r
2090 \r
2091         status = verbs_bind_mw(h_mw, h_qp, p_mw_bind, p_rkey);\r
2092 \r
2093         p_mw_bind->h_mr = h_mr;\r
2094 \r
2095         AL_EXIT( AL_DBG_MW );\r
2096         return status;\r
2097 }\r