[DAPL2] DAPL Counters & 2.0.3 extensions to support counter retrieval.
[mirror/winof/.git] / ulp / dapl2 / dapl / common / dapl_ep_connect.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_connect.c\r
31  *\r
32  * PURPOSE: Endpoint management\r
33  *\r
34  * $Id:$\r
35  **********************************************************************/\r
36 \r
37 #include "dapl.h"\r
38 #include "dapl_ep_util.h"\r
39 #include "dapl_adapter_util.h"\r
40 #include "dapl_evd_util.h"\r
41 #include "dapl_timer_util.h"\r
42 \r
43 /*\r
44  * dapl_ep_connect\r
45  *\r
46  * Request a connection be established between the local Endpoint\r
47  * and a remote Endpoint. This operation is used by the active/client\r
48  * side of a connection\r
49  *\r
50  * Input:\r
51  *      ep_handle\r
52  *      remote_ia_address\r
53  *      remote_conn_qual\r
54  *      timeout\r
55  *      private_data_size\r
56  *      privaet_data\r
57  *      qos\r
58  *      connect_flags\r
59  *\r
60  * Output:\r
61  *      None\r
62  *\r
63  * Returns:\r
64  *      DAT_SUCCESS\r
65  *      DAT_INSUFFICIENT_RESOUCRES\r
66  *      DAT_INVALID_PARAMETER\r
67  *      DAT_MODLE_NOT_SUPPORTED\r
68  */\r
69 DAT_RETURN DAT_API\r
70 dapl_ep_connect (\r
71         IN      DAT_EP_HANDLE           ep_handle,\r
72         IN      DAT_IA_ADDRESS_PTR      remote_ia_address,\r
73         IN      DAT_CONN_QUAL           remote_conn_qual,\r
74         IN      DAT_TIMEOUT             timeout,\r
75         IN      DAT_COUNT               private_data_size,\r
76         IN      const DAT_PVOID         private_data,\r
77         IN      DAT_QOS                 qos,\r
78         IN      DAT_CONNECT_FLAGS       connect_flags )\r
79 {\r
80     DAPL_EP             *ep_ptr;\r
81     DAPL_EP             alloc_ep;\r
82     DAT_RETURN          dat_status;\r
83     DAT_COUNT           req_hdr_size;\r
84     DAT_UINT32          max_req_pdata_size;\r
85     void                *private_data_ptr;\r
86 \r
87     dapl_dbg_log (DAPL_DBG_TYPE_API | DAPL_DBG_TYPE_CM,\r
88                 "dapl_ep_connect (%p, {%u.%u.%u.%u}, %X, %d, %d, %p, %x, %x)\n",\r
89                 ep_handle,\r
90                 remote_ia_address->sa_data[2],\r
91                 remote_ia_address->sa_data[3],\r
92                 remote_ia_address->sa_data[4],\r
93                 remote_ia_address->sa_data[5],\r
94                 remote_conn_qual,\r
95                 timeout,\r
96                 private_data_size,\r
97                 private_data,\r
98                 qos,\r
99                 connect_flags);\r
100 \r
101     dat_status = DAT_SUCCESS;\r
102     ep_ptr = (DAPL_EP *) ep_handle;\r
103 \r
104     /*\r
105      * Verify parameter & state. The connection handle must be good\r
106      * at this point.\r
107      */\r
108     if ( DAPL_BAD_HANDLE (ep_ptr, DAPL_MAGIC_EP ) )\r
109     {\r
110         dat_status = DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EP);\r
111         goto bail;\r
112     }\r
113 \r
114     if ( DAPL_BAD_HANDLE (ep_ptr->param.connect_evd_handle, DAPL_MAGIC_EVD) )\r
115     {\r
116         dat_status = DAT_ERROR (DAT_INVALID_HANDLE, DAT_INVALID_HANDLE_EVD_CONN);\r
117         goto bail;\r
118     }\r
119 \r
120     /* Can't do a connection in 0 time, reject outright */\r
121     if ( timeout == 0 )\r
122     {\r
123         dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG4);\r
124         goto bail;\r
125     }\r
126     DAPL_CNTR (ep_ptr, DCNT_EP_CONNECT);\r
127 \r
128     /*\r
129      * If the endpoint needs a QP, associated the QP with it.\r
130      * This needs to be done carefully, in order to:\r
131      *  * Avoid allocating under a lock.\r
132      *  * Not step on data structures being altered by\r
133      *    routines with which we are racing.\r
134      * So we:\r
135      *  * Confirm that a new QP is needed and is not forbidden by the\r
136      *    current state.\r
137      *  * Allocate it into a separate EP.\r
138      *  * Take the EP lock.\r
139      *  * Reconfirm that the EP is in a state where it needs a QP.\r
140      *  * Assign the QP and release the lock.\r
141      */\r
142     if ( ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED )\r
143     {\r
144         if ( ep_ptr->param.pz_handle == NULL\r
145              ||  DAPL_BAD_HANDLE (ep_ptr->param.pz_handle, DAPL_MAGIC_PZ) )\r
146         {\r
147             dat_status = DAT_ERROR (DAT_INVALID_STATE, DAT_INVALID_STATE_EP_NOTREADY);\r
148             goto bail;\r
149         }\r
150         alloc_ep = *ep_ptr;\r
151 \r
152         dat_status = dapls_ib_qp_alloc ( ep_ptr->header.owner_ia,\r
153                                          &alloc_ep,\r
154                                          ep_ptr );\r
155         if ( dat_status != DAT_SUCCESS )\r
156         {\r
157             dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY);\r
158             goto bail;\r
159         }\r
160 \r
161         dapl_os_lock ( &ep_ptr->header.lock );\r
162         /*\r
163          * PZ shouldn't have changed since we're only racing with\r
164          * dapl_cr_accept()\r
165          */\r
166         if ( ep_ptr->qp_state != DAPL_QP_STATE_UNATTACHED )\r
167         {\r
168             /* Bail, cleaning up.  */\r
169             dapl_os_unlock ( &ep_ptr->header.lock );\r
170             dat_status = dapls_ib_qp_free ( ep_ptr->header.owner_ia,\r
171                                             &alloc_ep );\r
172             if (dat_status != DAT_SUCCESS)\r
173             {\r
174                 dapl_dbg_log (DAPL_DBG_TYPE_WARN,\r
175                               "ep_connect: ib_qp_free failed with %x\n",\r
176                               dat_status);\r
177             }\r
178             dat_status = DAT_ERROR (DAT_INVALID_STATE, dapls_ep_state_subtype (ep_ptr));\r
179             goto bail;\r
180         }\r
181 \r
182         ep_ptr->qp_handle = alloc_ep.qp_handle;\r
183         ep_ptr->qpn = alloc_ep.qpn;\r
184         ep_ptr->qp_state = alloc_ep.qp_state;\r
185 \r
186         dapl_os_unlock ( &ep_ptr->header.lock );\r
187     }\r
188 \r
189     /*\r
190      * We do state checks and transitions under lock.\r
191      * The only code we're racing against is dapl_cr_accept.\r
192      */\r
193     dapl_os_lock ( &ep_ptr->header.lock );\r
194 \r
195     /*\r
196      * Verify the attributes of the EP handle before we connect it. Test\r
197      * all of the handles to make sure they are currently valid.\r
198      * Specifically:\r
199      *   pz_handle              required\r
200      *   recv_evd_handle        optional, but must be valid\r
201      *   request_evd_handle     optional, but must be valid\r
202      *   connect_evd_handle     required\r
203      */\r
204     if ( ep_ptr->param.pz_handle == NULL\r
205          ||  DAPL_BAD_HANDLE (ep_ptr->param.pz_handle, DAPL_MAGIC_PZ)\r
206          /* test connect handle */\r
207          || ep_ptr->param.connect_evd_handle == NULL\r
208          || DAPL_BAD_HANDLE (ep_ptr->param.connect_evd_handle, DAPL_MAGIC_EVD)\r
209          || ! (((DAPL_EVD *)ep_ptr->param.connect_evd_handle)->evd_flags & DAT_EVD_CONNECTION_FLAG)\r
210          /* test optional completion handles */\r
211          || (ep_ptr->param.recv_evd_handle != DAT_HANDLE_NULL &&\r
212              (DAPL_BAD_HANDLE (ep_ptr->param.recv_evd_handle, DAPL_MAGIC_EVD)))\r
213          || (ep_ptr->param.request_evd_handle != DAT_HANDLE_NULL &&\r
214              (DAPL_BAD_HANDLE (ep_ptr->param.request_evd_handle, DAPL_MAGIC_EVD))))\r
215     {\r
216         dapl_os_unlock ( &ep_ptr->header.lock );\r
217         dat_status = DAT_ERROR (DAT_INVALID_STATE, DAT_INVALID_STATE_EP_NOTREADY);\r
218         goto bail;\r
219     }\r
220 \r
221     /* Check both the EP state and the QP state: if we don't have a QP\r
222      *  we need to attach one now.\r
223      */\r
224     if ( ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED )\r
225     {\r
226         dat_status = dapls_ib_qp_alloc ( ep_ptr->header.owner_ia,\r
227                                          ep_ptr, ep_ptr );\r
228 \r
229         if ( dat_status != DAT_SUCCESS)\r
230         {\r
231             dapl_os_unlock ( &ep_ptr->header.lock );\r
232             dat_status = DAT_ERROR (DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_TEP);\r
233             goto bail;\r
234         }\r
235     }\r
236 \r
237     if ( ep_ptr->param.ep_state != DAT_EP_STATE_UNCONNECTED )\r
238     {\r
239         dapl_os_unlock ( &ep_ptr->header.lock );\r
240         dat_status = DAT_ERROR (DAT_INVALID_STATE, dapls_ep_state_subtype (ep_ptr));\r
241         goto bail;\r
242     }\r
243 \r
244     if ( qos != DAT_QOS_BEST_EFFORT ||\r
245          connect_flags != DAT_CONNECT_DEFAULT_FLAG )\r
246     {\r
247         /*\r
248          * At this point we only support one QOS level\r
249          */\r
250         dapl_os_unlock ( &ep_ptr->header.lock );\r
251         dat_status = DAT_ERROR (DAT_MODEL_NOT_SUPPORTED, 0);\r
252         goto bail;\r
253     }\r
254 \r
255     /*\r
256      * Verify the private data size doesn't exceed the max\r
257      * req_hdr_size will evaluate to 0 unless IBHOSTS_NAMING is enabled.\r
258      */\r
259     req_hdr_size = (sizeof (DAPL_PRIVATE) - DAPL_MAX_PRIVATE_DATA_SIZE);\r
260 \r
261     max_req_pdata_size = dapls_ib_private_data_size(\r
262                                 NULL, DAPL_PDATA_CONN_REQ,\r
263                                 ep_ptr->header.owner_ia->hca_ptr);\r
264 \r
265     if (private_data_size + req_hdr_size > (DAT_COUNT)max_req_pdata_size) \r
266     {\r
267         dapl_os_unlock ( &ep_ptr->header.lock );\r
268         dat_status = DAT_ERROR (DAT_INVALID_PARAMETER, DAT_INVALID_ARG5);\r
269         goto bail;\r
270     }\r
271 \r
272     /* transition the state before requesting a connection to avoid\r
273      * race conditions\r
274      */\r
275     ep_ptr->param.ep_state = DAT_EP_STATE_ACTIVE_CONNECTION_PENDING;\r
276 \r
277     /*\r
278      * At this point we're committed, and done with the endpoint\r
279      * except for the connect, so we can drop the lock.\r
280      */\r
281     dapl_os_unlock ( &ep_ptr->header.lock );\r
282 \r
283 #ifdef IBHOSTS_NAMING\r
284     /*\r
285      * Special case: put the remote HCA address into the private data\r
286      * prefix. This is a spec violation as it introduces a protocol, but\r
287      * some implementations may find it necessary for a time.\r
288      * Copy the private data into the EP area so the data is contiguous.\r
289      * If the provider needs to pad the buffer with NULLs, it happens at\r
290      * the provider layer.\r
291      */\r
292     dapl_os_memcpy (&ep_ptr->hca_address,\r
293                     &ep_ptr->header.owner_ia->hca_ptr->hca_address,\r
294                     sizeof (DAT_SOCK_ADDR));\r
295     dapl_os_memcpy (ep_ptr->private.private_data, private_data, private_data_size);\r
296     private_data_ptr = (void *)&ep_ptr->private.private_data;\r
297 #else\r
298     private_data_ptr = private_data;\r
299 #endif /* IBHOSTS_NAMING */\r
300 \r
301     /* Copy the connection qualifiers */\r
302     dapl_os_memcpy ( ep_ptr->param.remote_ia_address_ptr,\r
303                      remote_ia_address,\r
304                      sizeof ( DAT_SOCK_ADDR) );\r
305     ep_ptr->param.remote_port_qual = remote_conn_qual;\r
306 \r
307     dat_status =  dapls_ib_connect ( ep_handle,\r
308                                      remote_ia_address,\r
309                                      remote_conn_qual,\r
310                                      private_data_size + req_hdr_size,\r
311                                      private_data_ptr );\r
312 \r
313     if ( dat_status != DAT_SUCCESS )\r
314     {\r
315         ep_ptr->param.ep_state = DAT_EP_STATE_UNCONNECTED;\r
316 \r
317         /*\r
318          * Some implementations provide us with an error code that the\r
319          * remote destination is unreachable, but DAT doesn't have a\r
320          * synchronous error code to communicate this. So the provider\r
321          * layer generates an INTERNAL_ERROR with a subtype; when\r
322          * this happens, return SUCCESS and generate the event\r
323          */\r
324         if (dat_status == DAT_ERROR (DAT_INTERNAL_ERROR, 1) )\r
325         {\r
326             dapls_evd_post_connection_event (\r
327                         (DAPL_EVD *)ep_ptr->param.connect_evd_handle,\r
328                         DAT_CONNECTION_EVENT_UNREACHABLE,\r
329                         (DAT_HANDLE) ep_ptr,\r
330                         0,\r
331                         0);\r
332             dat_status = DAT_SUCCESS;\r
333         }\r
334     }\r
335     else\r
336     {\r
337         /*\r
338          * Acquire the lock and recheck the state of the EP; this\r
339          * thread could have been descheduled after issuing the connect\r
340          * request and the EP is now connected. Set up a timer if\r
341          * necessary.\r
342          */\r
343         dapl_os_lock ( &ep_ptr->header.lock );\r
344         if (ep_ptr->param.ep_state == DAT_EP_STATE_ACTIVE_CONNECTION_PENDING &&\r
345             timeout != DAT_TIMEOUT_INFINITE )\r
346         {\r
347             ep_ptr->cxn_timer =\r
348                 (DAPL_OS_TIMER *)dapl_os_alloc (sizeof (DAPL_OS_TIMER));\r
349 \r
350             dapls_timer_set ( ep_ptr->cxn_timer,\r
351                               dapls_ep_timeout,\r
352                               ep_ptr,\r
353                               timeout );\r
354         }\r
355         dapl_os_unlock ( &ep_ptr->header.lock );\r
356     }\r
357 \r
358 bail:\r
359     dapl_dbg_log (DAPL_DBG_TYPE_RTN | DAPL_DBG_TYPE_CM,\r
360                   "dapl_ep_connect () returns 0x%x\n",\r
361                   dat_status);\r
362 \r
363     return dat_status;\r
364 }\r
365 \r
366 /*\r
367  * dapl_ep_common_connect\r
368  *\r
369  * DAPL Requirements Version 2.0, 6.6.x\r
370  *\r
371  * Requests that a connection be established\r
372  * between the local Endpoint and a remote Endpoint specified by the\r
373  * remote_ia_address. This operation is used by the active/client side\r
374  * Consumer of the Connection establishment model.\r
375  *\r
376  * EP must be properly configured for this operation. The EP Communicator\r
377  * must be specified. As part of the successful completion of this operation,\r
378  * the local Endpoint is bound to a local IA Address if it had these assigned\r
379  * before.\r
380  * \r
381  * The local IP Address, port and protocol are passed to the remote side of\r
382  * the requested connection and is available to the remote Consumer in the\r
383  * Connection Request of the DAT_CONNECTION_REQUEST_EVENT.\r
384  * \r
385  * The Consumer-provided private_data is passed to the remote side and is\r
386  * provided to the remote Consumer in the Connection Request. Consumers\r
387  * can encapsulate any local Endpoint attributes that remote Consumers\r
388  * need to know as part of an upper-level protocol.\r
389  *\r
390  * Input:\r
391  *      ep_handle\r
392  *      remote_ia_address\r
393  *      timeout\r
394  *      private_data_size\r
395  *      private_date pointer\r
396  *\r
397  * Output:\r
398  *      none\r
399  * \r
400  * Returns:\r
401  *      DAT_SUCCESS\r
402  *      DAT_INSUFFICIENT_RESOURCES\r
403  *      DAT_INVALID_PARAMETER\r
404  *      DAT_INVALID_HANDLE\r
405  *      DAT_INVALID_STATE\r
406  *      DAT_MODEL_NOT_SUPPORTED\r
407  */\r
408 DAT_RETURN DAT_API\r
409 dapl_ep_common_connect (\r
410         IN      DAT_EP_HANDLE ep,               /* ep_handle            */\r
411         IN      DAT_IA_ADDRESS_PTR remote_addr, /* remote_ia_address    */\r
412         IN      DAT_TIMEOUT timeout,            /* timeout              */\r
413         IN      DAT_COUNT pdata_size,           /* private_data_size    */\r
414         IN      const DAT_PVOID pdata   )       /* private_data         */\r
415 {\r
416         return DAT_MODEL_NOT_SUPPORTED;\r
417 }\r
418 \r
419 /*\r
420  * Local variables:\r
421  *  c-indent-level: 4\r
422  *  c-basic-offset: 4\r
423  *  tab-width: 8\r
424  * End:\r
425  */\r