[DAPL2] DAPL Counters & 2.0.3 extensions to support counter retrieval.
[mirror/winof/.git] / ulp / dapl2 / dapl / udapl / dapl_evd_wait.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_evd_wait.c\r
31  *\r
32  * PURPOSE: EVENT management\r
33  *\r
34  * Description: Interfaces in this file are completely defined in \r
35  *              the uDAPL 1.1 API specification\r
36  *\r
37  * $Id:$\r
38  **********************************************************************/\r
39 \r
40 #include "dapl.h"\r
41 #include "dapl_evd_util.h"\r
42 #include "dapl_ring_buffer_util.h"\r
43 #include "dapl_adapter_util.h"\r
44 \r
45 /*\r
46  * dapl_evd_wait\r
47  *\r
48  * UDAPL Requirements Version xxx, \r
49  *\r
50  * Wait, up to specified timeout, for notification event on EVD.\r
51  * Then return first available event.\r
52  *\r
53  * Input:\r
54  *      evd_handle\r
55  *      timeout\r
56  *\r
57  * Output:\r
58  *      event\r
59  *\r
60  * Returns:\r
61  *      DAT_SUCCESS\r
62  *      DAT_INVALID_PARAMETER\r
63  *      DAT_INVALID_STATE\r
64  */\r
65 \r
66 DAT_RETURN DAT_API dapl_evd_wait (\r
67     IN  DAT_EVD_HANDLE  evd_handle,\r
68     IN  DAT_TIMEOUT     time_out,\r
69     IN  DAT_COUNT       threshold,\r
70     OUT DAT_EVENT       *event,\r
71     OUT DAT_COUNT       *nmore)\r
72 \r
73 {\r
74     DAPL_EVD            *evd_ptr;\r
75     DAT_RETURN          dat_status;\r
76     DAT_EVENT           *local_event;\r
77     DAT_BOOLEAN         notify_requested = DAT_FALSE;\r
78     DAT_BOOLEAN         waitable;\r
79     DAPL_EVD_STATE      evd_state;\r
80 \r
81     dapl_dbg_log (DAPL_DBG_TYPE_API,\r
82                   "dapl_evd_wait (%p, %d, %d, %p, %p)\n", \r
83                   evd_handle, \r
84                   time_out, \r
85                   threshold, \r
86                   event, \r
87                   nmore);\r
88 \r
89     evd_ptr = (DAPL_EVD *)evd_handle;\r
90     dat_status = DAT_SUCCESS;\r
91 \r
92     if (DAPL_BAD_HANDLE (evd_ptr, DAPL_MAGIC_EVD))\r
93     {\r
94         /*\r
95          * We return directly rather than bailing because\r
96          * bailing attempts to update the evd, and we don't have\r
97          * one.\r
98          */\r
99         dat_status = DAT_ERROR (DAT_INVALID_HANDLE,0);\r
100         goto bail;\r
101     }\r
102     if (!event)\r
103     {\r
104         dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG4);\r
105         goto bail;\r
106     }\r
107     if (!nmore)\r
108     {\r
109         dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG5);\r
110         goto bail;\r
111     }\r
112     if (threshold <= 0 ||\r
113         (threshold > 1 && evd_ptr->completion_type != DAPL_EVD_STATE_THRESHOLD) ||\r
114         threshold > evd_ptr->qlen)\r
115     {\r
116         dat_status = DAT_ERROR (DAT_INVALID_PARAMETER,DAT_INVALID_ARG3);\r
117         goto bail;\r
118     }\r
119     if ( evd_ptr->catastrophic_overflow )\r
120     {\r
121         dat_status = DAT_ERROR (DAT_INVALID_STATE,0);\r
122         goto bail;\r
123     }\r
124     DAPL_CNTR(evd_ptr, DCNT_EVD_WAIT);\r
125 \r
126     dapl_dbg_log (DAPL_DBG_TYPE_EVD, \r
127                   "dapl_evd_wait: EVD %p, CQ %p\n", \r
128                   evd_ptr,\r
129                   (void *)evd_ptr->ib_cq_handle);\r
130 \r
131     /*\r
132      * Make sure there are no other waiters and the evd is active.\r
133      * Currently this means only the OPEN state is allowed.\r
134      * Do this atomically.  We need to take a lock to synchronize\r
135      * with dapl_evd_dequeue(), but the atomic transition allows\r
136      * non-locking synchronization with dapl_evd_query() and\r
137      * dapl_evd_{query,enable,disable,{set,clear}_unwaitable}.\r
138      */\r
139 \r
140     dapl_os_lock ( &evd_ptr->header.lock );\r
141     waitable = evd_ptr->evd_waitable;\r
142 \r
143     dapl_os_assert ( sizeof(DAT_COUNT) == sizeof(DAPL_EVD_STATE) );\r
144     evd_state = dapl_os_atomic_assign ( (DAPL_ATOMIC *)&evd_ptr->evd_state,\r
145                                         (DAT_COUNT) DAPL_EVD_STATE_OPEN,\r
146                                         (DAT_COUNT) DAPL_EVD_STATE_WAITED );\r
147     dapl_os_unlock ( &evd_ptr->header.lock );\r
148 \r
149     if ( evd_state != DAPL_EVD_STATE_OPEN )\r
150     {\r
151         /* Bogus state, bail out */\r
152         dat_status = DAT_ERROR (DAT_INVALID_STATE,0);\r
153         goto bail;\r
154     }\r
155 \r
156     if (!waitable)\r
157     {\r
158         /* This EVD is not waitable, reset the state and bail */\r
159         (void) dapl_os_atomic_assign ((DAPL_ATOMIC *)&evd_ptr->evd_state,\r
160                                         (DAT_COUNT) DAPL_EVD_STATE_WAITED,\r
161                                         evd_state);\r
162         dat_status = DAT_ERROR (DAT_INVALID_STATE, DAT_INVALID_STATE_EVD_UNWAITABLE);\r
163         goto bail;\r
164     }\r
165 \r
166     /*\r
167      * We now own the EVD, even though we don't have the lock anymore,\r
168      * because we're in the WAITED state.\r
169      */\r
170 \r
171     evd_ptr->threshold = threshold;\r
172 \r
173     for (;;)\r
174     {\r
175         /*\r
176          * Ideally we'd just check the number of entries on the CQ, but\r
177          * we don't have a way to do that.  Because we have to set *nmore\r
178          * at some point in this routine, we'll need to do this copy\r
179          * sometime even if threshold == 1.\r
180          *\r
181          * For connection evd or async evd, the function checks and\r
182          * return right away if the ib_cq_handle associate with these evd\r
183          * equal to IB_INVALID_HANDLE\r
184          */\r
185         dapls_evd_copy_cq(evd_ptr);\r
186 \r
187         if (dapls_rbuf_count(&evd_ptr->pending_event_queue) >= threshold)\r
188         {\r
189             break;\r
190         }\r
191 \r
192         /*\r
193          * Do not enable the completion notification if this evd is not \r
194          * a DTO_EVD or RMR_BIND_EVD\r
195          */\r
196         if ( (!notify_requested) &&\r
197              ((evd_ptr->evd_flags & DAT_EVD_DTO_FLAG) ||\r
198               (evd_ptr->evd_flags & DAT_EVD_RMR_BIND_FLAG)) )\r
199         {\r
200             dat_status = dapls_ib_completion_notify (\r
201                 evd_ptr->header.owner_ia->hca_ptr->ib_hca_handle,\r
202                 evd_ptr,\r
203                 (evd_ptr->completion_type == DAPL_EVD_STATE_SOLICITED_WAIT) ?\r
204                      IB_NOTIFY_ON_SOLIC_COMP : IB_NOTIFY_ON_NEXT_COMP );  \r
205 \r
206             DAPL_CNTR(evd_ptr, DCNT_EVD_WAIT_NOTIFY);\r
207             /* FIXME report error */\r
208             dapl_os_assert(dat_status == DAT_SUCCESS);\r
209 \r
210             notify_requested = DAT_TRUE;\r
211 \r
212             /* Try again.  */\r
213             continue;\r
214         }\r
215 \r
216 \r
217         /*\r
218          * Unused by poster; it has no way to tell how many\r
219          * items are on the queue without copying them over to the\r
220          * EVD queue, and we're the only ones allowed to dequeue\r
221          * from the CQ for synchronization/locking reasons.\r
222          */\r
223         evd_ptr->threshold = threshold; \r
224 \r
225         DAPL_CNTR(evd_ptr, DCNT_EVD_WAIT_BLOCKED);\r
226 \r
227 #ifdef CQ_WAIT_OBJECT\r
228         if (evd_ptr->cq_wait_obj_handle)\r
229                 dat_status = dapls_ib_wait_object_wait (\r
230                                 evd_ptr->cq_wait_obj_handle, time_out );\r
231         else\r
232 #endif\r
233                 dat_status = dapl_os_wait_object_wait (\r
234                                 &evd_ptr->wait_object, time_out );\r
235         /*\r
236          * FIXME: if the thread loops around and waits again\r
237          * the time_out value needs to be updated.\r
238          */\r
239 \r
240         notify_requested = DAT_FALSE; /* We've used it up.  */\r
241 \r
242         /* See if we were awakened by evd_set_unwaitable */\r
243         if ( !evd_ptr->evd_waitable )\r
244         {\r
245                 dat_status = DAT_ERROR (DAT_INVALID_STATE,0);\r
246         }\r
247 \r
248         if (dat_status != DAT_SUCCESS)\r
249         {\r
250             /*\r
251              * If the status is DAT_TIMEOUT, we'll break out of the\r
252              * loop, *not* dequeue an event (because dat_status\r
253              * != DAT_SUCCESS), set *nmore (as we should for timeout)\r
254              * and return DAT_TIMEOUT.\r
255              */\r
256             break;\r
257         }\r
258     }\r
259             \r
260     evd_ptr->evd_state = DAPL_EVD_STATE_OPEN;\r
261 \r
262     if (dat_status == DAT_SUCCESS)\r
263     {\r
264         local_event = dapls_rbuf_remove(&evd_ptr->pending_event_queue);\r
265         *event = *local_event;\r
266         dapls_rbuf_add(&evd_ptr->free_event_queue, local_event);\r
267     }\r
268 \r
269     /*\r
270      * Valid if dat_status == DAT_SUCCESS || dat_status == DAT_TIMEOUT\r
271      * Undefined otherwise, so ok to set it.\r
272      */\r
273     *nmore = dapls_rbuf_count(&evd_ptr->pending_event_queue);\r
274 \r
275  bail:\r
276     if ( dat_status ) {\r
277         dapl_dbg_log (DAPL_DBG_TYPE_RTN,\r
278                         "dapl_evd_wait () returns 0x%x\n", dat_status);\r
279     }\r
280     return dat_status;\r
281 }\r