9292ecdc0895ece321c35f432fa49cfa861a4b50
[mirror/winof/.git] / core / al / user / ual_cm.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. \r
4  *\r
5  * This software is available to you under the OpenIB.org BSD license\r
6  * below:\r
7  *\r
8  *     Redistribution and use in source and binary forms, with or\r
9  *     without modification, are permitted provided that the following\r
10  *     conditions are met:\r
11  *\r
12  *      - Redistributions of source code must retain the above\r
13  *        copyright notice, this list of conditions and the following\r
14  *        disclaimer.\r
15  *\r
16  *      - Redistributions in binary form must reproduce the above\r
17  *        copyright notice, this list of conditions and the following\r
18  *        disclaimer in the documentation and/or other materials\r
19  *        provided with the distribution.\r
20  *\r
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
22  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
24  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
25  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
26  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
27  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
28  * SOFTWARE.\r
29  *\r
30  * $Id$\r
31  */\r
32 \r
33 #include <iba/ib_al.h>\r
34 #include "al.h"\r
35 #include "al_cm_shared.h"\r
36 #include "al_debug.h"\r
37 \r
38 #if defined(EVENT_TRACING)\r
39 #ifdef offsetof\r
40 #undef offsetof\r
41 #endif\r
42 #include "ual_cm.tmh"\r
43 #endif\r
44 \r
45 #include "al_dev.h"\r
46 #include "al_qp.h"\r
47 #include "ib_common.h"\r
48 #include "ual_cm.h"\r
49 \r
50 \r
51 \r
52 /*\r
53  * Attach the QP and connection object to each other.\r
54  */\r
55 static void\r
56 __bind_qp_and_conn(\r
57         IN              const   ib_cm_handle_t                          h_conn,\r
58         IN              const   ib_qp_handle_t                          h_qp )\r
59 {\r
60         h_conn->h_qp = h_qp;\r
61         ((al_conn_qp_t*)h_qp)->p_conn = h_conn;\r
62 }\r
63 \r
64 \r
65 static void\r
66 __free_listen(\r
67         IN                              struct _al_obj                          *p_obj )\r
68 {\r
69         destroy_al_obj( p_obj );\r
70         cl_free( p_obj );\r
71 }\r
72 \r
73 \r
74 \r
75 static void\r
76 __destroying_conn(\r
77         IN                              struct _al_obj                          *p_obj )\r
78 {\r
79         ib_cm_handle_t                  h_conn;\r
80 \r
81         h_conn = (ib_cm_handle_t)p_obj;\r
82 \r
83         if( h_conn->h_al )\r
84         {\r
85                 if( h_conn->h_qp )\r
86                 {\r
87                         /* Unbind the QP and connection from each other. */\r
88                         ((al_conn_qp_t*)h_conn->h_qp)->p_conn = NULL;\r
89                         h_conn->h_qp = NULL;\r
90                 }\r
91 \r
92                 /* Remove the connection object from AL's list. */\r
93                 al_remove_conn( h_conn );\r
94         }\r
95 }\r
96 \r
97 \r
98 \r
99 static void\r
100 __free_conn_req(\r
101         IN              const   ib_cm_handle_t                          h_conn )\r
102 {\r
103         if( !h_conn->p_conn_req )\r
104                 return;\r
105 \r
106         cl_free( h_conn->p_conn_req );\r
107         h_conn->p_conn_req = NULL;\r
108 }\r
109 \r
110 \r
111 \r
112 static void\r
113 __free_conn(\r
114         IN                              struct _al_obj                          *p_obj )\r
115 {\r
116         ib_cm_handle_t                  h_conn;\r
117 \r
118         h_conn = (ib_cm_handle_t)p_obj;\r
119 \r
120         /* Release all memory used to store the connection information. */\r
121         __free_conn_req( h_conn );\r
122         destroy_al_obj( p_obj );\r
123         cl_free( p_obj );\r
124 }\r
125 \r
126 \r
127 static void\r
128 __ual_conn_reject(\r
129         IN                              al_conn_t* const                        p_conn,\r
130         IN              const   ib_rej_status_t                         reason )\r
131 {\r
132         ib_cm_rej_t             rej = {0};\r
133 \r
134         rej.rej_status = reason;\r
135 \r
136         ib_cm_rej( p_conn, &rej );\r
137 }\r
138 \r
139 \r
140 /*\r
141  * Called by the QP upon destruction if still connected.\r
142  */\r
143 void\r
144 cm_conn_destroy(\r
145         IN                              al_conn_qp_t * const            p_conn_qp )\r
146 {\r
147         UNUSED_PARAM( p_conn_qp );\r
148 }\r
149 \r
150 \r
151 \r
152 /*\r
153  * Called by AL to destroy connection objects that were not destroyed\r
154  * properly.  In theory, this function should not be called, unless the\r
155  * application using AL is not written properly.\r
156  */\r
157 void\r
158 cm_cleanup_conn(\r
159         IN              const   ib_cm_handle_t                          h_conn )\r
160 {\r
161         /* Just destroy the connection object. */\r
162         ref_al_obj( &h_conn->obj );\r
163         h_conn->obj.pfn_destroy( &h_conn->obj, NULL );\r
164 }\r
165 \r
166 \r
167 \r
168 /*\r
169  * Allocate and initialize a structure to store CM information.\r
170  */\r
171 static ib_listen_handle_t\r
172 __get_listen(\r
173         IN              const   ib_al_handle_t                          h_al )\r
174 {\r
175         ib_listen_handle_t      h_listen;\r
176         ib_api_status_t         status;\r
177 \r
178         /* Allocate the structure. */\r
179         h_listen = cl_zalloc( sizeof( al_listen_t ) );\r
180         if( !h_listen )\r
181                 return NULL;\r
182 \r
183         /* Initialize the al object portion. */\r
184         construct_al_obj( &h_listen->obj, AL_OBJ_TYPE_H_LISTEN );\r
185         status = init_al_obj( &h_listen->obj, h_listen, TRUE,\r
186                 NULL, NULL, __free_listen );\r
187         if( status != IB_SUCCESS )\r
188         {\r
189                 cl_free( h_listen );\r
190                 return NULL;\r
191         }\r
192 \r
193         /* The CM info structure is a child of AL. */\r
194         attach_al_obj( &h_al->obj, &h_listen->obj );\r
195 \r
196         return h_listen;\r
197 }\r
198 \r
199 \r
200 \r
201 static ib_cm_handle_t\r
202 __get_conn(\r
203         IN              const   ib_al_handle_t                          h_al )\r
204 {\r
205         ib_cm_handle_t          h_conn;\r
206         ib_api_status_t         status;\r
207 \r
208         /* Allocate the structure. */\r
209         h_conn = cl_zalloc( sizeof( al_conn_t ) );\r
210         if( !h_conn )\r
211                 return NULL;\r
212 \r
213         /* Allocate resources to establish the connection. */\r
214         h_conn->p_conn_req = cl_zalloc( sizeof( conn_req_t ) );\r
215         if( !h_conn->p_conn_req )\r
216         {\r
217                 __free_conn( &h_conn->obj );\r
218                 return NULL;\r
219         }\r
220 \r
221         /* Initialize the al object portion. */\r
222         construct_al_obj( &h_conn->obj, AL_OBJ_TYPE_H_CONN );\r
223         status = init_al_obj( &h_conn->obj, h_conn, TRUE,\r
224                 __destroying_conn, NULL, __free_conn );\r
225         if( status != IB_SUCCESS )\r
226         {\r
227                 __free_conn( &h_conn->obj );\r
228                 return NULL;\r
229         }\r
230 \r
231         al_insert_conn( h_al, h_conn );\r
232         return h_conn;\r
233 }\r
234 \r
235 \r
236 \r
237 /*\r
238  * Reject a connection request.\r
239  */\r
240 static void\r
241 __rej_conn(\r
242         IN              const   ib_cm_handle_t                          h_cm,\r
243         IN                              ib_rej_status_t                         rej_status )\r
244 {\r
245         ib_cm_rej_t                                     cm_rej;\r
246 \r
247         cl_memclr( &cm_rej, sizeof( ib_cm_rej_t ) );\r
248         cm_rej.rej_status = rej_status;\r
249         ib_cm_rej( h_cm, &cm_rej );\r
250 }\r
251 \r
252 \r
253 \r
254 /*\r
255  * Initiate a listen for a connection request.\r
256  */\r
257 ib_api_status_t\r
258 ib_cm_listen(\r
259         IN              const   ib_al_handle_t                          h_al,\r
260         IN              const   ib_cm_listen_t* const           p_cm_listen,\r
261         IN              const   ib_pfn_listen_err_cb_t          pfn_listen_err_cb,\r
262         IN              const   void* const                                     listen_context,\r
263                 OUT                     ib_listen_handle_t* const       ph_cm_listen )\r
264 {\r
265         ual_cm_listen_ioctl_t   *p_cm_ioctl;\r
266         size_t                                  ioctl_buf_sz;\r
267         uintn_t                                 bytes_ret;\r
268         ib_api_status_t                 status;\r
269         cl_status_t                             cl_status;\r
270         ib_listen_handle_t              h_listen;\r
271 \r
272         AL_ENTER( AL_DBG_CM );\r
273 \r
274         /* Validate input parameters. */\r
275         if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) )\r
276         {\r
277                 AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, ("Invalid AL handle.\n") );\r
278                 return IB_INVALID_AL_HANDLE;\r
279         }\r
280         if( !p_cm_listen || !ph_cm_listen )\r
281         {\r
282                 AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, ("NULL parameter.\n") );\r
283                 return IB_INVALID_PARAMETER;\r
284         }\r
285 \r
286         /* Get a listen structure. */\r
287         h_listen = __get_listen( h_al );\r
288         if( !h_listen )\r
289         {\r
290                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
291                         ("Failed to allocate listen structure.\n") );\r
292                 return IB_INSUFFICIENT_MEMORY;\r
293         }\r
294 \r
295         /* Save the user's information. */\r
296         h_listen->pfn_cm_req_cb = p_cm_listen->pfn_cm_req_cb;\r
297         h_listen->pfn_cm_mra_cb = p_cm_listen->pfn_cm_mra_cb;\r
298         h_listen->pfn_cm_rej_cb = p_cm_listen->pfn_cm_rej_cb;\r
299         h_listen->pfn_listen_err_cb = pfn_listen_err_cb;\r
300         h_listen->obj.context = listen_context;\r
301         h_listen->sidr_context = p_cm_listen->sidr_context;\r
302 \r
303         ioctl_buf_sz = sizeof(p_cm_ioctl->in);\r
304         if( p_cm_listen->p_compare_buffer )\r
305                 ioctl_buf_sz += p_cm_listen->compare_length;\r
306 \r
307         p_cm_ioctl = (ual_cm_listen_ioctl_t*)cl_zalloc( ioctl_buf_sz );\r
308         if( !p_cm_ioctl )\r
309         {\r
310                 h_listen->obj.pfn_destroy( &h_listen->obj, NULL );\r
311                 AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, ("Failed to allocate IOCTL buffer.\n") );\r
312                 return IB_INSUFFICIENT_MEMORY;\r
313         }\r
314 \r
315         /* Initialize the IOCTL. */\r
316         p_cm_ioctl->in.context = h_listen;\r
317         p_cm_ioctl->in.cm_listen = *p_cm_listen;\r
318         /* Convert the user's information to ALs. */\r
319         p_cm_ioctl->in.cm_listen.sidr_context = h_listen;\r
320         if( p_cm_listen->p_compare_buffer )\r
321         {\r
322                 cl_memcpy( (uint8_t*)((&p_cm_ioctl->in.cm_listen) + 1),\r
323                         p_cm_listen->p_compare_buffer, p_cm_listen->compare_length );\r
324         }\r
325 \r
326         /* Call the kernel CM to do the listen. */\r
327         cl_status = do_al_dev_ioctl( UAL_CM_LISTEN, &p_cm_ioctl->in, ioctl_buf_sz,\r
328                 &p_cm_ioctl->out, sizeof(p_cm_ioctl->out), &bytes_ret );\r
329 \r
330         if( cl_status != CL_SUCCESS || bytes_ret != sizeof(p_cm_ioctl->out) )\r
331         {\r
332                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
333                         ("UAL_CM_LISTEN IOCTL returned %s\n", CL_STATUS_MSG(cl_status)) );\r
334                 status = IB_ERROR;\r
335         }\r
336         else\r
337         {\r
338                 status = p_cm_ioctl->out.status;\r
339         }\r
340 \r
341         if( status != IB_SUCCESS )\r
342         {\r
343                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
344                         ("Failed to listen: %s.\n", ib_get_err_str(status) ) );\r
345                 h_listen->obj.pfn_destroy( &h_listen->obj, NULL );\r
346         }\r
347         else\r
348         {\r
349                 h_listen->obj.hdl = p_cm_ioctl->out.h_cm_listen;\r
350                 *ph_cm_listen = h_listen;\r
351 \r
352                 /* Release the reference taken in init_al_obj (__get_listen). */\r
353                 deref_al_obj( &h_listen->obj );\r
354         }\r
355 \r
356         cl_free( p_cm_ioctl );\r
357         AL_EXIT( AL_DBG_CM );\r
358         return status;\r
359 }\r
360 \r
361 \r
362 \r
363 ib_api_status_t\r
364 ib_cm_cancel(\r
365         IN              const   ib_listen_handle_t                      h_cm_listen,\r
366         IN              const   ib_pfn_destroy_cb_t                     pfn_destroy_cb OPTIONAL )\r
367 {\r
368         ual_cm_cancel_ioctl_t   cm_ioctl;\r
369         uintn_t                                 bytes_ret;\r
370         ib_api_status_t                 status;\r
371         cl_status_t                             cl_status;\r
372 \r
373         AL_ENTER( AL_DBG_CM );\r
374 \r
375         if( AL_OBJ_INVALID_HANDLE( h_cm_listen, AL_OBJ_TYPE_H_LISTEN ) )\r
376         {\r
377                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("Invalid listen handle.\n") );\r
378                 return IB_INVALID_HANDLE;\r
379         }\r
380 \r
381         /* Take a reference on the listen until the IOCTL completes. */\r
382         ref_al_obj( &h_cm_listen->obj );\r
383 \r
384         /* Initialize the IOCTL. */\r
385         cl_memclr( &cm_ioctl, sizeof( cm_ioctl ) );\r
386         cm_ioctl.in.h_cm_listen = h_cm_listen->obj.hdl;\r
387 \r
388         /* Call the kernel CM to do the cancel. */\r
389         cl_status = do_al_dev_ioctl( UAL_CM_CANCEL, &cm_ioctl.in,\r
390                 sizeof(cm_ioctl.in), &cm_ioctl.out, sizeof(cm_ioctl.out), &bytes_ret );\r
391 \r
392         if( cl_status != CL_SUCCESS || bytes_ret != sizeof(cm_ioctl.out) )\r
393         {\r
394                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
395                         ("UAL_CM_CANCEL IOCTL returned %s\n", CL_STATUS_MSG(cl_status)) );\r
396                 status = IB_ERROR;\r
397         }\r
398         else\r
399         {\r
400                 status = cm_ioctl.out.status;\r
401         }\r
402         if( status != IB_SUCCESS )\r
403         {\r
404                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
405                         ("Failed to cancel: %s.\n", ib_get_err_str(status) ) );\r
406                 deref_al_obj( &h_cm_listen->obj );\r
407         }\r
408         else\r
409         {\r
410                 h_cm_listen->obj.pfn_destroy( &h_cm_listen->obj, pfn_destroy_cb );\r
411         }\r
412 \r
413         AL_EXIT( AL_DBG_CM );\r
414         return status;\r
415 }\r
416 \r
417 \r
418 \r
419 /*\r
420  * Initiate a connection request.\r
421  */\r
422 ib_api_status_t\r
423 ib_cm_req(\r
424         IN      const           ib_cm_req_t* const                      p_cm_req )\r
425 {\r
426         ib_cm_handle_t                  h_conn;\r
427         ual_cm_req_ioctl_t              *p_cm_ioctl;\r
428         size_t                                  ioctl_buf_sz;\r
429         uint8_t                                 *p_data;\r
430         uintn_t                                 bytes_ret;\r
431         ib_api_status_t                 status;\r
432         cl_status_t                             cl_status;\r
433 \r
434         AL_ENTER( AL_DBG_CM );\r
435 \r
436         /* Validate input parameters. */\r
437         if( !p_cm_req || !p_cm_req->p_primary_path )\r
438         {\r
439                 AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR,\r
440                         ("NULL p_cm_req or primary path\n") );\r
441                 return IB_INVALID_PARAMETER;\r
442         }\r
443 \r
444         ioctl_buf_sz = sizeof(p_cm_ioctl->in);\r
445         if( p_cm_req->p_compare_buffer )\r
446                 ioctl_buf_sz += p_cm_req->compare_length;\r
447         if( p_cm_req->p_req_pdata )\r
448                 ioctl_buf_sz += p_cm_req->req_length;\r
449         if( p_cm_req->p_alt_path )\r
450                 ioctl_buf_sz += sizeof(ib_path_rec_t);\r
451 \r
452         p_cm_ioctl = (ual_cm_req_ioctl_t*)cl_zalloc( ioctl_buf_sz );\r
453         if( !p_cm_ioctl )\r
454         {\r
455                 AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR,\r
456                         ("Failed to allocate IOCTL buf.\n") );\r
457                 return IB_INSUFFICIENT_MEMORY;\r
458         }\r
459 \r
460         /*\r
461          * Save the user's information and replace the handles with appropriate\r
462          * kernel handles.\r
463          */\r
464         p_cm_ioctl->in.cm_req = *p_cm_req;\r
465         switch( p_cm_req->qp_type )\r
466         {\r
467         case IB_QPT_RELIABLE_CONN:\r
468         case IB_QPT_UNRELIABLE_CONN:\r
469                 if( AL_OBJ_INVALID_HANDLE( p_cm_req->h_qp, AL_OBJ_TYPE_H_QP ) ||\r
470                         (p_cm_req->h_qp->type != p_cm_req->qp_type) )\r
471                 {\r
472                         AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
473                                 ("IB_INVALID_QP_HANDLE\n") );\r
474                         status = IB_INVALID_QP_HANDLE;\r
475                         goto cleanup;\r
476                 }\r
477 \r
478                 /* Update the QP destroy timeout = timeout x retries + 2 seconds. */\r
479                 set_al_obj_timeout( &p_cm_req->h_qp->obj,\r
480                         p_cm_req->timeout_ms * p_cm_req->max_cm_retries + 2000 );\r
481 \r
482                 /* Get a connection structure. */\r
483                 h_conn = __get_conn( (ib_al_handle_t)\r
484                         p_cm_req->h_qp->obj.p_parent_obj->p_parent_obj->p_parent_obj );\r
485                 if( !h_conn )\r
486                 {\r
487                         AL_PRINT(TRACE_LEVEL_ERROR , AL_DBG_ERROR ,\r
488                                 ("Failed to allocate connection structure.\n") );\r
489                         status = IB_INSUFFICIENT_MEMORY;\r
490                         goto cleanup;\r
491                 }\r
492 \r
493                 __bind_qp_and_conn( h_conn, p_cm_req->h_qp );\r
494                 p_cm_ioctl->in.h_qp = p_cm_req->h_qp->obj.hdl;\r
495 \r
496                 /* Record the connection information for QP transitions. */\r
497                 h_conn->p_conn_req->path_rec = *p_cm_req->p_primary_path;\r
498                 if( p_cm_req->p_alt_path )\r
499                         h_conn->p_conn_req->alt_path_rec = *p_cm_req->p_alt_path;\r
500 \r
501                 /* Transition the QP to the init state to allow posting receives. */\r
502                 status = cm_init_qp( h_conn->h_qp, &p_cm_req->p_primary_path->sgid,\r
503                         p_cm_req->p_primary_path->pkey,\r
504                         (IB_AC_RDMA_READ | IB_AC_RDMA_WRITE | IB_AC_LOCAL_WRITE | IB_AC_MW_BIND) );\r
505                         //h_conn->p_req_info->qp_mod_rts.state.rts.access_ctrl );\r
506                 if( status != IB_SUCCESS )\r
507                 {\r
508                         h_conn->obj.pfn_destroy( &h_conn->obj, NULL );\r
509                         AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
510                                 ("cm_init_qp returned %s\n", ib_get_err_str(status)) );\r
511                         goto cleanup;\r
512                 }\r
513                 break;\r
514 \r
515         case IB_QPT_UNRELIABLE_DGRM:\r
516                 if( AL_OBJ_INVALID_HANDLE( p_cm_req->h_al, AL_OBJ_TYPE_H_AL ) )\r
517                 {\r
518                         AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
519                                 ("IB_INVALID_AL_HANDLE\n") );\r
520                         status = IB_INVALID_AL_HANDLE;\r
521                         goto cleanup;\r
522                 }\r
523                 /* Get a connection structure. */\r
524                 h_conn = __get_conn( p_cm_req->h_al );\r
525                 if( !h_conn )\r
526                 {\r
527                         AL_PRINT(TRACE_LEVEL_ERROR , AL_DBG_ERROR ,\r
528                                 ("Failed to allocate connection structure.\n") );\r
529                         status = IB_INSUFFICIENT_MEMORY;\r
530                         goto cleanup;\r
531                 }\r
532                 p_cm_ioctl->in.cm_req.h_al = NULL;\r
533                 h_conn->sidr_context = p_cm_req->sidr_context;\r
534                 p_cm_ioctl->in.cm_req.sidr_context = h_conn;\r
535                 break;\r
536 \r
537         default:\r
538                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("Invalid qp_type.\n") );\r
539                 status = IB_INVALID_SETTING;\r
540                 goto cleanup;\r
541         }\r
542 \r
543         h_conn->p_conn_req->pfn_cm_req_cb = p_cm_req->pfn_cm_req_cb;\r
544         h_conn->p_conn_req->pfn_cm_rep_cb = p_cm_req->pfn_cm_rep_cb;\r
545         h_conn->pfn_cm_mra_cb = p_cm_req->pfn_cm_mra_cb;\r
546         h_conn->pfn_cm_rej_cb = p_cm_req->pfn_cm_rej_cb;\r
547 \r
548         p_cm_ioctl->in.paths[0] = *p_cm_req->p_primary_path;\r
549         p_data = (uint8_t*)&p_cm_ioctl->in.paths[1];\r
550         if( p_cm_req->p_alt_path )\r
551         {\r
552                 p_cm_ioctl->in.paths[1] = *p_cm_req->p_alt_path;\r
553                 p_data += sizeof(ib_path_rec_t);\r
554         }\r
555         if( p_cm_req->req_length )\r
556         {\r
557                 cl_memcpy( p_data, p_cm_req->p_req_pdata, p_cm_req->req_length );\r
558                 p_data += p_cm_req->req_length;\r
559         }\r
560         if( p_cm_req->compare_length )\r
561         {\r
562                 cl_memcpy( p_data, p_cm_req->p_compare_buffer,\r
563                         p_cm_req->compare_length );\r
564         }\r
565 \r
566         cl_status = do_al_dev_ioctl( UAL_CM_REQ, &p_cm_ioctl->in, ioctl_buf_sz,\r
567                 &p_cm_ioctl->out, sizeof(p_cm_ioctl->out), &bytes_ret );\r
568 \r
569         if( cl_status != CL_SUCCESS || bytes_ret != sizeof(p_cm_ioctl->out) )\r
570         {\r
571                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
572                         ("UAL_CM_REQ IOCTL returned %s\n", CL_STATUS_MSG(cl_status)) );\r
573                 status = IB_ERROR;\r
574         }\r
575         else\r
576         {\r
577                 status = p_cm_ioctl->out.status;\r
578         }\r
579 \r
580         if( status != IB_SUCCESS )\r
581         {\r
582                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
583                         ("Connection request ioctl failed with status (%s)\n",\r
584                         ib_get_err_str(status) ) );\r
585                 h_conn->obj.pfn_destroy( &h_conn->obj, NULL );\r
586         }\r
587         else\r
588         {\r
589                 /* Release the reference taken in init_al_obj (__get_conn). */\r
590                 deref_al_obj( &h_conn->obj );\r
591         }\r
592 \r
593 cleanup:\r
594         cl_free( p_cm_ioctl );\r
595         AL_EXIT( AL_DBG_CM );\r
596         return status;\r
597 }\r
598 \r
599 \r
600 \r
601 static ib_api_status_t\r
602 __save_user_rep(\r
603         IN              const   ib_cm_handle_t                          h_conn,\r
604         IN              const   ib_cm_rep_t* const                      p_cm_rep )\r
605 {\r
606         ib_port_attr_t          *p_port_attr;\r
607         ib_qp_handle_t          h_qp;\r
608 \r
609         AL_ENTER(AL_DBG_CM);\r
610 \r
611         __bind_qp_and_conn( h_conn, p_cm_rep->h_qp );\r
612         h_qp = p_cm_rep->h_qp;\r
613 \r
614         /* Get the port attributes. */\r
615         ci_ca_lock_attr( h_qp->obj.p_ci_ca );\r
616         p_port_attr = get_port_attr( h_qp->obj.p_ci_ca->p_pnp_attr, \r
617                 &h_conn->p_conn_req->path_rec.sgid );\r
618         if( !p_port_attr )\r
619         {\r
620                 ci_ca_unlock_attr( h_qp->obj.p_ci_ca );\r
621                 AL_PRINT(TRACE_LEVEL_ERROR , AL_DBG_ERROR , ("invalid p_gid\n" ) );\r
622                 return IB_INVALID_GID;\r
623         }\r
624 \r
625         cm_save_rep_qp_attr( p_cm_rep, p_port_attr, &h_conn->p_conn_req->path_rec,\r
626                 &h_conn->p_conn_req->alt_path_rec, &h_conn->p_conn_req->qp_mod_rtr,\r
627                 &h_conn->p_conn_req->qp_mod_rts );\r
628         ci_ca_unlock_attr( h_qp->obj.p_ci_ca );\r
629 \r
630         AL_EXIT(AL_DBG_CM);\r
631         return IB_SUCCESS;\r
632 }\r
633 \r
634 \r
635 \r
636 ib_api_status_t\r
637 ib_cm_rep(\r
638         IN              const   ib_cm_handle_t                          h_cm_req,\r
639         IN              const   ib_cm_rep_t* const                      p_cm_rep )\r
640 {\r
641         ib_cm_handle_t                  h_conn;\r
642         ual_cm_rep_ioctl_t              *p_cm_ioctl;\r
643         size_t                                  ioctl_buf_sz;\r
644         uintn_t                                 bytes_ret;\r
645         ib_api_status_t                 status;\r
646         cl_status_t                             cl_status;\r
647 \r
648         AL_ENTER(AL_DBG_CM);\r
649 \r
650         /* Validate input parameters. */\r
651         h_conn = h_cm_req;\r
652         if( AL_OBJ_INVALID_HANDLE( h_conn, AL_OBJ_TYPE_H_CONN ) )\r
653         {\r
654                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("Invalid REQ handle.\n") );\r
655                 return IB_INVALID_HANDLE;\r
656         }\r
657         if( !p_cm_rep )\r
658         {\r
659                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("NULL p_cm_rep\n") );\r
660                 return IB_INVALID_PARAMETER;\r
661         }\r
662 \r
663         /* Save the user's information. */\r
664         h_conn->p_conn_req->pfn_cm_rtu_cb = p_cm_rep->pfn_cm_rtu_cb;\r
665         h_conn->pfn_cm_lap_cb = p_cm_rep->pfn_cm_lap_cb;\r
666         h_conn->pfn_cm_dreq_cb = p_cm_rep->pfn_cm_dreq_cb;\r
667 \r
668         /* Calculate the size of the IOCTL buffer needed. */\r
669         ioctl_buf_sz = sizeof(p_cm_ioctl->in);\r
670         if( p_cm_rep->p_rep_pdata )\r
671                 ioctl_buf_sz += p_cm_rep->rep_length;\r
672 \r
673         /* Allocate the IOCTL buffer. */\r
674         p_cm_ioctl = (ual_cm_rep_ioctl_t*)cl_zalloc( ioctl_buf_sz );\r
675         if( !p_cm_ioctl )\r
676         {\r
677                 AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, ("Failed to allocate IOCTL buffer.\n") );\r
678                 return IB_INSUFFICIENT_MEMORY;\r
679         }\r
680 \r
681         /* Replace the handles with appropriate kernel handles. */\r
682         p_cm_ioctl->in.cm_rep = *p_cm_rep;\r
683         if( AL_OBJ_INVALID_HANDLE( p_cm_rep->h_qp, AL_OBJ_TYPE_H_QP ) ||\r
684                 p_cm_rep->h_qp->type != p_cm_rep->qp_type )\r
685         {\r
686                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
687                         ("Invalid QP handle.\n") );\r
688                 status = IB_INVALID_QP_HANDLE;\r
689                 goto cleanup;\r
690         }\r
691         p_cm_ioctl->in.h_qp = p_cm_rep->h_qp->obj.hdl;\r
692 \r
693         /* Update the QP destruction timeout, use value provided by kernel CM. */\r
694         set_al_obj_timeout( &p_cm_rep->h_qp->obj, h_conn->p_conn_req->timeout_ms );\r
695 \r
696         status = __save_user_rep( h_conn, p_cm_rep );\r
697         if( status != IB_SUCCESS )\r
698         {\r
699                 __ual_conn_reject( h_conn, IB_REJ_INSUF_QP );\r
700                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
701                         ("__save_user_rep returned %s\n", ib_get_err_str(status) ) );\r
702                 goto cleanup;\r
703         }\r
704 \r
705         /* Transition the QP to the init state to allow posting receives. */\r
706         status = cm_init_qp( p_cm_rep->h_qp, &h_conn->p_conn_req->path_rec.sgid,\r
707                 h_conn->p_conn_req->path_rec.pkey, p_cm_rep->access_ctrl );\r
708         if( status != IB_SUCCESS )\r
709         {\r
710                 __ual_conn_reject( h_conn, IB_REJ_INSUF_QP );\r
711                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
712                         ("cm_init_qp returned %s\n", ib_get_err_str(status) ) );\r
713                 goto cleanup;\r
714         }\r
715 \r
716         /* Prepost receives. */\r
717         if( p_cm_rep->p_recv_wr )\r
718         {\r
719                 status = ib_post_recv( p_cm_rep->h_qp, p_cm_rep->p_recv_wr,\r
720                         p_cm_rep->pp_recv_failure );\r
721                 if( status != IB_SUCCESS )\r
722                 {\r
723                         __ual_conn_reject( h_conn, IB_REJ_INSUF_QP );\r
724                         AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
725                                 ("ib_post_recv returned %s.\n", ib_get_err_str(status)) );\r
726                         goto cleanup;\r
727                 }\r
728         }\r
729         p_cm_ioctl->in.cm_rep.p_recv_wr = NULL;\r
730 \r
731         /* Transition the QP to the RTS state. */\r
732         status = cm_rts_qp( h_conn->h_qp, &h_conn->p_conn_req->qp_mod_rtr,\r
733                 &h_conn->p_conn_req->qp_mod_rts );\r
734         if( status != IB_SUCCESS )\r
735         {\r
736                 __ual_conn_reject( h_conn, IB_REJ_INSUF_QP );\r
737                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
738                         ("cm_rts_qp with status (%s)\n", ib_get_err_str(status) ) );\r
739                 goto cleanup;\r
740         }\r
741 \r
742         p_cm_ioctl->in.h_cm_req = h_conn->obj.hdl;\r
743         /* Copy the private data. */\r
744         if( p_cm_rep->p_rep_pdata )\r
745         {\r
746                 cl_memcpy( (&p_cm_ioctl->in.cm_rep) + 1,\r
747                         p_cm_rep->p_rep_pdata, p_cm_rep->rep_length );\r
748         }\r
749 \r
750         cl_status = do_al_dev_ioctl( UAL_CM_REP,\r
751                 &p_cm_ioctl->in, ioctl_buf_sz,\r
752                 &p_cm_ioctl->out, sizeof(p_cm_ioctl->out),\r
753                 &bytes_ret );\r
754 \r
755         if( cl_status != CL_SUCCESS || bytes_ret != sizeof(p_cm_ioctl->out) )\r
756         {\r
757                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
758                         ("UAL_CM_REP IOCTL returned %s\n", CL_STATUS_MSG(cl_status)) );\r
759                 status = IB_ERROR;\r
760         }\r
761         else\r
762         {\r
763                 status = p_cm_ioctl->out.status;\r
764         }\r
765 \r
766         if( status != IB_SUCCESS )\r
767         {\r
768                 AL_PRINT(TRACE_LEVEL_ERROR , AL_DBG_ERROR ,\r
769                         ("Connection reply ioctl failed with status (%s)\n",\r
770                         ib_get_err_str(status) ) );\r
771                 cm_reset_qp( h_conn->h_qp, 0 );\r
772                 ref_al_obj( &h_conn->obj );\r
773                 h_conn->obj.pfn_destroy( &h_conn->obj, NULL );\r
774         }\r
775 \r
776 cleanup:\r
777         cl_free( p_cm_ioctl );\r
778         AL_EXIT( AL_DBG_CM );\r
779         return status;\r
780 }\r
781 \r
782 \r
783 \r
784 ib_api_status_t\r
785 ib_cm_rtu(\r
786         IN      const           ib_cm_handle_t                          h_cm_rep,\r
787         IN      const           ib_cm_rtu_t* const                      p_cm_rtu )\r
788 {\r
789         ib_cm_handle_t                  h_conn;\r
790         ual_cm_rtu_ioctl_t              *p_cm_ioctl;\r
791         size_t                                  ioctl_buf_sz;\r
792         uintn_t                                 bytes_ret;\r
793         ib_api_status_t                 status;\r
794         cl_status_t                             cl_status;\r
795 \r
796         AL_ENTER(AL_DBG_CM);\r
797 \r
798         /* Validate input parameters. */\r
799         h_conn = h_cm_rep;\r
800         if( AL_OBJ_INVALID_HANDLE( h_conn, AL_OBJ_TYPE_H_CONN ) )\r
801         {\r
802                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("Invalid rep handle.\n") );\r
803                 return IB_INVALID_HANDLE;\r
804         }\r
805         if( !p_cm_rtu )\r
806         {\r
807                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("NULL p_cm_rtu\n") );\r
808                 return IB_INVALID_PARAMETER;\r
809         }\r
810 \r
811         /* Save the user's information. */\r
812         h_conn->pfn_cm_apr_cb = p_cm_rtu->pfn_cm_apr_cb;\r
813         h_conn->pfn_cm_dreq_cb = p_cm_rtu->pfn_cm_dreq_cb;\r
814         cm_save_rtu_qp_attr( p_cm_rtu, &h_conn->p_conn_req->qp_mod_rtr );\r
815 \r
816         /* Transition the QP to the RTS state. */\r
817         status = cm_rts_qp( h_conn->h_qp, &h_conn->p_conn_req->qp_mod_rtr,\r
818                 &h_conn->p_conn_req->qp_mod_rts );\r
819         if( status != IB_SUCCESS )\r
820         {\r
821                 __ual_conn_reject( h_conn, IB_REJ_INSUF_QP );\r
822                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
823                         ("cm_rts_qp with status (%s)\n", ib_get_err_str(status) ) );\r
824                 return status;\r
825         }\r
826 \r
827         /*\r
828          * We are done with this connection establishment.  After we send the\r
829          * RTU, the user can disconnect the QP, destroy it, close AL, or do\r
830          * one of any number of difficult things to deal with, so we destroy\r
831          * the connection request structure here to avoid possible duplicate\r
832          * destructions.\r
833          */\r
834         __free_conn_req( h_conn );\r
835 \r
836         ioctl_buf_sz = sizeof(p_cm_ioctl->in);\r
837         if( p_cm_rtu->p_rtu_pdata )\r
838                 ioctl_buf_sz += p_cm_rtu->rtu_length;\r
839 \r
840         p_cm_ioctl = (ual_cm_rtu_ioctl_t*)cl_zalloc( ioctl_buf_sz );\r
841         if( !p_cm_ioctl )\r
842         {\r
843                 AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, ("Failed to allocate IOCTL buffer\n") );\r
844                 return IB_INSUFFICIENT_MEMORY;\r
845         }\r
846 \r
847         p_cm_ioctl->in.h_cm_rep = h_conn->obj.hdl;\r
848         p_cm_ioctl->in.cm_rtu = *p_cm_rtu;\r
849         if( p_cm_rtu->p_rtu_pdata )\r
850         {\r
851                 cl_memcpy( (&p_cm_ioctl->in.cm_rtu) + 1,\r
852                         p_cm_rtu->p_rtu_pdata, p_cm_rtu->rtu_length );\r
853         }\r
854 \r
855         cl_status = do_al_dev_ioctl( UAL_CM_RTU,\r
856                 &p_cm_ioctl->in, ioctl_buf_sz,\r
857                 &p_cm_ioctl->out, sizeof(p_cm_ioctl->out),\r
858                 &bytes_ret );\r
859 \r
860         if( cl_status != CL_SUCCESS || bytes_ret != sizeof(p_cm_ioctl->out) )\r
861         {\r
862                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
863                         ("UAL_CM_RTU IOCTL returned %s\n", CL_STATUS_MSG(cl_status)) );\r
864                 status = IB_ERROR;\r
865         }\r
866         else\r
867         {\r
868                 status = p_cm_ioctl->out.status;\r
869         }\r
870 \r
871         if( IB_SUCCESS != status )\r
872         {\r
873                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
874                         ("IOCTL status %s.\n", ib_get_err_str(status)) );\r
875                 ref_al_obj( &h_conn->obj );\r
876                 h_conn->obj.pfn_destroy( &h_conn->obj, NULL );\r
877         }\r
878 \r
879         cl_free( p_cm_ioctl );\r
880         AL_EXIT( AL_DBG_CM );\r
881         return status;\r
882 }\r
883 \r
884 \r
885 \r
886 ib_api_status_t\r
887 ib_cm_handoff(\r
888         IN              const   ib_cm_handle_t                          h_cm_req,\r
889         IN              const   ib_net64_t                                      svc_id )\r
890 {\r
891         ib_cm_handle_t                  h_conn;\r
892         ual_cm_handoff_ioctl_t  cm_ioctl;\r
893         uintn_t                                 bytes_ret;\r
894         cl_status_t                             cl_status;\r
895 \r
896         AL_ENTER( AL_DBG_CM );\r
897 \r
898         /* Validate input parameters. */\r
899         h_conn = h_cm_req;\r
900         if( AL_OBJ_INVALID_HANDLE( h_conn, AL_OBJ_TYPE_H_CONN ) )\r
901         {\r
902                 AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, ("Invalid REQ handle.\n") );\r
903                 return IB_INVALID_HANDLE;\r
904         }\r
905         if( !svc_id )\r
906         {\r
907                 AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, ("0 svc_id\n" ) );\r
908                 return IB_INVALID_PARAMETER;\r
909         }\r
910 \r
911         cl_memclr( &cm_ioctl, sizeof(ual_cm_rej_ioctl_t) );\r
912 \r
913         cm_ioctl.in.h_cm = h_conn->obj.hdl;\r
914         CL_ASSERT( cm_ioctl.in.h_cm );\r
915         cm_ioctl.in.sid = svc_id;\r
916 \r
917         cl_status = do_al_dev_ioctl( UAL_CM_HANDOFF,\r
918                 &cm_ioctl.in, sizeof(cm_ioctl.in), &cm_ioctl.out, sizeof(cm_ioctl.out),\r
919                 &bytes_ret );\r
920 \r
921         if( cl_status != CL_SUCCESS || bytes_ret != sizeof(cm_ioctl.out) )\r
922         {\r
923                 AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR,\r
924                         ("UAL_CM_HANDOFF IOCTL returned %s\n", CL_STATUS_MSG(cl_status)) );\r
925                 return IB_ERROR;\r
926         }\r
927         else if( cm_ioctl.out.status != IB_SUCCESS )\r
928         {\r
929                 AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR,\r
930                         ("IOCTL status %s\n", ib_get_err_str(cm_ioctl.out.status)) );\r
931         }\r
932 \r
933         /* Move the QP (if any) to the error state. */\r
934         if( h_conn->h_qp )\r
935                 cm_reset_qp( h_conn->h_qp, 0 );\r
936 \r
937         AL_EXIT( AL_DBG_CM );\r
938         return cm_ioctl.out.status;\r
939 }\r
940 \r
941 \r
942 \r
943 ib_api_status_t\r
944 ib_cm_rej(\r
945         IN      const           ib_cm_handle_t                          h_cm,\r
946         IN      const           ib_cm_rej_t* const                      p_cm_rej )\r
947 {\r
948         ib_cm_handle_t                  h_conn;\r
949         ual_cm_rej_ioctl_t              *p_cm_ioctl;\r
950         size_t                                  ioctl_buf_sz;\r
951         uint8_t                                 *p_data;\r
952         uintn_t                                 bytes_ret;\r
953         ib_api_status_t                 status;\r
954         cl_status_t                             cl_status;\r
955 \r
956         AL_ENTER(AL_DBG_CM);\r
957 \r
958         /* Validate input parameters. */\r
959         h_conn = h_cm;\r
960         if( AL_OBJ_INVALID_HANDLE( h_conn, AL_OBJ_TYPE_H_CONN ) )\r
961         {\r
962                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("Invalid REJ handle.\n") );\r
963                 return IB_INVALID_HANDLE;\r
964         }\r
965         if( !p_cm_rej )\r
966         {\r
967                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("NULL p_cm_rej\n") );\r
968                 return IB_INVALID_PARAMETER;\r
969         }\r
970 \r
971         ioctl_buf_sz = sizeof(p_cm_ioctl->in);\r
972         if( p_cm_rej->p_ari )\r
973                 ioctl_buf_sz += p_cm_rej->ari_length;\r
974         if( p_cm_rej->p_rej_pdata )\r
975                 ioctl_buf_sz += p_cm_rej->rej_length;\r
976 \r
977         p_cm_ioctl = (ual_cm_rej_ioctl_t*)cl_zalloc( ioctl_buf_sz );\r
978         if( !p_cm_ioctl )\r
979         {\r
980                 AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR,\r
981                         ("Failed to allocate IOCTL buffer.\n") );\r
982                 return IB_INSUFFICIENT_MEMORY;\r
983         }\r
984 \r
985         p_cm_ioctl->in.h_cm = h_conn->obj.hdl;\r
986         CL_ASSERT( p_cm_ioctl->in.h_cm );\r
987         p_cm_ioctl->in.cm_rej = *p_cm_rej;\r
988         p_data = (uint8_t*)((&p_cm_ioctl->in.cm_rej) + 1);\r
989         if( p_cm_rej->p_ari )\r
990         {\r
991                 cl_memcpy( p_data, p_cm_rej->p_ari, p_cm_rej->ari_length );\r
992                 p_data += p_cm_rej->ari_length;\r
993         }\r
994         if( p_cm_rej->p_rej_pdata )\r
995                 cl_memcpy( p_data, p_cm_rej->p_rej_pdata, p_cm_rej->rej_length );\r
996 \r
997         cl_status = do_al_dev_ioctl( UAL_CM_REJ,\r
998                 &p_cm_ioctl->in, ioctl_buf_sz,\r
999                 &p_cm_ioctl->out, sizeof(p_cm_ioctl->out),\r
1000                 &bytes_ret );\r
1001 \r
1002         if( cl_status != CL_SUCCESS || bytes_ret != sizeof(p_cm_ioctl->out) )\r
1003         {\r
1004                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
1005                         ("UAL_CM_REJ IOCTL returned %s\n", CL_STATUS_MSG(cl_status)) );\r
1006                 status = IB_ERROR;\r
1007         }\r
1008         else\r
1009         {\r
1010                 status = p_cm_ioctl->out.status;\r
1011         }\r
1012 \r
1013         if( h_conn->h_qp )\r
1014                 cm_reset_qp( h_conn->h_qp, 0 );\r
1015 \r
1016         if( IB_SUCCESS == status )\r
1017         {\r
1018                 /* Cleanup the connection request. */\r
1019                 ref_al_obj( &h_conn->obj );\r
1020                 h_conn->obj.pfn_destroy( &h_conn->obj, NULL );\r
1021         }\r
1022         else\r
1023         {\r
1024                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
1025                         ("IOCTL status %s.\n", ib_get_err_str(status)) );\r
1026         }\r
1027 \r
1028         cl_free( p_cm_ioctl );\r
1029         AL_EXIT( AL_DBG_CM );\r
1030         return status;\r
1031 }\r
1032 \r
1033 \r
1034 \r
1035 ib_api_status_t\r
1036 ib_cm_mra(\r
1037         IN      const           ib_cm_handle_t                          h_cm,\r
1038         IN      const           ib_cm_mra_t* const                      p_cm_mra )\r
1039 {\r
1040         ib_cm_handle_t                  h_conn;\r
1041         ual_cm_mra_ioctl_t              *p_cm_ioctl;\r
1042         size_t                                  ioctl_buf_sz;\r
1043         uintn_t                                 bytes_ret;\r
1044         ib_api_status_t                 status;\r
1045         cl_status_t                             cl_status;\r
1046 \r
1047         AL_ENTER(AL_DBG_CM);\r
1048 \r
1049         /* Validate input parameters. */\r
1050         h_conn = h_cm;\r
1051         if( AL_OBJ_INVALID_HANDLE( h_conn, AL_OBJ_TYPE_H_CONN ) )\r
1052         {\r
1053                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("Invalid CM handle.\n") );\r
1054                 return IB_INVALID_HANDLE;\r
1055         }\r
1056         if( !p_cm_mra )\r
1057         {\r
1058                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("NULL p_cm_mra\n") );\r
1059                 return IB_INVALID_PARAMETER;\r
1060         }\r
1061 \r
1062         ioctl_buf_sz = sizeof(p_cm_ioctl->in);\r
1063         if( p_cm_mra->p_mra_pdata )\r
1064                 ioctl_buf_sz += p_cm_mra->mra_length;\r
1065 \r
1066         p_cm_ioctl = (ual_cm_mra_ioctl_t*)cl_zalloc( ioctl_buf_sz );\r
1067         if( !p_cm_ioctl )\r
1068         {\r
1069                 AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR,\r
1070                         ("Failed to allocate IOCTL buffer\n") );\r
1071                 return IB_INSUFFICIENT_MEMORY;\r
1072         }\r
1073 \r
1074         p_cm_ioctl->in.h_cm = h_conn->obj.hdl;\r
1075         CL_ASSERT( p_cm_ioctl->in.h_cm );\r
1076         p_cm_ioctl->in.cm_mra = *p_cm_mra;\r
1077         if( p_cm_mra->p_mra_pdata )\r
1078         {\r
1079                 cl_memcpy( (uint8_t*)((&p_cm_ioctl->in.cm_mra) + 1),\r
1080                         p_cm_mra->p_mra_pdata, p_cm_mra->mra_length );\r
1081         }\r
1082 \r
1083         cl_status = do_al_dev_ioctl( UAL_CM_MRA, &p_cm_ioctl->in, ioctl_buf_sz,\r
1084                 &p_cm_ioctl->out, sizeof(p_cm_ioctl->out), &bytes_ret );\r
1085 \r
1086         if( cl_status != CL_SUCCESS || bytes_ret != sizeof(p_cm_ioctl->out) )\r
1087         {\r
1088                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
1089                         ("UAL_CM_MRA IOCTL returned %s\n", CL_STATUS_MSG(cl_status)) );\r
1090                 status = IB_ERROR;\r
1091         }\r
1092         else\r
1093         {\r
1094                 status = p_cm_ioctl->out.status;\r
1095                 if( status != IB_SUCCESS )\r
1096                 {\r
1097                         AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
1098                                 ("IOCTL status %s.\n", ib_get_err_str(status)) );\r
1099                 }\r
1100         }\r
1101 \r
1102         cl_free( p_cm_ioctl );\r
1103         AL_EXIT(AL_DBG_CM);\r
1104         return status;\r
1105 }\r
1106 \r
1107 \r
1108 \r
1109 ib_api_status_t\r
1110 ib_cm_lap(\r
1111         IN      const           ib_cm_lap_t* const                      p_cm_lap )\r
1112 {\r
1113         ib_cm_handle_t                  h_conn;\r
1114         ual_cm_lap_ioctl_t              *p_cm_ioctl;\r
1115         size_t                                  ioctl_buf_sz;\r
1116         uintn_t                                 bytes_ret;\r
1117         ib_api_status_t                 status;\r
1118         cl_status_t                             cl_status;\r
1119 \r
1120         AL_ENTER(AL_DBG_CM);\r
1121 \r
1122         /* Validate input parameters. */\r
1123         if( !p_cm_lap || !p_cm_lap->p_alt_path )\r
1124         {\r
1125                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("NULL p_cm_lap\n") );\r
1126                 return IB_INVALID_PARAMETER;\r
1127         }\r
1128 \r
1129         ioctl_buf_sz = sizeof(p_cm_ioctl->in);\r
1130         if( p_cm_lap->p_lap_pdata )\r
1131                 ioctl_buf_sz += p_cm_lap->lap_length;\r
1132 \r
1133         p_cm_ioctl = (ual_cm_lap_ioctl_t*)cl_zalloc( ioctl_buf_sz );\r
1134         if( !p_cm_ioctl )\r
1135         {\r
1136                 AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, ("Failed to allocate IOCTL buffer.\n") );\r
1137                 return IB_INSUFFICIENT_MEMORY;\r
1138         }\r
1139 \r
1140         /* Convert to the kernel-mode handles. */\r
1141         p_cm_ioctl->in.cm_lap = *p_cm_lap;\r
1142         switch( p_cm_lap->qp_type )\r
1143         {\r
1144         case IB_QPT_RELIABLE_CONN:\r
1145         case IB_QPT_UNRELIABLE_CONN:\r
1146                 if( AL_OBJ_INVALID_HANDLE( p_cm_lap->h_qp, AL_OBJ_TYPE_H_QP ) ||\r
1147                         (p_cm_lap->h_qp->type != p_cm_lap->qp_type) )\r
1148                 {\r
1149                         AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
1150                                 ("IB_INVALID_QP_HANDLE\n") );\r
1151                         status = IB_INVALID_QP_HANDLE;\r
1152                         goto cleanup;\r
1153                 }\r
1154                 p_cm_ioctl->in.h_qp = p_cm_lap->h_qp->obj.hdl;\r
1155                 h_conn = ((al_conn_qp_t*)p_cm_lap->h_qp)->p_conn;\r
1156                 break;\r
1157 \r
1158         default:\r
1159                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("Invalid qp_type.\n") );\r
1160                 status = IB_INVALID_SETTING;\r
1161                 goto cleanup;\r
1162         }\r
1163 \r
1164         if( AL_OBJ_INVALID_HANDLE( h_conn, AL_OBJ_TYPE_H_CONN ) )\r
1165         {\r
1166                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
1167                         ("No connection info!\n") );\r
1168                 status = IB_INVALID_SETTING;\r
1169                 goto cleanup;\r
1170         }\r
1171         h_conn->pfn_cm_apr_cb = p_cm_lap->pfn_cm_apr_cb;\r
1172 \r
1173         /* Copy the path. */\r
1174         p_cm_ioctl->in.alt_path = *p_cm_lap->p_alt_path;\r
1175         /* Copy the private data. */\r
1176         if( p_cm_lap->p_lap_pdata )\r
1177         {\r
1178                 cl_memcpy( (&p_cm_ioctl->in.alt_path) + 1,\r
1179                         p_cm_lap->p_lap_pdata, p_cm_lap->lap_length );\r
1180         }\r
1181 \r
1182         cl_status = do_al_dev_ioctl( UAL_CM_LAP, &p_cm_ioctl->in, ioctl_buf_sz,\r
1183                 &p_cm_ioctl->out, sizeof(p_cm_ioctl->out), &bytes_ret );\r
1184 \r
1185         if( cl_status != CL_SUCCESS || bytes_ret != sizeof(p_cm_ioctl->out) )\r
1186         {\r
1187                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
1188                         ("UAL_CM_LAP IOCTL returned %s\n", CL_STATUS_MSG(cl_status)) );\r
1189                 status = IB_ERROR;\r
1190         }\r
1191         else\r
1192         {\r
1193                 status = p_cm_ioctl->out.status;\r
1194                 if( status != IB_SUCCESS )\r
1195                 {\r
1196                         AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
1197                                 ("IOCTL status %s.\n", ib_get_err_str(status)) );\r
1198                 }\r
1199         }\r
1200 \r
1201 cleanup:\r
1202         cl_free( p_cm_ioctl );\r
1203         AL_EXIT(AL_DBG_CM);\r
1204         return status;\r
1205 }\r
1206 \r
1207 \r
1208 \r
1209 ib_api_status_t\r
1210 ib_force_apm(\r
1211         IN      const           ib_qp_handle_t                          h_qp )\r
1212 {\r
1213         ual_force_apm_ioctl_t   cm_ioctl;\r
1214         uintn_t                                 bytes_ret;\r
1215         ib_api_status_t                 status;\r
1216         cl_status_t                             cl_status;\r
1217 \r
1218         AL_ENTER(AL_DBG_CM);\r
1219 \r
1220         /* Clear the apm_ioctl */\r
1221         cl_memclr( &cm_ioctl, sizeof( cm_ioctl ) );\r
1222 \r
1223         /* Replace the handles with kernel handles appropriately */\r
1224         if( AL_OBJ_INVALID_HANDLE( h_qp, AL_OBJ_TYPE_H_QP ) )\r
1225         {\r
1226                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("Invalid QP handle.\n") );\r
1227                 return IB_INVALID_QP_HANDLE;\r
1228         }\r
1229         \r
1230         cm_ioctl.in.h_qp = h_qp->obj.hdl;\r
1231 \r
1232         cl_status = do_al_dev_ioctl( UAL_CM_FORCE_APM,\r
1233                 &cm_ioctl.in, sizeof(cm_ioctl.in), &cm_ioctl.out, sizeof(cm_ioctl.out),\r
1234                 &bytes_ret );\r
1235 \r
1236         if( cl_status != CL_SUCCESS || bytes_ret != sizeof(cm_ioctl.out) )\r
1237         {\r
1238                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
1239                         ("UAL_CM_FORCE_APM IOCTL returned %s\n",\r
1240                         CL_STATUS_MSG(cl_status)) );\r
1241                 status = IB_ERROR;\r
1242         }\r
1243         else\r
1244         {\r
1245                 status = cm_ioctl.out.status;\r
1246                 if( status != IB_SUCCESS )\r
1247                 {\r
1248                         AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
1249                                 ("IOCTL status %s.\n", ib_get_err_str(status)) );\r
1250                 }\r
1251         }\r
1252 \r
1253         AL_EXIT(AL_DBG_CM);\r
1254         return status;\r
1255 }\r
1256 \r
1257 \r
1258 \r
1259 ib_api_status_t\r
1260 ib_cm_apr(\r
1261         IN              const   ib_cm_handle_t                          h_cm_lap,\r
1262         IN              const   ib_cm_apr_t* const                      p_cm_apr )\r
1263 {\r
1264         ib_cm_handle_t                  h_conn;\r
1265         ual_cm_apr_ioctl_t              *p_cm_ioctl;\r
1266         size_t                                  ioctl_buf_sz;\r
1267         uintn_t                                 bytes_ret;\r
1268         ib_api_status_t                 status;\r
1269         cl_status_t                             cl_status;\r
1270         uint8_t                                 *p_buf;\r
1271 \r
1272         AL_ENTER(AL_DBG_CM);\r
1273 \r
1274         /* Validate input parameters. */\r
1275         h_conn = h_cm_lap;\r
1276         if( AL_OBJ_INVALID_HANDLE( h_conn, AL_OBJ_TYPE_H_CONN ) )\r
1277         {\r
1278                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("Invalid lap handle.\n") );\r
1279                 return IB_INVALID_HANDLE;\r
1280         }\r
1281         if( !p_cm_apr )\r
1282         {\r
1283                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("NULL p_cm_apr\n") );\r
1284                 return IB_INVALID_PARAMETER;\r
1285         }\r
1286 \r
1287         ioctl_buf_sz = sizeof(p_cm_ioctl->in);\r
1288         if( p_cm_apr->p_info )\r
1289                 ioctl_buf_sz += p_cm_apr->info_length;\r
1290         if( p_cm_apr->p_apr_pdata )\r
1291                 ioctl_buf_sz += p_cm_apr->apr_length;\r
1292 \r
1293         p_cm_ioctl = (ual_cm_apr_ioctl_t*)cl_zalloc( ioctl_buf_sz );\r
1294         if( !p_cm_ioctl )\r
1295         {\r
1296                 AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, ("Failed to allocate IOCTL buffer.\n") );\r
1297                 return IB_INSUFFICIENT_MEMORY;\r
1298         }\r
1299 \r
1300         /* Replace the handles with kernel handles appropriately */\r
1301         p_cm_ioctl->in.h_cm_lap = h_conn->obj.hdl;\r
1302         CL_ASSERT( p_cm_ioctl->in.h_cm_lap );\r
1303 \r
1304         /* Convert to the kernel-mode handles. */\r
1305         p_cm_ioctl->in.cm_apr = *p_cm_apr;\r
1306         switch( p_cm_apr->qp_type )\r
1307         {\r
1308         case IB_QPT_RELIABLE_CONN:\r
1309         case IB_QPT_UNRELIABLE_CONN:\r
1310                 if( AL_OBJ_INVALID_HANDLE( p_cm_apr->h_qp, AL_OBJ_TYPE_H_QP ) ||\r
1311                         (p_cm_apr->h_qp->type != p_cm_apr->qp_type) )\r
1312                 {\r
1313                         AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
1314                                 ("IB_INVALID_QP_HANDLE\n") );\r
1315                         status = IB_INVALID_QP_HANDLE;\r
1316                         goto cleanup;\r
1317                 }\r
1318                 p_cm_ioctl->in.h_qp = p_cm_apr->h_qp->obj.hdl;\r
1319                 h_conn = ((al_conn_qp_t*)p_cm_apr->h_qp)->p_conn;\r
1320                 break;\r
1321 \r
1322         default:\r
1323                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("Invalid qp_type.\n") );\r
1324                 status = IB_INVALID_SETTING;\r
1325                 goto cleanup;\r
1326         }\r
1327 \r
1328         if( AL_OBJ_INVALID_HANDLE( h_conn, AL_OBJ_TYPE_H_CONN ) )\r
1329         {\r
1330                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
1331                         ("No connection info!\n") );\r
1332                 status = IB_INVALID_SETTING;\r
1333                 goto cleanup;\r
1334         }\r
1335 \r
1336         /* Copy the apr info and private data. */\r
1337         p_buf = (uint8_t*)((&p_cm_ioctl->in.cm_apr) + 1);\r
1338         if( p_cm_apr->p_info )\r
1339         {\r
1340                 cl_memcpy( p_buf, p_cm_apr->p_info, p_cm_apr->info_length );\r
1341                 p_buf += p_cm_apr->info_length;\r
1342         }\r
1343         if( p_cm_apr->p_apr_pdata )\r
1344                 cl_memcpy( p_buf, p_cm_apr->p_apr_pdata, p_cm_apr->apr_length );\r
1345 \r
1346         cl_status = do_al_dev_ioctl( UAL_CM_APR,\r
1347                 &p_cm_ioctl->in, ioctl_buf_sz,\r
1348                 &p_cm_ioctl->out, sizeof(p_cm_ioctl->out),\r
1349                 &bytes_ret );\r
1350 \r
1351         if( cl_status != CL_SUCCESS || bytes_ret != sizeof(p_cm_ioctl->out) )\r
1352         {\r
1353                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
1354                         ("UAL_CM_APR IOCTL returned %s.\n", CL_STATUS_MSG(cl_status)) );\r
1355                 status = IB_ERROR;\r
1356         }\r
1357         else\r
1358         {\r
1359                 status = p_cm_ioctl->out.status;\r
1360                 if( status != IB_SUCCESS )\r
1361                 {\r
1362                         AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
1363                                 ("IOCTL status %s.\n", ib_get_err_str(status)) );\r
1364                 }\r
1365         }\r
1366 \r
1367         /* Release the reference taken when processing the callback. */\r
1368         deref_al_obj( &h_conn->obj );\r
1369 \r
1370 cleanup:\r
1371         cl_free( p_cm_ioctl );\r
1372         AL_EXIT(AL_DBG_CM);\r
1373         return IB_SUCCESS;\r
1374 }\r
1375 \r
1376 \r
1377 \r
1378 ib_api_status_t\r
1379 ib_cm_dreq(\r
1380         IN      const           ib_cm_dreq_t* const                     p_cm_dreq )\r
1381 {\r
1382         ib_cm_handle_t                  h_conn;\r
1383         ual_cm_dreq_ioctl_t             *p_cm_ioctl;\r
1384         size_t                                  ioctl_buf_sz;\r
1385         uintn_t                                 bytes_ret;\r
1386         ib_api_status_t                 status;\r
1387         cl_status_t                             cl_status;\r
1388 \r
1389         AL_ENTER(AL_DBG_CM);\r
1390 \r
1391         /* Validate input parameters. */\r
1392         if( !p_cm_dreq )\r
1393         {\r
1394                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("NULL p_cm_dreq\n") );\r
1395                 return IB_INVALID_PARAMETER;\r
1396         }\r
1397 \r
1398         ioctl_buf_sz = sizeof(p_cm_ioctl->in);\r
1399         if( p_cm_dreq->p_dreq_pdata )\r
1400                 ioctl_buf_sz += p_cm_dreq->dreq_length;\r
1401 \r
1402         p_cm_ioctl = (ual_cm_dreq_ioctl_t*)cl_zalloc( ioctl_buf_sz );\r
1403         if( !p_cm_ioctl )\r
1404         {\r
1405                 AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR, ("Failed to allocate IOCTL buffer.\n") );\r
1406                 return IB_INSUFFICIENT_MEMORY;\r
1407         }\r
1408 \r
1409         /* Convert to the kernel-mode handles. */\r
1410         p_cm_ioctl->in.cm_dreq = *p_cm_dreq;\r
1411         switch( p_cm_dreq->qp_type )\r
1412         {\r
1413         case IB_QPT_RELIABLE_CONN:\r
1414         case IB_QPT_UNRELIABLE_CONN:\r
1415                 if( AL_OBJ_INVALID_HANDLE( p_cm_dreq->h_qp, AL_OBJ_TYPE_H_QP ) ||\r
1416                         (p_cm_dreq->h_qp->type != p_cm_dreq->qp_type) )\r
1417                 {\r
1418                         AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
1419                                 ("IB_INVALID_QP_HANDLE\n") );\r
1420                         status = IB_INVALID_QP_HANDLE;\r
1421                         goto cleanup;\r
1422                 }\r
1423                 p_cm_ioctl->in.h_qp = p_cm_dreq->h_qp->obj.hdl;\r
1424                 h_conn = ((al_conn_qp_t*)p_cm_dreq->h_qp)->p_conn;\r
1425                 break;\r
1426 \r
1427         default:\r
1428                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("Invalid qp_type.\n") );\r
1429                 status = IB_INVALID_SETTING;\r
1430                 goto cleanup;\r
1431         }\r
1432 \r
1433         if( AL_OBJ_INVALID_HANDLE( h_conn, AL_OBJ_TYPE_H_CONN ) )\r
1434         {\r
1435                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
1436                         ("No connection info!\n") );\r
1437                 status = IB_INVALID_SETTING;\r
1438                 goto cleanup;\r
1439         }\r
1440         h_conn->pfn_cm_drep_cb = p_cm_dreq->pfn_cm_drep_cb;\r
1441 \r
1442         /* Copy the private data. */\r
1443         if( p_cm_dreq->p_dreq_pdata )\r
1444         {\r
1445                 cl_memcpy( (&p_cm_ioctl->in.cm_dreq) + 1,\r
1446                         p_cm_dreq->p_dreq_pdata, p_cm_dreq->dreq_length );\r
1447         }\r
1448 \r
1449         cl_status = do_al_dev_ioctl( UAL_CM_DREQ,\r
1450                 &p_cm_ioctl->in, ioctl_buf_sz,\r
1451                 &p_cm_ioctl->out, sizeof(p_cm_ioctl->out),\r
1452                 &bytes_ret );\r
1453 \r
1454         if( cl_status != CL_SUCCESS || bytes_ret != sizeof(p_cm_ioctl->out) )\r
1455         {\r
1456                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
1457                         ("UAL_CM_DREQ IOCTL returned %s\n", CL_STATUS_MSG(cl_status)) );\r
1458                 status = IB_ERROR;\r
1459         }\r
1460         else\r
1461         {\r
1462                 status = p_cm_ioctl->out.status;\r
1463                 if( IB_SUCCESS != status )\r
1464                 {\r
1465                         /* We can fail if we just received a DREQ, which is not an error. */\r
1466                         AL_PRINT(TRACE_LEVEL_INFORMATION ,AL_DBG_CM ,\r
1467                                 ("IOCTL status %s\n", ib_get_err_str(status)) );\r
1468                 }\r
1469         }\r
1470 \r
1471 cleanup:\r
1472         cl_free( p_cm_ioctl );\r
1473         AL_EXIT(AL_DBG_CM);\r
1474         return status;\r
1475 }\r
1476 \r
1477 \r
1478 \r
1479 ib_api_status_t\r
1480 ib_cm_drep(\r
1481         IN      const           ib_cm_handle_t                          h_cm_dreq,\r
1482         IN      const           ib_cm_drep_t*   const           p_cm_drep )\r
1483 {\r
1484         ib_cm_handle_t                  h_conn;\r
1485         ual_cm_drep_ioctl_t             *p_cm_ioctl;\r
1486         size_t                                  ioctl_buf_sz;\r
1487         uintn_t                                 bytes_ret;\r
1488         ib_api_status_t                 status;\r
1489         cl_status_t                             cl_status;\r
1490 \r
1491         AL_ENTER(AL_DBG_CM);\r
1492 \r
1493         /* Validate input parameters. */\r
1494         h_conn = h_cm_dreq;\r
1495         if( AL_OBJ_INVALID_HANDLE( h_conn, AL_OBJ_TYPE_H_CONN ) )\r
1496         {\r
1497                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("Invalid DREP handle.\n") );\r
1498                 return IB_INVALID_HANDLE;\r
1499         }\r
1500         if( !p_cm_drep )\r
1501         {\r
1502                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("NULL p_cm_drep\n") );\r
1503                 return IB_INVALID_PARAMETER;\r
1504         }\r
1505 \r
1506         ioctl_buf_sz = sizeof(p_cm_ioctl->in);\r
1507         if( p_cm_drep->p_drep_pdata )\r
1508                 ioctl_buf_sz += p_cm_drep->drep_length;\r
1509 \r
1510         p_cm_ioctl = (ual_cm_drep_ioctl_t*)cl_zalloc( ioctl_buf_sz );\r
1511         if( !p_cm_ioctl )\r
1512         {\r
1513                 AL_PRINT_EXIT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR,\r
1514                         ("Failed to allocate IOCTL buffer.\n") );\r
1515                 return IB_INSUFFICIENT_MEMORY;\r
1516         }\r
1517 \r
1518         p_cm_ioctl->in.h_cm_dreq = h_conn->obj.hdl;\r
1519         CL_ASSERT( p_cm_ioctl->in.h_cm_dreq );\r
1520         p_cm_ioctl->in.cm_drep = *p_cm_drep;\r
1521         if( p_cm_drep->p_drep_pdata )\r
1522         {\r
1523                 cl_memcpy( (uint8_t*)((&p_cm_ioctl->in.cm_drep) + 1),\r
1524                         p_cm_drep->p_drep_pdata, p_cm_drep->drep_length );\r
1525         }\r
1526 \r
1527         cl_status = do_al_dev_ioctl( UAL_CM_DREP,\r
1528                 &p_cm_ioctl->in, ioctl_buf_sz,\r
1529                 &p_cm_ioctl->out, sizeof(p_cm_ioctl->out),\r
1530                 &bytes_ret );\r
1531 \r
1532         if( cl_status != CL_SUCCESS || bytes_ret != sizeof(p_cm_ioctl->out) )\r
1533         {\r
1534                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
1535                         ("UAL_CM_DREP IOCTL returned %s\n", CL_STATUS_MSG(cl_status)) );\r
1536                 status = IB_ERROR;\r
1537         }\r
1538         else\r
1539         {\r
1540                 status = p_cm_ioctl->out.status;\r
1541         }\r
1542 \r
1543         if( IB_SUCCESS == status )\r
1544         {\r
1545                 cm_reset_qp( h_conn->h_qp, 0 );\r
1546                 /* Cleanup the connection request. */\r
1547                 h_conn->obj.pfn_destroy( &h_conn->obj, NULL );\r
1548         }\r
1549         else\r
1550         {\r
1551                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
1552                         ("IOCTL status %s\n", ib_get_err_str(status)) );\r
1553 \r
1554                 /* Release the reference taken when processing the callback. */\r
1555                 deref_al_obj( &h_conn->obj );\r
1556         }\r
1557 \r
1558         cl_free( p_cm_ioctl );\r
1559         AL_EXIT(AL_DBG_CM);\r
1560         return status;\r
1561 }\r
1562 \r
1563 \r
1564 \r
1565 void\r
1566 ual_listen_err_cb(\r
1567         IN                              ib_listen_err_rec_t                     *p_listen_err_rec )\r
1568 {\r
1569         ib_listen_handle_t              h_listen;\r
1570 \r
1571         AL_ENTER(AL_DBG_CM);\r
1572         \r
1573         /* Get the listen object. */\r
1574         h_listen = p_listen_err_rec->listen_context;\r
1575         if( AL_OBJ_INVALID_HANDLE( h_listen, AL_OBJ_TYPE_H_LISTEN ) )\r
1576                 return;\r
1577 \r
1578         /* Convert to the user's handles and structures. */\r
1579         p_listen_err_rec->listen_context = (void*)h_listen->obj.context;\r
1580         p_listen_err_rec->h_cm_listen = h_listen;\r
1581 \r
1582         /* Call the user's callback. */\r
1583         h_listen->pfn_listen_err_cb( p_listen_err_rec );\r
1584 \r
1585         /* Destroy the listen request. */\r
1586         ref_al_obj( &h_listen->obj );\r
1587         h_listen->obj.pfn_destroy( &h_listen->obj, NULL );\r
1588 \r
1589         AL_EXIT(AL_DBG_CM);\r
1590 }\r
1591 \r
1592 \r
1593 \r
1594 void\r
1595 ual_cm_req_cb(\r
1596         IN                              ib_cm_req_rec_t*                        p_cm_req_rec,\r
1597         IN                              ib_qp_mod_t*                            p_qp_rtr,\r
1598         IN                              ib_qp_mod_t*                            p_qp_rts,\r
1599         IN                              uint32_t                                        timeout_ms )\r
1600 {\r
1601         ib_listen_handle_t                      h_listen;\r
1602         ib_cm_handle_t                          h_conn;\r
1603         ib_qp_handle_t                          h_qp;\r
1604 \r
1605         AL_ENTER(AL_DBG_CM);\r
1606 \r
1607         if( p_cm_req_rec->h_cm_listen )\r
1608         {\r
1609                 /* \r
1610                  * This was generated in response for a listen request.  Store\r
1611                  * the kernel handle in the user mode handle in case the\r
1612                  * ib_cm_listen call has not returned yet.\r
1613                  */\r
1614                 h_listen = (ib_listen_handle_t)p_cm_req_rec->context;\r
1615                 h_listen->obj.hdl = (uint64_t)p_cm_req_rec->h_cm_listen;\r
1616 \r
1617                 /*\r
1618                  * Replace the listen handle with UAL handle and the context with\r
1619                  * the application's context.\r
1620                  */\r
1621                 p_cm_req_rec->h_cm_listen = h_listen;\r
1622                 p_cm_req_rec->context = h_listen->obj.context;\r
1623                 p_cm_req_rec->sidr_context = h_listen->sidr_context;\r
1624 \r
1625                 /* For a req callback as a result of a listen, there is no\r
1626                  * connection handle associated with the user mode yet.  So\r
1627                  * create one that can be used in the reply.\r
1628                  */\r
1629                 h_conn = __get_conn( (ib_al_handle_t)h_listen->obj.p_parent_obj );\r
1630                 if( !h_conn )\r
1631                 {\r
1632                         AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR ,\r
1633                                 ("__get_conn failed.\n") );\r
1634                         __rej_conn( p_cm_req_rec->h_cm_req, IB_REJ_INSUF_RESOURCES );\r
1635                         return;\r
1636                 }\r
1637 \r
1638                 deref_al_obj( &h_conn->obj );\r
1639 \r
1640                 /* Copy the callbacks from the listen. */\r
1641                 h_conn->p_conn_req->pfn_cm_req_cb = h_listen->pfn_cm_req_cb;\r
1642                 h_conn->pfn_cm_rej_cb = h_listen->pfn_cm_rej_cb;\r
1643                 h_conn->pfn_cm_mra_cb = h_listen->pfn_cm_mra_cb;\r
1644         }\r
1645         else\r
1646         {\r
1647                 /* This callback was generated for peer-to-peer connections */\r
1648                 h_qp = (ib_qp_handle_t)p_cm_req_rec->context;\r
1649                 p_cm_req_rec->context = h_qp->obj.context;\r
1650 \r
1651                 /* Get the connection handle associated with this QP. */\r
1652                 h_conn = ((al_conn_qp_t*)h_qp)->p_conn;\r
1653 \r
1654                 /*\r
1655                  * Unbind this QP.  This allows the user to use a different QP\r
1656                  * when replying to the connection.\r
1657                  */\r
1658                 cm_unbind_qp( h_conn );\r
1659                 deref_al_obj( &h_qp->obj );\r
1660         }\r
1661 \r
1662         /* Store & replace the kernel handle */\r
1663         h_conn->obj.hdl = (uint64_t)p_cm_req_rec->h_cm_req;\r
1664         p_cm_req_rec->h_cm_req = h_conn;\r
1665 \r
1666         /*\r
1667          * Copy the connection request information needed to properly configure\r
1668          * the QP.\r
1669          */\r
1670         h_conn->p_conn_req->path_rec = p_cm_req_rec->primary_path;\r
1671         h_conn->p_conn_req->alt_path_rec = p_cm_req_rec->alt_path;\r
1672         h_conn->p_conn_req->qp_mod_rtr = *p_qp_rtr;\r
1673         h_conn->p_conn_req->qp_mod_rts = *p_qp_rts;\r
1674         h_conn->p_conn_req->timeout_ms = timeout_ms;\r
1675 \r
1676         /* Invoke the user's callback. */\r
1677         h_conn->p_conn_req->pfn_cm_req_cb( p_cm_req_rec );\r
1678 \r
1679         AL_EXIT(AL_DBG_CM);\r
1680 }\r
1681 \r
1682 \r
1683 \r
1684 void\r
1685 ual_cm_rep_cb(\r
1686         IN                              ib_cm_rep_rec_t*                        p_cm_rep_rec,\r
1687         IN                              ib_qp_mod_t*                            p_qp_rtr,\r
1688         IN                              ib_qp_mod_t*                            p_qp_rts )\r
1689 {\r
1690         ib_cm_handle_t                          h_conn;\r
1691         ib_qp_handle_t                          h_qp;\r
1692 \r
1693         AL_ENTER(AL_DBG_CM);\r
1694 \r
1695         /* Get the user's context. */\r
1696         switch( p_cm_rep_rec->qp_type )\r
1697         {\r
1698         case IB_QPT_RELIABLE_CONN:\r
1699         case IB_QPT_UNRELIABLE_CONN:\r
1700                 h_qp = (ib_qp_handle_t)p_cm_rep_rec->qp_context;\r
1701                 p_cm_rep_rec->qp_context = h_qp->obj.context;\r
1702 \r
1703                 /* Get the connection handle associated with this QP. */\r
1704                 h_conn = ((al_conn_qp_t*)h_qp)->p_conn;\r
1705 \r
1706                 /* Store the kernel reply handle. */\r
1707                 h_conn->obj.hdl = (uint64_t)p_cm_rep_rec->h_cm_rep;\r
1708                 p_cm_rep_rec->h_cm_rep = h_conn;\r
1709 \r
1710                 /*\r
1711                  * Copy the connection request information needed to properly\r
1712                  * configure the QP.\r
1713                  */\r
1714                 h_conn->p_conn_req->qp_mod_rtr = *p_qp_rtr;\r
1715                 h_conn->p_conn_req->qp_mod_rts = *p_qp_rts;\r
1716 \r
1717                 /* Call the application callback */\r
1718                 h_conn->p_conn_req->pfn_cm_rep_cb( p_cm_rep_rec );\r
1719                 break;\r
1720 \r
1721         case IB_QPT_UNRELIABLE_DGRM:\r
1722                 /* Get the SIDR request handle associated with this request. */\r
1723                 h_conn = (ib_cm_handle_t)p_cm_rep_rec->sidr_context;\r
1724                 p_cm_rep_rec->sidr_context = h_conn->sidr_context;\r
1725 \r
1726                 /* Call the application callback */\r
1727                 h_conn->p_conn_req->pfn_cm_rep_cb( p_cm_rep_rec );\r
1728 \r
1729                 /* Destroy the SIDR request. */\r
1730                 ref_al_obj( &h_conn->obj );\r
1731                 h_conn->obj.pfn_destroy( &h_conn->obj, NULL );\r
1732                 break;\r
1733 \r
1734         default:\r
1735                 AL_PRINT(TRACE_LEVEL_ERROR , AL_DBG_ERROR , ("Invalid qp_type.\n") );\r
1736                 break;\r
1737         }\r
1738 \r
1739         AL_EXIT(AL_DBG_CM);\r
1740 }\r
1741 \r
1742 \r
1743 \r
1744 void\r
1745 ual_cm_rtu_cb(\r
1746         IN                              ib_cm_rtu_rec_t*                        p_cm_rtu_rec )\r
1747 {\r
1748         ib_cm_handle_t                          h_conn;\r
1749         ib_qp_handle_t                          h_qp;\r
1750         ib_pfn_cm_rtu_cb_t                      pfn_cm_rtu_cb;\r
1751 \r
1752         AL_ENTER(AL_DBG_CM);\r
1753 \r
1754         h_qp = (ib_qp_handle_t)p_cm_rtu_rec->qp_context;\r
1755         p_cm_rtu_rec->qp_context = h_qp->obj.context;\r
1756 \r
1757         /* Get the connection handle associated with this QP. */\r
1758         h_conn = ((al_conn_qp_t*)h_qp)->p_conn;\r
1759 \r
1760         /*\r
1761          * We are done with this connection establishment.  After we call the\r
1762          * user back, they can disconnect the QP, destroy it, close AL, or do\r
1763          * one of any number of difficult things to deal with, so we need to\r
1764          * handle the case where the connection structure may be destroyed.\r
1765          * Get a copy of the user's callback.\r
1766          */\r
1767         pfn_cm_rtu_cb = h_conn->p_conn_req->pfn_cm_rtu_cb;\r
1768         __free_conn_req( h_conn );\r
1769 \r
1770         /* Invoke the user's callback. */\r
1771         pfn_cm_rtu_cb( p_cm_rtu_rec );\r
1772 \r
1773         AL_EXIT(AL_DBG_CM);\r
1774 }\r
1775 \r
1776 \r
1777 \r
1778 void\r
1779 ual_cm_rej_cb(\r
1780         IN                              ib_cm_rej_rec_t*                        p_cm_rej_rec )\r
1781 {\r
1782         ib_cm_handle_t                          h_conn;\r
1783         ib_qp_handle_t                          h_qp;\r
1784         ib_pfn_cm_rej_cb_t                      pfn_cm_rej_cb;\r
1785 \r
1786         AL_ENTER(AL_DBG_CM);\r
1787 \r
1788         h_qp = (ib_qp_handle_t)p_cm_rej_rec->qp_context;\r
1789         p_cm_rej_rec->qp_context = h_qp->obj.context;\r
1790 \r
1791         /* Get the connection handle associated with this QP. */\r
1792         h_conn = ((al_conn_qp_t*)h_qp)->p_conn;\r
1793 \r
1794         if( !h_conn )\r
1795         {\r
1796                 AL_EXIT( AL_DBG_CM );\r
1797                 return;\r
1798         }\r
1799 \r
1800         /* Move the QP to the error state.  Timewait is tracked in the kernel. */\r
1801         cm_reset_qp( h_qp, 0 );\r
1802 \r
1803         /* \r
1804          * Since user can reuse the QP associated with this connection after\r
1805          * receiving the reject message, we need to disassociate this\r
1806          * connection handle from the QP before calling the user back.\r
1807          */\r
1808         if ( h_conn )\r
1809         {\r
1810             pfn_cm_rej_cb = h_conn->pfn_cm_rej_cb;\r
1811             ref_al_obj( &h_conn->obj );\r
1812             h_conn->obj.pfn_destroy( &h_conn->obj, NULL );\r
1813         \r
1814             /* Invoke the user's callback. */\r
1815             if( pfn_cm_rej_cb )\r
1816                 pfn_cm_rej_cb( p_cm_rej_rec );\r
1817         }\r
1818         AL_EXIT(AL_DBG_CM);\r
1819 }\r
1820 \r
1821 \r
1822 \r
1823 void\r
1824 ual_cm_mra_cb(\r
1825         IN                              ib_cm_mra_rec_t*                        p_cm_mra_rec )\r
1826 {\r
1827         ib_cm_handle_t                          h_conn;\r
1828         ib_qp_handle_t                          h_qp;\r
1829 \r
1830         AL_ENTER(AL_DBG_CM);\r
1831 \r
1832         /* Convert the user's handles. */\r
1833         switch( p_cm_mra_rec->qp_type )\r
1834         {\r
1835         case IB_QPT_RELIABLE_CONN:\r
1836         case IB_QPT_UNRELIABLE_CONN:\r
1837                 h_qp = (ib_qp_handle_t)p_cm_mra_rec->qp_context;\r
1838                 p_cm_mra_rec->qp_context = h_qp->obj.context;\r
1839                 h_conn = ((al_conn_qp_t*)h_qp)->p_conn;\r
1840                 break;\r
1841 \r
1842         default:\r
1843                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("Invalid qp_type.\n") );\r
1844                 return;\r
1845         }\r
1846 \r
1847         /* Call the application callback */\r
1848         h_conn->pfn_cm_mra_cb( p_cm_mra_rec );\r
1849 \r
1850         AL_EXIT(AL_DBG_CM);\r
1851 }\r
1852 \r
1853 \r
1854 \r
1855 void\r
1856 ual_cm_lap_cb(\r
1857         IN                              ib_cm_lap_rec_t*                        p_cm_lap_rec )\r
1858 {\r
1859         ib_cm_handle_t                          h_conn;\r
1860         ib_qp_handle_t                          h_qp;\r
1861 \r
1862         AL_ENTER(AL_DBG_CM);\r
1863 \r
1864         /* Convert the user's handles. */\r
1865         switch( p_cm_lap_rec->qp_type )\r
1866         {\r
1867         case IB_QPT_RELIABLE_CONN:\r
1868         case IB_QPT_UNRELIABLE_CONN:\r
1869                 h_qp = (ib_qp_handle_t)p_cm_lap_rec->qp_context;\r
1870                 p_cm_lap_rec->qp_context = h_qp->obj.context;\r
1871                 h_conn = ((al_conn_qp_t*)h_qp)->p_conn;\r
1872                 break;\r
1873 \r
1874         default:\r
1875                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("Invalid qp_type.\n") );\r
1876                 return;\r
1877         }\r
1878 \r
1879         /* Store & replace the kernel handle */\r
1880         h_conn->obj.hdl = (uint64_t)p_cm_lap_rec->h_cm_lap;\r
1881         p_cm_lap_rec->h_cm_lap = h_conn;\r
1882 \r
1883         /* Reference the connection until the user calls ib_cm_apr. */\r
1884         ref_al_obj( &h_conn->obj );\r
1885 \r
1886         /* Call the application callback */\r
1887         h_conn->pfn_cm_lap_cb( p_cm_lap_rec );\r
1888 \r
1889         AL_EXIT(AL_DBG_CM);\r
1890 }\r
1891 \r
1892 \r
1893 \r
1894 void\r
1895 ual_cm_apr_cb(\r
1896         IN                              ib_cm_apr_rec_t*                        p_cm_apr_rec )\r
1897 {\r
1898         ib_cm_handle_t                          h_conn;\r
1899         ib_qp_handle_t                          h_qp;\r
1900 \r
1901         AL_ENTER(AL_DBG_CM);\r
1902 \r
1903         /* Convert the user's handles. */\r
1904         switch( p_cm_apr_rec->qp_type )\r
1905         {\r
1906         case IB_QPT_RELIABLE_CONN:\r
1907         case IB_QPT_UNRELIABLE_CONN:\r
1908                 h_qp = (ib_qp_handle_t)p_cm_apr_rec->qp_context;\r
1909                 p_cm_apr_rec->qp_context = h_qp->obj.context;\r
1910                 h_conn = ((al_conn_qp_t*)h_qp)->p_conn;\r
1911                 break;\r
1912 \r
1913         default:\r
1914                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("Invalid qp_type.\n") );\r
1915                 return;\r
1916         }\r
1917 \r
1918         /* Call the application callback */\r
1919         h_conn->pfn_cm_apr_cb( p_cm_apr_rec );\r
1920 \r
1921         AL_EXIT(AL_DBG_CM);\r
1922 }\r
1923 \r
1924 \r
1925 \r
1926 void\r
1927 ual_cm_dreq_cb(\r
1928         IN                              ib_cm_dreq_rec_t*                       p_cm_dreq_rec )\r
1929 {\r
1930         ib_cm_handle_t                          h_conn;\r
1931         ib_qp_handle_t                          h_qp;\r
1932 \r
1933         AL_ENTER(AL_DBG_CM);\r
1934 \r
1935         /* Convert the user's handles. */\r
1936         switch( p_cm_dreq_rec->qp_type )\r
1937         {\r
1938         case IB_QPT_RELIABLE_CONN:\r
1939         case IB_QPT_UNRELIABLE_CONN:\r
1940                 h_qp = (ib_qp_handle_t)p_cm_dreq_rec->qp_context;\r
1941                 p_cm_dreq_rec->qp_context = h_qp->obj.context;\r
1942                 h_conn = ((al_conn_qp_t*)h_qp)->p_conn;\r
1943                 break;\r
1944 \r
1945         default:\r
1946                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("Invalid qp_type.\n") );\r
1947                 return;\r
1948         }\r
1949 \r
1950         /* Store the kernel reply handle. */\r
1951         h_conn->obj.hdl = (uint64_t)p_cm_dreq_rec->h_cm_dreq;\r
1952         p_cm_dreq_rec->h_cm_dreq = h_conn;\r
1953 \r
1954         /* Reference the connection until the user calls ib_cm_drep. */\r
1955         ref_al_obj( &h_conn->obj );\r
1956 \r
1957         /* Call the application callback */\r
1958         h_conn->pfn_cm_dreq_cb( p_cm_dreq_rec );\r
1959         AL_EXIT(AL_DBG_CM);\r
1960 }\r
1961 \r
1962 \r
1963 \r
1964 void\r
1965 ual_cm_drep_cb(\r
1966         IN                              ib_cm_drep_rec_t*                       p_cm_drep_rec )\r
1967 {\r
1968         ib_cm_handle_t                          h_conn;\r
1969         ib_qp_handle_t                          h_qp;\r
1970         ib_pfn_cm_drep_cb_t                     pfn_cm_drep_cb;\r
1971 \r
1972         AL_ENTER(AL_DBG_CM);\r
1973 \r
1974         /* Convert the user's handles. */\r
1975         switch( p_cm_drep_rec->qp_type )\r
1976         {\r
1977         case IB_QPT_RELIABLE_CONN:\r
1978         case IB_QPT_UNRELIABLE_CONN:\r
1979                 h_qp = (ib_qp_handle_t)p_cm_drep_rec->qp_context;\r
1980                 p_cm_drep_rec->qp_context = h_qp->obj.context;\r
1981                 h_conn = ((al_conn_qp_t*)h_qp)->p_conn;\r
1982                 break;\r
1983 \r
1984         default:\r
1985                 AL_PRINT(TRACE_LEVEL_ERROR ,AL_DBG_ERROR , ("Invalid qp_type.\n") );\r
1986                 return;\r
1987         }\r
1988 \r
1989         /* TODO: Handle timewait. */\r
1990         cm_reset_qp( h_qp, 0 );\r
1991 \r
1992         /*\r
1993          * We are done with this connection.  After we call the user back,\r
1994          * they can close AL, or do one of any number of difficult things\r
1995          * to deal with, so we need to handle the case where the connection\r
1996          * structure may be destroyed.  Get a copy of the user's callback.\r
1997          */\r
1998         pfn_cm_drep_cb = h_conn->pfn_cm_drep_cb;\r
1999         ref_al_obj( &h_conn->obj );\r
2000         h_conn->obj.pfn_destroy( &h_conn->obj, NULL );\r
2001 \r
2002         /* Invoke the user's callback. */\r
2003         pfn_cm_drep_cb( p_cm_drep_rec );\r
2004 \r
2005         AL_EXIT(AL_DBG_CM);\r
2006 }\r