2 * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.
\r
3 * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved.
\r
5 * This software is available to you under the OpenIB.org BSD license
\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
12 * - Redistributions of source code must retain the above
\r
13 * copyright notice, this list of conditions and the following
\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
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
34 #include <iba/ib_al.h>
\r
37 #include "al_cm_cep.h"
\r
38 #include "al_cm_conn.h"
\r
39 #include "al_cm_sidr.h"
\r
41 #include "al_debug.h"
\r
44 #if defined(EVENT_TRACING)
\r
48 #include "al_cm_qp.tmh"
\r
51 typedef struct _al_listen
\r
56 ib_pfn_cm_req_cb_t pfn_cm_req_cb;
\r
58 /* valid for ud qp_type only */
\r
59 const void* sidr_context;
\r
67 * Structure for queuing received MADs to the asynchronous processing
\r
70 typedef struct _cep_async_mad
\r
72 cl_async_proc_item_t item;
\r
73 ib_al_handle_t h_al;
\r
78 #endif /* CL_KERNEL */
\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
90 IN const ib_qp_handle_t h_qp )
\r
92 uint64_t timewait = 0;
\r
94 ib_api_status_t status;
\r
96 AL_ENTER( AL_DBG_CM );
\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
104 if( al_cep_get_timewait( h_qp->obj.h_al,
\r
105 ((al_conn_qp_t*)h_qp)->cid, &timewait ) == IB_SUCCESS )
\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
112 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );
\r
116 cl_memclr( &qp_mod, sizeof(ib_qp_mod_t) );
\r
117 qp_mod.req_state = IB_QPS_ERROR;
\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
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
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
135 AL_EXIT( AL_DBG_CM );
\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
145 AL_ENTER( AL_DBG_CM );
\r
147 CL_ASSERT( p_req );
\r
148 CL_ASSERT( p_path );
\r
149 CL_ASSERT( p_path_rec );
\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
159 ib_path_rec_init_local( p_path_rec,
\r
160 &p_path->local_gid,
\r
161 &p_path->remote_gid,
\r
163 p_path->remote_lid,
\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
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
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
182 AL_EXIT( AL_DBG_CM );
\r
188 IN const mad_cm_req_t* const p_req,
\r
189 OUT ib_cm_req_rec_t *p_req_rec )
\r
191 AL_ENTER( AL_DBG_CM );
\r
193 CL_ASSERT( p_req );
\r
194 CL_ASSERT( p_req_rec );
\r
196 cl_memclr( p_req_rec, sizeof(ib_cm_req_rec_t) );
\r
198 /* format version specific data */
\r
199 p_req_rec->p_req_pdata = p_req->pdata;
\r
201 p_req_rec->qp_type = conn_req_get_qp_type( p_req );
\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
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
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
218 AL_EXIT( AL_DBG_CM );
\r
222 /******************************************************************************
\r
223 * Functions that handle incoming REQs that matched to an outstanding listen.
\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
234 ib_cm_req_rec_t req_rec;
\r
236 AL_ENTER( AL_DBG_CM );
\r
238 CL_ASSERT( p_listen );
\r
239 CL_ASSERT( new_cid != AL_INVALID_CID );
\r
240 CL_ASSERT( p_req );
\r
242 /* Format the callback record. */
\r
243 __format_req_rec( p_req, &req_rec );
\r
245 /* update listen based rec */
\r
246 req_rec.context = p_listen->obj.context;
\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
252 req_rec.h_cm_listen = p_listen;
\r
254 /* Invoke the user's callback. */
\r
255 p_listen->pfn_cm_req_cb( &req_rec );
\r
257 AL_EXIT( AL_DBG_CM );
\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
267 AL_ENTER( AL_DBG_CM );
\r
269 /* Context is a listen - MAD must be a REQ or SIDR REQ */
\r
270 switch( p_mad->attr_id )
\r
272 case CM_REQ_ATTR_ID:
\r
274 p_listen, new_cid, (mad_cm_req_t*)p_mad );
\r
277 case CM_SIDR_REQ_ATTR_ID:
\r
278 /* TODO - implement SIDR. */
\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
286 AL_EXIT( AL_DBG_CM );
\r
290 /******************************************************************************
\r
291 * Functions that handle send timeouts:
\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
301 __proc_conn_timeout(
\r
302 IN const ib_qp_handle_t h_qp )
\r
304 ib_cm_rej_rec_t rej_rec;
\r
306 AL_ENTER( AL_DBG_CM );
\r
311 * Format the reject record before aborting the connection since
\r
312 * we need the QP context.
\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
319 /* Unbind the QP from the CEP. */
\r
320 __cep_timewait_qp( h_qp );
\r
322 al_destroy_cep( h_qp->obj.h_al, &((al_conn_qp_t*)h_qp)->cid, TRUE );
\r
324 /* Invoke the callback. */
\r
325 ((al_conn_qp_t*)h_qp)->pfn_cm_rej_cb( &rej_rec );
\r
327 AL_EXIT( AL_DBG_CM );
\r
332 * callback to process a LAP timeout due to APR not being received.
\r
335 __proc_lap_timeout(
\r
336 IN const ib_qp_handle_t h_qp )
\r
338 ib_cm_apr_rec_t apr_rec;
\r
340 AL_ENTER( AL_DBG_CM );
\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
351 /* Notify the user that the LAP failed. */
\r
352 ((al_conn_qp_t*)h_qp)->pfn_cm_apr_cb( &apr_rec );
\r
354 AL_EXIT( AL_DBG_CM );
\r
359 * Callback to process a disconnection timeout due to not receiving the DREP
\r
360 * within allowable time.
\r
363 __proc_dconn_timeout(
\r
364 IN const ib_qp_handle_t h_qp )
\r
366 ib_cm_drep_rec_t drep_rec;
\r
368 AL_ENTER( AL_DBG_CM );
\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
376 __cep_timewait_qp( h_qp );
\r
378 al_destroy_cep( h_qp->obj.h_al, &((al_conn_qp_t*)h_qp)->cid, TRUE );
\r
380 /* Call the user back. */
\r
381 ((al_conn_qp_t*)h_qp)->pfn_cm_drep_cb( &drep_rec );
\r
383 AL_EXIT( AL_DBG_CM );
\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
392 AL_ENTER( AL_DBG_CM );
\r
394 /* Failure indicates a send. */
\r
395 switch( p_mad->attr_id )
\r
397 case CM_REQ_ATTR_ID:
\r
398 case CM_REP_ATTR_ID:
\r
399 __proc_conn_timeout( h_qp );
\r
401 case CM_LAP_ATTR_ID:
\r
402 __proc_lap_timeout( h_qp );
\r
404 case CM_DREQ_ATTR_ID:
\r
405 __proc_dconn_timeout( h_qp );
\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
413 AL_EXIT( AL_DBG_CM );
\r
417 /******************************************************************************
\r
418 * Functions that handle received MADs on a connection (not listen)
\r
425 IN const ib_cm_handle_t* const p_cm,
\r
426 IN const mad_cm_req_t* const p_req )
\r
428 ib_cm_req_rec_t req_rec;
\r
430 AL_ENTER( AL_DBG_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
438 /* Format the callback record. */
\r
439 __format_req_rec( p_req, &req_rec );
\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
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
449 AL_EXIT( AL_DBG_CM );
\r
455 IN const ib_cm_handle_t* const p_cm,
\r
456 IN const mad_cm_mra_t* const p_mra )
\r
458 ib_cm_mra_rec_t mra_rec;
\r
460 AL_ENTER( AL_DBG_CM );
\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
465 /* Format the MRA callback record. */
\r
466 cl_memclr( &mra_rec, sizeof(ib_cm_mra_rec_t) );
\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
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
476 ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_mra_cb( &mra_rec );
\r
478 AL_EXIT( AL_DBG_CM );
\r
484 IN const ib_cm_handle_t* const p_cm,
\r
485 IN const mad_cm_rej_t* const p_rej )
\r
487 ib_cm_rej_rec_t rej_rec;
\r
489 AL_ENTER( AL_DBG_CM );
\r
493 /* Format the REJ callback record. */
\r
494 cl_memclr( &rej_rec, sizeof(ib_cm_rej_rec_t) );
\r
496 rej_rec.h_qp = p_cm->h_qp;
\r
497 rej_rec.qp_context = p_cm->h_qp->obj.context;
\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
505 * Unbind the QP from the connection object. This allows the QP to
\r
506 * be immediately reused in another connection request.
\r
508 __cep_timewait_qp( p_cm->h_qp );
\r
510 al_destroy_cep( p_cm->h_al, &((al_conn_qp_t*)p_cm->h_qp)->cid, TRUE );
\r
512 /* Call the user back. */
\r
513 ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_rej_cb( &rej_rec );
\r
516 AL_EXIT( AL_DBG_CM );
\r
522 IN ib_cm_handle_t* const p_cm,
\r
523 IN mad_cm_rep_t* const p_rep )
\r
525 ib_cm_rep_rec_t rep_rec;
\r
527 AL_ENTER( AL_DBG_CM );
\r
529 cl_memclr( &rep_rec, sizeof(ib_cm_rep_rec_t) );
\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
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
541 /* Notify the user of the reply. */
\r
542 ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_rep_cb( &rep_rec );
\r
544 AL_EXIT( AL_DBG_CM );
\r
550 IN ib_cm_handle_t* const p_cm,
\r
551 IN mad_cm_rtu_t* const p_rtu )
\r
553 ib_cm_rtu_rec_t rtu_rec;
\r
555 AL_ENTER( AL_DBG_CM );
\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
561 ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_rtu_cb( &rtu_rec );
\r
563 AL_EXIT( AL_DBG_CM );
\r
569 IN ib_cm_handle_t* const p_cm,
\r
570 IN mad_cm_dreq_t* const p_dreq )
\r
572 ib_cm_dreq_rec_t dreq_rec;
\r
574 AL_ENTER( AL_DBG_CM );
\r
576 cl_memclr( &dreq_rec, sizeof(ib_cm_dreq_rec_t) );
\r
578 dreq_rec.h_cm_dreq = *p_cm;
\r
579 dreq_rec.p_dreq_pdata = p_dreq->pdata;
\r
581 dreq_rec.qp_context = p_cm->h_qp->obj.context;
\r
583 ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_dreq_cb( &dreq_rec );
\r
585 AL_EXIT( AL_DBG_CM );
\r
591 IN ib_cm_handle_t* const p_cm,
\r
592 IN mad_cm_drep_t* const p_drep )
\r
594 ib_cm_drep_rec_t drep_rec;
\r
596 AL_ENTER( AL_DBG_CM );
\r
598 cl_memclr( &drep_rec, sizeof(ib_cm_drep_rec_t) );
\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
606 __cep_timewait_qp( p_cm->h_qp );
\r
608 al_destroy_cep( p_cm->h_al, &((al_conn_qp_t*)p_cm->h_qp)->cid, TRUE );
\r
610 ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_drep_cb( &drep_rec );
\r
612 AL_EXIT( AL_DBG_CM );
\r
618 IN ib_cm_handle_t* const p_cm,
\r
619 IN const mad_cm_lap_t* const p_lap )
\r
621 ib_cm_lap_rec_t lap_rec;
\r
622 const lap_path_info_t* const p_path = &p_lap->alternate_path;
\r
624 AL_ENTER( AL_DBG_CM );
\r
627 CL_ASSERT( p_cm->h_qp );
\r
628 CL_ASSERT( p_lap );
\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
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
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
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
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
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
665 lap_rec.alt_path.tclass =
\r
666 conn_lap_path_get_tclass( &p_lap->alternate_path );
\r
669 ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_lap_cb( &lap_rec );
\r
671 AL_EXIT( AL_DBG_CM );
\r
675 static ib_api_status_t
\r
677 IN ib_cm_handle_t* const p_cm )
\r
679 ib_api_status_t status;
\r
680 ib_qp_mod_t qp_mod;
\r
682 AL_ENTER( AL_DBG_CM );
\r
684 status = al_cep_get_rts_attr( p_cm->h_al, p_cm->cid, &qp_mod );
\r
685 if( status != IB_SUCCESS )
\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
692 status = ib_modify_qp( p_cm->h_qp, &qp_mod );
\r
693 if( status != IB_SUCCESS )
\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
700 AL_EXIT( AL_DBG_CM );
\r
707 IN ib_cm_handle_t* const p_cm,
\r
708 IN mad_cm_apr_t* const p_apr )
\r
710 ib_cm_apr_rec_t apr_rec;
\r
712 AL_ENTER( AL_DBG_CM );
\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
721 if( apr_rec.apr_status == IB_AP_SUCCESS )
\r
723 apr_rec.cm_status = __cep_lap_qp( p_cm );
\r
727 apr_rec.cm_status = IB_ERROR;
\r
730 ((al_conn_qp_t*)p_cm->h_qp)->pfn_cm_apr_cb( &apr_rec );
\r
732 AL_EXIT( AL_DBG_CM );
\r
738 IN ib_cm_handle_t* const p_cm,
\r
739 IN ib_mad_t* const p_mad )
\r
741 AL_ENTER( AL_DBG_CM );
\r
743 /* Success indicates a receive. */
\r
744 switch( p_mad->attr_id )
\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
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
760 case CM_REJ_ATTR_ID:
\r
761 __proc_rej( p_cm, (mad_cm_rej_t*)p_mad );
\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
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
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
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
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
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
804 //case CM_SIDR_REQ_ATTR_ID:
\r
805 // p_async_mad->item.pfn_callback = __process_cm_sidr_req;
\r
808 //case CM_SIDR_REP_ATTR_ID:
\r
809 // p_async_mad->item.pfn_callback = __process_cm_sidr_rep;
\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
817 AL_EXIT( AL_DBG_CM );
\r
820 /******************************************************************************
\r
821 * CEP callback handler.
\r
832 IN const ib_al_handle_t h_al,
\r
833 IN const net32_t cid )
\r
835 ib_api_status_t status;
\r
838 ib_mad_element_t *p_mad;
\r
839 ib_cm_handle_t h_cm;
\r
841 AL_ENTER( AL_DBG_CM );
\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
847 /* Something to do - WOOT!!! */
\r
848 if( new_cid != AL_INVALID_CID )
\r
850 __proc_listen( (al_listen_t*)context,
\r
851 new_cid, ib_get_mad_buf( p_mad ) );
\r
853 else if( p_mad->status != IB_SUCCESS )
\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
863 h_cm.h_qp = (ib_qp_handle_t)context;
\r
864 __proc_conn( &h_cm, ib_get_mad_buf( p_mad ) );
\r
866 ib_put_mad( p_mad );
\r
874 __process_cep_async(
\r
875 IN cl_async_proc_item_t *p_item )
\r
877 cep_async_mad_t *p_async_mad;
\r
879 AL_ENTER( AL_DBG_CM );
\r
881 p_async_mad = PARENT_STRUCT( p_item, cep_async_mad_t, item );
\r
883 __process_cep_cb( p_async_mad->h_al, p_async_mad->cid );
\r
885 cl_free( p_async_mad );
\r
887 AL_EXIT( AL_DBG_CM );
\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
898 IN const ib_al_handle_t h_al,
\r
899 IN const net32_t cid )
\r
901 cep_async_mad_t *p_async_mad;
\r
903 AL_ENTER( AL_DBG_CM );
\r
905 p_async_mad = (cep_async_mad_t*)cl_zalloc( sizeof(cep_async_mad_t) );
\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
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
918 /* Queue the MAD for asynchronous processing. */
\r
919 cl_async_proc_queue( gp_async_proc_mgr, &p_async_mad->item );
\r
921 AL_EXIT( AL_DBG_CM );
\r
923 #endif /* CL_KERNEL */
\r
927 * Transition the QP to the INIT state, if it is not already in the
\r
932 IN const ib_qp_handle_t h_qp,
\r
933 IN ib_qp_mod_t* const p_init )
\r
935 ib_qp_mod_t qp_mod;
\r
936 ib_api_status_t status;
\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
944 if( h_qp->state != IB_QPS_INIT )
\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
950 status = ib_modify_qp( h_qp, &qp_mod );
\r
951 if( status != IB_SUCCESS )
\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
958 /* Initialize the QP. */
\r
959 status = ib_modify_qp( h_qp, p_init );
\r
960 if( status != IB_SUCCESS )
\r
962 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,
\r
963 ("ib_modify_qp returned %s.\n", ib_get_err_str(status) ) );
\r
971 static ib_api_status_t
\r
973 IN const ib_cm_req_t* const p_cm_req )
\r
975 ib_api_status_t status;
\r
976 ib_qp_mod_t qp_mod;
\r
978 AL_ENTER( AL_DBG_CM );
\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
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
989 /* Transition QP through state machine */
\r
991 * Warning! Using all access rights. We need to modify
\r
992 * the ib_cm_req_t to include this.
\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
999 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,
\r
1000 ("__cep_init_qp returned %s\n", ib_get_err_str(status)) );
\r
1004 AL_EXIT( AL_DBG_CM );
\r
1005 return IB_SUCCESS;
\r
1009 static ib_api_status_t
\r
1011 IN const ib_al_handle_t h_al,
\r
1012 IN const ib_cm_req_t* const p_cm_req )
\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
1020 AL_ENTER( AL_DBG_CM );
\r
1022 /* event based mechanism */
\r
1023 if( p_cm_req->flags & IB_FLAGS_SYNC )
\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
1031 // __deref_conn( p_conn );
\r
1032 // return ib_convert_cl_status( cl_status );
\r
1034 //p_conn->p_sync_event = p_sync_event = &sync_event;
\r
1037 p_qp = (al_conn_qp_t*)p_cm_req->h_qp;
\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
1043 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,
\r
1044 ("al_create_cep returned %s.\n", ib_get_err_str( status )) );
\r
1048 /* Take a reference on behalf of the CEP. */
\r
1049 ref_al_obj( &p_qp->qp.obj );
\r
1051 status = __cep_pre_req( p_cm_req );
\r
1052 if( status != IB_SUCCESS )
\r
1054 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,
\r
1055 ("__cep_pre_req returned %s.\n", ib_get_err_str( status )) );
\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
1065 /* Send the REQ. */
\r
1066 status = al_cep_send_req( h_al, p_qp->cid );
\r
1067 if( status != IB_SUCCESS )
\r
1069 //if( p_sync_event )
\r
1070 // cl_event_destroy( p_sync_event );
\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
1075 al_destroy_cep( h_al, &p_qp->cid, TRUE );
\r
1078 /* wait on event if synchronous operation */
\r
1079 //if( p_sync_event )
\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
1085 // cl_event_destroy( p_sync_event );
\r
1089 AL_EXIT( AL_DBG_CM );
\r
1096 IN const ib_cm_req_t* const p_cm_req )
\r
1098 ib_api_status_t status;
\r
1100 AL_ENTER( AL_DBG_CM );
\r
1104 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );
\r
1105 return IB_INVALID_PARAMETER;
\r
1108 /* Only supported qp types allowed */
\r
1109 switch( p_cm_req->qp_type )
\r
1112 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid qp_type.\n") );
\r
1113 return IB_INVALID_SETTING;
\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
1120 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );
\r
1121 return IB_INVALID_QP_HANDLE;
\r
1124 status = __cep_conn_req( qp_get_al( p_cm_req->h_qp ), p_cm_req );
\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
1130 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AL_HANDLE\n") );
\r
1131 return IB_INVALID_AL_HANDLE;
\r
1133 status = IB_UNSUPPORTED;
\r
1134 // status = cm_sidr_req( p_cm_req->h_al, p_cm_req );
\r
1138 AL_EXIT( AL_DBG_CM );
\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
1148 static ib_api_status_t
\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
1156 ib_api_status_t status;
\r
1157 ib_qp_mod_t qp_mod;
\r
1159 AL_ENTER( AL_DBG_CM );
\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
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
1172 qp_mod.state.rtr.access_ctrl = access_ctrl;
\r
1173 qp_mod.state.rtr.opts |= IB_MOD_QP_ACCESS_CTRL;
\r
1178 qp_mod.state.rtr.sq_depth = sq_depth;
\r
1179 qp_mod.state.rtr.opts |= IB_MOD_QP_SQ_DEPTH;
\r
1184 qp_mod.state.rtr.rq_depth = rq_depth;
\r
1185 qp_mod.state.rtr.opts |= IB_MOD_QP_RQ_DEPTH;
\r
1188 status = ib_modify_qp( h_qp, &qp_mod );
\r
1189 if( status != IB_SUCCESS )
\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
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
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
1205 status = ib_modify_qp( h_qp, &qp_mod );
\r
1206 if( status != IB_SUCCESS )
\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
1213 AL_EXIT( AL_DBG_CM );
\r
1214 return IB_SUCCESS;
\r
1218 static ib_api_status_t
\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
1224 ib_api_status_t status;
\r
1226 AL_ENTER( AL_DBG_CM );
\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
1233 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,
\r
1234 ("cm_init_qp returned %s.\n", ib_get_err_str(status)) );
\r
1238 /* Prepost receives. */
\r
1239 if( p_cm_rep->p_recv_wr )
\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
1245 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,
\r
1246 ("ib_post_recv returned %s.\n", ib_get_err_str(status)) );
\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
1256 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,
\r
1257 ("__cep_rts_qp returned %s.\n", ib_get_err_str(status)) );
\r
1260 AL_EXIT( AL_DBG_CM );
\r
1265 static ib_api_status_t
\r
1267 IN ib_cm_handle_t h_cm,
\r
1268 IN const ib_cm_rep_t* const p_cm_rep )
\r
1270 ib_api_status_t status;
\r
1271 ib_qp_mod_t qp_mod;
\r
1273 AL_ENTER( AL_DBG_CM );
\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
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
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
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
1297 /* Take a reference on behalf of the CEP. */
\r
1298 ref_al_obj( &p_cm_rep->h_qp->obj );
\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
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
1311 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,
\r
1312 ("__cep_pre_req returned %s\n", ib_get_err_str(status)) );
\r
1316 status = al_cep_send_rep( h_cm.h_al, h_cm.cid );
\r
1317 if( status != IB_SUCCESS )
\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
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
1326 h_cm.h_al, &((al_conn_qp_t*)p_cm_rep->h_qp)->cid, TRUE );
\r
1329 AL_EXIT( AL_DBG_CM );
\r
1336 IN const ib_cm_handle_t h_cm_req,
\r
1337 IN const ib_cm_rep_t* const p_cm_rep )
\r
1339 ib_api_status_t status;
\r
1342 AL_ENTER( AL_DBG_CM );
\r
1346 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );
\r
1347 return IB_INVALID_PARAMETER;
\r
1350 /* Only supported qp types allowed */
\r
1351 status = IB_SUCCESS;
\r
1352 switch( p_cm_rep->qp_type )
\r
1355 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid qp_type.\n") );
\r
1356 status = IB_INVALID_SETTING;
\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
1364 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );
\r
1365 status = IB_INVALID_QP_HANDLE;
\r
1367 else if( p_cm_rep->h_qp->obj.h_al != h_cm_req.h_al )
\r
1369 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );
\r
1370 status = IB_INVALID_QP_HANDLE;
\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
1379 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );
\r
1380 status = IB_INVALID_QP_HANDLE;
\r
1385 if( status != IB_SUCCESS )
\r
1387 cid = h_cm_req.cid;
\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
1392 AL_EXIT( AL_DBG_CM );
\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
1399 status = __cep_conn_rep( h_cm_req, p_cm_rep );
\r
1401 AL_EXIT( AL_DBG_CM );
\r
1408 IN const ib_cm_handle_t h_cm_rep,
\r
1409 IN const ib_cm_rtu_t* const p_cm_rtu )
\r
1411 ib_api_status_t status;
\r
1413 AL_ENTER( AL_DBG_CM );
\r
1417 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );
\r
1418 return IB_INVALID_PARAMETER;
\r
1422 // * Call invalid if event is still processed.
\r
1423 // * User may have called rtu in rep callback.
\r
1425 //if( p_conn->p_sync_event )
\r
1427 // AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,
\r
1428 // ("Connection in invalid state. Sync call in progress.\n" ) );
\r
1430 // cm_res_release( p_conn );
\r
1431 // __deref_conn( p_conn );
\r
1432 // return IB_INVALID_STATE;
\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
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
1442 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,
\r
1443 ("__cep_rts_qp returned %s.\n", ib_get_err_str( status )) );
\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
1452 /* Reject and abort the connection. */
\r
1454 h_cm_rep.h_al, h_cm_rep.cid, IB_REJ_INSUF_QP, NULL, 0, NULL, 0 );
\r
1456 __cep_timewait_qp( h_cm_rep.h_qp );
\r
1459 h_cm_rep.h_al, &((al_conn_qp_t*)h_cm_rep.h_qp)->cid, TRUE );
\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
1466 AL_EXIT( AL_DBG_CM );
\r
1473 IN const ib_cm_handle_t h_cm,
\r
1474 IN const ib_cm_mra_t* const p_cm_mra )
\r
1476 ib_api_status_t status;
\r
1478 AL_ENTER( AL_DBG_CM );
\r
1482 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );
\r
1483 return IB_INVALID_PARAMETER;
\r
1486 status = al_cep_mra( h_cm.h_al, h_cm.cid, p_cm_mra );
\r
1487 if( status != IB_SUCCESS )
\r
1489 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,
\r
1490 ("al_cep_mra returned %s\n", ib_get_err_str( status )) );
\r
1493 AL_EXIT( AL_DBG_CM );
\r
1500 IN const ib_cm_handle_t h_cm,
\r
1501 IN const ib_cm_rej_t* const p_cm_rej )
\r
1503 ib_api_status_t status;
\r
1506 AL_ENTER( AL_DBG_CM );
\r
1510 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );
\r
1511 return IB_INVALID_PARAMETER;
\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
1520 __cep_timewait_qp( h_cm.h_qp );
\r
1523 h_cm.h_al, &((al_conn_qp_t*)h_cm.h_qp)->cid, TRUE );
\r
1528 al_destroy_cep( h_cm.h_al, &cid, FALSE );
\r
1531 AL_EXIT( AL_DBG_CM );
\r
1538 IN const ib_cm_dreq_t* const p_cm_dreq )
\r
1540 ib_api_status_t status;
\r
1542 AL_ENTER( AL_DBG_CM );
\r
1546 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );
\r
1547 return IB_INVALID_PARAMETER;
\r
1550 /* Only supported qp types allowed */
\r
1551 switch( p_cm_dreq->qp_type )
\r
1554 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid qp_type.\n") );
\r
1555 return IB_INVALID_SETTING;
\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
1562 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );
\r
1563 return IB_INVALID_QP_HANDLE;
\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
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
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
1585 /* Wait for the DREP or timeout. */
\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
1596 __cep_timewait_qp( p_cm_dreq->h_qp );
\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
1603 AL_EXIT( AL_DBG_CM );
\r
1611 IN const ib_cm_handle_t h_cm_dreq,
\r
1612 IN const ib_cm_drep_t* const p_cm_drep )
\r
1614 ib_api_status_t status;
\r
1616 AL_ENTER( AL_DBG_CM );
\r
1620 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );
\r
1621 return IB_INVALID_PARAMETER;
\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
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
1637 * Some other out-of-resource error - continue as if we succeeded in
\r
1638 * sending the DREP.
\r
1640 status = IB_SUCCESS;
\r
1641 /* Fall through */
\r
1643 __cep_timewait_qp( h_cm_dreq.h_qp );
\r
1645 al_destroy_cep( h_cm_dreq.h_al,
\r
1646 &((al_conn_qp_t*)h_cm_dreq.h_qp)->cid, TRUE );
\r
1649 AL_EXIT( AL_DBG_CM );
\r
1656 IN const ib_cm_lap_t* const p_cm_lap )
\r
1658 ib_api_status_t status;
\r
1660 AL_ENTER( AL_DBG_CM );
\r
1664 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );
\r
1665 return IB_INVALID_PARAMETER;
\r
1668 /* Only supported qp types allowed */
\r
1669 switch( p_cm_lap->qp_type )
\r
1672 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid qp_type.\n") );
\r
1673 return IB_INVALID_SETTING;
\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
1680 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );
\r
1681 return IB_INVALID_QP_HANDLE;
\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
1690 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,
\r
1691 ("al_cep_lap returned %s.\n", ib_get_err_str( status )) );
\r
1694 AL_EXIT( AL_DBG_CM );
\r
1701 IN const ib_cm_handle_t h_cm_lap,
\r
1702 IN const ib_cm_apr_t* const p_cm_apr )
\r
1704 ib_api_status_t status;
\r
1705 ib_qp_mod_t qp_mod;
\r
1707 AL_ENTER( AL_DBG_CM );
\r
1711 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );
\r
1712 return IB_INVALID_PARAMETER;
\r
1715 /* Only supported qp types allowed */
\r
1716 switch( p_cm_apr->qp_type )
\r
1719 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid qp_type.\n") );
\r
1720 return IB_INVALID_SETTING;
\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
1727 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );
\r
1728 return IB_INVALID_QP_HANDLE;
\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
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
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
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
1751 status = al_cep_send_apr( h_cm_lap.h_al, h_cm_lap.cid );
\r
1753 AL_EXIT( AL_DBG_CM );
\r
1760 IN const ib_qp_handle_t h_qp )
\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
1766 AL_ENTER( AL_DBG_CM );
\r
1768 if( AL_OBJ_INVALID_HANDLE( h_qp, AL_OBJ_TYPE_H_QP ) )
\r
1770 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_QP_HANDLE\n") );
\r
1771 return IB_INVALID_QP_HANDLE;
\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
1780 /* Set the QP to RTS. */
\r
1781 status = ib_modify_qp( h_qp, &qp_mod );
\r
1783 AL_EXIT( AL_DBG_CM );
\r
1789 __destroying_listen(
\r
1790 IN al_obj_t* p_obj )
\r
1792 al_listen_t *p_listen;
\r
1794 p_listen = PARENT_STRUCT( p_obj, al_listen_t, obj );
\r
1796 /* Destroy the listen's CEP. */
\r
1797 al_destroy_cep( p_obj->h_al, &p_listen->cid, TRUE );
\r
1804 IN al_obj_t* p_obj )
\r
1806 destroy_al_obj( p_obj );
\r
1807 cl_free( PARENT_STRUCT( p_obj, al_listen_t, obj ) );
\r
1811 static ib_api_status_t
\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
1818 ib_api_status_t status;
\r
1819 al_listen_t *p_listen;
\r
1820 ib_cep_listen_t cep_listen;
\r
1822 AL_ENTER( AL_DBG_CM );
\r
1824 /* Allocate the listen object. */
\r
1825 p_listen = (al_listen_t*)cl_zalloc( sizeof(al_listen_t) );
\r
1828 AL_EXIT( AL_DBG_CM );
\r
1829 return IB_INSUFFICIENT_MEMORY;
\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
1835 /* valid for ud qp_type only */
\r
1836 p_listen->sidr_context = p_cm_listen->sidr_context;
\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
1843 __free_listen( &p_listen->obj );
\r
1844 AL_EXIT( AL_DBG_CM );
\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
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
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
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
1869 /* Take a reference on behalf of the CEP. */
\r
1870 ref_al_obj( &p_listen->obj );
\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
1878 status = al_cep_listen( h_al, p_listen->cid, &cep_listen );
\r
1879 if( status != IB_SUCCESS )
\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
1887 *ph_cm_listen = p_listen;
\r
1889 /* Release the reference taken in init_al_obj. */
\r
1890 deref_al_obj( &p_listen->obj );
\r
1892 AL_EXIT( AL_DBG_CM );
\r
1893 return IB_SUCCESS;
\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
1904 ib_api_status_t status;
\r
1906 AL_ENTER( AL_DBG_CM );
\r
1908 if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) )
\r
1910 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AL_HANDLE\n") );
\r
1911 return IB_INVALID_AL_HANDLE;
\r
1913 if( !p_cm_listen || !ph_cm_listen )
\r
1915 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );
\r
1916 return IB_INVALID_PARAMETER;
\r
1919 status = __cep_listen(h_al, p_cm_listen, listen_context, ph_cm_listen );
\r
1921 AL_EXIT( AL_DBG_CM );
\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
1931 AL_ENTER( AL_DBG_CM );
\r
1933 if( AL_OBJ_INVALID_HANDLE( h_cm_listen, AL_OBJ_TYPE_H_LISTEN ) )
\r
1935 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") );
\r
1936 return IB_INVALID_HANDLE;
\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
1942 AL_EXIT( AL_DBG_CM );
\r
1943 return IB_SUCCESS;
\r
1949 IN const ib_cm_handle_t h_cm_req,
\r
1950 IN const ib_net64_t svc_id )
\r
1952 UNUSED_PARAM( h_cm_req );
\r
1953 UNUSED_PARAM( svc_id );
\r
1954 return IB_UNSUPPORTED;
\r