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