ib_types: update SA attribute definitions
[mirror/winof/.git] / core / al / al_cm_qp.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  * Portions Copyright (c) 2008 Microsoft 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 <iba/ib_al.h>\r
35 #include "al.h"\r
36 #include "al_qp.h"\r
37 #include "al_cm_cep.h"\r
38 #include "al_cm_conn.h"\r
39 #include "al_cm_sidr.h"\r
40 #include "al_mgr.h"\r
41 #include "al_debug.h"\r
42 \r
43 \r
44 #if defined(EVENT_TRACING)\r
45 #ifdef offsetof\r
46 #undef offsetof\r
47 #endif\r
48 #include "al_cm_qp.tmh"\r
49 #endif\r
50 \r
51 typedef struct _al_listen\r
52 {\r
53         al_obj_t                                        obj;\r
54         net32_t                                         cid;\r
55 \r
56         ib_pfn_cm_req_cb_t                      pfn_cm_req_cb;\r
57 \r
58         /* valid for ud qp_type only */\r
59         const void*                                     sidr_context;\r
60 \r
61 }       al_listen_t;\r
62 \r
63 \r
64 #ifdef CL_KERNEL\r
65 \r
66 /*\r
67  * Structure for queuing received MADs to the asynchronous processing\r
68  * manager.\r
69  */\r
70 typedef struct _cep_async_mad\r
71 {\r
72         cl_async_proc_item_t    item;\r
73         ib_al_handle_t                  h_al;\r
74         net32_t                                 cid;\r
75 \r
76 }       cep_async_mad_t;\r
77 \r
78 #endif /* CL_KERNEL */\r
79 \r
80 \r
81 /*\r
82  * Transition the QP to the error state to flush all oustanding work\r
83  * requests and sets the timewait time.  This function may be called\r
84  * when destroying the QP in order to flush all work requests, so we\r
85  * cannot call through the main API, or the call will fail since the\r
86  * QP is no longer in the initialize state.\r
87  */\r
88 static void\r
89 __cep_timewait_qp(\r
90         IN              const   ib_qp_handle_t                          h_qp )\r
91 {\r
92         uint64_t                        timewait = 0;\r
93         ib_qp_mod_t                     qp_mod;\r
94         ib_api_status_t         status;\r
95 \r
96         AL_ENTER( AL_DBG_CM );\r
97 \r
98         CL_ASSERT( h_qp );\r
99 \r
100         /*\r
101          * The CM should have set the proper timewait time-out value.  Reset\r
102          * the QP and let it enter the timewait state.\r
103          */\r
104         if( al_cep_get_timewait( h_qp->obj.h_al,\r
105                 ((al_conn_qp_t*)h_qp)->cid, &timewait ) == IB_SUCCESS )\r
106         {\r
107                 /* Special checks on the QP state for error handling - see above. */\r
108                 if( !h_qp || !AL_OBJ_IS_TYPE( h_qp, AL_OBJ_TYPE_H_QP ) ||\r
109                         ( (h_qp->obj.state != CL_INITIALIZED) && \r
110                         (h_qp->obj.state != CL_DESTROYING) ) )\r
111                 {\r
112                         AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );\r
113                         return;\r
114                 }\r
115 \r
116                 cl_memclr( &qp_mod, sizeof(ib_qp_mod_t) );\r
117                 qp_mod.req_state = IB_QPS_ERROR;\r
118 \r
119                 /* Modify to error state using function pointers - see above. */\r
120                 status = h_qp->pfn_modify_qp( h_qp, &qp_mod, NULL );\r
121                 if( status != IB_SUCCESS )\r
122                 {\r
123                         AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
124                                 ("pfn_modify_qp to IB_QPS_ERROR returned %s\n",\r
125                                 ib_get_err_str( status )) );\r
126                         return;\r
127                 }\r
128 \r
129 #ifdef CL_KERNEL\r
130                 /* Store the timestamp after which the QP exits timewait. */\r
131                 h_qp->timewait = cl_get_time_stamp() + timewait;\r
132 #endif  /* CL_KERNEL */\r
133         }\r
134 \r
135         AL_EXIT( AL_DBG_CM );\r
136 }\r
137 \r
138 \r
139 static void\r
140 __format_req_path_rec(\r
141         IN              const   mad_cm_req_t* const                     p_req,\r
142         IN              const   req_path_info_t* const          p_path,\r
143                 OUT                     ib_path_rec_t* const            p_path_rec )\r
144 {\r
145         AL_ENTER( AL_DBG_CM );\r
146 \r
147         CL_ASSERT( p_req );\r
148         CL_ASSERT( p_path );\r
149         CL_ASSERT( p_path_rec );\r
150 \r
151         /*\r
152          * Format a local path record. The local ack timeout specified in the\r
153          * REQ is twice the packet life plus the sender's CA ACK delay.  When\r
154          * reporting the packet life, we divide the local ack timeout by 2 to\r
155          * approach the path's packet lifetime.  Since local ack timeout is\r
156          * expressed as 4.096 * 2^x, subtracting 1 is equivalent to dividing the\r
157          * time in half.\r
158          */\r
159         ib_path_rec_init_local( p_path_rec,\r
160                 &p_path->local_gid,\r
161                 &p_path->remote_gid,\r
162                 p_path->local_lid,\r
163                 p_path->remote_lid,\r
164                 1, p_req->pkey,\r
165                 conn_req_path_get_svc_lvl( p_path ), 0,\r
166                 IB_PATH_SELECTOR_EXACTLY, conn_req_get_mtu( p_req ),\r
167                 IB_PATH_SELECTOR_EXACTLY,\r
168                 conn_req_path_get_pkt_rate( p_path ),\r
169                 IB_PATH_SELECTOR_EXACTLY,\r
170                 (uint8_t)( conn_req_path_get_lcl_ack_timeout( p_path ) - 1 ),\r
171                 0 );\r
172 \r
173         /* Add global routing info as necessary. */\r
174         if( !conn_req_path_get_subn_lcl( p_path ) )\r
175         {\r
176                 ib_path_rec_set_hop_flow_raw( p_path_rec, p_path->hop_limit,\r
177                         conn_req_path_get_flow_lbl( p_path ), FALSE );\r
178                 p_path_rec->tclass = p_path->traffic_class;\r
179         }\r
180 \r
181         AL_EXIT( AL_DBG_CM );\r
182 }\r
183 \r
184 \r
185 static void\r
186 __format_req_rec(\r
187         IN              const   mad_cm_req_t* const                     p_req,\r
188                 OUT                     ib_cm_req_rec_t                         *p_req_rec )\r
189 {\r
190         AL_ENTER( AL_DBG_CM );\r
191 \r
192         CL_ASSERT( p_req );\r
193         CL_ASSERT( p_req_rec );\r
194 \r
195         cl_memclr( p_req_rec, sizeof(ib_cm_req_rec_t) );\r
196 \r
197         /* format version specific data */\r
198         p_req_rec->p_req_pdata = p_req->pdata;\r
199 \r
200         p_req_rec->qp_type = conn_req_get_qp_type( p_req );\r
201 \r
202         p_req_rec->resp_res = conn_req_get_resp_res( p_req );\r
203         p_req_rec->flow_ctrl = conn_req_get_flow_ctrl( p_req );\r
204         p_req_rec->rnr_retry_cnt = conn_req_get_rnr_retry_cnt( p_req );\r
205 \r
206         __format_req_path_rec( p_req, &p_req->primary_path,\r
207                 &p_req_rec->primary_path );\r
208         __format_req_path_rec( p_req, &p_req->alternate_path,\r
209                 &p_req_rec->alt_path );\r
210 \r
211         /* These values are filled in later based on listen or peer connections\r
212         p_req_rec->context = ;\r
213         p_req_rec->h_cm_req = ;\r
214         p_req_rec->h_cm_listen = ;\r
215         */\r
216 \r
217         AL_EXIT( AL_DBG_CM );\r
218 }\r
219 \r
220 \r
221 /******************************************************************************\r
222 * Functions that handle incoming REQs that matched to an outstanding listen.\r
223 *\r
224 */\r
225 \r
226 \r
227 static void\r
228 __listen_req(\r
229         IN                              al_listen_t* const                      p_listen,\r
230         IN              const   net32_t                                         new_cid,\r
231         IN              const   mad_cm_req_t* const                     p_req )\r
232 {\r
233         ib_cm_req_rec_t         req_rec;\r
234 \r
235         AL_ENTER( AL_DBG_CM );\r
236 \r
237         CL_ASSERT( p_listen );\r
238         CL_ASSERT( new_cid != AL_INVALID_CID );\r
239         CL_ASSERT( p_req );\r
240 \r
241         /* Format the callback record. */\r
242         __format_req_rec( p_req, &req_rec );\r
243 \r
244         /* update listen based rec */\r
245         req_rec.context = p_listen->obj.context;\r
246 \r
247         req_rec.h_cm_req.cid = new_cid;\r
248         req_rec.h_cm_req.h_al = p_listen->obj.h_al;\r
249         req_rec.h_cm_req.h_qp = NULL;\r
250 \r
251         req_rec.h_cm_listen = p_listen;\r
252 \r
253         /* Invoke the user's callback. */\r
254         p_listen->pfn_cm_req_cb( &req_rec );\r
255 \r
256         AL_EXIT( AL_DBG_CM );\r
257 }\r
258 \r
259 \r
260 static void\r
261 __proc_listen(\r
262         IN                              al_listen_t* const                      p_listen,\r
263         IN                              net32_t                                         new_cid,\r
264         IN              const   ib_mad_t* const                         p_mad )\r
265 {\r
266         AL_ENTER( AL_DBG_CM );\r
267 \r
268         /* Context is a listen - MAD must be a REQ or SIDR REQ */\r
269         switch( p_mad->attr_id )\r
270         {\r
271         case CM_REQ_ATTR_ID:\r
272                 __listen_req(\r
273                         p_listen, new_cid, (mad_cm_req_t*)p_mad );\r
274                 break;\r
275 \r
276         case CM_SIDR_REQ_ATTR_ID:\r
277                 /* TODO - implement SIDR. */\r
278         default:\r
279                 CL_ASSERT( p_mad->attr_id == CM_REQ_ATTR_ID ||\r
280                         p_mad->attr_id == CM_SIDR_REQ_ATTR_ID );\r
281                 /* Destroy the new CEP as it won't ever be reported to the user. */\r
282                 al_destroy_cep( p_listen->obj.h_al, &new_cid, FALSE );\r
283         }\r
284 \r
285         AL_EXIT( AL_DBG_CM );\r
286 }\r
287 \r
288 \r
289 /******************************************************************************\r
290 * Functions that handle send timeouts:\r
291 *\r
292 */\r
293 \r
294 /*\r
295  * callback to process a connection establishment timeout due to reply not\r
296  * being received.  The connection object has a reference\r
297  * taken when the timer is set or when the send is sent.\r
298  */\r
299 static void\r
300 __proc_conn_timeout(\r
301         IN              const   ib_qp_handle_t                          h_qp )\r
302 {\r
303         ib_cm_rej_rec_t         rej_rec;\r
304 \r
305         AL_ENTER( AL_DBG_CM );\r
306 \r
307         CL_ASSERT( h_qp );\r
308 \r
309         /*\r
310          * Format the reject record before aborting the connection since\r
311          * we need the QP context.\r
312          */\r
313         cl_memclr( &rej_rec, sizeof(ib_cm_rej_rec_t) );\r
314         rej_rec.h_qp = h_qp;\r
315         rej_rec.qp_context = h_qp->obj.context;\r
316         rej_rec.rej_status = IB_REJ_TIMEOUT;\r
317 \r
318         /* Unbind the QP from the CEP. */\r
319         __cep_timewait_qp( h_qp );\r
320 \r
321         al_destroy_cep( h_qp->obj.h_al, &((al_conn_qp_t*)h_qp)->cid, TRUE );\r
322 \r
323         /* Invoke the callback. */\r
324         ((al_conn_qp_t*)h_qp)->pfn_cm_rej_cb( &rej_rec );\r
325 \r
326         AL_EXIT( AL_DBG_CM );\r
327 }\r
328 \r
329 \r
330 /*\r
331  * callback to process a LAP timeout due to APR not being received.\r
332  */\r
333 static void\r
334 __proc_lap_timeout(\r
335         IN              const   ib_qp_handle_t                          h_qp )\r
336 {\r
337         ib_cm_apr_rec_t         apr_rec;\r
338 \r
339         AL_ENTER( AL_DBG_CM );\r
340 \r
341         CL_ASSERT( h_qp );\r
342 \r
343         /* Report the timeout. */\r
344         cl_memclr( &apr_rec, sizeof(ib_cm_apr_rec_t) );\r
345         apr_rec.h_qp = h_qp;\r
346         apr_rec.qp_context = h_qp->obj.context;\r
347         apr_rec.cm_status = IB_TIMEOUT;\r
348         apr_rec.apr_status = IB_AP_REJECT;\r
349 \r
350         /* Notify the user that the LAP failed. */\r
351         ((al_conn_qp_t*)h_qp)->pfn_cm_apr_cb( &apr_rec );\r
352 \r
353         AL_EXIT( AL_DBG_CM );\r
354 }\r
355 \r
356 \r
357 /*\r
358  * Callback to process a disconnection timeout due to not receiving the DREP\r
359  * within allowable time.\r
360  */\r
361 static void\r
362 __proc_dconn_timeout(\r
363         IN              const   ib_qp_handle_t                          h_qp )\r
364 {\r
365         ib_cm_drep_rec_t        drep_rec;\r
366 \r
367         AL_ENTER( AL_DBG_CM );\r
368 \r
369         /* No response.  We're done.  Deliver a DREP callback. */\r
370         cl_memclr( &drep_rec, sizeof(ib_cm_drep_rec_t) );\r
371         drep_rec.h_qp = h_qp;\r
372         drep_rec.qp_context = h_qp->obj.context;\r
373         drep_rec.cm_status = IB_TIMEOUT;\r
374 \r
375         __cep_timewait_qp( h_qp );\r
376 \r
377         al_destroy_cep( h_qp->obj.h_al, &((al_conn_qp_t*)h_qp)->cid, TRUE );\r
378 \r
379         /* Call the user back. */\r
380         ((al_conn_qp_t*)h_qp)->pfn_cm_drep_cb( &drep_rec );\r
381 \r
382         AL_EXIT( AL_DBG_CM );\r
383 }\r
384 \r
385 \r
386 static void\r
387 __proc_failed_send(\r
388         IN                              ib_qp_handle_t                          h_qp,\r
389         IN              const   ib_mad_t* const                         p_mad )\r
390 {\r
391         AL_ENTER( AL_DBG_CM );\r
392 \r
393         /* Failure indicates a send. */\r
394         switch( p_mad->attr_id )\r
395         {\r
396         case CM_REQ_ATTR_ID:\r
397         case CM_REP_ATTR_ID:\r
398                 __proc_conn_timeout( h_qp );\r
399                 break;\r
400         case CM_LAP_ATTR_ID:\r
401                 __proc_lap_timeout( h_qp );\r
402                 break;\r
403         case CM_DREQ_ATTR_ID:\r
404                 __proc_dconn_timeout( h_qp );\r
405                 break;\r
406         default:\r
407                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
408                         ("Invalid CM send MAD attribute ID %d.\n", p_mad->attr_id) );\r
409                 break;\r
410         }\r
411 \r
412         AL_EXIT( AL_DBG_CM );\r
413 }\r
414 \r
415 \r
416 /******************************************************************************\r
417 * Functions that handle received MADs on a connection (not listen)\r
418 *\r
419 */\r
420 \r
421 \r
422 void\r
423 __proc_peer_req(\r
424         IN              const   ib_cm_handle_t* const           p_cm,\r
425         IN              const   mad_cm_req_t* const                     p_req )\r
426 {\r
427         ib_cm_req_rec_t req_rec;\r
428 \r
429         AL_ENTER( AL_DBG_CM );\r
430 \r
431         CL_ASSERT( p_cm );\r
432         CL_ASSERT( p_cm->h_qp );\r
433         /* Must be peer-to-peer. */\r
434         CL_ASSERT( ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_req_cb );\r
435         CL_ASSERT( p_req );\r
436 \r
437         /* Format the callback record. */\r
438         __format_req_rec( p_req, &req_rec );\r
439 \r
440         /* update peer based rec handles and context values */\r
441         req_rec.context = p_cm->h_qp->obj.context;\r
442         req_rec.h_cm_req = *p_cm;\r
443         req_rec.h_cm_listen = NULL;\r
444 \r
445         /* Invoke the user's callback.  User must call ib_cm_rep or ib_cm_rej. */\r
446         ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_req_cb( &req_rec );\r
447 \r
448         AL_EXIT( AL_DBG_CM );\r
449 }\r
450 \r
451 \r
452 void\r
453 __proc_mra(\r
454         IN              const   ib_cm_handle_t* const           p_cm,\r
455         IN              const   mad_cm_mra_t* const                     p_mra )\r
456 {\r
457         ib_cm_mra_rec_t mra_rec;\r
458 \r
459         AL_ENTER( AL_DBG_CM );\r
460 \r
461         CL_ASSERT( p_cm->h_qp );\r
462         CL_ASSERT( ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_mra_cb );\r
463 \r
464         /* Format the MRA callback record. */\r
465         cl_memclr( &mra_rec, sizeof(ib_cm_mra_rec_t) );\r
466 \r
467         mra_rec.h_qp = p_cm->h_qp;\r
468         mra_rec.qp_context = p_cm->h_qp->obj.context;\r
469         mra_rec.p_mra_pdata = p_mra->pdata;\r
470 \r
471         /*\r
472          * Call the user back. Note that users will get a callback only\r
473          * for the first MRA received in response to a REQ, REP, or LAP.\r
474          */\r
475         ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_mra_cb( &mra_rec );\r
476 \r
477         AL_EXIT( AL_DBG_CM );\r
478 }\r
479 \r
480 \r
481 void\r
482 __proc_rej(\r
483         IN              const   ib_cm_handle_t* const           p_cm,\r
484         IN              const   mad_cm_rej_t* const                     p_rej )\r
485 {\r
486         ib_cm_rej_rec_t rej_rec;\r
487 \r
488         AL_ENTER( AL_DBG_CM );\r
489 \r
490         if( p_cm->h_qp )\r
491         {\r
492                 /* Format the REJ callback record. */\r
493                 cl_memclr( &rej_rec, sizeof(ib_cm_rej_rec_t) );\r
494 \r
495                 rej_rec.h_qp = p_cm->h_qp;\r
496                 rej_rec.qp_context = p_cm->h_qp->obj.context;\r
497 \r
498                 rej_rec.p_rej_pdata = p_rej->pdata;\r
499                 rej_rec.p_ari = p_rej->ari;\r
500                 rej_rec.ari_length = conn_rej_get_ari_len( p_rej );\r
501                 rej_rec.rej_status = p_rej->reason;\r
502 \r
503                 /*\r
504                  * Unbind the QP from the connection object.  This allows the QP to\r
505                  * be immediately reused in another connection request.\r
506                  */\r
507                 __cep_timewait_qp( p_cm->h_qp );\r
508 \r
509                 al_destroy_cep( p_cm->h_al, &((al_conn_qp_t*)p_cm->h_qp)->cid, TRUE );\r
510 \r
511                 /* Call the user back. */\r
512                 ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_rej_cb( &rej_rec );\r
513         }\r
514 \r
515         AL_EXIT( AL_DBG_CM );\r
516 }\r
517 \r
518 \r
519 static void\r
520 __proc_rep(\r
521         IN                              ib_cm_handle_t* const           p_cm,\r
522         IN                              mad_cm_rep_t* const                     p_rep )\r
523 {\r
524         ib_cm_rep_rec_t         rep_rec;\r
525 \r
526         AL_ENTER( AL_DBG_CM );\r
527 \r
528         cl_memclr( &rep_rec, sizeof(ib_cm_rep_rec_t) );\r
529 \r
530         /* fill the rec callback data */\r
531         rep_rec.p_rep_pdata = p_rep->pdata;\r
532         rep_rec.qp_type = p_cm->h_qp->type;\r
533 \r
534         rep_rec.h_cm_rep = *p_cm;\r
535         rep_rec.qp_context = p_cm->h_qp->obj.context;\r
536         rep_rec.resp_res = p_rep->resp_resources;\r
537         rep_rec.flow_ctrl = conn_rep_get_e2e_flow_ctl( p_rep );\r
538         rep_rec.apr_status = conn_rep_get_failover( p_rep );\r
539 \r
540         /* Notify the user of the reply. */\r
541         ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_rep_cb( &rep_rec );\r
542 \r
543         AL_EXIT( AL_DBG_CM );\r
544 }\r
545 \r
546 \r
547 static void\r
548 __proc_rtu(\r
549         IN                              ib_cm_handle_t* const           p_cm,\r
550         IN                              mad_cm_rtu_t* const                     p_rtu )\r
551 {\r
552         ib_cm_rtu_rec_t                 rtu_rec;\r
553 \r
554         AL_ENTER( AL_DBG_CM );\r
555 \r
556         rtu_rec.p_rtu_pdata = p_rtu->pdata;\r
557         rtu_rec.h_qp = p_cm->h_qp;\r
558         rtu_rec.qp_context = p_cm->h_qp->obj.context;\r
559 \r
560         ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_rtu_cb( &rtu_rec );\r
561 \r
562         AL_EXIT( AL_DBG_CM );\r
563 }\r
564 \r
565 \r
566 static void\r
567 __proc_dreq(\r
568         IN                              ib_cm_handle_t* const           p_cm,\r
569         IN                              mad_cm_dreq_t* const            p_dreq )\r
570 {\r
571         ib_cm_dreq_rec_t        dreq_rec;\r
572 \r
573         AL_ENTER( AL_DBG_CM );\r
574 \r
575         cl_memclr( &dreq_rec, sizeof(ib_cm_dreq_rec_t) );\r
576 \r
577         dreq_rec.h_cm_dreq = *p_cm;\r
578         dreq_rec.p_dreq_pdata = p_dreq->pdata;\r
579 \r
580         dreq_rec.qp_context = p_cm->h_qp->obj.context;\r
581 \r
582         ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_dreq_cb( &dreq_rec );\r
583 \r
584         AL_EXIT( AL_DBG_CM );\r
585 }\r
586 \r
587 \r
588 void\r
589 __proc_drep(\r
590         IN                              ib_cm_handle_t* const           p_cm,\r
591         IN                              mad_cm_drep_t* const            p_drep )\r
592 {\r
593         ib_cm_drep_rec_t        drep_rec;\r
594 \r
595         AL_ENTER( AL_DBG_CM );\r
596 \r
597         cl_memclr( &drep_rec, sizeof(ib_cm_drep_rec_t) );\r
598 \r
599         /* Copy qp context before the connection is released */\r
600         drep_rec.cm_status = IB_SUCCESS;\r
601         drep_rec.p_drep_pdata = p_drep->pdata;\r
602         drep_rec.h_qp = p_cm->h_qp;\r
603         drep_rec.qp_context = p_cm->h_qp->obj.context;\r
604 \r
605         __cep_timewait_qp( p_cm->h_qp );\r
606 \r
607         al_destroy_cep( p_cm->h_al, &((al_conn_qp_t*)p_cm->h_qp)->cid, TRUE );\r
608 \r
609         ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_drep_cb( &drep_rec );\r
610 \r
611         AL_EXIT( AL_DBG_CM );\r
612 }\r
613 \r
614 \r
615 void\r
616 __proc_lap(\r
617         IN                              ib_cm_handle_t* const           p_cm,\r
618         IN              const   mad_cm_lap_t* const                     p_lap )\r
619 {\r
620         ib_cm_lap_rec_t lap_rec;\r
621         const lap_path_info_t* const    p_path = &p_lap->alternate_path;\r
622 \r
623         AL_ENTER( AL_DBG_CM );\r
624 \r
625         CL_ASSERT( p_cm );\r
626         CL_ASSERT( p_cm->h_qp );\r
627         CL_ASSERT( p_lap );\r
628 \r
629         cl_memclr( &lap_rec, sizeof(ib_cm_lap_rec_t) );\r
630         lap_rec.qp_context = p_cm->h_qp->obj.context;\r
631         lap_rec.h_cm_lap = *p_cm;\r
632 \r
633         /*\r
634          * Format the path record. The local ack timeout specified in the\r
635          * LAP is twice the packet life plus the sender's CA ACK delay.  When\r
636          * reporting the packet life, we divide the local ack timeout by 2 to\r
637          * approach the path's packet lifetime.  Since local ack timeout is\r
638          * expressed as 4.096 * 2^x, subtracting 1 is equivalent to dividing the\r
639          * time in half.\r
640          */\r
641         ib_path_rec_init_local( &lap_rec.alt_path,\r
642                 &p_lap->alternate_path.local_gid,\r
643                 &p_lap->alternate_path.remote_gid,\r
644                 p_lap->alternate_path.local_lid,\r
645                 p_lap->alternate_path.remote_lid,\r
646                 1, IB_DEFAULT_PKEY,\r
647                 conn_lap_path_get_svc_lvl( &p_lap->alternate_path ), 0,\r
648                 IB_PATH_SELECTOR_EXACTLY,\r
649                 IB_MTU_LEN_2048,\r
650                 IB_PATH_SELECTOR_EXACTLY,\r
651                 conn_lap_path_get_pkt_rate( p_path ),\r
652                 IB_PATH_SELECTOR_EXACTLY,\r
653                 (uint8_t)( conn_lap_path_get_lcl_ack_timeout( p_path ) - 1 ),\r
654                 0 );\r
655 \r
656         /* Add global routing info as necessary. */\r
657         if( !conn_lap_path_get_subn_lcl( &p_lap->alternate_path ) )\r
658         {\r
659                 ib_path_rec_set_hop_flow_raw( &lap_rec.alt_path,\r
660                         p_lap->alternate_path.hop_limit,\r
661                         conn_lap_path_get_flow_lbl( &p_lap->alternate_path ),\r
662                         FALSE );\r
663                 lap_rec.alt_path.tclass =\r
664                         conn_lap_path_get_tclass( &p_lap->alternate_path );\r
665         }\r
666 \r
667         ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_lap_cb( &lap_rec );\r
668 \r
669         AL_EXIT( AL_DBG_CM );\r
670 }\r
671 \r
672 \r
673 static ib_api_status_t\r
674 __cep_lap_qp(\r
675         IN                              ib_cm_handle_t* const           p_cm )\r
676 {\r
677         ib_api_status_t         status;\r
678         ib_qp_mod_t                     qp_mod;\r
679 \r
680         AL_ENTER( AL_DBG_CM );\r
681 \r
682         status = al_cep_get_rts_attr( p_cm->h_al, p_cm->cid, &qp_mod );\r
683         if( status != IB_SUCCESS )\r
684         {\r
685                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
686                         ("al_cep_get_rts_attr returned %s.\n", ib_get_err_str(status)) );\r
687                 goto done;\r
688         }\r
689 \r
690         status = ib_modify_qp( p_cm->h_qp, &qp_mod );\r
691         if( status != IB_SUCCESS )\r
692         {\r
693                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
694                         ("ib_modify_qp for LAP returned %s.\n", ib_get_err_str(status)) );\r
695         }\r
696 \r
697 done:\r
698         AL_EXIT( AL_DBG_CM );\r
699         return status;\r
700 }\r
701 \r
702 \r
703 static void\r
704 __proc_apr(\r
705         IN                              ib_cm_handle_t* const           p_cm,\r
706         IN                              mad_cm_apr_t* const                     p_apr )\r
707 {\r
708         ib_cm_apr_rec_t apr_rec;\r
709 \r
710         AL_ENTER( AL_DBG_CM );\r
711 \r
712         apr_rec.h_qp = p_cm->h_qp;\r
713         apr_rec.qp_context = p_cm->h_qp->obj.context;\r
714         apr_rec.p_info = (const uint8_t*)&p_apr->info;\r
715         apr_rec.info_length = p_apr->info_len;\r
716         apr_rec.p_apr_pdata = p_apr->pdata;\r
717         apr_rec.apr_status = p_apr->status;\r
718 \r
719         if( apr_rec.apr_status == IB_AP_SUCCESS )\r
720         {\r
721                 apr_rec.cm_status = __cep_lap_qp( p_cm );\r
722         }\r
723         else\r
724         {\r
725                 apr_rec.cm_status = IB_ERROR;\r
726         }\r
727 \r
728         ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_apr_cb( &apr_rec );\r
729 \r
730         AL_EXIT( AL_DBG_CM );\r
731 }\r
732 \r
733 \r
734 static void\r
735 __proc_conn(\r
736         IN                              ib_cm_handle_t* const           p_cm,\r
737         IN                              ib_mad_t* const                         p_mad )\r
738 {\r
739         AL_ENTER( AL_DBG_CM );\r
740 \r
741         /* Success indicates a receive. */\r
742         switch( p_mad->attr_id )\r
743         {\r
744         case CM_REQ_ATTR_ID:\r
745                 CL_ASSERT( ((al_conn_qp_t*)p_cm->h_qp)->cid == (int32_t)p_cm->cid ||\r
746                         ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_RESERVED_CID ||\r
747                         ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_INVALID_CID );\r
748                 __proc_peer_req( p_cm, (mad_cm_req_t*)p_mad );\r
749                 break;\r
750 \r
751         case CM_MRA_ATTR_ID:\r
752                 CL_ASSERT( ((al_conn_qp_t*)p_cm->h_qp)->cid == (int32_t)p_cm->cid ||\r
753                         ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_RESERVED_CID ||\r
754                         ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_INVALID_CID );\r
755                 __proc_mra( p_cm, (mad_cm_mra_t*)p_mad );\r
756                 break;\r
757 \r
758         case CM_REJ_ATTR_ID:\r
759                 __proc_rej( p_cm, (mad_cm_rej_t*)p_mad );\r
760                 break;\r
761 \r
762         case CM_REP_ATTR_ID:\r
763                 CL_ASSERT( ((al_conn_qp_t*)p_cm->h_qp)->cid == (int32_t)p_cm->cid ||\r
764                         ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_RESERVED_CID ||\r
765                         ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_INVALID_CID );\r
766                 __proc_rep( p_cm, (mad_cm_rep_t*)p_mad );\r
767                 break;\r
768 \r
769         case CM_RTU_ATTR_ID:\r
770                 CL_ASSERT( ((al_conn_qp_t*)p_cm->h_qp)->cid == (int32_t)p_cm->cid ||\r
771                         ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_RESERVED_CID ||\r
772                         ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_INVALID_CID );\r
773                 __proc_rtu( p_cm, (mad_cm_rtu_t*)p_mad );\r
774                 break;\r
775 \r
776         case CM_DREQ_ATTR_ID:\r
777                 CL_ASSERT( ((al_conn_qp_t*)p_cm->h_qp)->cid == (int32_t)p_cm->cid ||\r
778                         ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_INVALID_CID );\r
779                 __proc_dreq( p_cm, (mad_cm_dreq_t*)p_mad );\r
780                 break;\r
781 \r
782         case CM_DREP_ATTR_ID:\r
783                 CL_ASSERT( ((al_conn_qp_t*)p_cm->h_qp)->cid == (int32_t)p_cm->cid ||\r
784                         ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_RESERVED_CID ||\r
785                         ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_INVALID_CID );\r
786                 __proc_drep( p_cm, (mad_cm_drep_t*)p_mad );\r
787                 break;\r
788 \r
789         case CM_LAP_ATTR_ID:\r
790                 CL_ASSERT( ((al_conn_qp_t*)p_cm->h_qp)->cid == (int32_t)p_cm->cid ||\r
791                         ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_RESERVED_CID ||\r
792                         ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_INVALID_CID );\r
793                 __proc_lap( p_cm, (mad_cm_lap_t*)p_mad );\r
794                 break;\r
795 \r
796         case CM_APR_ATTR_ID:\r
797                 CL_ASSERT( ((al_conn_qp_t*)p_cm->h_qp)->cid == (int32_t)p_cm->cid ||\r
798                         ((al_conn_qp_t*)p_cm->h_qp)->cid == AL_INVALID_CID );\r
799                 __proc_apr( p_cm, (mad_cm_apr_t*)p_mad );\r
800                 break;\r
801 \r
802         //case CM_SIDR_REQ_ATTR_ID:\r
803         //      p_async_mad->item.pfn_callback = __process_cm_sidr_req;\r
804         //      break;\r
805 \r
806         //case CM_SIDR_REP_ATTR_ID:\r
807         //      p_async_mad->item.pfn_callback = __process_cm_sidr_rep;\r
808         //      break;\r
809 \r
810         default:\r
811                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
812                         ("Invalid CM recv MAD attribute ID %d.\n", p_mad->attr_id) );\r
813         }\r
814 \r
815         AL_EXIT( AL_DBG_CM );\r
816 }\r
817 \r
818 /******************************************************************************\r
819 * CEP callback handler.\r
820 *\r
821 */\r
822 \r
823 #ifdef CL_KERNEL\r
824 static void\r
825 __process_cep_cb(\r
826 #else\r
827 static void\r
828 __cm_handler(\r
829 #endif\r
830         IN              const   ib_al_handle_t                          h_al,\r
831         IN              const   net32_t                                         cid )\r
832 {\r
833         ib_api_status_t         status;\r
834         void*                           context;\r
835         net32_t                         new_cid;\r
836         ib_mad_element_t        *p_mad;\r
837         ib_cm_handle_t          h_cm;\r
838 \r
839         AL_ENTER( AL_DBG_CM );\r
840 \r
841         for( status = al_cep_poll( h_al, cid, &context, &new_cid, &p_mad );\r
842                 status == IB_SUCCESS;\r
843                 status = al_cep_poll( h_al, cid, &context, &new_cid, &p_mad ) )\r
844         {\r
845                 /* Something to do - WOOT!!! */\r
846                 if( new_cid != AL_INVALID_CID )\r
847                 {\r
848                         __proc_listen( (al_listen_t*)context,\r
849                                 new_cid, ib_get_mad_buf( p_mad ) );\r
850                 }\r
851                 else if( p_mad->status != IB_SUCCESS )\r
852                 {\r
853                         /* Context is a QP handle, and a sent MAD timed out. */\r
854                         __proc_failed_send(\r
855                                 (ib_qp_handle_t)context, ib_get_mad_buf( p_mad ) );\r
856                 }\r
857                 else\r
858                 {\r
859                         h_cm.h_al = h_al;\r
860                         h_cm.cid = cid;\r
861                         h_cm.h_qp = (ib_qp_handle_t)context;\r
862                         __proc_conn( &h_cm, ib_get_mad_buf( p_mad ) );\r
863                 }\r
864                 ib_put_mad( p_mad );\r
865         }\r
866 }\r
867 \r
868 \r
869 #ifdef CL_KERNEL\r
870 \r
871 static void\r
872 __process_cep_async(\r
873         IN                              cl_async_proc_item_t            *p_item )\r
874 {\r
875         cep_async_mad_t *p_async_mad;\r
876 \r
877         AL_ENTER( AL_DBG_CM );\r
878 \r
879         p_async_mad = PARENT_STRUCT( p_item, cep_async_mad_t, item );\r
880 \r
881         __process_cep_cb( p_async_mad->h_al, p_async_mad->cid );\r
882 \r
883         cl_free( p_async_mad );\r
884 \r
885         AL_EXIT( AL_DBG_CM );\r
886 }\r
887 \r
888 \r
889 /*\r
890  * The handler is invoked at DISPATCH_LEVEL in kernel mode.  We need to switch\r
891  * to a passive level thread context to perform QP modify and invoke user\r
892  * callbacks.\r
893  */\r
894 static void\r
895 __cm_handler(\r
896         IN              const   ib_al_handle_t                          h_al,\r
897         IN              const   net32_t                                         cid )\r
898 {\r
899         cep_async_mad_t *p_async_mad;\r
900 \r
901         AL_ENTER( AL_DBG_CM );\r
902 \r
903         p_async_mad = (cep_async_mad_t*)cl_zalloc( sizeof(cep_async_mad_t) );\r
904         if( !p_async_mad )\r
905         {\r
906                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
907                         ("failed to cl_zalloc cm_async_mad_t (%d bytes)\n",\r
908                         sizeof(cep_async_mad_t)) );\r
909                 return;\r
910         }\r
911 \r
912         p_async_mad->h_al = h_al;\r
913         p_async_mad->cid = cid;\r
914         p_async_mad->item.pfn_callback = __process_cep_async;\r
915 \r
916         /* Queue the MAD for asynchronous processing. */\r
917         cl_async_proc_queue( gp_async_proc_mgr, &p_async_mad->item );\r
918 \r
919         AL_EXIT( AL_DBG_CM );\r
920 }\r
921 #endif  /* CL_KERNEL */\r
922 \r
923 \r
924 /*\r
925  * Transition the QP to the INIT state, if it is not already in the\r
926  * INIT state.\r
927  */\r
928 ib_api_status_t\r
929 __cep_init_qp(\r
930         IN              const   ib_qp_handle_t                          h_qp,\r
931         IN                              ib_qp_mod_t* const                      p_init )\r
932 {\r
933         ib_qp_mod_t                     qp_mod;\r
934         ib_api_status_t         status;\r
935 \r
936         /*\r
937          * Move to the init state to allow posting of receive buffers.\r
938          * Chech the current state of the QP.  The user may have already\r
939          * transitioned it and posted some receives to the QP, so we\r
940          * should not reset the QP if it is already in the INIT state.\r
941          */\r
942         if( h_qp->state != IB_QPS_INIT )\r
943         {\r
944                 /* Reset the QP. */\r
945                 cl_memclr( &qp_mod, sizeof(ib_qp_mod_t) );\r
946                 qp_mod.req_state = IB_QPS_RESET;\r
947 \r
948                 status = ib_modify_qp( h_qp, &qp_mod );\r
949                 if( status != IB_SUCCESS )\r
950                 {\r
951                         AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
952                                 ("ib_modify_qp to IB_QPS_RESET returned %s\n",\r
953                                 ib_get_err_str(status) ) );\r
954                 }\r
955 \r
956                 /* Initialize the QP. */\r
957                 status = ib_modify_qp( h_qp, p_init );\r
958                 if( status != IB_SUCCESS )\r
959                 {\r
960                         AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
961                                 ("ib_modify_qp returned %s.\n", ib_get_err_str(status) ) );\r
962                         return status;\r
963                 }\r
964         }\r
965 \r
966         return IB_SUCCESS;\r
967 }\r
968 \r
969 static ib_api_status_t\r
970 __cep_pre_req(\r
971         IN              const   ib_cm_req_t* const                      p_cm_req )\r
972 {\r
973         ib_api_status_t         status;\r
974         ib_qp_mod_t                     qp_mod;\r
975 \r
976         AL_ENTER( AL_DBG_CM );\r
977 \r
978         status = al_cep_pre_req( qp_get_al( p_cm_req->h_qp ),\r
979                 ((al_conn_qp_t*)p_cm_req->h_qp)->cid, p_cm_req, &qp_mod );\r
980         if( status != IB_SUCCESS )\r
981         {\r
982                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
983                         ("al_cep_pre_req returned %s.\n", ib_get_err_str( status )) );\r
984                 return status;\r
985         }\r
986 \r
987         /* Transition QP through state machine */\r
988         /*\r
989          * Warning! Using all access rights.  We need to modify\r
990          * the ib_cm_req_t to include this.\r
991          */\r
992         qp_mod.state.init.access_ctrl |=\r
993                 IB_AC_RDMA_READ | IB_AC_RDMA_WRITE | IB_AC_ATOMIC;\r
994         status = __cep_init_qp( p_cm_req->h_qp, &qp_mod );\r
995         if( status != IB_SUCCESS )\r
996         {\r
997                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
998                         ("__cep_init_qp returned %s\n", ib_get_err_str(status)) );\r
999                 return status;\r
1000         }\r
1001 \r
1002         AL_EXIT( AL_DBG_CM );\r
1003         return IB_SUCCESS;\r
1004 }\r
1005 \r
1006 \r
1007 static ib_api_status_t\r
1008 __cep_conn_req(\r
1009         IN              const   ib_al_handle_t                          h_al,\r
1010         IN              const   ib_cm_req_t* const                      p_cm_req )\r
1011 {\r
1012         ib_api_status_t         status;\r
1013         //cl_status_t                   cl_status;\r
1014         //cl_event_t                    sync_event;\r
1015         //cl_event_t                    *p_sync_event = NULL;\r
1016         al_conn_qp_t            *p_qp;\r
1017 \r
1018         AL_ENTER( AL_DBG_CM );\r
1019 \r
1020         /* event based mechanism */\r
1021         if( p_cm_req->flags & IB_FLAGS_SYNC )\r
1022         {\r
1023                 AL_EXIT( AL_DBG_CM );\r
1024                 return IB_UNSUPPORTED;\r
1025                 //cl_event_construct( &sync_event );\r
1026                 //cl_status = cl_event_init( &sync_event, FALSE );\r
1027                 //if( cl_status != CL_SUCCESS )\r
1028                 //{\r
1029                 //      __deref_conn( p_conn );\r
1030                 //      return ib_convert_cl_status( cl_status );\r
1031                 //}\r
1032                 //p_conn->p_sync_event = p_sync_event = &sync_event;\r
1033         }\r
1034 \r
1035         p_qp = (al_conn_qp_t*)p_cm_req->h_qp;\r
1036 \r
1037         /* Get a CEP and bind it to the QP. */\r
1038         status = al_create_cep( h_al, __cm_handler, p_qp, deref_al_obj, &p_qp->cid );\r
1039         if( status != IB_SUCCESS )\r
1040         {\r
1041                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1042                         ("al_create_cep returned %s.\n", ib_get_err_str( status )) );\r
1043                 goto done;\r
1044         }\r
1045 \r
1046         /* Take a reference on behalf of the CEP. */\r
1047         ref_al_obj( &p_qp->qp.obj );\r
1048 \r
1049         status = __cep_pre_req( p_cm_req );\r
1050         if( status != IB_SUCCESS )\r
1051         {\r
1052                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1053                         ("__cep_pre_req returned %s.\n", ib_get_err_str( status )) );\r
1054                 goto err;\r
1055         }\r
1056 \r
1057         /* Store callback pointers. */\r
1058         p_qp->pfn_cm_req_cb = p_cm_req->pfn_cm_req_cb;\r
1059         p_qp->pfn_cm_rep_cb = p_cm_req->pfn_cm_rep_cb;\r
1060         p_qp->pfn_cm_mra_cb = p_cm_req->pfn_cm_mra_cb;\r
1061         p_qp->pfn_cm_rej_cb = p_cm_req->pfn_cm_rej_cb;\r
1062 \r
1063         /* Send the REQ. */\r
1064         status = al_cep_send_req( h_al, p_qp->cid );\r
1065         if( status != IB_SUCCESS )\r
1066         {\r
1067                 //if( p_sync_event )\r
1068                 //      cl_event_destroy( p_sync_event );\r
1069 \r
1070                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1071                         ("al_cep_send_req returned %s.\n", ib_get_err_str(status)) );\r
1072 err:\r
1073                 al_destroy_cep( h_al, &p_qp->cid, TRUE );\r
1074         }\r
1075 \r
1076         /* wait on event if synchronous operation */\r
1077         //if( p_sync_event )\r
1078         //{\r
1079         //      AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM,\r
1080         //              ("event blocked on REQ...\n") );\r
1081         //      cl_event_wait_on( p_sync_event, EVENT_NO_TIMEOUT, FALSE );\r
1082 \r
1083         //      cl_event_destroy( p_sync_event );\r
1084         //}\r
1085 \r
1086 done:\r
1087         AL_EXIT( AL_DBG_CM );\r
1088         return status;\r
1089 }\r
1090 \r
1091 \r
1092 ib_api_status_t\r
1093 ib_cm_req(\r
1094         IN              const   ib_cm_req_t* const                      p_cm_req )\r
1095 {\r
1096         ib_api_status_t         status;\r
1097 \r
1098         AL_ENTER( AL_DBG_CM );\r
1099 \r
1100         if( !p_cm_req )\r
1101         {\r
1102                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
1103                 return IB_INVALID_PARAMETER;\r
1104         }\r
1105 \r
1106         /* Only supported qp types allowed */\r
1107         switch( p_cm_req->qp_type )\r
1108         {\r
1109         default:\r
1110                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid qp_type.\n") );\r
1111                 return IB_INVALID_SETTING;\r
1112 \r
1113         case IB_QPT_RELIABLE_CONN:\r
1114         case IB_QPT_UNRELIABLE_CONN:\r
1115                 if( AL_OBJ_INVALID_HANDLE( p_cm_req->h_qp, AL_OBJ_TYPE_H_QP ) ||\r
1116                         (p_cm_req->h_qp->type != p_cm_req->qp_type) )\r
1117                 {\r
1118                         AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );\r
1119                         return IB_INVALID_QP_HANDLE;\r
1120                 }\r
1121 \r
1122                 status = __cep_conn_req( qp_get_al( p_cm_req->h_qp ), p_cm_req );\r
1123                 break;\r
1124 \r
1125         case IB_QPT_UNRELIABLE_DGRM:\r
1126                 if( AL_OBJ_INVALID_HANDLE( p_cm_req->h_al, AL_OBJ_TYPE_H_AL ) )\r
1127                 {\r
1128                         AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AL_HANDLE\n") );\r
1129                         return IB_INVALID_AL_HANDLE;\r
1130                 }\r
1131                 status = IB_UNSUPPORTED;\r
1132 //              status = cm_sidr_req( p_cm_req->h_al, p_cm_req );\r
1133                 break;\r
1134         }\r
1135 \r
1136         AL_EXIT( AL_DBG_CM );\r
1137         return status;\r
1138 }\r
1139 \r
1140 \r
1141 /*\r
1142  * Note: we pass in the QP handle separately because it comes form different\r
1143  * sources.  It comes from the ib_cm_rep_t structure in the ib_cm_rep path, and\r
1144  * from the ib_cm_handle_t structure in the ib_cm_rtu path.\r
1145  */\r
1146 static ib_api_status_t\r
1147 __cep_rts_qp(\r
1148         IN              const   ib_cm_handle_t                          h_cm,\r
1149         IN              const   ib_qp_handle_t                          h_qp,\r
1150         IN              const   ib_access_t                                     access_ctrl,\r
1151         IN              const   uint32_t                                        sq_depth,\r
1152         IN              const   uint32_t                                        rq_depth )\r
1153 {\r
1154         ib_api_status_t status;\r
1155         ib_qp_mod_t             qp_mod;\r
1156 \r
1157         AL_ENTER( AL_DBG_CM );\r
1158 \r
1159         /* Set the QP to RTR. */\r
1160         status = al_cep_get_rtr_attr( h_cm.h_al, h_cm.cid, &qp_mod );\r
1161         if( status != IB_SUCCESS )\r
1162         {\r
1163                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1164                         ("al_cep_get_rtr_attr returned %s\n", ib_get_err_str( status )) );\r
1165                 return status;\r
1166         }\r
1167 \r
1168         if( access_ctrl )\r
1169         {\r
1170                 qp_mod.state.rtr.access_ctrl = access_ctrl;\r
1171                 qp_mod.state.rtr.opts |= IB_MOD_QP_ACCESS_CTRL;\r
1172         }\r
1173 \r
1174         if( sq_depth )\r
1175         {\r
1176                 qp_mod.state.rtr.sq_depth = sq_depth;\r
1177                 qp_mod.state.rtr.opts |= IB_MOD_QP_SQ_DEPTH;\r
1178         }\r
1179 \r
1180         if( rq_depth )\r
1181         {\r
1182                 qp_mod.state.rtr.rq_depth = rq_depth;\r
1183                 qp_mod.state.rtr.opts |= IB_MOD_QP_RQ_DEPTH;\r
1184         }\r
1185 \r
1186         status = ib_modify_qp( h_qp, &qp_mod );\r
1187         if( status != IB_SUCCESS )\r
1188         {\r
1189                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1190                         ("ib_modify_qp to RTR returned %s.\n", ib_get_err_str(status) ) );\r
1191                 return status;\r
1192         }\r
1193 \r
1194         /* Set the QP to RTS. */\r
1195         status = al_cep_get_rts_attr( h_cm.h_al, h_cm.cid, &qp_mod );\r
1196         if( status != IB_SUCCESS )\r
1197         {\r
1198                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1199                         ("al_cep_get_rts_attr returned %s\n", ib_get_err_str( status )) );\r
1200                 return status;\r
1201         }\r
1202 \r
1203         status = ib_modify_qp( h_qp, &qp_mod );\r
1204         if( status != IB_SUCCESS )\r
1205         {\r
1206                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1207                         ("ib_modify_qp to RTS returned %s.\n", ib_get_err_str(status) ) );\r
1208                 return status;\r
1209         }\r
1210 \r
1211         AL_EXIT( AL_DBG_CM );\r
1212         return IB_SUCCESS;\r
1213 }\r
1214 \r
1215 \r
1216 static ib_api_status_t\r
1217 __cep_pre_rep(\r
1218         IN              const   ib_cm_handle_t                          h_cm,\r
1219         IN                              ib_qp_mod_t* const                      p_qp_mod,\r
1220         IN              const   ib_cm_rep_t* const                      p_cm_rep )\r
1221 {\r
1222         ib_api_status_t         status;\r
1223 \r
1224         AL_ENTER( AL_DBG_CM );\r
1225 \r
1226         /* Transition the QP to the INIT state. */\r
1227         p_qp_mod->state.init.access_ctrl = p_cm_rep->access_ctrl;\r
1228         status = __cep_init_qp( p_cm_rep->h_qp, p_qp_mod );\r
1229         if( status != IB_SUCCESS )\r
1230         {\r
1231                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1232                         ("cm_init_qp returned %s.\n", ib_get_err_str(status)) );\r
1233                 return status;\r
1234         }\r
1235 \r
1236         /* Prepost receives. */\r
1237         if( p_cm_rep->p_recv_wr )\r
1238         {\r
1239                 status = ib_post_recv( p_cm_rep->h_qp, p_cm_rep->p_recv_wr,\r
1240                         (ib_recv_wr_t**)p_cm_rep->pp_recv_failure );\r
1241                 if( status != IB_SUCCESS )\r
1242                 {\r
1243                         AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1244                                 ("ib_post_recv returned %s.\n", ib_get_err_str(status)) );\r
1245                         return status;\r
1246                 }\r
1247         }\r
1248 \r
1249         /* Transition the QP to the RTR and RTS states. */\r
1250         status = __cep_rts_qp( h_cm, p_cm_rep->h_qp,\r
1251                 p_cm_rep->access_ctrl, p_cm_rep->sq_depth, p_cm_rep->rq_depth );\r
1252         if( status != IB_SUCCESS )\r
1253         {\r
1254                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1255                         ("__cep_rts_qp returned %s.\n", ib_get_err_str(status)) );\r
1256         }\r
1257 \r
1258         AL_EXIT( AL_DBG_CM );\r
1259         return status;\r
1260 }\r
1261 \r
1262 \r
1263 static ib_api_status_t\r
1264 __cep_conn_rep(\r
1265         IN                              ib_cm_handle_t                          h_cm,\r
1266         IN      const           ib_cm_rep_t* const                      p_cm_rep )\r
1267 {\r
1268         ib_api_status_t         status;\r
1269         ib_qp_mod_t                     qp_mod;\r
1270 \r
1271         AL_ENTER( AL_DBG_CM );\r
1272 \r
1273         status = al_cep_pre_rep(\r
1274                 h_cm.h_al, h_cm.cid, p_cm_rep->h_qp, deref_al_obj, p_cm_rep,\r
1275                 &((al_conn_qp_t*)p_cm_rep->h_qp)->cid, &qp_mod );\r
1276         switch( status )\r
1277         {\r
1278         case IB_SUCCESS:\r
1279                 break;\r
1280 \r
1281         case IB_RESOURCE_BUSY:\r
1282                 /* We don't destroy the CEP to allow the user to retry accepting. */\r
1283                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("QP already connected.\n") );\r
1284                 return IB_INVALID_QP_HANDLE;\r
1285 \r
1286         default:\r
1287                 al_cep_rej( h_cm.h_al, h_cm.cid, IB_REJ_INSUF_RESOURCES, NULL, 0, NULL, 0 );\r
1288                 al_destroy_cep( h_cm.h_al, &h_cm.cid, FALSE );\r
1289 \r
1290                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1291                         ("al_cep_pre_rep returned %s.\n", ib_get_err_str( status )) );\r
1292                 return status;\r
1293         }\r
1294 \r
1295         /* Take a reference on behalf of the CEP. */\r
1296         ref_al_obj( &p_cm_rep->h_qp->obj );\r
1297 \r
1298         /* Store the CM callbacks. */\r
1299         ((al_conn_qp_t*)p_cm_rep->h_qp)->pfn_cm_rej_cb = p_cm_rep->pfn_cm_rej_cb;\r
1300         ((al_conn_qp_t*)p_cm_rep->h_qp)->pfn_cm_mra_cb = p_cm_rep->pfn_cm_mra_cb;\r
1301         ((al_conn_qp_t*)p_cm_rep->h_qp)->pfn_cm_rtu_cb = p_cm_rep->pfn_cm_rtu_cb;\r
1302         ((al_conn_qp_t*)p_cm_rep->h_qp)->pfn_cm_lap_cb = p_cm_rep->pfn_cm_lap_cb;\r
1303         ((al_conn_qp_t*)p_cm_rep->h_qp)->pfn_cm_dreq_cb = p_cm_rep->pfn_cm_dreq_cb;\r
1304 \r
1305         /* Transition QP through state machine */\r
1306         status = __cep_pre_rep( h_cm, &qp_mod, p_cm_rep );\r
1307         if( status != IB_SUCCESS )\r
1308         {\r
1309                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1310                         ("__cep_pre_req returned %s\n", ib_get_err_str(status)) );\r
1311                 goto err;\r
1312         }\r
1313 \r
1314         status = al_cep_send_rep( h_cm.h_al, h_cm.cid );\r
1315         if( status != IB_SUCCESS )\r
1316         {\r
1317                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1318                         ("al_cep_send_rep returned %s\n", ib_get_err_str(status)) );\r
1319 err:\r
1320 \r
1321                 /* Reject and abort the connection. */\r
1322                 al_cep_rej( h_cm.h_al, h_cm.cid, IB_REJ_INSUF_QP, NULL, 0, NULL, 0 );\r
1323                 al_destroy_cep(\r
1324                         h_cm.h_al, &((al_conn_qp_t*)p_cm_rep->h_qp)->cid, TRUE );\r
1325         }\r
1326 \r
1327         AL_EXIT( AL_DBG_CM );\r
1328         return status;\r
1329 }\r
1330 \r
1331 \r
1332 ib_api_status_t\r
1333 ib_cm_rep(\r
1334         IN              const   ib_cm_handle_t                          h_cm_req,\r
1335         IN              const   ib_cm_rep_t* const                      p_cm_rep )\r
1336 {\r
1337         ib_api_status_t         status;\r
1338         net32_t                         cid;\r
1339 \r
1340         AL_ENTER( AL_DBG_CM );\r
1341 \r
1342         if( !p_cm_rep )\r
1343         {\r
1344                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
1345                 return IB_INVALID_PARAMETER;\r
1346         }\r
1347 \r
1348         /* Only supported qp types allowed */\r
1349         status = IB_SUCCESS;\r
1350         switch( p_cm_rep->qp_type )\r
1351         {\r
1352         default:\r
1353                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid qp_type.\n") );\r
1354                 status = IB_INVALID_SETTING;\r
1355                 break;\r
1356 \r
1357         case IB_QPT_RELIABLE_CONN:\r
1358         case IB_QPT_UNRELIABLE_CONN:\r
1359                 if( AL_OBJ_INVALID_HANDLE( p_cm_rep->h_qp, AL_OBJ_TYPE_H_QP ) ||\r
1360                         (p_cm_rep->h_qp->type != p_cm_rep->qp_type) )\r
1361                 {\r
1362                         AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );\r
1363                         status = IB_INVALID_QP_HANDLE;\r
1364                 }\r
1365                 else if( p_cm_rep->h_qp->obj.h_al != h_cm_req.h_al )\r
1366                 {\r
1367                         AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );\r
1368                         status = IB_INVALID_QP_HANDLE;\r
1369                 }\r
1370                 break;\r
1371 \r
1372         case IB_QPT_UNRELIABLE_DGRM:\r
1373                 if( ( p_cm_rep->status == IB_SIDR_SUCCESS ) &&\r
1374                         (AL_OBJ_INVALID_HANDLE( p_cm_rep->h_qp, AL_OBJ_TYPE_H_QP ) ||\r
1375                         (p_cm_rep->h_qp->type != p_cm_rep->qp_type) ) )\r
1376                 {\r
1377                         AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );\r
1378                         status = IB_INVALID_QP_HANDLE;\r
1379                 }\r
1380                 break;\r
1381         }\r
1382 \r
1383         if( status != IB_SUCCESS )\r
1384         {\r
1385                 cid = h_cm_req.cid;\r
1386                 al_cep_rej(\r
1387                         h_cm_req.h_al, h_cm_req.cid, IB_REJ_INSUF_QP, NULL, 0, NULL, 0 );\r
1388                 al_destroy_cep( h_cm_req.h_al, &cid, FALSE );\r
1389 \r
1390                 AL_EXIT( AL_DBG_CM );\r
1391                 return status;\r
1392         }\r
1393 \r
1394         if( p_cm_rep->qp_type == IB_QPT_UNRELIABLE_DGRM )\r
1395                 status = IB_UNSUPPORTED;//status = cm_sidr_rep( p_conn, p_cm_rep );\r
1396         else\r
1397                 status = __cep_conn_rep( h_cm_req, p_cm_rep );\r
1398 \r
1399         AL_EXIT( AL_DBG_CM );\r
1400         return status;\r
1401 }\r
1402 \r
1403 \r
1404 ib_api_status_t\r
1405 ib_cm_rtu(\r
1406         IN              const   ib_cm_handle_t                          h_cm_rep,\r
1407         IN              const   ib_cm_rtu_t* const                      p_cm_rtu )\r
1408 {\r
1409         ib_api_status_t         status;\r
1410 \r
1411         AL_ENTER( AL_DBG_CM );\r
1412 \r
1413         if( !p_cm_rtu )\r
1414         {\r
1415                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
1416                 return IB_INVALID_PARAMETER;\r
1417         }\r
1418 \r
1419         ///*\r
1420         // * Call invalid if event is still processed.\r
1421         // * User may have called rtu in rep callback.\r
1422         // */\r
1423         //if( p_conn->p_sync_event )\r
1424         //{\r
1425         //      AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1426         //              ("Connection in invalid state. Sync call in progress.\n" ) );\r
1427 \r
1428         //      cm_res_release( p_conn );\r
1429         //      __deref_conn( p_conn );\r
1430         //      return IB_INVALID_STATE;\r
1431         //}\r
1432         ((al_conn_qp_t*)h_cm_rep.h_qp)->pfn_cm_apr_cb = p_cm_rtu->pfn_cm_apr_cb;\r
1433         ((al_conn_qp_t*)h_cm_rep.h_qp)->pfn_cm_dreq_cb = p_cm_rtu->pfn_cm_dreq_cb;\r
1434 \r
1435         /* Transition QP through state machine */\r
1436         status = __cep_rts_qp( h_cm_rep, h_cm_rep.h_qp,\r
1437                 p_cm_rtu->access_ctrl, p_cm_rtu->sq_depth, p_cm_rtu->rq_depth );\r
1438         if( status != IB_SUCCESS )\r
1439         {\r
1440                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1441                         ("__cep_rts_qp returned %s.\n", ib_get_err_str( status )) );\r
1442                 goto err;\r
1443         }\r
1444 \r
1445         status = al_cep_rtu( h_cm_rep.h_al, h_cm_rep.cid,\r
1446                 p_cm_rtu->p_rtu_pdata, p_cm_rtu->rtu_length );\r
1447         if( status != IB_SUCCESS && status != IB_INVALID_STATE )\r
1448         {\r
1449 err:\r
1450                 /* Reject and abort the connection. */\r
1451                 al_cep_rej(\r
1452                         h_cm_rep.h_al, h_cm_rep.cid, IB_REJ_INSUF_QP, NULL, 0, NULL, 0 );\r
1453 \r
1454                 __cep_timewait_qp( h_cm_rep.h_qp );\r
1455 \r
1456                 al_destroy_cep(\r
1457                         h_cm_rep.h_al, &((al_conn_qp_t*)h_cm_rep.h_qp)->cid, TRUE );\r
1458 \r
1459                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1460                         ("al_cep_rtu returned %s.\n", ib_get_err_str( status )) );\r
1461                 return status;\r
1462         }\r
1463 \r
1464         AL_EXIT( AL_DBG_CM );\r
1465         return status;\r
1466 }\r
1467 \r
1468 \r
1469 ib_api_status_t\r
1470 ib_cm_mra(\r
1471         IN              const   ib_cm_handle_t                          h_cm,\r
1472         IN              const   ib_cm_mra_t* const                      p_cm_mra )\r
1473 {\r
1474         ib_api_status_t         status;\r
1475 \r
1476         AL_ENTER( AL_DBG_CM );\r
1477 \r
1478         if( !p_cm_mra )\r
1479         {\r
1480                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
1481                 return IB_INVALID_PARAMETER;\r
1482         }\r
1483 \r
1484         status = al_cep_mra( h_cm.h_al, h_cm.cid, p_cm_mra );\r
1485         if( status != IB_SUCCESS )\r
1486         {\r
1487                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1488                         ("al_cep_mra returned %s\n", ib_get_err_str( status )) );\r
1489         }\r
1490 \r
1491         AL_EXIT( AL_DBG_CM );\r
1492         return status;\r
1493 }\r
1494 \r
1495 \r
1496 ib_api_status_t\r
1497 ib_cm_rej(\r
1498         IN              const   ib_cm_handle_t                          h_cm,\r
1499         IN              const   ib_cm_rej_t* const                      p_cm_rej )\r
1500 {\r
1501         ib_api_status_t         status;\r
1502         net32_t                         cid;\r
1503 \r
1504         AL_ENTER( AL_DBG_CM );\r
1505 \r
1506         if( !p_cm_rej )\r
1507         {\r
1508                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
1509                 return IB_INVALID_PARAMETER;\r
1510         }\r
1511 \r
1512         status = al_cep_rej( h_cm.h_al, h_cm.cid, p_cm_rej->rej_status,\r
1513                 p_cm_rej->p_ari->data, p_cm_rej->ari_length,\r
1514                 p_cm_rej->p_rej_pdata, p_cm_rej->rej_length );\r
1515 \r
1516         if( h_cm.h_qp )\r
1517         {\r
1518                 __cep_timewait_qp( h_cm.h_qp );\r
1519 \r
1520                 al_destroy_cep(\r
1521                         h_cm.h_al, &((al_conn_qp_t*)h_cm.h_qp)->cid, TRUE );\r
1522         }\r
1523         else\r
1524         {\r
1525                 cid = h_cm.cid;\r
1526                 al_destroy_cep( h_cm.h_al, &cid, FALSE );\r
1527         }\r
1528 \r
1529         AL_EXIT( AL_DBG_CM );\r
1530         return status;\r
1531 }\r
1532 \r
1533 \r
1534 ib_api_status_t\r
1535 ib_cm_dreq(\r
1536         IN              const   ib_cm_dreq_t* const                     p_cm_dreq )\r
1537 {\r
1538         ib_api_status_t status;\r
1539 \r
1540         AL_ENTER( AL_DBG_CM );\r
1541 \r
1542         if( !p_cm_dreq )\r
1543         {\r
1544                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
1545                 return IB_INVALID_PARAMETER;\r
1546         }\r
1547 \r
1548         /* Only supported qp types allowed */\r
1549         switch( p_cm_dreq->qp_type )\r
1550         {\r
1551         default:\r
1552                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid qp_type.\n") );\r
1553                 return IB_INVALID_SETTING;\r
1554 \r
1555         case IB_QPT_RELIABLE_CONN:\r
1556         case IB_QPT_UNRELIABLE_CONN:\r
1557                 if( AL_OBJ_INVALID_HANDLE( p_cm_dreq->h_qp, AL_OBJ_TYPE_H_QP ) ||\r
1558                         (p_cm_dreq->h_qp->type != p_cm_dreq->qp_type) )\r
1559                 {\r
1560                         AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );\r
1561                         return IB_INVALID_QP_HANDLE;\r
1562                 }\r
1563                 break;\r
1564         }\r
1565 \r
1566         /* Store the callback pointers. */\r
1567         ((al_conn_qp_t*)p_cm_dreq->h_qp)->pfn_cm_drep_cb =\r
1568                 p_cm_dreq->pfn_cm_drep_cb;\r
1569 \r
1570         status = al_cep_dreq( p_cm_dreq->h_qp->obj.h_al,\r
1571                 ((al_conn_qp_t*)p_cm_dreq->h_qp)->cid,\r
1572                 p_cm_dreq->p_dreq_pdata, p_cm_dreq->dreq_length );\r
1573         switch( status )\r
1574         {\r
1575         case IB_INVALID_STATE:\r
1576         case IB_INVALID_HANDLE:\r
1577         case IB_INVALID_PARAMETER:\r
1578         case IB_INVALID_SETTING:\r
1579                 /* Bad call - don't touch the QP. */\r
1580                 break;\r
1581 \r
1582         case IB_SUCCESS:\r
1583                 /* Wait for the DREP or timeout. */\r
1584                 break;\r
1585 \r
1586         default:\r
1587                 /*\r
1588                  * If we failed to send the DREQ, just release the connection.  It's\r
1589                  * unreliable anyway.  The local port may be down.  Note that we could\r
1590                  * not send the DREQ, but we still could have received one.  The DREQ\r
1591                  * will have a reference on the connection until the user calls\r
1592                  * ib_cm_drep.\r
1593                  */\r
1594                 __cep_timewait_qp( p_cm_dreq->h_qp );\r
1595 \r
1596                 al_destroy_cep( p_cm_dreq->h_qp->obj.h_al,\r
1597                         &((al_conn_qp_t*)p_cm_dreq->h_qp)->cid, TRUE );\r
1598                 status = IB_SUCCESS;\r
1599         }\r
1600 \r
1601         AL_EXIT( AL_DBG_CM );\r
1602         return status;\r
1603 }\r
1604 \r
1605 \r
1606 \r
1607 ib_api_status_t\r
1608 ib_cm_drep(\r
1609         IN              const   ib_cm_handle_t                          h_cm_dreq,\r
1610         IN              const   ib_cm_drep_t* const                     p_cm_drep )\r
1611 {\r
1612         ib_api_status_t         status;\r
1613 \r
1614         AL_ENTER( AL_DBG_CM );\r
1615 \r
1616         if( !p_cm_drep )\r
1617         {\r
1618                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
1619                 return IB_INVALID_PARAMETER;\r
1620         }\r
1621 \r
1622         status = al_cep_drep( h_cm_dreq.h_al, h_cm_dreq.cid,\r
1623                 p_cm_drep->p_drep_pdata, p_cm_drep->drep_length );\r
1624         switch( status )\r
1625         {\r
1626         case IB_INVALID_SETTING:\r
1627         case IB_INVALID_HANDLE:\r
1628         case IB_INVALID_PARAMETER:\r
1629         case IB_INVALID_STATE:\r
1630                 /* Bad call - don't touch the QP. */\r
1631                 break;\r
1632 \r
1633         default:\r
1634                 /*\r
1635                  * Some other out-of-resource error - continue as if we succeeded in\r
1636                  * sending the DREP.\r
1637                  */\r
1638                 status = IB_SUCCESS;\r
1639                 /* Fall through */\r
1640         case IB_SUCCESS:\r
1641                 __cep_timewait_qp( h_cm_dreq.h_qp );\r
1642 \r
1643                 al_destroy_cep( h_cm_dreq.h_al,\r
1644                         &((al_conn_qp_t*)h_cm_dreq.h_qp)->cid, TRUE );\r
1645         }\r
1646 \r
1647         AL_EXIT( AL_DBG_CM );\r
1648         return status;\r
1649 }\r
1650 \r
1651 \r
1652 ib_api_status_t\r
1653 ib_cm_lap(\r
1654         IN              const   ib_cm_lap_t* const                      p_cm_lap )\r
1655 {\r
1656         ib_api_status_t status;\r
1657 \r
1658         AL_ENTER( AL_DBG_CM );\r
1659 \r
1660         if( !p_cm_lap )\r
1661         {\r
1662                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
1663                 return IB_INVALID_PARAMETER;\r
1664         }\r
1665 \r
1666         /* Only supported qp types allowed */\r
1667         switch( p_cm_lap->qp_type )\r
1668         {\r
1669         default:\r
1670                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid qp_type.\n") );\r
1671                 return IB_INVALID_SETTING;\r
1672 \r
1673         case IB_QPT_RELIABLE_CONN:\r
1674         case IB_QPT_UNRELIABLE_CONN:\r
1675                 if( AL_OBJ_INVALID_HANDLE( p_cm_lap->h_qp, AL_OBJ_TYPE_H_QP ) ||\r
1676                         (p_cm_lap->h_qp->type != p_cm_lap->qp_type) )\r
1677                 {\r
1678                         AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );\r
1679                         return IB_INVALID_QP_HANDLE;\r
1680                 }\r
1681                 break;\r
1682         }\r
1683 \r
1684         status = al_cep_lap( p_cm_lap->h_qp->obj.h_al,\r
1685                 ((al_conn_qp_t*)p_cm_lap->h_qp)->cid, p_cm_lap );\r
1686         if( status != IB_SUCCESS )\r
1687         {\r
1688                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1689                         ("al_cep_lap returned %s.\n", ib_get_err_str( status )) );\r
1690         }\r
1691 \r
1692         AL_EXIT( AL_DBG_CM );\r
1693         return status;\r
1694 }\r
1695 \r
1696 \r
1697 ib_api_status_t\r
1698 ib_cm_apr(\r
1699         IN              const   ib_cm_handle_t                          h_cm_lap,\r
1700         IN              const   ib_cm_apr_t* const                      p_cm_apr )\r
1701 {\r
1702         ib_api_status_t         status;\r
1703         ib_qp_mod_t                     qp_mod;\r
1704 \r
1705         AL_ENTER( AL_DBG_CM );\r
1706 \r
1707         if( !p_cm_apr )\r
1708         {\r
1709                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
1710                 return IB_INVALID_PARAMETER;\r
1711         }\r
1712 \r
1713         /* Only supported qp types allowed */\r
1714         switch( p_cm_apr->qp_type )\r
1715         {\r
1716         default:\r
1717                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid qp_type.\n") );\r
1718                 return IB_INVALID_SETTING;\r
1719 \r
1720         case IB_QPT_RELIABLE_CONN:\r
1721         case IB_QPT_UNRELIABLE_CONN:\r
1722                 if( AL_OBJ_INVALID_HANDLE( p_cm_apr->h_qp, AL_OBJ_TYPE_H_QP ) ||\r
1723                         (p_cm_apr->h_qp->type != p_cm_apr->qp_type) )\r
1724                 {\r
1725                         AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );\r
1726                         return IB_INVALID_QP_HANDLE;\r
1727                 }\r
1728                 break;\r
1729         }\r
1730 \r
1731         status = al_cep_pre_apr( h_cm_lap.h_al, h_cm_lap.cid, p_cm_apr, &qp_mod );\r
1732         if( status != IB_SUCCESS )\r
1733         {\r
1734                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1735                         ("al_cep_pre_apr returned %s.\n", ib_get_err_str( status )) );\r
1736                 return status;\r
1737         }\r
1738 \r
1739         /* Load alt path into QP */\r
1740         status = ib_modify_qp( h_cm_lap.h_qp, &qp_mod );\r
1741         if( status != IB_SUCCESS )\r
1742         {\r
1743                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1744                         ("ib_modify_qp for LAP returned %s.\n",\r
1745                         ib_get_err_str( status )) );\r
1746                 return status;\r
1747         }\r
1748         \r
1749         status = al_cep_send_apr( h_cm_lap.h_al, h_cm_lap.cid );\r
1750 \r
1751         AL_EXIT( AL_DBG_CM );\r
1752         return status;\r
1753 }\r
1754 \r
1755 \r
1756 ib_api_status_t\r
1757 ib_force_apm(\r
1758         IN              const   ib_qp_handle_t                          h_qp )\r
1759 {\r
1760         ib_api_status_t status;\r
1761         al_conn_qp_t    *p_conn_qp;\r
1762         ib_qp_mod_t             qp_mod;\r
1763 \r
1764         AL_ENTER( AL_DBG_CM );\r
1765 \r
1766         if( AL_OBJ_INVALID_HANDLE( h_qp, AL_OBJ_TYPE_H_QP ) )\r
1767         {\r
1768                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );\r
1769                 return IB_INVALID_QP_HANDLE;\r
1770         }\r
1771 \r
1772         p_conn_qp = PARENT_STRUCT( h_qp, al_conn_qp_t, qp );\r
1773         cl_memclr( &qp_mod, sizeof(ib_qp_mod_t) );\r
1774         qp_mod.req_state = IB_QPS_RTS;\r
1775         qp_mod.state.rts.apm_state = IB_APM_MIGRATED;\r
1776         qp_mod.state.rts.opts = IB_MOD_QP_APM_STATE;\r
1777 \r
1778         /* Set the QP to RTS. */\r
1779         status = ib_modify_qp( h_qp, &qp_mod );\r
1780 \r
1781         AL_EXIT( AL_DBG_CM );\r
1782         return status;\r
1783 }\r
1784 \r
1785 \r
1786 static void\r
1787 __destroying_listen(\r
1788         IN                              al_obj_t*                                       p_obj )\r
1789 {\r
1790         al_listen_t             *p_listen;\r
1791 \r
1792         p_listen = PARENT_STRUCT( p_obj, al_listen_t, obj );\r
1793 \r
1794         /* Destroy the listen's CEP. */\r
1795         al_destroy_cep( p_obj->h_al, &p_listen->cid, TRUE );\r
1796 }\r
1797 \r
1798 \r
1799 \r
1800 static void\r
1801 __free_listen(\r
1802         IN                              al_obj_t*                                       p_obj )\r
1803 {\r
1804         destroy_al_obj( p_obj );\r
1805         cl_free( PARENT_STRUCT( p_obj, al_listen_t, obj ) );\r
1806 }\r
1807 \r
1808 \r
1809 static ib_api_status_t\r
1810 __cep_listen(\r
1811         IN              const   ib_al_handle_t                          h_al,\r
1812         IN              const   ib_cm_listen_t* const           p_cm_listen,\r
1813         IN              const   void* const                                     listen_context,\r
1814                 OUT                     ib_listen_handle_t* const       ph_cm_listen )\r
1815 {\r
1816         ib_api_status_t         status;\r
1817         al_listen_t                     *p_listen;\r
1818         ib_cep_listen_t         cep_listen;\r
1819 \r
1820         AL_ENTER( AL_DBG_CM );\r
1821 \r
1822         /* Allocate the listen object. */\r
1823         p_listen = (al_listen_t*)cl_zalloc( sizeof(al_listen_t) );\r
1824         if( !p_listen )\r
1825         {\r
1826                 AL_EXIT( AL_DBG_CM );\r
1827                 return IB_INSUFFICIENT_MEMORY;\r
1828         }\r
1829 \r
1830         /* Copy the listen request information for matching incoming requests. */\r
1831         p_listen->pfn_cm_req_cb = p_cm_listen->pfn_cm_req_cb;\r
1832 \r
1833         /* valid for ud qp_type only */\r
1834         p_listen->sidr_context = p_cm_listen->sidr_context;\r
1835 \r
1836         construct_al_obj( &p_listen->obj, AL_OBJ_TYPE_H_LISTEN );\r
1837         status = init_al_obj( &p_listen->obj, listen_context, TRUE,\r
1838                 __destroying_listen, NULL, __free_listen );\r
1839         if( status != IB_SUCCESS )\r
1840         {\r
1841                 __free_listen( &p_listen->obj );\r
1842                 AL_EXIT( AL_DBG_CM );\r
1843                 return status;\r
1844         }\r
1845 \r
1846         /* Add the listen to the AL instance's object list. */\r
1847         status = attach_al_obj( &h_al->obj, &p_listen->obj );\r
1848         if( status != IB_SUCCESS )\r
1849         {\r
1850                 p_listen->obj.pfn_destroy( &p_listen->obj, NULL );\r
1851                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1852                         ("attach_al_obj returned %s.\n", ib_get_err_str(status)) );\r
1853                 return status;\r
1854         }\r
1855 \r
1856         /* Create a CEP to listen on. */\r
1857     p_listen->cid = AL_INVALID_CID;\r
1858         status = al_create_cep( h_al, __cm_handler, p_listen, deref_al_obj, &p_listen->cid );\r
1859         if( status != IB_SUCCESS )\r
1860         {\r
1861                 p_listen->obj.pfn_destroy( &p_listen->obj, NULL );\r
1862                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1863                         ("al_create_cep returned %s.\n", ib_get_err_str(status)) );\r
1864                 return status;\r
1865         }\r
1866 \r
1867         /* Take a reference on behalf of the CEP. */\r
1868         ref_al_obj( &p_listen->obj );\r
1869 \r
1870         cep_listen.cmp_len = p_cm_listen->compare_length;\r
1871         cep_listen.cmp_offset = p_cm_listen->compare_offset;\r
1872         cep_listen.p_cmp_buf = p_cm_listen->p_compare_buffer;\r
1873         cep_listen.port_guid = p_cm_listen->port_guid;\r
1874         cep_listen.svc_id = p_cm_listen->svc_id;\r
1875 \r
1876         status = al_cep_listen( h_al, p_listen->cid, &cep_listen );\r
1877         if( status != IB_SUCCESS )\r
1878         {\r
1879                 p_listen->obj.pfn_destroy( &p_listen->obj, NULL );\r
1880                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1881                         ("al_cep_listen returned %s.\n", ib_get_err_str(status)) );\r
1882                 return status;\r
1883         }\r
1884 \r
1885         *ph_cm_listen = p_listen;\r
1886 \r
1887         /* Release the reference taken in init_al_obj. */\r
1888         deref_al_obj( &p_listen->obj );\r
1889 \r
1890         AL_EXIT( AL_DBG_CM );\r
1891         return IB_SUCCESS;\r
1892 }\r
1893 \r
1894 \r
1895 ib_api_status_t\r
1896 ib_cm_listen(\r
1897         IN              const   ib_al_handle_t                          h_al,\r
1898         IN              const   ib_cm_listen_t* const           p_cm_listen,\r
1899         IN              const   void* const                                     listen_context,\r
1900                 OUT                     ib_listen_handle_t* const       ph_cm_listen )\r
1901 {\r
1902         ib_api_status_t         status;\r
1903 \r
1904         AL_ENTER( AL_DBG_CM );\r
1905 \r
1906         if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) )\r
1907         {\r
1908                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AL_HANDLE\n") );\r
1909                 return IB_INVALID_AL_HANDLE;\r
1910         }\r
1911         if( !p_cm_listen || !ph_cm_listen )\r
1912         {\r
1913                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
1914                 return IB_INVALID_PARAMETER;\r
1915         }\r
1916 \r
1917         status = __cep_listen(h_al, p_cm_listen, listen_context, ph_cm_listen );\r
1918 \r
1919         AL_EXIT( AL_DBG_CM );\r
1920         return status;\r
1921 }\r
1922 \r
1923 \r
1924 ib_api_status_t\r
1925 ib_cm_cancel(\r
1926         IN              const   ib_listen_handle_t                      h_cm_listen,\r
1927         IN              const   ib_pfn_destroy_cb_t                     pfn_destroy_cb OPTIONAL )\r
1928 {\r
1929         AL_ENTER( AL_DBG_CM );\r
1930 \r
1931         if( AL_OBJ_INVALID_HANDLE( h_cm_listen, AL_OBJ_TYPE_H_LISTEN ) )\r
1932         {\r
1933                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") );\r
1934                 return IB_INVALID_HANDLE;\r
1935         }\r
1936 \r
1937         ref_al_obj( &h_cm_listen->obj );\r
1938         h_cm_listen->obj.pfn_destroy( &h_cm_listen->obj, pfn_destroy_cb );\r
1939 \r
1940         AL_EXIT( AL_DBG_CM );\r
1941         return IB_SUCCESS;\r
1942 }\r
1943 \r
1944 \r
1945 ib_api_status_t\r
1946 ib_cm_handoff(\r
1947         IN              const   ib_cm_handle_t                          h_cm_req,\r
1948         IN              const   ib_net64_t                                      svc_id )\r
1949 {\r
1950         UNUSED_PARAM( h_cm_req );\r
1951         UNUSED_PARAM( svc_id );\r
1952         return IB_UNSUPPORTED;\r
1953 }\r