[DAPL2] DAPL Counters & 2.0.3 extensions to support counter retrieval.
[mirror/winof/.git] / ulp / dapl2 / dapl / common / dapl_evd_util.c
1 /*\r
2  * Copyright (c) 2002-2005, 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  *    in the file LICENSE.txt in the root directory. The license is also\r
8  *    available from the Open Source Initiative, see\r
9  *    http://www.opensource.org/licenses/cpl.php.\r
10  *\r
11  * 2) under the terms of the "The BSD License" a copy of which is in the file\r
12  *    LICENSE2.txt in the root directory. The license is also available from\r
13  *    the Open Source Initiative, see\r
14  *    http://www.opensource.org/licenses/bsd-license.php.\r
15  *\r
16  * 3) under the terms of the "GNU General Public License (GPL) Version 2" a \r
17  *    copy of which is in the file LICENSE3.txt in the root directory. The \r
18  *    license is also available from the Open Source Initiative, see\r
19  *    http://www.opensource.org/licenses/gpl-license.php.\r
20  *\r
21  * Licensee has the right to choose one of the above licenses.\r
22  *\r
23  * Redistributions of source code must retain the above copyright\r
24  * notice and one of the license notices.\r
25  *\r
26  * Redistributions in binary form must reproduce both the above copyright\r
27  * notice, one of the license notices in the documentation\r
28  * and/or other materials provided with the distribution.\r
29  */\r
30 \r
31 /**********************************************************************\r
32  *\r
33  * MODULE: dapl_evd_util.c\r
34  *\r
35  * PURPOSE: Manage EVD Info structure\r
36  *\r
37  * $Id: dapl_evd_util.c 1410 2006-07-19 17:12:02Z ardavis $\r
38  **********************************************************************/\r
39 \r
40 #include "dapl_evd_util.h"\r
41 #include "dapl_ia_util.h"\r
42 #include "dapl_cno_util.h"\r
43 #include "dapl_ring_buffer_util.h"\r
44 #include "dapl_adapter_util.h"\r
45 #include "dapl_cookie.h"\r
46 #include "dapl.h"\r
47 \r
48 #ifdef __linux__\r
49 #include <sys/socket.h>\r
50 #include <netinet/in.h>\r
51 #include <arpa/inet.h>\r
52 #endif\r
53 \r
54 STATIC _INLINE_ void dapli_evd_eh_print_cqe (\r
55         IN  ib_work_completion_t        *cqe);\r
56 \r
57 DAT_RETURN dapli_evd_event_alloc (\r
58         IN  DAPL_EVD            *evd_ptr,\r
59         IN  DAT_COUNT           qlen);\r
60 \r
61 \r
62 char *dapl_event_str( IN DAT_EVENT_NUMBER  event_num )\r
63 {\r
64 #if defined(DAPL_DBG)\r
65     struct dat_event_str { char *str; DAT_EVENT_NUMBER num;};\r
66     static struct dat_event_str events[] = {\r
67     {"DAT_DTO_COMPLETION_EVENT", DAT_DTO_COMPLETION_EVENT},\r
68     {"DAT_RMR_BIND_COMPLETION_EVENT", DAT_RMR_BIND_COMPLETION_EVENT},\r
69     {"DAT_CONNECTION_REQUEST_EVENT", DAT_CONNECTION_REQUEST_EVENT},\r
70     {"DAT_CONNECTION_EVENT_ESTABLISHED", DAT_CONNECTION_EVENT_ESTABLISHED},\r
71     {"DAT_CONNECTION_EVENT_PEER_REJECTED", DAT_CONNECTION_EVENT_PEER_REJECTED},\r
72     {"DAT_CONNECTION_EVENT_NON_PEER_REJECTED", DAT_CONNECTION_EVENT_NON_PEER_REJECTED},\r
73     {"DAT_CONNECTION_EVENT_ACCEPT_COMPLETION_ERROR", DAT_CONNECTION_EVENT_ACCEPT_COMPLETION_ERROR},\r
74     {"DAT_CONNECTION_EVENT_DISCONNECTED", DAT_CONNECTION_EVENT_DISCONNECTED},\r
75     {"DAT_CONNECTION_EVENT_BROKEN", DAT_CONNECTION_EVENT_BROKEN},\r
76     {"DAT_CONNECTION_EVENT_TIMED_OUT", DAT_CONNECTION_EVENT_TIMED_OUT},\r
77     {"DAT_CONNECTION_EVENT_UNREACHABLE", DAT_CONNECTION_EVENT_UNREACHABLE},\r
78     {"DAT_ASYNC_ERROR_EVD_OVERFLOW", DAT_ASYNC_ERROR_EVD_OVERFLOW},\r
79     {"DAT_ASYNC_ERROR_IA_CATASTROPHIC", DAT_ASYNC_ERROR_IA_CATASTROPHIC},\r
80     {"DAT_ASYNC_ERROR_EP_BROKEN", DAT_ASYNC_ERROR_EP_BROKEN},\r
81     {"DAT_ASYNC_ERROR_TIMED_OUT", DAT_ASYNC_ERROR_TIMED_OUT},\r
82     {"DAT_ASYNC_ERROR_PROVIDER_INTERNAL_ERROR", DAT_ASYNC_ERROR_PROVIDER_INTERNAL_ERROR},\r
83     {"DAT_HA_DOWN_TO_1", DAT_HA_DOWN_TO_1},\r
84     {"DAT_HA_UP_TO_MULTI_PATH", DAT_HA_UP_TO_MULTI_PATH},\r
85     {"DAT_SOFTWARE_EVENT", DAT_SOFTWARE_EVENT},\r
86 #ifdef DAT_EXTENSIONS\r
87     {"DAT_EXTENSION_EVENT", DAT_EXTENSION_EVENT},\r
88     {"DAT_IB_EXTENSION_RANGE_BASE", DAT_IB_EXTENSION_RANGE_BASE},\r
89     {"DAT_IW_EXTENSION_RANGE_BASE", DAT_IW_EXTENSION_RANGE_BASE},\r
90 #endif /* DAT_EXTENSIONS */\r
91     {NULL,0},\r
92     };\r
93     int i;\r
94 \r
95     for(i=0; events[i].str; i++)\r
96     {\r
97         if (events[i].num == event_num)\r
98             return events[i].str;\r
99     }\r
100     return "Unknown DAT event?";\r
101 #else\r
102     static char str[16];\r
103     sprintf(str,"%x",event_num);\r
104     return str;\r
105 #endif\r
106 }\r
107 \r
108 /*\r
109  * dapls_evd_internal_create\r
110  *\r
111  * actually create the evd.  this is called after all parameter checking\r
112  * has been performed in dapl_ep_create.  it is also called from dapl_ia_open\r
113  * to create the default async evd.\r
114  *\r
115  * Input:\r
116  *      ia_ptr\r
117  *      cno_ptr\r
118  *      qlen\r
119  *      evd_flags\r
120  *\r
121  * Output:\r
122  *      evd_ptr_ptr\r
123  *\r
124  * Returns:\r
125  *      none\r
126  *\r
127  */\r
128 \r
129 DAT_RETURN\r
130 dapls_evd_internal_create (\r
131     DAPL_IA             *ia_ptr,\r
132     DAPL_CNO            *cno_ptr,\r
133     DAT_COUNT           min_qlen,\r
134     DAT_EVD_FLAGS       evd_flags,\r
135     DAPL_EVD            **evd_ptr_ptr)\r
136 {\r
137     DAPL_EVD    *evd_ptr;\r
138     DAT_COUNT   cq_len;\r
139     DAT_RETURN  dat_status;\r
140 \r
141     dat_status   = DAT_SUCCESS;\r
142     *evd_ptr_ptr = NULL;\r
143     cq_len       = min_qlen;\r
144 \r
145     evd_ptr = dapls_evd_alloc (ia_ptr,\r
146                                cno_ptr,\r
147                                evd_flags,\r
148                                min_qlen);\r
149     if (!evd_ptr)\r
150     {\r
151         dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY);\r
152         goto bail;\r
153     }\r
154 \r
155     /*\r
156      * If we are dealing with event streams besides a CQ event stream,\r
157      * be conservative and set producer side locking.  Otherwise, no.\r
158      */\r
159     evd_ptr->evd_producer_locking_needed =\r
160         ((evd_flags & ~ (DAT_EVD_DTO_FLAG|DAT_EVD_RMR_BIND_FLAG)) != 0);\r
161 \r
162     /* Before we setup any callbacks, transition state to OPEN.  */\r
163     evd_ptr->evd_state = DAPL_EVD_STATE_OPEN;\r
164 \r
165     if (evd_flags & DAT_EVD_ASYNC_FLAG)\r
166     {\r
167         /*\r
168          * There is no cq associate with async evd. Set it to invalid\r
169          */\r
170         evd_ptr->ib_cq_handle = IB_INVALID_HANDLE;\r
171 \r
172     }\r
173     else if ( 0 != (evd_flags & ~ (DAT_EVD_SOFTWARE_FLAG\r
174                                    | DAT_EVD_CONNECTION_FLAG\r
175                                    | DAT_EVD_CR_FLAG) ) )\r
176     {\r
177 #if defined(_VENDOR_IBAL_)\r
178         /* \r
179          * The creation of CQ required a PD (PZ) associated with it and\r
180          * we do not have a PD here; therefore, the work-around is that we\r
181          * will postpone the creation of the cq till the creation of QP which\r
182          * this cq will associate with.\r
183          */\r
184         evd_ptr->ib_cq_handle = IB_INVALID_HANDLE;\r
185 #else\r
186         dat_status = dapls_ib_cq_alloc (ia_ptr,\r
187                                         evd_ptr,\r
188                                         &cq_len);\r
189         if (dat_status != DAT_SUCCESS)\r
190         {\r
191             goto bail;\r
192         }\r
193 \r
194         /* Now reset the cq_len in the attributes, it may have changed */\r
195         evd_ptr->qlen = cq_len;\r
196 \r
197         dat_status =\r
198             dapls_ib_setup_async_callback (\r
199                                    ia_ptr,\r
200                                    DAPL_ASYNC_CQ_COMPLETION,\r
201                                    evd_ptr,\r
202                                    (ib_async_handler_t)dapl_evd_dto_callback,\r
203                                    evd_ptr);\r
204         if (dat_status != DAT_SUCCESS)\r
205         {\r
206             goto bail;\r
207         }\r
208 \r
209         dat_status = dapls_set_cq_notify (ia_ptr, evd_ptr);\r
210 \r
211         if (dat_status != DAT_SUCCESS)\r
212         {\r
213             goto bail;\r
214         }\r
215 \r
216 #endif /* _VENDOR_IBAL_ */\r
217     }\r
218 \r
219     /* We now have an accurate count of events, so allocate them into\r
220      * the EVD\r
221      */\r
222     dat_status = dapli_evd_event_alloc (evd_ptr, cq_len);\r
223     if (dat_status != DAT_SUCCESS)\r
224     {\r
225         goto bail;\r
226     }\r
227 \r
228     dapl_ia_link_evd (ia_ptr, evd_ptr);\r
229     *evd_ptr_ptr = evd_ptr;\r
230 \r
231 bail:\r
232     if (dat_status != DAT_SUCCESS)\r
233     {\r
234         if (evd_ptr)\r
235         {\r
236             dapls_evd_dealloc (evd_ptr);\r
237         }\r
238     }\r
239 \r
240     return dat_status;\r
241 }\r
242 \r
243 /*\r
244  * dapls_evd_alloc\r
245  *\r
246  * alloc and initialize an EVD struct\r
247  *\r
248  * Input:\r
249  *      ia\r
250  *\r
251  * Output:\r
252  *      evd_ptr\r
253  *\r
254  * Returns:\r
255  *      none\r
256  *\r
257  */\r
258 DAPL_EVD *\r
259 dapls_evd_alloc (\r
260     IN DAPL_IA          *ia_ptr,\r
261     IN DAPL_CNO         *cno_ptr,\r
262     IN DAT_EVD_FLAGS    evd_flags,\r
263     IN DAT_COUNT        qlen)\r
264 {\r
265     DAPL_EVD    *evd_ptr;\r
266 \r
267     /* Allocate EVD */\r
268     evd_ptr = (DAPL_EVD *)dapl_os_alloc (sizeof (DAPL_EVD));\r
269     if (!evd_ptr)\r
270     {\r
271         goto bail;\r
272     }\r
273 \r
274     /* zero the structure */\r
275     dapl_os_memzero (evd_ptr, sizeof (DAPL_EVD));\r
276 \r
277 #ifdef DAPL_COUNTERS\r
278     /* Allocate counters */\r
279     evd_ptr->cntrs = dapl_os_alloc(sizeof(DAT_UINT64) * DCNT_EVD_ALL_COUNTERS);\r
280     if (evd_ptr->cntrs == NULL) {\r
281         dapl_os_free(evd_ptr, sizeof(DAPL_EVD));\r
282         return (NULL);\r
283     }\r
284     dapl_os_memzero(evd_ptr->cntrs, \r
285                     sizeof(DAT_UINT64) * DCNT_EVD_ALL_COUNTERS);\r
286 #endif /* DAPL_COUNTERS */\r
287 \r
288     /*\r
289      * initialize the header\r
290      */\r
291     evd_ptr->header.provider            = ia_ptr->header.provider;\r
292     evd_ptr->header.magic               = DAPL_MAGIC_EVD;\r
293     evd_ptr->header.handle_type         = DAT_HANDLE_TYPE_EVD;\r
294     evd_ptr->header.owner_ia            = ia_ptr;\r
295     evd_ptr->header.user_context.as_64  = 0;\r
296     evd_ptr->header.user_context.as_ptr = NULL;\r
297     dapl_llist_init_entry (&evd_ptr->header.ia_list_entry);\r
298     dapl_os_lock_init (&evd_ptr->header.lock);\r
299 \r
300     /*\r
301      * Initialize the body\r
302      */\r
303     evd_ptr->evd_state     = DAPL_EVD_STATE_INITIAL;\r
304     evd_ptr->evd_flags     = evd_flags;\r
305     evd_ptr->evd_enabled   = DAT_TRUE;\r
306     evd_ptr->evd_waitable  = DAT_TRUE;\r
307     evd_ptr->evd_producer_locking_needed = 1;/* Conservative value.  */\r
308     evd_ptr->ib_cq_handle  = IB_INVALID_HANDLE;\r
309     dapl_os_atomic_set (&evd_ptr->evd_ref_count, 0);\r
310     evd_ptr->catastrophic_overflow = DAT_FALSE;\r
311     evd_ptr->qlen          = qlen;\r
312     evd_ptr->completion_type = DAPL_EVD_STATE_THRESHOLD; /* FIXME: should be DAPL_EVD_STATE_INIT */\r
313     dapl_os_wait_object_init (&evd_ptr->wait_object);\r
314 \r
315 #ifdef CQ_WAIT_OBJECT\r
316     /* Create CQ wait object; no CNO and data stream type */\r
317     if (( cno_ptr == NULL ) && \r
318             ((evd_flags & ~ (DAT_EVD_DTO_FLAG|DAT_EVD_RMR_BIND_FLAG)) == 0 ))\r
319     {\r
320         dapls_ib_wait_object_create (evd_ptr, &evd_ptr->cq_wait_obj_handle);\r
321         if (evd_ptr->cq_wait_obj_handle == NULL) {\r
322                 dapl_os_free(evd_ptr, sizeof (DAPL_EVD));\r
323                 evd_ptr = NULL;\r
324                 goto bail;\r
325         }\r
326     }\r
327 #endif\r
328 \r
329     evd_ptr->cno_active_count = 0;\r
330     if ( cno_ptr != NULL )\r
331     {\r
332         /* Take a reference count on the CNO */\r
333         dapl_os_atomic_inc (&cno_ptr->cno_ref_count);\r
334     }\r
335     evd_ptr->cno_ptr = cno_ptr;\r
336 \r
337 bail:\r
338     return evd_ptr;\r
339 }\r
340 \r
341 \r
342 /*\r
343  * dapls_evd_event_alloc\r
344  *\r
345  * alloc events into an EVD.\r
346  *\r
347  * Input:\r
348  *      evd_ptr\r
349  *      qlen\r
350  *\r
351  * Output:\r
352  *      NONE\r
353  *\r
354  * Returns:\r
355  *      DAT_SUCCESS\r
356  *      ERROR\r
357  *\r
358  */\r
359 DAT_RETURN\r
360 dapli_evd_event_alloc (\r
361     IN DAPL_EVD         *evd_ptr,\r
362     IN DAT_COUNT        qlen)\r
363 {\r
364     DAT_EVENT   *event_ptr;\r
365     DAT_COUNT   i;\r
366     DAT_RETURN  dat_status;\r
367 \r
368     dat_status = DAT_SUCCESS;\r
369 \r
370     /* Allocate EVENTs */\r
371     event_ptr = (DAT_EVENT *) dapl_os_alloc (evd_ptr->qlen * sizeof (DAT_EVENT));\r
372     if (event_ptr == NULL)\r
373     {\r
374         dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY);\r
375         goto bail;\r
376     }\r
377     evd_ptr->events = event_ptr;\r
378 \r
379     /* allocate free event queue */\r
380     dat_status = dapls_rbuf_alloc (&evd_ptr->free_event_queue, qlen);\r
381     if (dat_status != DAT_SUCCESS)\r
382     {\r
383         goto bail;\r
384     }\r
385 \r
386     /* allocate pending event queue */\r
387     dat_status = dapls_rbuf_alloc (&evd_ptr->pending_event_queue, qlen);\r
388     if (dat_status != DAT_SUCCESS)\r
389     {\r
390         goto bail;\r
391     }\r
392 \r
393     /* add events to free event queue */\r
394     for (i = 0; i < evd_ptr->qlen; i++)\r
395     {\r
396         dapls_rbuf_add (&evd_ptr->free_event_queue, (void *)event_ptr);\r
397         event_ptr++;\r
398     }\r
399 \r
400     evd_ptr->cq_notified = DAT_FALSE;\r
401     evd_ptr->cq_notified_when = 0;\r
402     evd_ptr->threshold = 0;\r
403 \r
404 bail:\r
405     return dat_status;\r
406 }\r
407 \r
408 \r
409 /*\r
410  * dapls_evd_event_realloc\r
411  *\r
412  * realloc events into an EVD.\r
413  *\r
414  * Input:\r
415  *      evd_ptr\r
416  *      qlen\r
417  *\r
418  * Output:\r
419  *      NONE\r
420  *\r
421  * Returns:\r
422  *      DAT_SUCCESS\r
423  *      ERROR\r
424  *\r
425  */\r
426 DAT_RETURN\r
427 dapls_evd_event_realloc (\r
428     IN DAPL_EVD         *evd_ptr,\r
429     IN DAT_COUNT        qlen)\r
430 {\r
431     DAT_EVENT   *events;\r
432     DAT_COUNT   old_qlen;\r
433     DAT_COUNT   i;\r
434     intptr_t    diff;\r
435     DAT_RETURN  dat_status;\r
436 \r
437     /* Allocate EVENTs */\r
438     events = (DAT_EVENT *) dapl_os_realloc (evd_ptr->events,\r
439                                                 qlen * sizeof (DAT_EVENT));\r
440     if ( NULL == events )\r
441     {\r
442         dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY);\r
443         goto bail;\r
444     }\r
445 \r
446     diff = events - evd_ptr->events;\r
447     evd_ptr->events = events;\r
448 \r
449     old_qlen = evd_ptr->qlen;\r
450     evd_ptr->qlen = qlen;\r
451 \r
452     /* reallocate free event queue */\r
453     dat_status = dapls_rbuf_realloc (&evd_ptr->free_event_queue, qlen);\r
454     if (dat_status != DAT_SUCCESS)\r
455     {\r
456         goto bail;\r
457     }\r
458     dapls_rbuf_adjust (&evd_ptr->free_event_queue, diff);\r
459 \r
460     /* reallocate pending event queue */\r
461     dat_status = dapls_rbuf_realloc (&evd_ptr->pending_event_queue, qlen);\r
462     if (dat_status != DAT_SUCCESS)\r
463     {\r
464         goto bail;\r
465     }\r
466     dapls_rbuf_adjust (&evd_ptr->pending_event_queue, diff);\r
467 \r
468     /*\r
469      * add new events to free event queue. \r
470      */\r
471     for (i = old_qlen; i < qlen; i++)\r
472     {\r
473         dapls_rbuf_add (&evd_ptr->free_event_queue, (void *) &events[i]);\r
474     }\r
475 \r
476 bail:\r
477     return dat_status;\r
478 }\r
479 \r
480 /*\r
481  * dapls_evd_dealloc\r
482  *\r
483  * Free the passed in EVD structure. If an error occurs, this function\r
484  * will clean up all of the internal data structures and report the\r
485  * error.\r
486  *\r
487  * Input:\r
488  *      evd_ptr\r
489  *\r
490  * Output:\r
491  *      none\r
492  *\r
493  * Returns:\r
494  *      status\r
495  *\r
496  */\r
497 DAT_RETURN\r
498 dapls_evd_dealloc (\r
499     IN DAPL_EVD         *evd_ptr )\r
500 {\r
501     DAT_RETURN  dat_status;\r
502     DAPL_IA     *ia_ptr;\r
503 \r
504     dat_status = DAT_SUCCESS;\r
505 \r
506     dapl_os_assert (evd_ptr->header.magic == DAPL_MAGIC_EVD);\r
507     dapl_os_assert (dapl_os_atomic_read (&evd_ptr->evd_ref_count) == 0);\r
508 \r
509     /*\r
510      * Destroy the CQ first, to keep any more callbacks from coming\r
511      * up from it.\r
512      */\r
513     if (evd_ptr->ib_cq_handle != IB_INVALID_HANDLE)\r
514     {\r
515         ia_ptr = evd_ptr->header.owner_ia;\r
516 \r
517         dat_status = dapls_ib_cq_free (ia_ptr, evd_ptr);\r
518         if (dat_status != DAT_SUCCESS)\r
519         {\r
520             goto bail;\r
521         }\r
522     }\r
523 \r
524     /*\r
525      * We should now be safe to invalidate the EVD; reset the\r
526      * magic to prevent reuse.\r
527      */\r
528     evd_ptr->header.magic = DAPL_MAGIC_INVALID;\r
529 \r
530     /* Release reference on the CNO if it exists */\r
531     if ( evd_ptr->cno_ptr != NULL )\r
532     {\r
533         dapl_os_atomic_dec ( &evd_ptr->cno_ptr->cno_ref_count );\r
534         evd_ptr->cno_ptr = NULL;\r
535     }\r
536 \r
537     /* If the ring buffer allocation failed, then the dapls_rbuf_destroy   */\r
538     /* function will detect that the ring buffer's internal data (ex. base */\r
539     /* pointer) are invalid and will handle the situation appropriately    */\r
540     dapls_rbuf_destroy (&evd_ptr->free_event_queue);\r
541     dapls_rbuf_destroy (&evd_ptr->pending_event_queue);\r
542 \r
543     if (evd_ptr->events)\r
544     {\r
545         dapl_os_free (evd_ptr->events, evd_ptr->qlen * sizeof (DAT_EVENT));\r
546     }\r
547 \r
548     dapl_os_wait_object_destroy (&evd_ptr->wait_object);\r
549 \r
550 #ifdef CQ_WAIT_OBJECT\r
551     if (evd_ptr->cq_wait_obj_handle)\r
552     {\r
553         dapls_ib_wait_object_destroy (evd_ptr->cq_wait_obj_handle);\r
554     }\r
555 #endif\r
556 \r
557 #ifdef DAPL_COUNTERS\r
558     dapl_os_free(evd_ptr->cntrs, sizeof(DAT_UINT64) * DCNT_EVD_ALL_COUNTERS);\r
559 #endif /* DAPL_COUNTERS */\r
560 \r
561     dapl_os_free (evd_ptr, sizeof (DAPL_EVD));\r
562 \r
563 bail:\r
564     return dat_status;\r
565 }\r
566 \r
567 STATIC _INLINE_ char * DAPL_GET_DTO_OP_STR(int op)\r
568 {\r
569     static char *dto_ops[] =\r
570     {\r
571         "OP_SEND",\r
572         "OP_RECEIVE",\r
573         "OP_RDMA_WRITE",\r
574         "OP_RDMA_READ"\r
575     };\r
576     return ((op < 0 || op > 3) ? "Invalid DTO OP?" : dto_ops[op]);\r
577 }\r
578 \r
579 #if !defined(DAPL_GET_CQE_OP_STR)\r
580 #define DAPL_GET_CQE_OP_STR(e) "Unknown CEQ OP String?"\r
581 #endif\r
582 #if !defined(DAPL_GET_CQE_VENDOR_ERR)\r
583 #define DAPL_GET_CQE_VENDOR_ERR(e) 0\r
584 #endif\r
585 \r
586 /*\r
587  * dapli_evd_eh_print_cqe\r
588  *\r
589  * Input:\r
590  *      cqe_ptr\r
591  *\r
592  * Output:\r
593  *      none\r
594  *\r
595  * Prints out a CQE for debug purposes\r
596  *\r
597  */\r
598 \r
599 void\r
600 dapli_evd_eh_print_cqe (\r
601     IN  ib_work_completion_t    *cqe_ptr)\r
602 {\r
603 #ifdef DAPL_DBG\r
604     dapl_dbg_log (DAPL_DBG_TYPE_CALLBACK,\r
605                   "\t >>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<\n");\r
606     dapl_dbg_log (DAPL_DBG_TYPE_CALLBACK,\r
607                   "\t dapl_evd_dto_callback : CQE \n");\r
608     dapl_dbg_log (DAPL_DBG_TYPE_CALLBACK,\r
609                   "\t\t work_req_id %lli\n",\r
610                   DAPL_GET_CQE_WRID (cqe_ptr));\r
611     if (DAPL_GET_CQE_STATUS (cqe_ptr) == 0)\r
612     {\r
613         dapl_dbg_log (DAPL_DBG_TYPE_CALLBACK,\r
614                   "\t\t op_type: %s\n",\r
615                   DAPL_GET_CQE_OP_STR(cqe_ptr));\r
616         dapl_dbg_log (DAPL_DBG_TYPE_CALLBACK,\r
617                   "\t\t bytes_num %d\n",\r
618                   DAPL_GET_CQE_BYTESNUM (cqe_ptr));\r
619     }\r
620     dapl_dbg_log (DAPL_DBG_TYPE_CALLBACK,\r
621                   "\t\t status %d vendor_err 0x%x\n",\r
622                   DAPL_GET_CQE_STATUS(cqe_ptr),\r
623                   DAPL_GET_CQE_VENDOR_ERR(cqe_ptr));\r
624     dapl_dbg_log (DAPL_DBG_TYPE_CALLBACK,\r
625                   "\t >>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<\n");\r
626 #endif\r
627     return;\r
628 }\r
629 \r
630 \r
631 \r
632 /*\r
633  * Event posting code follows.\r
634  */\r
635 \r
636 /*\r
637  * These next two functions (dapli_evd_get_event and dapli_evd_post_event)\r
638  * are a pair.  They are always called together, from one of the functions\r
639  * at the end of this file (dapl_evd_post_*_event).\r
640  *\r
641  * Note that if producer side locking is enabled, the first one takes the\r
642  * EVD lock and the second releases it.\r
643  */\r
644 \r
645 /* dapli_evd_get_event\r
646  *\r
647  * Get an event struct from the evd.  The caller should fill in the event\r
648  * and call dapl_evd_post_event.\r
649  *\r
650  * If there are no events available, an overflow event is generated to the\r
651  * async EVD handler.\r
652  *\r
653  * If this EVD required producer locking, a successful return implies\r
654  * that the lock is held.\r
655  *\r
656  * Input:\r
657  *      evd_ptr\r
658  *\r
659  * Output:\r
660  *      event\r
661  *\r
662  */\r
663 \r
664 static DAT_EVENT *\r
665 dapli_evd_get_event (\r
666     DAPL_EVD *evd_ptr)\r
667 {\r
668     DAT_EVENT   *event;\r
669 \r
670     if (evd_ptr->evd_producer_locking_needed)\r
671     {\r
672         dapl_os_lock (&evd_ptr->header.lock);\r
673     }\r
674 \r
675     event = (DAT_EVENT *)dapls_rbuf_remove (&evd_ptr->free_event_queue);\r
676 \r
677     /* Release the lock if it was taken and the call failed.  */\r
678     if (!event && evd_ptr->evd_producer_locking_needed)\r
679     {\r
680         dapl_os_unlock (&evd_ptr->header.lock);\r
681     }\r
682 \r
683     return event;\r
684 }\r
685 \r
686 /* dapli_evd_post_event\r
687  *\r
688  * Post the <event> to the evd.  If possible, invoke the evd's CNO.\r
689  * Otherwise post the event on the pending queue.\r
690  *\r
691  * If producer side locking is required, the EVD lock must be held upon\r
692  * entry to this function.\r
693  *\r
694  * Input:\r
695  *      evd_ptr\r
696  *      event\r
697  *\r
698  * Output:\r
699  *      none\r
700  *\r
701  */\r
702 \r
703 static void\r
704 dapli_evd_post_event (\r
705     IN  DAPL_EVD        *evd_ptr,\r
706     IN  const DAT_EVENT *event_ptr)\r
707 {\r
708     DAT_RETURN  dat_status;\r
709     DAPL_CNO    *cno_to_trigger = NULL;\r
710 \r
711     dapl_dbg_log (DAPL_DBG_TYPE_EVD, "%s: Called with event %s\n",\r
712                   __FUNCTION__, dapl_event_str(event_ptr->event_number));\r
713 \r
714     dat_status = dapls_rbuf_add (&evd_ptr->pending_event_queue,\r
715                                      (void *)event_ptr);\r
716     dapl_os_assert (dat_status == DAT_SUCCESS);\r
717 \r
718     dapl_os_assert (evd_ptr->evd_state == DAPL_EVD_STATE_WAITED\r
719                    || evd_ptr->evd_state == DAPL_EVD_STATE_OPEN);\r
720 \r
721     if (evd_ptr->evd_state == DAPL_EVD_STATE_OPEN)\r
722     {\r
723         /* No waiter.  Arrange to trigger a CNO if it exists.  */\r
724 \r
725         if (evd_ptr->evd_enabled)\r
726         {\r
727             cno_to_trigger = evd_ptr->cno_ptr;\r
728         }\r
729         if (evd_ptr->evd_producer_locking_needed)\r
730         {\r
731             dapl_os_unlock (&evd_ptr->header.lock);\r
732         }\r
733     }\r
734     else\r
735     {\r
736         /*\r
737          * We're in DAPL_EVD_STATE_WAITED.  Take the lock if\r
738          * we don't have it, recheck, and signal.\r
739          */\r
740         if (!evd_ptr->evd_producer_locking_needed)\r
741         {\r
742             dapl_os_lock (&evd_ptr->header.lock);\r
743         }\r
744 \r
745         if (evd_ptr->evd_state == DAPL_EVD_STATE_WAITED\r
746             && (dapls_rbuf_count (&evd_ptr->pending_event_queue)\r
747                 >= evd_ptr->threshold))\r
748         {\r
749             dapl_os_unlock (&evd_ptr->header.lock);\r
750 \r
751 #ifdef CQ_WAIT_OBJECT\r
752             if (evd_ptr->cq_wait_obj_handle)\r
753                 dapls_ib_wait_object_wakeup (evd_ptr->cq_wait_obj_handle);\r
754             else\r
755 #endif\r
756                 dapl_os_wait_object_wakeup (&evd_ptr->wait_object);\r
757         }\r
758         else\r
759         {\r
760             dapl_os_unlock (&evd_ptr->header.lock);\r
761         }\r
762     }\r
763 \r
764     if (cno_to_trigger != NULL)\r
765     {\r
766         dapl_internal_cno_trigger (cno_to_trigger, evd_ptr);\r
767     }\r
768 }\r
769 \r
770 /* dapli_evd_post_event_nosignal\r
771  *\r
772  * Post the <event> to the evd.  Do not do any wakeup processing.\r
773  * This function should only be called if it is known that there are\r
774  * no waiters that it is appropriate to wakeup on this EVD.  An example\r
775  * of such a situation is during internal dat_evd_wait() processing.\r
776  *\r
777  * If producer side locking is required, the EVD lock must be held upon\r
778  * entry to this function.\r
779  *\r
780  * Input:\r
781  *      evd_ptr\r
782  *      event\r
783  *\r
784  * Output:\r
785  *      none\r
786  *\r
787  */\r
788 \r
789 static void\r
790 dapli_evd_post_event_nosignal (\r
791     IN  DAPL_EVD        *evd_ptr,\r
792     IN  const DAT_EVENT *event_ptr)\r
793 {\r
794     DAT_RETURN  dat_status;\r
795 \r
796     dapl_dbg_log (DAPL_DBG_TYPE_EVD, "%s: Called with event %s\n",\r
797                   __FUNCTION__, dapl_event_str(event_ptr->event_number));\r
798 \r
799     dat_status = dapls_rbuf_add (&evd_ptr->pending_event_queue,\r
800                                      (void *)event_ptr);\r
801     dapl_os_assert (dat_status == DAT_SUCCESS);\r
802 \r
803     dapl_os_assert (evd_ptr->evd_state == DAPL_EVD_STATE_WAITED\r
804                    || evd_ptr->evd_state == DAPL_EVD_STATE_OPEN);\r
805 \r
806     if (evd_ptr->evd_producer_locking_needed)\r
807     {\r
808         dapl_os_unlock (&evd_ptr->header.lock);\r
809     }\r
810 }\r
811 \r
812 /* dapli_evd_format_overflow_event\r
813  *\r
814  * format an overflow event for posting\r
815  *\r
816  * Input:\r
817  *      evd_ptr\r
818  *      event_ptr\r
819  *\r
820  * Output:\r
821  *      none\r
822  *\r
823  */\r
824 static void\r
825 dapli_evd_format_overflow_event (\r
826         IN  DAPL_EVD  *evd_ptr,\r
827         OUT DAT_EVENT *event_ptr)\r
828 {\r
829     DAPL_IA *ia_ptr;\r
830 \r
831     ia_ptr = evd_ptr->header.owner_ia;\r
832 \r
833     event_ptr->evd_handle   = (DAT_EVD_HANDLE)evd_ptr;\r
834     event_ptr->event_number = DAT_ASYNC_ERROR_EVD_OVERFLOW;\r
835     event_ptr->event_data.asynch_error_event_data.dat_handle = (DAT_HANDLE)ia_ptr;\r
836 }\r
837 \r
838 /* dapli_evd_post_overflow_event\r
839  *\r
840  * post an overflow event\r
841  *\r
842  * Input:\r
843  *      async_evd_ptr\r
844  *      evd_ptr\r
845  *\r
846  * Output:\r
847  *      none\r
848  *\r
849  */\r
850 static void\r
851 dapli_evd_post_overflow_event (\r
852     IN  DAPL_EVD  *async_evd_ptr,\r
853     IN  DAPL_EVD  *overflow_evd_ptr)\r
854 {\r
855     DAT_EVENT *overflow_event;\r
856 \r
857     /* The overflow_evd_ptr mght be the same as evd.\r
858      * In that case we've got a catastrophic overflow.\r
859      */\r
860     if (async_evd_ptr == overflow_evd_ptr)\r
861     {\r
862         async_evd_ptr->catastrophic_overflow = DAT_TRUE;\r
863         async_evd_ptr->evd_state = DAPL_EVD_STATE_DEAD;\r
864         return;\r
865     }\r
866 \r
867     overflow_event = dapli_evd_get_event (overflow_evd_ptr);\r
868     if (!overflow_event)\r
869     {\r
870         /* this is not good */\r
871         overflow_evd_ptr->catastrophic_overflow = DAT_TRUE;\r
872         overflow_evd_ptr->evd_state = DAPL_EVD_STATE_DEAD;\r
873         return;\r
874     }\r
875     dapli_evd_format_overflow_event (overflow_evd_ptr, overflow_event);\r
876     dapli_evd_post_event (overflow_evd_ptr, overflow_event);\r
877 \r
878     return;\r
879 }\r
880 \r
881 static DAT_EVENT *\r
882 dapli_evd_get_and_init_event (\r
883     IN DAPL_EVD                         *evd_ptr,\r
884     IN DAT_EVENT_NUMBER                 event_number)\r
885 {\r
886     DAT_EVENT           *event_ptr;\r
887 \r
888     event_ptr = dapli_evd_get_event (evd_ptr);\r
889     if (NULL == event_ptr)\r
890     {\r
891         dapli_evd_post_overflow_event (\r
892             evd_ptr->header.owner_ia->async_error_evd,\r
893             evd_ptr);\r
894     }\r
895     else\r
896     {\r
897         event_ptr->evd_handle = (DAT_EVD_HANDLE) evd_ptr;\r
898         event_ptr->event_number = event_number;\r
899     }\r
900 \r
901     return event_ptr;\r
902 }\r
903 \r
904 DAT_RETURN\r
905 dapls_evd_post_cr_arrival_event (\r
906     IN DAPL_EVD                         *evd_ptr,\r
907     IN DAT_EVENT_NUMBER                 event_number,\r
908     IN DAT_SP_HANDLE                    sp_handle,\r
909     DAT_IA_ADDRESS_PTR                  ia_address_ptr,\r
910     DAT_CONN_QUAL                       conn_qual,\r
911     DAT_CR_HANDLE                       cr_handle)\r
912 {\r
913     DAT_EVENT           *event_ptr;\r
914     event_ptr = dapli_evd_get_and_init_event (evd_ptr, event_number);\r
915     /*\r
916      * Note event lock may be held on successful return\r
917      * to be released by dapli_evd_post_event(), if provider side locking\r
918      * is needed.\r
919      */\r
920 \r
921     if (event_ptr == NULL)\r
922     {\r
923         return DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY);\r
924     }\r
925 \r
926     event_ptr->event_data.cr_arrival_event_data.sp_handle = sp_handle;\r
927     event_ptr->event_data.cr_arrival_event_data.local_ia_address_ptr\r
928         = ia_address_ptr;\r
929     event_ptr->event_data.cr_arrival_event_data.conn_qual = conn_qual;\r
930     event_ptr->event_data.cr_arrival_event_data.cr_handle = cr_handle;\r
931 \r
932     dapli_evd_post_event (evd_ptr, event_ptr);\r
933 \r
934     return DAT_SUCCESS;\r
935 }\r
936 \r
937 \r
938 DAT_RETURN\r
939 dapls_evd_post_connection_event (\r
940     IN DAPL_EVD                         *evd_ptr,\r
941     IN DAT_EVENT_NUMBER                 event_number,\r
942     IN DAT_EP_HANDLE                    ep_handle,\r
943     IN DAT_COUNT                        private_data_size,\r
944     IN DAT_PVOID                        private_data)\r
945 {\r
946     DAT_EVENT           *event_ptr;\r
947     event_ptr = dapli_evd_get_and_init_event (evd_ptr, event_number);\r
948     /*\r
949      * Note event lock may be held on successful return\r
950      * to be released by dapli_evd_post_event(), if provider side locking\r
951      * is needed.\r
952      */\r
953 \r
954     if (event_ptr == NULL)\r
955     {\r
956         return DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY);\r
957     }\r
958 \r
959     event_ptr->event_data.connect_event_data.ep_handle = ep_handle;\r
960     event_ptr->event_data.connect_event_data.private_data_size\r
961         = private_data_size;\r
962     event_ptr->event_data.connect_event_data.private_data = private_data;\r
963 \r
964     dapli_evd_post_event (evd_ptr, event_ptr);\r
965 \r
966     return DAT_SUCCESS;\r
967 }\r
968 \r
969 \r
970 DAT_RETURN\r
971 dapls_evd_post_async_error_event (\r
972     IN DAPL_EVD                         *evd_ptr,\r
973     IN DAT_EVENT_NUMBER                 event_number,\r
974     IN DAT_IA_HANDLE                    ia_handle)\r
975 {\r
976     DAT_EVENT           *event_ptr;\r
977 \r
978     dapl_dbg_log (DAPL_DBG_TYPE_ERR, "%s: event_num %d\n",      \r
979                                         __FUNCTION__,event_number);\r
980 \r
981     event_ptr = dapli_evd_get_and_init_event (evd_ptr, event_number);\r
982     /*\r
983      * Note event lock may be held on successful return\r
984      * to be released by dapli_evd_post_event(), if provider side locking\r
985      * is needed.\r
986      */\r
987 \r
988     if (event_ptr == NULL)\r
989     {\r
990         dapl_dbg_log (DAPL_DBG_TYPE_ERR,\r
991                         "%s: Err: unable to get evd by event num\n",\r
992                          __FUNCTION__,event_number);\r
993         return DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY);\r
994     }\r
995 \r
996     event_ptr->event_data.asynch_error_event_data.dat_handle = (DAT_HANDLE)ia_handle;\r
997 \r
998     dapli_evd_post_event (evd_ptr, event_ptr);\r
999 \r
1000     dapl_dbg_log (DAPL_DBG_TYPE_CALLBACK, "%s: posted evd %p num 0x%x(%d)\n",\r
1001                 __FUNCTION__, evd_ptr, event_number, event_number);\r
1002 \r
1003     return DAT_SUCCESS;\r
1004 }\r
1005 \r
1006 \r
1007 DAT_RETURN\r
1008 dapls_evd_post_software_event (\r
1009     IN DAPL_EVD                         *evd_ptr,\r
1010     IN DAT_EVENT_NUMBER                 event_number,\r
1011     IN DAT_PVOID                        pointer)\r
1012 {\r
1013     DAT_EVENT           *event_ptr;\r
1014     event_ptr = dapli_evd_get_and_init_event (evd_ptr, event_number);\r
1015     /*\r
1016      * Note event lock may be held on successful return\r
1017      * to be released by dapli_evd_post_event(), if provider side locking\r
1018      * is needed.\r
1019      */\r
1020 \r
1021     if (event_ptr == NULL)\r
1022     {\r
1023         return DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY);\r
1024     }\r
1025 \r
1026     event_ptr->event_data.software_event_data.pointer = pointer;\r
1027 \r
1028     dapli_evd_post_event (evd_ptr, event_ptr);\r
1029 \r
1030     return DAT_SUCCESS;\r
1031 }\r
1032 \r
1033 \r
1034 /*\r
1035  * dapls_evd_post_generic_event\r
1036  *\r
1037  * Post a generic event type. Not used by all providers\r
1038  *\r
1039  * Input:\r
1040  *      evd_ptr\r
1041  *      event_number\r
1042  *      data\r
1043  *\r
1044  * Output:\r
1045  *      none\r
1046  *\r
1047  * Returns:\r
1048  *      DAT_SUCCESS\r
1049  *\r
1050  */\r
1051 DAT_RETURN\r
1052 dapls_evd_post_generic_event (\r
1053     IN DAPL_EVD                         *evd_ptr,\r
1054     IN DAT_EVENT_NUMBER                 event_number,\r
1055     IN DAT_EVENT_DATA                   *data)\r
1056 {\r
1057     DAT_EVENT           *event_ptr;\r
1058 \r
1059     event_ptr = dapli_evd_get_and_init_event (evd_ptr, event_number);\r
1060     /*\r
1061      * Note event lock may be held on successful return\r
1062      * to be released by dapli_evd_post_event(), if provider side locking\r
1063      * is needed.\r
1064      */\r
1065 \r
1066     if (event_ptr == NULL)\r
1067     {\r
1068         return DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY);\r
1069     }\r
1070 \r
1071     event_ptr->event_data = *data;\r
1072 \r
1073     dapli_evd_post_event (evd_ptr, event_ptr);\r
1074 \r
1075     return DAT_SUCCESS;\r
1076 }\r
1077 \r
1078 /*\r
1079  * dapli_evd_cqe_to_event\r
1080  *\r
1081  * Convert a CQE into an event structure.\r
1082  *\r
1083  * Input:\r
1084  *      evd_ptr\r
1085  *      cqe_ptr\r
1086  *\r
1087  * Output:\r
1088  *      event_ptr\r
1089  *\r
1090  * Returns:\r
1091  *      none\r
1092  *\r
1093  */\r
1094 static void\r
1095 dapli_evd_cqe_to_event (\r
1096     IN  DAPL_EVD                *evd_ptr,\r
1097     IN  void                    *cqe_ptr,\r
1098     OUT DAT_EVENT               *event_ptr)\r
1099 {\r
1100     DAPL_EP                     *ep_ptr;\r
1101     DAPL_COOKIE                 *cookie;\r
1102     DAT_DTO_COMPLETION_STATUS   dto_status;\r
1103     DAPL_COOKIE_BUFFER          *buffer;\r
1104     \r
1105     /*\r
1106      * All that can be relied on if the status is bad is the status\r
1107      * and WRID.\r
1108      */\r
1109     dto_status = dapls_ib_get_dto_status (cqe_ptr);\r
1110 \r
1111     cookie = (DAPL_COOKIE *) (uintptr_t) DAPL_GET_CQE_WRID (cqe_ptr);\r
1112     dapl_os_assert ( (NULL != cookie) );\r
1113 \r
1114     ep_ptr = cookie->ep;\r
1115     dapl_os_assert ( (NULL != ep_ptr) );\r
1116     if (ep_ptr->header.magic != DAPL_MAGIC_EP)\r
1117     {\r
1118         /* ep may have been freed, just return */\r
1119         return;\r
1120     }\r
1121 \r
1122     dapls_io_trc_update_completion (ep_ptr, cookie, dto_status);\r
1123 \r
1124     event_ptr->evd_handle = (DAT_EVD_HANDLE) evd_ptr;\r
1125 \r
1126     switch (cookie->type)\r
1127     {\r
1128         case DAPL_COOKIE_TYPE_DTO:\r
1129         {\r
1130 #ifdef DAT_EXTENSIONS\r
1131             /* Extended via request post or message receive */\r
1132             if ((cookie->val.dto.type == DAPL_DTO_TYPE_EXTENSION) ||\r
1133                 (cookie->val.dto.type == DAPL_DTO_TYPE_RECV && \r
1134                 DAPL_GET_CQE_OPTYPE(cqe_ptr) !=  OP_RECEIVE))\r
1135             {\r
1136                 dapls_cqe_to_event_extension (ep_ptr, cookie, cqe_ptr, event_ptr);\r
1137                 if (cookie->val.dto.type == DAPL_DTO_TYPE_RECV)\r
1138                         dapls_cookie_dealloc (&ep_ptr->recv_buffer, cookie);\r
1139                 else\r
1140                         dapls_cookie_dealloc (&ep_ptr->req_buffer, cookie);\r
1141                 break;\r
1142             }\r
1143 #endif\r
1144 \r
1145             if (DAPL_DTO_TYPE_RECV == cookie->val.dto.type)\r
1146                 buffer = &ep_ptr->recv_buffer;\r
1147             else\r
1148                 buffer = &ep_ptr->req_buffer;\r
1149             \r
1150             event_ptr->event_number = DAT_DTO_COMPLETION_EVENT;\r
1151             event_ptr->event_data.dto_completion_event_data.ep_handle =\r
1152                 cookie->ep;\r
1153             event_ptr->event_data.dto_completion_event_data.user_cookie =\r
1154                 cookie->val.dto.cookie;\r
1155             event_ptr->event_data.dto_completion_event_data.status = dto_status;\r
1156 \r
1157             if ( cookie->val.dto.type == DAPL_DTO_TYPE_SEND ||\r
1158                  cookie->val.dto.type == DAPL_DTO_TYPE_RDMA_WRITE )\r
1159             {\r
1160                 /* Get size from DTO; CQE value may be off.  */\r
1161                 event_ptr->event_data.dto_completion_event_data.transfered_length =\r
1162                     cookie->val.dto.size;\r
1163             }\r
1164             else\r
1165             {\r
1166                 event_ptr->event_data.dto_completion_event_data.transfered_length =\r
1167                      DAPL_GET_CQE_BYTESNUM (cqe_ptr);\r
1168             }\r
1169 \r
1170             dapls_cookie_dealloc (buffer, cookie);\r
1171             break;\r
1172         }\r
1173 \r
1174         case DAPL_COOKIE_TYPE_RMR:\r
1175         {\r
1176             event_ptr->event_number = DAT_RMR_BIND_COMPLETION_EVENT;\r
1177 \r
1178             event_ptr->event_data.rmr_completion_event_data.rmr_handle =\r
1179                 cookie->val.rmr.rmr;\r
1180             event_ptr->event_data.rmr_completion_event_data.user_cookie =\r
1181                 cookie->val.rmr.cookie;\r
1182             if (dto_status == DAT_DTO_SUCCESS)\r
1183             {\r
1184                 event_ptr->event_data.rmr_completion_event_data.status =\r
1185                     DAT_RMR_BIND_SUCCESS;\r
1186                 dapl_os_assert ((DAPL_GET_CQE_OPTYPE (cqe_ptr)) == OP_BIND_MW);\r
1187             }\r
1188             else\r
1189             {\r
1190                 dapl_dbg_log (DAPL_DBG_TYPE_DTO_COMP_ERR,\r
1191                               " MW bind completion ERROR: %d: op %#x ep: %p\n", \r
1192                               dto_status, \r
1193                               DAPL_GET_CQE_OPTYPE (cqe_ptr), ep_ptr);\r
1194                 event_ptr->event_data.rmr_completion_event_data.status =\r
1195                     DAT_RMR_OPERATION_FAILED;\r
1196                 dapl_os_atomic_dec(&cookie->val.rmr.rmr->lmr->lmr_ref_count);\r
1197             }\r
1198 \r
1199             dapls_cookie_dealloc (&ep_ptr->req_buffer, cookie);\r
1200             break;\r
1201         }\r
1202         default:\r
1203         {\r
1204             dapl_os_assert (!"Invalid Operation type");\r
1205             break;\r
1206         }\r
1207     } /* end switch */\r
1208 \r
1209     /*\r
1210      * Most error DTO ops result in disconnecting the EP. See\r
1211      * IBTA Vol 1.1, Chapter 10,Table 68, for expected effect on\r
1212      * state.\r
1213      */\r
1214     if ((dto_status != DAT_DTO_SUCCESS) &&\r
1215         (dto_status != DAT_DTO_ERR_FLUSHED))\r
1216     {\r
1217         DAPL_EVD                *evd_ptr;\r
1218 \r
1219         /*\r
1220          * If we are connected, generate disconnect and generate an\r
1221          * event. We may be racing with other disconnect ops, so we\r
1222          * need to check. We may also be racing CM connection events,\r
1223          * requiring us to check for connection pending states too.\r
1224          */\r
1225         dapl_os_lock ( &ep_ptr->header.lock );\r
1226         if (ep_ptr->param.ep_state == DAT_EP_STATE_CONNECTED ||\r
1227             ep_ptr->param.ep_state == DAT_EP_STATE_ACTIVE_CONNECTION_PENDING ||\r
1228             ep_ptr->param.ep_state == DAT_EP_STATE_PASSIVE_CONNECTION_PENDING||\r
1229             ep_ptr->param.ep_state == DAT_EP_STATE_COMPLETION_PENDING )\r
1230 \r
1231         {\r
1232             ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED;\r
1233             dapl_os_unlock ( &ep_ptr->header.lock );\r
1234             dapls_io_trc_dump (ep_ptr, cqe_ptr, dto_status);\r
1235 \r
1236             /* Let the other side know we have disconnected */\r
1237             (void) dapls_ib_disconnect (ep_ptr, DAT_CLOSE_ABRUPT_FLAG);\r
1238 \r
1239             /* ... and clean up the local side */\r
1240             evd_ptr = (DAPL_EVD *) ep_ptr->param.connect_evd_handle;\r
1241             if (evd_ptr != NULL)\r
1242             {\r
1243                 dapls_evd_post_connection_event (evd_ptr,\r
1244                                                 DAT_CONNECTION_EVENT_BROKEN,\r
1245                                                 (DAT_HANDLE) ep_ptr,\r
1246                                                 0,\r
1247                                                 0);\r
1248             }\r
1249         }\r
1250         else\r
1251         {\r
1252             dapl_os_unlock ( &ep_ptr->header.lock );\r
1253         }\r
1254 \r
1255         dapl_log(DAPL_DBG_TYPE_ERR,\r
1256                  "DTO completion ERR: status %d, op %s, vendor_err 0x%x - %s\n",\r
1257                  DAPL_GET_CQE_STATUS(cqe_ptr),\r
1258                  DAPL_GET_DTO_OP_STR(cookie->val.dto.type),\r
1259                  DAPL_GET_CQE_VENDOR_ERR(cqe_ptr),\r
1260                  inet_ntoa(((struct sockaddr_in *)&ep_ptr->remote_ia_address)->sin_addr));\r
1261     }\r
1262 }\r
1263 \r
1264 /*\r
1265  * dapls_evd_copy_cq\r
1266  *\r
1267  * Copy all entries on a CQ associated with the EVD onto that EVD\r
1268  * Up to caller to handle races, if any.  Note that no EVD waiters will\r
1269  * be awoken by this copy.\r
1270  *\r
1271  * Input:\r
1272  *      evd_ptr\r
1273  *\r
1274  * Output:\r
1275  *      None\r
1276  *\r
1277  * Returns:\r
1278  *      none\r
1279  *\r
1280  */\r
1281 void\r
1282 dapls_evd_copy_cq (\r
1283     DAPL_EVD    *evd_ptr)\r
1284 {\r
1285     ib_work_completion_t        cur_cqe;\r
1286     DAT_RETURN                  dat_status;\r
1287     DAT_EVENT                   *event;\r
1288 \r
1289     if (evd_ptr->ib_cq_handle == IB_INVALID_HANDLE)\r
1290     {\r
1291         /* Nothing to do if no CQ.  */\r
1292         return;\r
1293     }\r
1294 \r
1295     while (1)\r
1296     {\r
1297         dat_status = dapls_ib_completion_poll (evd_ptr->header.owner_ia->hca_ptr,\r
1298                                                evd_ptr,\r
1299                                                &cur_cqe);\r
1300 \r
1301         if (dat_status != DAT_SUCCESS)\r
1302         {\r
1303             break;\r
1304         }\r
1305 \r
1306         /* For debugging.  */\r
1307         dapli_evd_eh_print_cqe (&cur_cqe);\r
1308 \r
1309         /*\r
1310          * Can use DAT_DTO_COMPLETION_EVENT because dapli_evd_cqe_to_event\r
1311          * will overwrite.\r
1312          */\r
1313 \r
1314         event = dapli_evd_get_and_init_event (\r
1315                 evd_ptr, DAT_DTO_COMPLETION_EVENT );\r
1316         if (event == NULL)\r
1317         {\r
1318             /* We've already attempted the overflow post; return.  */\r
1319             return;\r
1320         }\r
1321 \r
1322         dapli_evd_cqe_to_event ( evd_ptr, &cur_cqe, event );\r
1323 \r
1324         dapli_evd_post_event_nosignal ( evd_ptr, event );\r
1325     }\r
1326 \r
1327     if ( DAT_GET_TYPE (dat_status) != DAT_QUEUE_EMPTY )\r
1328     {\r
1329         dapl_dbg_log (DAPL_DBG_TYPE_EVD,\r
1330             "dapls_evd_copy_cq: dapls_ib_completion_poll returned 0x%x\n",\r
1331             dat_status);\r
1332         dapl_os_assert (!"Bad return from dapls_ib_completion_poll");\r
1333     }\r
1334 }\r
1335 \r
1336 /*\r
1337  * dapls_evd_cq_poll_to_event\r
1338  *\r
1339  * Attempt to dequeue a single CQE from a CQ and turn it into\r
1340  * an event.\r
1341  *\r
1342  * Input:\r
1343  *      evd_ptr\r
1344  *\r
1345  * Output:\r
1346  *      event\r
1347  *\r
1348  * Returns:\r
1349  *      Status of operation\r
1350  *\r
1351  */\r
1352 DAT_RETURN\r
1353 dapls_evd_cq_poll_to_event (\r
1354     IN DAPL_EVD         *evd_ptr,\r
1355     OUT DAT_EVENT       *event)\r
1356 {\r
1357     DAT_RETURN                  dat_status;\r
1358     ib_work_completion_t        cur_cqe;\r
1359 \r
1360     dat_status = dapls_ib_completion_poll (evd_ptr->header.owner_ia->hca_ptr,\r
1361                                            evd_ptr,\r
1362                                            &cur_cqe);\r
1363     if (dat_status == DAT_SUCCESS)\r
1364     {\r
1365         /* For debugging.  */\r
1366         dapli_evd_eh_print_cqe (&cur_cqe);\r
1367 \r
1368         dapli_evd_cqe_to_event (evd_ptr, &cur_cqe, event);\r
1369     }\r
1370 \r
1371     return dat_status;\r
1372 }\r
1373 #ifdef DAPL_DBG_IO_TRC\r
1374 /*\r
1375  * Update I/O completions in the I/O trace buffer. I/O is posted to\r
1376  * the buffer, then we find it here using the cookie and mark it\r
1377  * completed with the completion status\r
1378  */\r
1379 void\r
1380 dapls_io_trc_update_completion (\r
1381     DAPL_EP                     *ep_ptr,\r
1382     DAPL_COOKIE                 *cookie,\r
1383     DAT_DTO_COMPLETION_STATUS   dto_status)\r
1384 {\r
1385     int i;\r
1386     static unsigned int         c_cnt = 1;\r
1387 \r
1388     for (i = 0; i < DBG_IO_TRC_QLEN; i++)\r
1389     {\r
1390         if (ep_ptr->ibt_base[i].cookie == cookie)\r
1391         {\r
1392             ep_ptr->ibt_base[i].status = dto_status;\r
1393             ep_ptr->ibt_base[i].done   = c_cnt++;\r
1394         }\r
1395     }\r
1396 }\r
1397 \r
1398 \r
1399 /*\r
1400  * Dump the I/O trace buffers\r
1401  */\r
1402 void\r
1403 dapls_io_trc_dump (\r
1404     DAPL_EP                     *ep_ptr,\r
1405     void                        *cqe_ptr,\r
1406     DAT_DTO_COMPLETION_STATUS   dto_status)\r
1407 {\r
1408     struct io_buf_track *ibt;\r
1409     int                  i;\r
1410     int                  cnt;\r
1411 \r
1412     dapl_os_printf ("DISCONNECTING: dto_status     = %x\n", dto_status);\r
1413     dapl_os_printf ("               OpType        = %x\n",\r
1414                    DAPL_GET_CQE_OPTYPE (cqe_ptr));\r
1415     dapl_os_printf ("               Bytes         = %x\n",\r
1416                    DAPL_GET_CQE_BYTESNUM (cqe_ptr));\r
1417     dapl_os_printf ("               WRID (cookie) = %llx\n",\r
1418                    DAPL_GET_CQE_WRID (cqe_ptr));\r
1419 \r
1420     if (ep_ptr->ibt_dumped == 0)\r
1421     {\r
1422 \r
1423         dapl_os_printf ("EP %p (qpn %d) I/O trace buffer\n",\r
1424                        ep_ptr, ep_ptr->qpn);\r
1425 \r
1426         ep_ptr->ibt_dumped = 1;\r
1427         ibt = (struct io_buf_track *)dapls_rbuf_remove (&ep_ptr->ibt_queue);\r
1428         cnt = DBG_IO_TRC_QLEN;\r
1429         while (ibt != NULL && cnt > 0)\r
1430         {\r
1431             dapl_os_printf ("%2d. %3s (%2d, %d) OP: %x cookie %p wqe %p rmv_target_addr %llx rmv_rmr_context %x\n",\r
1432                 cnt, ibt->done == 0 ? "WRK" : "DON", ibt->status, ibt->done,\r
1433                 ibt->op_type, ibt->cookie, ibt->wqe,\r
1434                 ibt->remote_iov.target_address,\r
1435                 ibt->remote_iov.rmr_context);\r
1436             for (i = 0; i < 3; i++)\r
1437             {\r
1438                 if (ibt->iov[i].segment_length != 0)\r
1439                 {\r
1440                     dapl_os_printf ("     (%4llx, %8x, %8llx)\n",\r
1441                                    ibt->iov[i].segment_length,\r
1442                                    ibt->iov[i].lmr_context,\r
1443                                    ibt->iov[i].virtual_address);\r
1444                 }\r
1445             }\r
1446             ibt = (struct io_buf_track *)dapls_rbuf_remove (&ep_ptr->ibt_queue);\r
1447             cnt--;\r
1448         }\r
1449     }\r
1450 }\r
1451 #endif /* DAPL_DBG_IO_TRC */\r
1452 \r
1453 /*\r
1454  * Local variables:\r
1455  *  c-indent-level: 4\r
1456  *  c-basic-offset: 4\r
1457  *  tab-width: 8\r
1458  * End:\r
1459  */\r