[DAPL2] DAPL Counters & 2.0.3 extensions to support counter retrieval.
[mirror/winof/.git] / ulp / dapl2 / dapl / common / dapl_ep_util.c
1 /*\r
2  * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved.\r
3  *\r
4  * This Software is licensed under one of the following licenses:\r
5  *\r
6  * 1) under the terms of the "Common Public License 1.0" a copy of which is\r
7  *    available from the Open Source Initiative, see\r
8  *    http://www.opensource.org/licenses/cpl.php.\r
9  *\r
10  * 2) under the terms of the "The BSD License" a copy of which is\r
11  *    available from the Open Source Initiative, see\r
12  *    http://www.opensource.org/licenses/bsd-license.php.\r
13  *\r
14  * 3) under the terms of the "GNU General Public License (GPL) Version 2" a\r
15  *    copy of which is available from the Open Source Initiative, see\r
16  *    http://www.opensource.org/licenses/gpl-license.php.\r
17  *\r
18  * Licensee has the right to choose one of the above licenses.\r
19  *\r
20  * Redistributions of source code must retain the above copyright\r
21  * notice and one of the license notices.\r
22  *\r
23  * Redistributions in binary form must reproduce both the above copyright\r
24  * notice, one of the license notices in the documentation\r
25  * and/or other materials provided with the distribution.\r
26  */\r
27 \r
28 /**********************************************************************\r
29  *\r
30  * MODULE: dapl_ep_util.c\r
31  *\r
32  * PURPOSE: Manage EP Info structure\r
33  *\r
34  * $Id:$\r
35  **********************************************************************/\r
36 \r
37 #include "dapl_ep_util.h"\r
38 #include "dapl_ring_buffer_util.h"\r
39 #include "dapl_cookie.h"\r
40 #include "dapl_adapter_util.h"\r
41 #include "dapl_evd_util.h"\r
42 #include "dapl_cr_util.h"               /* for callback routine */\r
43 \r
44 /*\r
45  * Local definitions\r
46  */\r
47 /*\r
48  * Default number of I/O operations on an end point\r
49  */\r
50 #define IB_IO_DEFAULT   16\r
51 /*\r
52  * Default number of scatter/gather entries available to a single\r
53  * post send/recv\r
54  */\r
55 #define IB_IOV_DEFAULT  4\r
56 \r
57 /*\r
58  * Default number of RDMA operations in progress at a time\r
59  */\r
60 #define IB_RDMA_DEFAULT 4\r
61 \r
62 extern void dapli_ep_default_attrs (\r
63     IN DAPL_EP                  *ep_ptr );\r
64 \r
65 \r
66 \r
67 char *dapl_get_ep_state_str(DAT_EP_STATE state)\r
68 {\r
69     static char *state_str[DAT_EP_STATE_CONNECTED_MULTI_PATH+1] = {\r
70         "DAT_EP_STATE_UNCONNECTED",                  /* quiescent state */\r
71         "DAT_EP_STATE_UNCONFIGURED_UNCONNECTED",\r
72         "DAT_EP_STATE_RESERVED",\r
73         "DAT_EP_STATE_UNCONFIGURED_RESERVED",\r
74         "DAT_EP_STATE_PASSIVE_CONNECTION_PENDING",\r
75         "DAT_EP_STATE_UNCONFIGURED_PASSIVE",\r
76         "DAT_EP_STATE_ACTIVE_CONNECTION_PENDING",\r
77         "DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING",\r
78         "DAT_EP_STATE_UNCONFIGURED_TENTATIVE",\r
79         "DAT_EP_STATE_CONNECTED",\r
80         "DAT_EP_STATE_DISCONNECT_PENDING",\r
81         "DAT_EP_STATE_DISCONNECTED",\r
82         "DAT_EP_STATE_COMPLETION_PENDING",\r
83         "DAT_EP_STATE_CONNECTED_SINGLE_PATH",\r
84         "DAT_EP_STATE_CONNECTED_MULTI_PATH"\r
85      };\r
86      return (state > DAT_EP_STATE_CONNECTED_MULTI_PATH ?\r
87                 "BAD EP STATE" : state_str[state]);\r
88 }\r
89 \r
90 \r
91 /*\r
92  * dapl_ep_alloc\r
93  *\r
94  * alloc and initialize an EP INFO struct\r
95  *\r
96  * Input:\r
97  *      IA INFO struct ptr\r
98  *\r
99  * Output:\r
100  *      ep_ptr\r
101  *\r
102  * Returns:\r
103  *      none\r
104  *\r
105  */\r
106 DAPL_EP *\r
107 dapl_ep_alloc (\r
108         IN DAPL_IA              *ia_ptr,\r
109         IN const DAT_EP_ATTR    *ep_attr )\r
110 {\r
111     DAPL_EP             *ep_ptr;\r
112 \r
113     /* Allocate EP */\r
114     ep_ptr = (DAPL_EP *)dapl_os_alloc (sizeof (DAPL_EP) + sizeof (DAT_SOCK_ADDR));\r
115     if ( ep_ptr == NULL )\r
116     {\r
117         goto bail;\r
118     }\r
119 \r
120     /* zero the structure */\r
121     dapl_os_memzero (ep_ptr, sizeof (DAPL_EP) + sizeof (DAT_SOCK_ADDR));\r
122 \r
123 #ifdef DAPL_COUNTERS\r
124     /* Allocate counters */\r
125     ep_ptr->cntrs = dapl_os_alloc(sizeof(DAT_UINT64) * DCNT_EP_ALL_COUNTERS);\r
126     if (ep_ptr->cntrs == NULL) {\r
127         dapl_os_free(ep_ptr, sizeof (DAPL_EP) + sizeof (DAT_SOCK_ADDR));\r
128         return (NULL);\r
129     }\r
130     dapl_os_memzero (ep_ptr->cntrs, sizeof(DAT_UINT64) * DCNT_EP_ALL_COUNTERS);\r
131 #endif /* DAPL_COUNTERS */\r
132 \r
133     /*\r
134      * initialize the header\r
135      */\r
136     ep_ptr->header.provider            = ia_ptr->header.provider;\r
137     ep_ptr->header.magic               = DAPL_MAGIC_EP;\r
138     ep_ptr->header.handle_type         = DAT_HANDLE_TYPE_EP;\r
139     ep_ptr->header.owner_ia            = ia_ptr;\r
140     ep_ptr->header.user_context.as_64  = 0;\r
141     ep_ptr->header.user_context.as_ptr = NULL;\r
142 \r
143     dapl_llist_init_entry (&ep_ptr->header.ia_list_entry);\r
144     dapl_os_lock_init (&ep_ptr->header.lock);\r
145 \r
146     /*\r
147      * Initialize the body\r
148      */\r
149     /*\r
150      * Set up default parameters if the user passed in a NULL\r
151      */\r
152     if ( ep_attr == NULL )\r
153     {\r
154         dapli_ep_default_attrs (ep_ptr);\r
155     }\r
156     else\r
157     {\r
158         ep_ptr->param.ep_attr = *ep_attr;\r
159     }\r
160 \r
161     /*\r
162      * IBM OS API specific fields\r
163      */\r
164     ep_ptr->qp_handle = IB_INVALID_HANDLE;\r
165     ep_ptr->qpn       = 0;\r
166     ep_ptr->qp_state  = DAPL_QP_STATE_UNATTACHED;\r
167     ep_ptr->cm_handle = IB_INVALID_HANDLE;\r
168 \r
169     if ( DAT_SUCCESS != dapls_cb_create (\r
170              &ep_ptr->req_buffer,\r
171              ep_ptr,\r
172              ep_ptr->param.ep_attr.max_request_dtos) )\r
173     {\r
174         dapl_ep_dealloc (ep_ptr);\r
175         ep_ptr = NULL;\r
176         goto bail;\r
177     }\r
178 \r
179     if ( DAT_SUCCESS != dapls_cb_create (\r
180              &ep_ptr->recv_buffer,\r
181              ep_ptr,\r
182              ep_ptr->param.ep_attr.max_recv_dtos) )\r
183     {\r
184         dapl_ep_dealloc (ep_ptr);\r
185         ep_ptr = NULL;\r
186         goto bail;\r
187     }\r
188 \r
189     dapls_io_trc_alloc (ep_ptr);\r
190 \r
191 bail:\r
192     return ep_ptr;\r
193 }\r
194 \r
195 \r
196 /*\r
197  * dapl_ep_dealloc\r
198  *\r
199  * Free the passed in EP structure.\r
200  *\r
201  * Input:\r
202  *      entry point pointer\r
203  *\r
204  * Output:\r
205  *      none\r
206  *\r
207  * Returns:\r
208  *      none\r
209  *\r
210  */\r
211 void\r
212 dapl_ep_dealloc (\r
213         IN DAPL_EP              *ep_ptr )\r
214 {\r
215     dapl_os_assert (ep_ptr->header.magic == DAPL_MAGIC_EP);\r
216 \r
217     ep_ptr->header.magic = DAPL_MAGIC_INVALID;  /* reset magic to prevent reuse */\r
218 \r
219     dapls_cb_free ( &ep_ptr->req_buffer );\r
220     dapls_cb_free ( &ep_ptr->recv_buffer );\r
221 \r
222     if ( NULL != ep_ptr->cxn_timer )\r
223     {\r
224         dapl_os_free ( ep_ptr->cxn_timer, sizeof ( DAPL_OS_TIMER ) );\r
225     }\r
226 \r
227 #if defined(_WIN32) || defined(_WIN64)\r
228     if ( ep_ptr->ibal_cm_handle )\r
229     {\r
230         dapl_os_free ( ep_ptr->ibal_cm_handle,\r
231                        sizeof ( *ep_ptr->ibal_cm_handle ) );\r
232         ep_ptr->ibal_cm_handle = NULL;\r
233     }\r
234 #endif\r
235 \r
236 #ifdef DAPL_COUNTERS\r
237     dapl_os_free(ep_ptr->cntrs, sizeof(DAT_UINT64) * DCNT_EP_ALL_COUNTERS);\r
238 #endif /* DAPL_COUNTERS */\r
239 \r
240     dapl_os_free (ep_ptr, sizeof (DAPL_EP) + sizeof (DAT_SOCK_ADDR) );\r
241 }\r
242 \r
243 \r
244 /*\r
245  * dapl_ep_default_attrs\r
246  *\r
247  * Set default values in the parameter fields\r
248  *\r
249  * Input:\r
250  *      entry point pointer\r
251  *\r
252  * Output:\r
253  *      none\r
254  *\r
255  * Returns:\r
256  *      none\r
257  *\r
258  */\r
259 void\r
260 dapli_ep_default_attrs (\r
261         IN DAPL_EP              *ep_ptr )\r
262 {\r
263     DAT_EP_ATTR         ep_attr_limit;\r
264     DAT_EP_ATTR         *ep_attr;\r
265     DAT_RETURN          dat_status;\r
266 \r
267     ep_attr = &ep_ptr->param.ep_attr;\r
268     /* Set up defaults */\r
269     dapl_os_memzero (ep_attr, sizeof (DAT_EP_ATTR));\r
270 \r
271     /* mtu and rdma sizes fixed in IB as per IBTA 1.1, 9.4.3, 9.4.4, 9.7.7.  */\r
272     ep_attr->max_mtu_size     = 0x80000000;\r
273     ep_attr->max_rdma_size    = 0x80000000;\r
274 \r
275     ep_attr->qos              = DAT_QOS_BEST_EFFORT;\r
276     ep_attr->service_type     = DAT_SERVICE_TYPE_RC;\r
277     ep_attr->max_recv_dtos    = IB_IO_DEFAULT;\r
278     ep_attr->max_request_dtos = IB_IO_DEFAULT;\r
279     ep_attr->max_recv_iov     = IB_IOV_DEFAULT;\r
280     ep_attr->max_request_iov  = IB_IOV_DEFAULT;\r
281     ep_attr->max_rdma_read_in = IB_RDMA_DEFAULT;\r
282     ep_attr->max_rdma_read_out= IB_RDMA_DEFAULT;\r
283 \r
284     /*\r
285      * Configure the EP as a standard completion type, which will be\r
286      * used by the EVDs. A threshold of 1 is the default state of an\r
287      * EVD.\r
288      */\r
289     ep_attr->request_completion_flags = DAT_COMPLETION_EVD_THRESHOLD_FLAG;\r
290     ep_attr->recv_completion_flags    = DAT_COMPLETION_EVD_THRESHOLD_FLAG;\r
291     /*\r
292      * Unspecified defaults:\r
293      *    - ep_privileges: No RDMA capabilities\r
294      *    - num_transport_specific_params: none\r
295      *    - transport_specific_params: none\r
296      *    - num_provider_specific_params: 0\r
297      *    - provider_specific_params: 0\r
298      */\r
299 \r
300      dat_status = dapls_ib_query_hca (ep_ptr->header.owner_ia->hca_ptr, \r
301                                       NULL, &ep_attr_limit, NULL);\r
302      /* check against HCA maximums */\r
303      if (dat_status == DAT_SUCCESS)\r
304      {\r
305          ep_ptr->param.ep_attr.max_mtu_size =\r
306              DAPL_MIN(ep_ptr->param.ep_attr.max_mtu_size,\r
307                       ep_attr_limit.max_mtu_size);\r
308          ep_ptr->param.ep_attr.max_rdma_size =\r
309              DAPL_MIN(ep_ptr->param.ep_attr.max_rdma_size,\r
310                       ep_attr_limit.max_rdma_size);\r
311          ep_ptr->param.ep_attr.max_recv_dtos =\r
312              DAPL_MIN(ep_ptr->param.ep_attr.max_recv_dtos,\r
313                       ep_attr_limit.max_recv_dtos);\r
314          ep_ptr->param.ep_attr.max_request_dtos =\r
315              DAPL_MIN(ep_ptr->param.ep_attr.max_request_dtos,\r
316                       ep_attr_limit.max_request_dtos);\r
317          ep_ptr->param.ep_attr.max_recv_iov =\r
318              DAPL_MIN(ep_ptr->param.ep_attr.max_recv_iov,\r
319                       ep_attr_limit.max_recv_iov);\r
320          ep_ptr->param.ep_attr.max_request_iov =\r
321              DAPL_MIN(ep_ptr->param.ep_attr.max_request_iov,\r
322                       ep_attr_limit.max_request_iov);\r
323          ep_ptr->param.ep_attr.max_rdma_read_in =\r
324              DAPL_MIN(ep_ptr->param.ep_attr.max_rdma_read_in,\r
325                       ep_attr_limit.max_rdma_read_in);\r
326          ep_ptr->param.ep_attr.max_rdma_read_out =\r
327              DAPL_MIN(ep_ptr->param.ep_attr.max_rdma_read_out,\r
328                       ep_attr_limit.max_rdma_read_out);\r
329      }\r
330 }\r
331 \r
332 \r
333 DAT_RETURN\r
334 dapl_ep_check_recv_completion_flags (\r
335     DAT_COMPLETION_FLAGS        flags )\r
336 {\r
337 \r
338     /*\r
339      * InfiniBand will not allow signal suppression for RECV completions,\r
340      * see the 1.0.1 spec section 10.7.3.1, 10.8.6.\r
341      * N.B. SIGNALLED has a different meaning in dapl than it does\r
342      *      in IB; IB SIGNALLED is the same as DAPL SUPPRESS. DAPL\r
343      *      SIGNALLED simply means the user will not get awakened when\r
344      *      an EVD completes, even though the dapl handler is invoked.\r
345      */\r
346 \r
347     if (flags & DAT_COMPLETION_SUPPRESS_FLAG)\r
348     {\r
349         return DAT_INVALID_PARAMETER;\r
350     }\r
351 \r
352     return DAT_SUCCESS;\r
353 }\r
354 \r
355 DAT_RETURN\r
356 dapl_ep_check_request_completion_flags (\r
357     DAT_COMPLETION_FLAGS        flags )\r
358 {\r
359     return DAT_SUCCESS;\r
360 }\r
361 \r
362 \r
363 DAT_RETURN\r
364 dapl_ep_post_send_req (\r
365     IN  DAT_EP_HANDLE           ep_handle,\r
366     IN  DAT_COUNT               num_segments,\r
367     IN  DAT_LMR_TRIPLET         *local_iov,\r
368     IN  DAT_DTO_COOKIE          user_cookie,\r
369     IN  const DAT_RMR_TRIPLET   *remote_iov,\r
370     IN  DAT_COMPLETION_FLAGS    completion_flags,\r
371     IN  DAPL_DTO_TYPE           dto_type,\r
372     IN  int                     op_type)\r
373 {\r
374     DAPL_EP             *ep_ptr;\r
375     DAPL_COOKIE         *cookie;\r
376     DAT_RETURN          dat_status;\r
377 \r
378     if ( DAPL_BAD_HANDLE (ep_handle, DAPL_MAGIC_EP) )\r
379     {\r
380         dat_status = DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP);\r
381         goto bail;\r
382     }\r
383 \r
384     ep_ptr = (DAPL_EP *) ep_handle;\r
385 \r
386     /*\r
387      * Synchronization ok since this buffer is only used for send\r
388      * requests, which aren't allowed to race with each other.\r
389      */\r
390     dat_status = dapls_dto_cookie_alloc (\r
391                  &ep_ptr->req_buffer,\r
392                  dto_type,\r
393                  user_cookie,\r
394                  &cookie );\r
395     if (dat_status != DAT_SUCCESS) {\r
396         dapl_log(DAPL_DBG_TYPE_ERR,\r
397                  " dapl_post_req resource ERR:"\r
398                  " dtos pending = %d, max_dtos %d, max_cb %d hd %d tl %d\n",\r
399                  dapls_cb_pending(&ep_ptr->req_buffer),\r
400                  ep_ptr->param.ep_attr.max_request_dtos,\r
401                  ep_ptr->req_buffer.pool_size,\r
402                  ep_ptr->req_buffer.head,\r
403                  ep_ptr->req_buffer.tail);\r
404 \r
405         goto bail;\r
406     }\r
407 \r
408     /*\r
409      * Invoke provider specific routine to post DTO\r
410      */\r
411     dat_status = dapls_ib_post_send ( ep_ptr,\r
412                                       op_type,\r
413                                       cookie,\r
414                                       num_segments,\r
415                                       local_iov,\r
416                                       remote_iov,\r
417                                       completion_flags );\r
418 \r
419     if ( dat_status != DAT_SUCCESS )\r
420     {\r
421         dapls_cookie_dealloc (&ep_ptr->req_buffer, cookie);\r
422     }\r
423 \r
424 bail:\r
425     return dat_status;\r
426 }\r
427 \r
428 \r
429 /*\r
430  * dapli_ep_timeout\r
431  *\r
432  * If this routine is invoked before a connection occurs, generate an\r
433  * event\r
434  */\r
435 void\r
436 dapls_ep_timeout (\r
437         uintptr_t                       arg )\r
438 {\r
439     DAPL_EP             *ep_ptr;\r
440     ib_cm_events_t      ib_cm_event;\r
441 \r
442     dapl_dbg_log (DAPL_DBG_TYPE_CM, "--> dapls_ep_timeout! ep %lx\n", arg);\r
443 \r
444     ep_ptr = (DAPL_EP *)arg;\r
445 \r
446     /* reset the EP state */\r
447     ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED;\r
448 \r
449     /* Clean up the EP and put the underlying QP into the ERROR state.\r
450      * The disconnect_clean interface requires the provided dependent \r
451      *cm event number.\r
452      */\r
453     ib_cm_event = dapls_ib_get_cm_event (DAT_CONNECTION_EVENT_DISCONNECTED);\r
454     dapls_ib_disconnect_clean ( ep_ptr,\r
455                                 DAT_TRUE,\r
456                                 ib_cm_event );\r
457 \r
458     (void) dapls_evd_post_connection_event (\r
459                 (DAPL_EVD *)ep_ptr->param.connect_evd_handle,\r
460                 DAT_CONNECTION_EVENT_TIMED_OUT,\r
461                 (DAT_HANDLE) ep_ptr,\r
462                 0,\r
463                 0);\r
464 }\r
465 \r
466 \r
467 /*\r
468  * dapls_ep_state_subtype\r
469  *\r
470  * Return the INVALID_STATE connection subtype associated with an\r
471  * INVALID_STATE on an EP. Strictly for error reporting.\r
472  */\r
473 DAT_RETURN_SUBTYPE\r
474 dapls_ep_state_subtype (\r
475     IN  DAPL_EP                 *ep_ptr )\r
476 {\r
477     DAT_RETURN_SUBTYPE  dat_status;\r
478 \r
479     switch ( ep_ptr->param.ep_state )\r
480     {\r
481         case DAT_EP_STATE_UNCONNECTED:\r
482         {\r
483             dat_status = DAT_INVALID_STATE_EP_UNCONNECTED;\r
484             break;\r
485         }\r
486         case DAT_EP_STATE_RESERVED:\r
487         {\r
488             dat_status = DAT_INVALID_STATE_EP_RESERVED;\r
489             break;\r
490         }\r
491         case DAT_EP_STATE_PASSIVE_CONNECTION_PENDING:\r
492         {\r
493             dat_status = DAT_INVALID_STATE_EP_PASSCONNPENDING;\r
494             break;\r
495         }\r
496         case DAT_EP_STATE_ACTIVE_CONNECTION_PENDING:\r
497         {\r
498             dat_status = DAT_INVALID_STATE_EP_ACTCONNPENDING;\r
499             break;\r
500         }\r
501         case DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING:\r
502         {\r
503             dat_status = DAT_INVALID_STATE_EP_TENTCONNPENDING;\r
504             break;\r
505         }\r
506         case DAT_EP_STATE_CONNECTED:\r
507         {\r
508             dat_status = DAT_INVALID_STATE_EP_CONNECTED;\r
509             break;\r
510         }\r
511         case DAT_EP_STATE_DISCONNECT_PENDING:\r
512         {\r
513             dat_status = DAT_INVALID_STATE_EP_DISCPENDING;\r
514             break;\r
515         }\r
516         case DAT_EP_STATE_DISCONNECTED:\r
517         {\r
518             dat_status = DAT_INVALID_STATE_EP_DISCONNECTED;\r
519             break;\r
520         }\r
521         case DAT_EP_STATE_COMPLETION_PENDING:\r
522         {\r
523             dat_status = DAT_INVALID_STATE_EP_COMPLPENDING;\r
524             break;\r
525         }\r
526 \r
527         default:\r
528         {\r
529             dat_status = 0;\r
530             break;\r
531         }\r
532     }\r
533 \r
534     return dat_status;\r
535 }\r
536 \r
537 #ifdef DAPL_DBG_IO_TRC\r
538 /* allocate trace buffer */\r
539 void\r
540 dapls_io_trc_alloc (\r
541     DAPL_EP             *ep_ptr)\r
542 {\r
543     DAT_RETURN          dat_status;\r
544     int                 i;\r
545     struct io_buf_track *ibt;\r
546 \r
547     ep_ptr->ibt_dumped = 0;             /* bool to control how often we print */\r
548     dat_status = dapls_rbuf_alloc (&ep_ptr->ibt_queue, DBG_IO_TRC_QLEN);\r
549     if (dat_status != DAT_SUCCESS)\r
550     {\r
551         goto bail;\r
552     }\r
553     ibt = (struct io_buf_track *)dapl_os_alloc (sizeof (struct io_buf_track) * DBG_IO_TRC_QLEN);\r
554 \r
555     if (dat_status != DAT_SUCCESS)\r
556     {\r
557         dapls_rbuf_destroy (&ep_ptr->ibt_queue);\r
558         goto bail;\r
559     }\r
560     ep_ptr->ibt_base = ibt;\r
561     dapl_os_memzero (ibt, sizeof (struct io_buf_track) * DBG_IO_TRC_QLEN);\r
562 \r
563     /* add events to free event queue */\r
564     for (i = 0; i < DBG_IO_TRC_QLEN; i++)\r
565     {\r
566         dapls_rbuf_add (&ep_ptr->ibt_queue, ibt++);\r
567     }\r
568 bail:\r
569     return;\r
570 }\r
571 #endif /* DAPL_DBG_IO_TRC */\r
572 \r
573 /*\r
574  * Generate a disconnect event on abruct close for older verbs providers \r
575  * that do not do it automatically.\r
576  */\r
577 \r
578 void\r
579 dapl_ep_legacy_post_disconnect(\r
580     DAPL_EP             *ep_ptr,\r
581     DAT_CLOSE_FLAGS     disconnect_flags)\r
582 {\r
583     ib_cm_events_t      ib_cm_event;\r
584     DAPL_CR             *cr_ptr;\r
585 \r
586     /*\r
587      * Acquire the lock and make sure we didn't get a callback\r
588      * that cleaned up.\r
589      */\r
590     dapl_os_lock ( &ep_ptr->header.lock );\r
591     if (disconnect_flags == DAT_CLOSE_ABRUPT_FLAG &&\r
592         ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECT_PENDING )\r
593     {\r
594         /*\r
595          * If this is an ABRUPT close, the provider will not generate\r
596          * a disconnect message so we do it manually here. Just invoke\r
597          * the CM callback as it will clean up the appropriate\r
598          * data structures, reset the state, and generate the event\r
599          * on the way out. Obtain the provider dependent cm_event to \r
600          * pass into the callback for a disconnect.\r
601          */\r
602         ib_cm_event = dapls_ib_get_cm_event (DAT_CONNECTION_EVENT_DISCONNECTED);\r
603 \r
604         cr_ptr = ep_ptr->cr_ptr;\r
605         dapl_os_unlock ( &ep_ptr->header.lock );\r
606 \r
607         if (cr_ptr != NULL)\r
608         {\r
609             dapl_dbg_log (DAPL_DBG_TYPE_API | DAPL_DBG_TYPE_CM,\r
610                 "    dapl_ep_disconnect force callback on EP %p CM handle %x\n",\r
611                  ep_ptr, cr_ptr->ib_cm_handle);\r
612 \r
613             dapls_cr_callback (cr_ptr->ib_cm_handle,\r
614                                ib_cm_event,\r
615                                NULL,\r
616                                cr_ptr->sp_ptr);\r
617         }\r
618         else\r
619         {\r
620             dapl_evd_connection_callback (ep_ptr->cm_handle,\r
621                                           ib_cm_event,\r
622                                           NULL,\r
623                                           (void *) ep_ptr);\r
624         }\r
625     }\r
626     else\r
627     {\r
628         dapl_os_unlock ( &ep_ptr->header.lock );\r
629     }\r
630 }\r
631 \r
632 /*\r
633  * Local variables:\r
634  *  c-indent-level: 4\r
635  *  c-basic-offset: 4\r
636  *  tab-width: 8\r
637  * End:\r
638  */\r