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