ff6a1dcd62208082bc619f341b8557692582633e
[mirror/winof/.git] / core / al / kernel / al_cm_conn.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_av.h"\r
36 #include "al_ca.h"\r
37 #include "al_cm.h"\r
38 #include "al_cm_shared.h"\r
39 #include "al_debug.h"\r
40 #include "al_mgr.h"\r
41 #include "al_qp.h"\r
42 #include "al_verbs.h"\r
43 #include "ib_common.h"\r
44 \r
45 \r
46 extern al_cm_agent_t    *gp_cm;\r
47 \r
48 \r
49 /*\r
50  * See if a REQ is a duplicate.\r
51  */\r
52 cl_status_t\r
53 __req_match_pending(\r
54         IN              const   cl_list_item_t* const           p_list_item,\r
55         IN                              void                                            *context )\r
56 {\r
57         mad_cm_req_t            *p_req;\r
58         al_conn_t                       *p_conn;\r
59 \r
60         AL_ENTER( AL_DBG_CM );\r
61 \r
62         CL_ASSERT( p_list_item );\r
63         CL_ASSERT( context );\r
64 \r
65         p_req = (mad_cm_req_t*)context;\r
66         p_conn = PARENT_STRUCT( p_list_item, al_conn_t, map_item );\r
67 \r
68         if( p_req->local_comm_id != p_conn->remote_comm_id )\r
69         {\r
70                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
71                         ("Remote comm ID mismatch.\n") );\r
72                 return CL_NOT_FOUND;\r
73         }\r
74 \r
75         if( p_req->local_ca_guid != p_conn->remote_ca_guid )\r
76         {\r
77                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
78                         ("Remote CA GUID mismatch.\n") );\r
79                 return CL_NOT_FOUND;\r
80         }\r
81 \r
82         /* Reference the connection since we're working on it... */\r
83         __ref_conn( p_conn );\r
84 \r
85         AL_EXIT( AL_DBG_CM );\r
86         return CL_SUCCESS;\r
87 }\r
88 \r
89 \r
90 /*\r
91  * See if message is for a connection that has already entered the timewait\r
92  * state.\r
93  */\r
94 cl_status_t\r
95 __match_timewait(\r
96         IN              const   cl_list_item_t* const           p_list_item,\r
97         IN                              void                                            *context )\r
98 {\r
99         mad_cm_req_t            *p_req;\r
100         al_conn_t                       *p_conn;\r
101         conn_req_t                      *p_info;\r
102 \r
103         AL_ENTER( AL_DBG_CM );\r
104 \r
105         CL_ASSERT( p_list_item );\r
106         CL_ASSERT( context );\r
107 \r
108         p_conn = PARENT_STRUCT( p_list_item, al_conn_t, map_item );\r
109         p_req = (mad_cm_req_t*)context;\r
110         p_info = PARENT_STRUCT( p_list_item, al_conn_t, map_item )->p_req_info;\r
111 \r
112         if( p_conn->remote_ca_guid != p_req->local_ca_guid ||\r
113                 conn_req_get_lcl_qpn( p_req ) != p_conn->remote_qpn )\r
114         {\r
115                 AL_EXIT( AL_DBG_CM );\r
116                 return CL_NOT_FOUND;\r
117         }\r
118 \r
119         AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
120                 ("REQ received for stale connection.\n") );\r
121         return CL_SUCCESS;\r
122 }\r
123 \r
124 \r
125 /*\r
126  * Search for a listening server.\r
127  */\r
128 cl_status_t\r
129 __match_conn_listen(\r
130         IN              const   cl_list_item_t* const           p_list_item,\r
131         IN                              void                                            *context )\r
132 {\r
133         mad_cm_req_t            *p_req;\r
134         al_listen_t                     *p_listen;\r
135 \r
136         AL_ENTER( AL_DBG_CM );\r
137 \r
138         CL_ASSERT( p_list_item );\r
139         CL_ASSERT( context );\r
140 \r
141         p_req = (mad_cm_req_t*)context;\r
142         p_listen = PARENT_STRUCT( p_list_item, al_listen_t, list_item );\r
143 \r
144         if( p_listen->info.qp_type == IB_QPT_UNRELIABLE_DGRM )\r
145                 return CL_NOT_FOUND;\r
146 \r
147         if( p_req->sid != p_listen->info.svc_id )\r
148         {\r
149                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM, ("Svc ID mismatch.\n") );\r
150                 return CL_NOT_FOUND;\r
151         }\r
152 \r
153         if( p_listen->info.p_compare_buffer )\r
154         {\r
155                 if( cl_memcmp( &p_req->pdata[p_listen->info.compare_offset],\r
156                         p_listen->info.p_compare_buffer, p_listen->info.compare_length ) )\r
157                 {\r
158                         AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
159                                 ("Svc ID match but compare buffer mismatch.\n") );\r
160                         return CL_NOT_FOUND;\r
161                 }\r
162         }\r
163 \r
164         /* Reference the listen so that it doesn't go away. */\r
165         ref_al_obj( &p_listen->obj );\r
166 \r
167         AL_EXIT( AL_DBG_CM );\r
168         return CL_SUCCESS;\r
169 }\r
170 \r
171 \r
172 /*\r
173  * Try to find a matching peer-to-peer request.\r
174  */\r
175 cl_status_t\r
176 __match_peer(\r
177         IN              const   cl_list_item_t* const           p_list_item,\r
178         IN                              void                                            *context )\r
179 {\r
180         mad_cm_req_t            *p_req;\r
181         al_conn_t                       *p_conn;\r
182 \r
183         AL_ENTER( AL_DBG_CM );\r
184 \r
185         CL_ASSERT( p_list_item );\r
186         CL_ASSERT( context );\r
187 \r
188         p_req = (mad_cm_req_t*)context;\r
189         p_conn = PARENT_STRUCT( p_list_item, al_conn_t, map_item );\r
190 \r
191         /* Only match against peer-to-peer requests, not client requests. */\r
192         if( !p_conn->p_req_info->pfn_cm_req_cb )\r
193         {\r
194                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM, ("Client request.\n") );\r
195                 return CL_NOT_FOUND;\r
196         }\r
197 \r
198         /* Validate the transport type against the connection's QP type. */\r
199         if( conn_req_get_qp_type( p_req ) != p_conn->h_qp->type )\r
200         {\r
201                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
202                         ("Transport type mismatch.\n") );\r
203                 return CL_NOT_FOUND;\r
204         }\r
205 \r
206         /* Compare SID and compare data. */\r
207         if( p_req->sid != p_conn->p_req_info->svc_id )\r
208         {\r
209                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM, ("Svc ID mismatch.\n") );\r
210                 return CL_NOT_FOUND;\r
211         }\r
212 \r
213         if( p_conn->state != CM_CONN_REQ_SENT )\r
214         {\r
215                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
216                         ("Peer connection already matched.\n") );\r
217                 return CL_NOT_FOUND;\r
218         }\r
219 \r
220         /*\r
221          * Make sure the CA GUID and local comm ID are not the same\r
222          * so that a peer request doesn't match itself.\r
223          */\r
224         if( p_conn->p_req_info->p_ca_attr->ca_guid == p_req->local_ca_guid )\r
225         {\r
226                 /* Trying to connect to the same CA as the request. */\r
227                 if( p_conn->local_comm_id == p_req->local_comm_id )\r
228                 {\r
229                         AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
230                                 ("Same peer request.\n") );\r
231                         return CL_NOT_FOUND;\r
232                 }\r
233         }\r
234 \r
235         /* do a local lid and gid match */\r
236         if( p_conn->path->slid != p_req->primary_path.remote_lid )\r
237         {\r
238                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
239                         ("slid mismatch. May be a different req in list\n") );\r
240                 return CL_NOT_FOUND;\r
241         }\r
242         if( cl_memcmp( &p_conn->path->sgid, &p_req->primary_path.remote_gid,\r
243                 sizeof(ib_gid_t) ) )\r
244         {\r
245                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
246                         ("sgid mismatch. May be a different req in list\n") );\r
247                 return CL_NOT_FOUND;\r
248         }\r
249 \r
250         if( p_conn->path->dlid != p_req->primary_path.local_lid )\r
251         {\r
252                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
253                         ("dlid mismatch. May be a different req in list\n") );\r
254                 return CL_NOT_FOUND;\r
255         }\r
256         if( cl_memcmp( &p_conn->path->dgid, &p_req->primary_path.local_gid,\r
257                 sizeof(ib_gid_t) ) )\r
258         {\r
259                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
260                         ("dgid mismatch. May be a different req in list\n") );\r
261                 return CL_NOT_FOUND;\r
262         }\r
263 \r
264         /* compare private data */\r
265         if( p_conn->p_req_info->p_compare_buffer )\r
266         {\r
267                 if( cl_memcmp( &p_req->pdata[p_conn->p_req_info->compare_offset],\r
268                         p_conn->p_req_info->p_compare_buffer,\r
269                         p_conn->p_req_info->compare_length ) )\r
270                 {\r
271                         AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
272                                 ("Svc ID match but compare buffer mismatch.\n") );\r
273                         return CL_NOT_FOUND;\r
274                 }\r
275         }\r
276 \r
277         /* Reference the connection object so it doesn't go away. */\r
278         __ref_conn( p_conn );\r
279 \r
280         AL_EXIT( AL_DBG_CM );\r
281         return CL_SUCCESS;\r
282 }\r
283 \r
284 cl_status_t\r
285 __match_conn_handoff(\r
286         IN              const   cl_list_item_t* const           p_list_item,\r
287         IN                              void                                            *context )\r
288 {\r
289         al_conn_t                       *p_conn;\r
290         al_listen_t                     *p_listen;\r
291 \r
292         AL_ENTER( AL_DBG_CM );\r
293 \r
294         CL_ASSERT( p_list_item );\r
295         CL_ASSERT( context );\r
296 \r
297         p_conn = (al_conn_t*)context;\r
298         p_listen = PARENT_STRUCT( p_list_item, al_listen_t, list_item );\r
299 \r
300         if( p_listen->info.qp_type == IB_QPT_UNRELIABLE_DGRM )\r
301                 return CL_NOT_FOUND;\r
302 \r
303         if( p_conn->p_req_info->svc_id != p_listen->info.svc_id )\r
304         {\r
305                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM, ("Svc ID mismatch.\n") );\r
306                 return CL_NOT_FOUND;\r
307         }\r
308 \r
309         if( p_listen->info.p_compare_buffer )\r
310         {\r
311                 if( !p_conn->p_req_info->p_compare_buffer )\r
312                 {\r
313                         AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
314                                 ("Svc ID match but compare buffer mismatch.\n") );\r
315                         return CL_NOT_FOUND;\r
316                 }\r
317                 if( ( p_conn->p_req_info->compare_length !=\r
318                                 p_listen->info.compare_length ) ||\r
319                         ( p_conn->p_req_info->compare_offset !=\r
320                                 p_listen->info.compare_offset ) )\r
321                 {\r
322                         AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
323                                 ("Svc ID match but compare buffer mismatch.\n") );\r
324                         return CL_NOT_FOUND;\r
325                 }\r
326                 if( cl_memcmp( p_conn->p_req_info->p_compare_buffer,\r
327                         p_listen->info.p_compare_buffer, p_listen->info.compare_length ) )\r
328                 {\r
329                         AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
330                                 ("Svc ID match but compare buffer mismatch.\n") );\r
331                         return CL_NOT_FOUND;\r
332                 }\r
333         }\r
334 \r
335         /* Reference the listen so that it doesn't go away. */\r
336         ref_al_obj( &p_listen->obj );\r
337 \r
338         AL_EXIT( AL_DBG_CM );\r
339         return CL_SUCCESS;\r
340 }\r
341 \r
342 \r
343 \r
344 /*\r
345  * Migrate a connection request from the pending list to the\r
346  * connection map.\r
347  */\r
348 static void\r
349 __migrate_conn_to_map(\r
350         IN                              al_conn_t                                       *p_conn )\r
351 {\r
352         uint64_t                key;\r
353 \r
354         cl_spinlock_acquire( &gp_cm->obj.lock );\r
355         __release_req_info( p_conn );\r
356 \r
357         cl_qlist_remove_item( &gp_cm->pending_list,\r
358                 (cl_list_item_t*)&p_conn->map_item );\r
359 \r
360         key = ((uint64_t)p_conn->local_comm_id << 32) |\r
361                 ((uint64_t)p_conn->remote_comm_id);\r
362         cl_qmap_insert( &gp_cm->conn_map, key, &p_conn->map_item );\r
363 \r
364         cl_spinlock_release( &gp_cm->obj.lock );\r
365 }\r
366 \r
367 \r
368 \r
369 void\r
370 __format_req_path_rec(\r
371         IN                              mad_cm_req_t                            *p_req,\r
372         IN                              req_path_info_t                         *p_path,\r
373                 OUT                     ib_path_rec_t                           *p_path_rec )\r
374 {\r
375         AL_ENTER( AL_DBG_CM );\r
376 \r
377         CL_ASSERT( p_req );\r
378         CL_ASSERT( p_path );\r
379         CL_ASSERT( p_path_rec );\r
380 \r
381         /*\r
382          * Format a local path record. The local ack timeout specified in the\r
383          * REQ is twice the packet life plus the sender's CA ACK delay.  When\r
384          * reporting the packet life, we divide the local ack timeout by 2 to\r
385          * approach the path's packet lifetime.  Since local ack timeout is\r
386          * expressed as 4.096 * 2^x, subtracting 1 is equivalent to dividing the\r
387          * time in half.\r
388          */\r
389         ib_path_rec_init_local( p_path_rec,\r
390                 &p_path->local_gid,\r
391                 &p_path->remote_gid,\r
392                 p_path->local_lid,\r
393                 p_path->remote_lid,\r
394                 1, p_req->pkey,\r
395                 conn_req_path_get_svc_lvl( p_path ),\r
396                 IB_PATH_SELECTOR_EXACTLY, conn_req_get_mtu( p_req ),\r
397                 IB_PATH_SELECTOR_EXACTLY,\r
398                 conn_req_path_get_pkt_rate( p_path ),\r
399                 IB_PATH_SELECTOR_EXACTLY,\r
400                 (uint8_t)( conn_req_path_get_lcl_ack_timeout( p_path ) - 1 ),\r
401                 0 );\r
402 \r
403         p_path_rec->hop_flow_raw.val = 0;\r
404         /* Add global routing info as necessary. */\r
405         if( !conn_req_path_get_subn_lcl( p_path ) )\r
406         {\r
407                 ib_path_rec_set_hop_flow_raw( p_path_rec, p_path->hop_limit,\r
408                         conn_req_path_get_flow_lbl( p_path ), FALSE );\r
409                 p_path_rec->tclass = p_path->traffic_class;\r
410         }\r
411 \r
412         AL_EXIT( AL_DBG_CM );\r
413 }\r
414 \r
415 ib_rej_status_t\r
416 __validate_req_2_listen_info(\r
417         IN                              cm_port_agent_t* const          p_port_cm,\r
418         IN                              al_listen_t* const                      p_listen,\r
419         IN                              ib_path_rec_t* const            p_path_rec )\r
420 {\r
421         ib_port_attr_t  *p_port_attr;\r
422 \r
423         AL_ENTER( AL_DBG_CM );\r
424 \r
425         p_port_attr = &p_port_cm->p_ca_attr->p_port_attr[p_port_cm->port_idx];\r
426 \r
427         /* match options set in the listen attributes */\r
428         if( ( p_listen->info.ca_guid != IB_ALL_CAS ) &&\r
429                 ( p_listen->info.ca_guid != p_port_cm->p_ca_attr->ca_guid ) )\r
430         {\r
431                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
432                         ("CaGuid mismatch on listen.\n") );\r
433                 return IB_REJ_INVALID_SID;\r
434         }\r
435 \r
436         if( ( p_listen->info.lid != IB_ALL_LIDS ) &&\r
437                 ( ( p_listen->info.lid != p_path_rec->slid ) ||\r
438                   ( p_listen->info.lid != p_port_attr->lid ) ) )\r
439         {\r
440                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
441                         ("lid mismatch on listen.\n") );\r
442                 return IB_REJ_INVALID_LID;\r
443         }\r
444 \r
445         if( ( p_listen->info.port_guid != IB_ALL_PORTS ) &&\r
446                 ( p_listen->info.port_guid != p_port_attr->port_guid ) )\r
447         {\r
448                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
449                         ("PortGuid mismatch on listen.\n") );\r
450                 return IB_REJ_INVALID_SID;\r
451         }\r
452 \r
453         if( ( p_listen->info.pkey != IB_ALL_PKEYS ) &&\r
454                 ( p_listen->info.pkey != p_path_rec->pkey ) )\r
455         {\r
456                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
457                         ("pkey mismatch on listen.\n") );\r
458                 return IB_REJ_INVALID_SID;\r
459         }\r
460 \r
461         AL_EXIT( AL_DBG_CM );\r
462         return 0;\r
463 }\r
464 \r
465 \r
466 ib_rej_status_t\r
467 __format_req_rec(\r
468         IN                              cm_port_agent_t* const          p_port_cm,\r
469         IN                              mad_cm_req_t* const                     p_req,\r
470         IN                              al_listen_t* const                      p_listen        OPTIONAL,\r
471                 OUT                     ib_cm_req_rec_t                         *p_req_rec )\r
472 {\r
473         ib_rej_status_t rej_status;\r
474 \r
475         AL_ENTER( AL_DBG_CM );\r
476 \r
477         CL_ASSERT( p_port_cm );\r
478         CL_ASSERT( p_req );\r
479         CL_ASSERT( p_req_rec );\r
480 \r
481         cl_memclr( p_req_rec, sizeof( ib_cm_req_rec_t ) );\r
482 \r
483         /* validate version and transport type info */\r
484         switch( p_req->hdr.class_ver )\r
485         {\r
486         default:\r
487                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
488                         ("Invalid class version type received.\n") );\r
489                 return IB_REJ_UNSUPPORTED;\r
490 \r
491         case IB_MCLASS_CM_VER_2:\r
492                 break;\r
493         }\r
494         if( conn_req_get_qp_type( p_req ) > IB_QPT_UNRELIABLE_CONN )\r
495         {\r
496                 /* Reserved value.  Reject. */\r
497                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
498                         ("Invalid transport type received.\n") );\r
499                 return IB_REJ_INVALID_XPORT;\r
500         }\r
501 \r
502         /* format version specific data */\r
503         p_req_rec->p_req_pdata = p_req->pdata;\r
504 \r
505         p_req_rec->qp_type = conn_req_get_qp_type( p_req );\r
506 \r
507         p_req_rec->resp_res = conn_req_get_resp_res( p_req );\r
508         p_req_rec->flow_ctrl = conn_req_get_flow_ctrl( p_req );\r
509         p_req_rec->rnr_retry_cnt = conn_req_get_rnr_retry_cnt( p_req );\r
510 \r
511         __format_req_path_rec( p_req, &p_req->primary_path,\r
512                 &p_req_rec->primary_path );\r
513         __format_req_path_rec( p_req, &p_req->alternate_path,\r
514                 &p_req_rec->alt_path );\r
515 \r
516         /* validate a listen's inputs for ca, port or lid info */\r
517         if( p_listen )\r
518         {\r
519                 rej_status = __validate_req_2_listen_info( p_port_cm, p_listen,\r
520                         &p_req_rec->primary_path );\r
521 \r
522                 if( rej_status )\r
523                         return rej_status;\r
524         }\r
525 \r
526         /* These values are filled in later based on listen or peer connections\r
527         p_req_rec->context = ;\r
528         p_req_rec->h_cm_req = ;\r
529         p_req_rec->h_cm_listen = ;\r
530         */\r
531 \r
532         AL_EXIT( AL_DBG_CM );\r
533         return 0;\r
534 }\r
535 \r
536 \r
537 void\r
538 __reject_req(\r
539         IN                              cm_port_agent_t* const          p_port_cm,\r
540         IN                              ib_mad_element_t* const         p_mad,\r
541         IN              const   ib_rej_status_t                         reason )\r
542 {\r
543         mad_cm_req_t    *p_req;\r
544         mad_cm_rej_t    *p_rej;\r
545 \r
546         AL_ENTER( AL_DBG_CM );\r
547 \r
548         CL_ASSERT( p_port_cm );\r
549         CL_ASSERT( p_mad );\r
550         CL_ASSERT( reason != 0 );\r
551 \r
552         p_req = (mad_cm_req_t*)p_mad->p_mad_buf;\r
553         p_rej = (mad_cm_rej_t*)p_mad->p_mad_buf;\r
554 \r
555         /*\r
556          * Format the reject information, overwriting the REQ data and send\r
557          * the response.\r
558          */\r
559         p_rej->hdr.attr_id = CM_REJ_ATTR_ID;\r
560         p_rej->remote_comm_id = p_req->local_comm_id;\r
561         p_rej->local_comm_id = 0;\r
562         conn_rej_set_msg_rejected( 0, p_rej );\r
563         p_rej->reason = reason;\r
564         conn_rej_set_ari( NULL, 0, p_rej );\r
565         conn_rej_set_pdata( NULL, 0, p_rej );\r
566         conn_rej_clr_rsvd_fields( p_rej );\r
567 \r
568         /* Assumption: The retry count, send options, etc are zeroed on a recv. */\r
569         __cm_send_mad( p_port_cm, p_mad );\r
570 \r
571         AL_EXIT( AL_DBG_CM );\r
572 }\r
573 \r
574 \r
575 /*\r
576  * Validates the primary path specified for a connection, and stores\r
577  * the assocated CA attributes and port index.\r
578  */\r
579 ib_api_status_t\r
580 __validate_primary_path(\r
581         IN      OUT                     al_conn_t* const                        p_conn,\r
582                 OUT                     cm_port_agent_t** const         pp_port_cm )\r
583 {\r
584         ib_api_status_t         status;\r
585         cm_port_agent_t         *p_port_cm;\r
586 \r
587         AL_ENTER( AL_DBG_CM );\r
588 \r
589         CL_ASSERT( p_conn );\r
590         CL_ASSERT( pp_port_cm );\r
591         CL_ASSERT( p_conn->p_req_info );\r
592         CL_ASSERT( p_conn->h_qp );\r
593 \r
594         /* Get the CA attributes for the paths requested. */\r
595         status = __get_port_attr( &p_conn->path[0].sgid, p_conn->path[0].slid,\r
596                 &p_port_cm, &p_conn->p_req_info->p_ca_attr );\r
597         if( status != IB_SUCCESS )\r
598         {\r
599                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
600                         ("__get_port_attr failed for primary path.\n") );\r
601                 return status;\r
602         }\r
603         /* Check that the primary path is on the same CA as the QP. */\r
604         if( p_conn->p_req_info->p_ca_attr->ca_guid !=\r
605                 p_conn->h_qp->obj.p_ci_ca->verbs.guid )\r
606         {\r
607                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
608                         ("Primary path is not on the same CA as QP.\n") );\r
609                 return IB_INVALID_SETTING;\r
610         }\r
611 \r
612         p_conn->p_req_info->port_idx = p_port_cm->port_idx;\r
613 \r
614         *pp_port_cm = p_port_cm;\r
615         AL_EXIT( AL_DBG_CM );\r
616         return IB_SUCCESS;\r
617 }\r
618 \r
619 \r
620 /*\r
621  * Validates the paths specified for a connection are valid, and stores\r
622  * the assocated CA attributes and port indeces.\r
623  */\r
624 ib_api_status_t\r
625 __validate_alt_path(\r
626         IN      OUT                     al_conn_t* const                        p_conn )\r
627 {\r
628         ib_api_status_t         status;\r
629         cm_port_agent_t         *p_port_cm;\r
630         ib_ca_attr_t            *p_ca_attr;\r
631 \r
632         AL_ENTER( AL_DBG_CM );\r
633 \r
634         /* Get the alternate path port attributes. */\r
635         status = __get_port_attr( &p_conn->path[1].sgid, p_conn->path[1].slid,\r
636                 &p_port_cm, &p_ca_attr );\r
637         if( status != IB_SUCCESS )\r
638         {\r
639                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
640                         ("__get_port_attr failed for alternate path.\n") );\r
641                 return status;\r
642         }\r
643         if( p_ca_attr->ca_guid != p_conn->p_req_info->p_ca_attr->ca_guid )\r
644         {\r
645                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
646                         ("Primary and alternate paths on different CAs.\n") );\r
647                 return IB_INVALID_SETTING;\r
648         }\r
649         p_conn->p_req_info->alt_port_idx = p_port_cm->port_idx;\r
650 \r
651         AL_EXIT( AL_DBG_CM );\r
652         return IB_SUCCESS;\r
653 }\r
654 \r
655 \r
656 /*\r
657  * How the QP modify structures are populated for the RTR and RTS transitions:\r
658  *\r
659  *\r
660  * The actual state transition to RTR and RTS is performed as per the IB spec.\r
661  *\r
662  * Matrix of the settings that are set for each MAD.\r
663  *\r
664  *                                                              |          REQ          |          REP          | RTU   | grp\r
665  *                                                              | send  | recv  | send  | recv  | send  |\r
666  * ----------------------------------------------------------------------------\r
667  *      RTR     rq_psn                                  |       x       |               |       x       |               |               |       2\r
668  *              dest_qp                                 |               |       x       |               |       x       |               |       3\r
669  *              primary_av                              |               |               |               |               |               |\r
670  *                      port_num                        |       x       |               |       x       |               |               |       2\r
671  *                      sl                                      |       x       |       x       |               |               |               |       1\r
672  *                      dlid                            |       x       |       x       |               |               |               |       1\r
673  *                      grh                                     |       x       |       x       |               |               |               |       1\r
674  *                      static_rate                     |       x       |       x       |               |               |               |       1\r
675  *                      path_bits                       |       x       |               |       x       |               |               |       2\r
676  *                      path_mtu                        |       x       |       x       |               |               |               |       1\r
677  *                      local_ack_timeout       |               |       x       |               |       x       |               |       3\r
678  *                      seq_err_retry_cnt       |       x       |       x       |               |               |               |       1\r
679  *                      rnr_retry_cnt           |               |       x       |               |       x       |               |       3\r
680  *              resp_res                                |               |  x(1) |       x       |       x       |               |  3,4\r
681  *              alt_av                                  |               |               |               |               |               |\r
682  *                      port_num                        |       x       |               |       x       |               |               |       2\r
683  *                      sl                                      |       x       |       x       |               |               |               |       1\r
684  *                      dlid                            |       x       |       x       |               |               |               |       1\r
685  *                      grh                                     |       x       |       x       |               |               |               |       1\r
686  *                      static_rate                     |       x       |       x       |               |               |               |       1\r
687  *                      path_bits                       |       x       |               |       x       |               |               |       2\r
688  *                      path_mtu                        |       x       |       x       |               |               |               |       1\r
689  *                      local_ack_timeout       |               |       x       |               |       x       |               |       3\r
690  *                      seq_err_retry_cnt       |       x       |       x       |               |               |               |       1\r
691  *                      rnr_retry_cnt           |               |       x       |               |       x       |               |       3\r
692  *              q_key                                   |               |  x(2) |               |  x(2) |               |       3\r
693  *              pkey_index                              |       x       |               |       x       |               |               |       2\r
694  *              access_ctrl                             |  *(5) |               |       x       |               |               |       2\r
695  *              sq_depth                                |               |               |       x       |               |       x       |       5\r
696  *              rq_depth                                |               |               |       x       |               |       x       |       5\r
697  *              rnr_nak_timeout                 |  *(5) |               |       x       |               |               |       2\r
698  * ----------------------------------------------------------------------\r
699  *      RTS     sq_psn                                  |               |       x       |               |       x       |               |       3\r
700  *              retry_cnt                               |       x       |       x       |               |               |               |       1\r
701  *              rnr_retry_cnt                   |               |       x       |               |       x       |               |       3\r
702  *              local_ack_timeout               |               |       x       |               |       x       |               |       3\r
703  *              init_depth                              |               |               |       x       |       x       |               |       4\r
704  *              qkey                                    |  (3)  |  (3)  |  (3)  |  (3)  |  (3)  |\r
705  *              access_ctrl                             |               |               |               |               |       x       |       5\r
706  *              resp_res                                |  (3)  |  (3)  |  (3)  |  (3)  |  (3)  |\r
707  *              alt_av                                  |  (3)  |  (3)  |  (3)  |  (3)  |  (3)  |\r
708  *              sq_depth                                |               |               |       x       |               |       x       |       5\r
709  *              rq_depth                                |               |               |       x       |               |       x       |       5\r
710  *              apm_state                               |               |               |       x       |       x       |               |       4\r
711  *              primary_port                    |  (4)  |  (4)  |  (4)  |  (4)  |  (4)  |\r
712  *              pkey_index                              |  (3)  |  (3)  |  (3)  |  (3)  |  (3)  |\r
713  * ----------------------------------------------------------------------------\r
714  * Notes:\r
715  * (1) the responder resources are initialized to REQ.init_depth and then\r
716  * scaled down when sending the REP if the local CA cannot support the\r
717  * requested value.\r
718  * (2) q_key is only used for RD and is not yet supported.\r
719  * (3) handled in the RTR transition.\r
720  * (4) handled in the INIT transition.\r
721  * (5) set by CM to allow all operations.  Real value set at RTU time.\r
722  */\r
723 \r
724 \r
725 \r
726 /*\r
727  * + Validates the path information provided in the REQ and stores the\r
728  *       associated CA attributes and port indeces.\r
729  * + Transitions a connection object from active to passive in the peer case.\r
730  * + Sets the path information in the connection and sets the CA GUID\r
731  *       in the REQ callback record.\r
732  */\r
733 void\r
734 __conn_save_wire_req(\r
735         IN              const   mad_cm_req_t* const                     p_req,\r
736                 OUT                     al_conn_t*       const                  p_conn,\r
737         IN      OUT                     ib_cm_req_rec_t* const          p_req_rec )\r
738 {\r
739         ib_qp_handle_t  h_qp;\r
740         struct _qp_rtr  *p_rtr;\r
741         struct _qp_rts  *p_rts;\r
742 \r
743         AL_ENTER( AL_DBG_CM );\r
744 \r
745         p_conn->state = CM_CONN_REQ_RCVD;\r
746         p_conn->was_active = FALSE;\r
747 \r
748         /* Store pertinent information in the connection. */\r
749         p_conn->remote_comm_id = p_req->local_comm_id;\r
750         p_conn->remote_ca_guid = p_req->local_ca_guid;\r
751 \r
752         p_conn->remote_qpn = conn_req_get_lcl_qpn( p_req );\r
753 \r
754         /*\r
755          * Release the QP, if any, since the user can change the QP handles\r
756          * when replying.  This prevents the connection from being\r
757          * aborted if the user destroys a QP that was used to send the REQ for\r
758          * a peer-to-peer request that lost the peer comparisson.\r
759          */\r
760         h_qp = p_conn->h_qp;\r
761         if( h_qp )\r
762         {\r
763                 cm_unbind_qp( p_conn );\r
764                 deref_al_obj( &h_qp->obj );\r
765         }\r
766 \r
767         /*\r
768          * Calculate the retry timeout.\r
769          * All timeout values in micro seconds are expressed as 4.096 * 2^x,\r
770          * where x is the timeout.  This approximates to 2^(x+2).\r
771          * Since we want milliseconds, we can further approximate to 2^(x-8).\r
772          * This results in a timeout that is roughly 5% on the low side, but\r
773          * good enough since OS timer resolutions are ~10ms.\r
774          */\r
775         if( conn_req_get_lcl_resp_timeout( p_req ) > 8 )\r
776         {\r
777                 p_conn->retry_timeout =\r
778                         1 << (conn_req_get_lcl_resp_timeout( p_req ) - 8);\r
779 \r
780                 /* Minimum 10 ms timeout - picked to match typical OS timer resolution. */\r
781                 if( p_conn->retry_timeout < 10 )\r
782                         p_conn->retry_timeout = 10;\r
783         }\r
784         else\r
785         {\r
786                 p_conn->retry_timeout = 10;\r
787         }\r
788 \r
789         /* Store the retry count. */\r
790         p_conn->max_cm_retries = conn_req_get_max_cm_retries( p_req );\r
791 \r
792         /*\r
793          * Copy the paths from the req_rec into the connection for\r
794          * future use.\r
795          */\r
796         cl_memcpy( &p_conn->path[0], &p_req_rec->primary_path,\r
797                 sizeof(ib_path_rec_t) );\r
798         cl_memcpy( &p_conn->path[1], &p_req_rec->alt_path, sizeof(ib_path_rec_t) );\r
799         p_conn->idx_primary = 0;\r
800 \r
801         /* Setup the QP modify structures for the RTR and RTS transitions */\r
802         p_rtr = &p_conn->p_req_info->qp_mod_rtr.state.rtr;\r
803         p_rts = &p_conn->p_req_info->qp_mod_rts.state.rts;\r
804 \r
805         /* Update RTR info */\r
806         p_rtr->dest_qp = conn_req_get_lcl_qpn( p_req );\r
807 \r
808         /* The responder resources may be scaled down when sending the REP. */\r
809         p_rtr->resp_res = conn_req_get_init_depth( p_req );\r
810 \r
811         /* updated in the REP\r
812         p_rtr->qkey;\r
813         p_rtr->access_ctrl;\r
814         p_rtr->sq_depth;\r
815         p_rtr->rq_depth;\r
816         p_rtr->rnr_nak_timeout;\r
817         p_rtr->primary_av;\r
818         p_rtr->alternate_av;\r
819         p_rtr->rq_psn;\r
820         */\r
821 \r
822         /* Update RTS info */\r
823         p_rts->retry_cnt = conn_req_get_retry_cnt( p_req );\r
824         p_rts->rnr_retry_cnt = conn_req_get_rnr_retry_cnt( p_req );\r
825         p_rts->local_ack_timeout = conn_req_path_get_lcl_ack_timeout(\r
826                 &p_req->primary_path );\r
827 \r
828         p_rts->init_depth = conn_req_get_resp_res( p_req );\r
829 \r
830         p_rts->opts = 0;\r
831         p_rts->resp_res = p_rtr->resp_res;\r
832         p_rts->sq_psn = conn_req_get_starting_psn( p_req );\r
833 \r
834         /* Set in the REP\r
835         p_rts->rnr_nak_timeout;\r
836         p_rts->qkey;\r
837         p_rts->access_ctrl;\r
838         p_rts->sq_depth;\r
839         p_rts->rq_depth;\r
840         p_rts->apm_state;\r
841         p_rts->primary_port;\r
842         */\r
843 \r
844         /* copy pdata for cm handoffs\r
845         cl_memcpy( p_conn->mads.req.pdata,\r
846                 p_req->pdata, IB_REQ_PDATA_SIZE );*/\r
847 \r
848         /* copy mad info for cm handoff */\r
849         p_conn->mads.req = *p_req;\r
850 \r
851         AL_EXIT( AL_DBG_CM );\r
852 }\r
853 \r
854 void\r
855 __listen_req(\r
856         IN                              cm_port_agent_t* const          p_port_cm,\r
857         IN                              al_listen_t* const                      p_listen,\r
858         IN                              ib_mad_element_t* const         p_mad )\r
859 {\r
860         al_conn_t                       *p_conn;\r
861         mad_cm_req_t            *p_req;\r
862         ib_cm_req_rec_t         req_rec;\r
863         ib_rej_status_t         rej_status;\r
864 \r
865         AL_ENTER( AL_DBG_CM );\r
866 \r
867         CL_ASSERT( p_port_cm );\r
868         CL_ASSERT( p_listen );\r
869         CL_ASSERT( p_mad );\r
870 \r
871         p_req = (mad_cm_req_t*)p_mad->p_mad_buf;\r
872 \r
873         /* Format the callback record. */\r
874         rej_status = __format_req_rec( p_port_cm, p_req, p_listen, &req_rec );\r
875         if( rej_status )\r
876         {\r
877                 /* The request is malformed.  Reject it. */\r
878                 __reject_req( p_port_cm, p_mad, rej_status );\r
879                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
880                         ("REJ sent for malformed REQ.\n") );\r
881                 return;\r
882         }\r
883 \r
884         /* Get a new connection object. */\r
885         p_conn = __get_conn( (ib_al_handle_t)p_listen->obj.p_parent_obj,\r
886                 req_rec.qp_type );\r
887         if( !p_conn )\r
888         {\r
889                 /* Reject the request for insufficient resources. */\r
890                 __reject_req( p_port_cm, p_mad, IB_REJ_INSUF_RESOURCES );\r
891                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
892                         ("REJ sent for insufficient resources.\n") );\r
893                 return;\r
894         }\r
895 \r
896         /* update p_conn from listen and req values. */\r
897         p_conn->p_req_info->pfn_cm_req_cb = NULL;\r
898         p_conn->pfn_cm_rej_cb = p_listen->info.pfn_cm_rej_cb;\r
899         p_conn->p_req_info->pfn_cm_rep_cb = NULL;\r
900         p_conn->pfn_cm_mra_cb = p_listen->info.pfn_cm_mra_cb;\r
901 \r
902         p_conn->p_port_cm = p_port_cm;\r
903 \r
904         /* update listen based rec */\r
905         req_rec.context = p_listen->obj.context;\r
906         req_rec.h_cm_req = p_conn;\r
907         req_rec.h_cm_listen = p_listen;\r
908 \r
909         /* save req info received */\r
910         __conn_save_wire_req( p_req, p_conn, &req_rec );\r
911 \r
912         /* Add the connection to the list of pending connections. */\r
913         cl_spinlock_acquire( &gp_cm->obj.lock );\r
914         cl_qlist_insert_tail( &gp_cm->pending_list,\r
915                 (cl_list_item_t*)&p_conn->map_item );\r
916         cl_spinlock_release( &gp_cm->obj.lock );\r
917 \r
918         /* Reference the connection object until the user calls REP or REJ. */\r
919         __ref_conn( p_conn );\r
920 \r
921         /* Invoke the user's callback. */\r
922         p_listen->info.pfn_cm_req_cb( &req_rec );\r
923 \r
924         /* Return the REQ to the mad pool */\r
925         ib_put_mad( p_mad );\r
926 \r
927         AL_EXIT( AL_DBG_CM );\r
928 }\r
929 \r
930 \r
931 void\r
932 __peer_req(\r
933         IN                              cm_port_agent_t* const          p_port_cm,\r
934         IN                              al_conn_t* const                        p_conn,\r
935         IN                              ib_mad_element_t* const         p_mad )\r
936 {\r
937         mad_cm_req_t    *p_req;\r
938         ib_cm_req_rec_t req_rec;\r
939         ib_rej_status_t rej_status;\r
940         ib_api_status_t status;\r
941 \r
942         AL_ENTER( AL_DBG_CM );\r
943 \r
944         CL_ASSERT( p_port_cm );\r
945         CL_ASSERT( p_conn );\r
946         CL_ASSERT( p_conn->p_req_info );\r
947         /* Must be peer-to-peer. */\r
948         CL_ASSERT( p_conn->p_req_info->pfn_cm_req_cb );\r
949         CL_ASSERT( p_mad );\r
950         CL_ASSERT( p_conn->h_qp );\r
951 \r
952         p_req = ib_get_mad_buf( p_mad );\r
953 \r
954         cm_res_acquire( p_conn );\r
955 \r
956         /* Perform peer comparison. */\r
957         if( cl_ntoh64( p_conn->p_req_info->p_ca_attr->ca_guid ) >\r
958                 cl_ntoh64( p_req->local_ca_guid ) )\r
959         {\r
960                 cm_res_release( p_conn );\r
961                 __repeated_mad( p_port_cm, p_conn, p_mad );\r
962                 /* Release reference on p_conn obtained from __match_peer. */\r
963                 __deref_conn( p_conn );\r
964                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
965                         ("Won peer compare, repeating REQ.\n") );\r
966                 return;\r
967         }\r
968         if( cl_ntoh32( p_conn->p_req_info->local_qpn ) >\r
969                 cl_ntoh32( conn_req_get_lcl_qpn( p_req ) ) )\r
970         {\r
971                 cm_res_release( p_conn );\r
972                 __repeated_mad( p_port_cm, p_conn, p_mad );\r
973                 /* Release reference on p_conn obtained from __match_peer. */\r
974                 __deref_conn( p_conn );\r
975                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
976                         ("Won peer compare, repeating REQ.\n") );\r
977                 return;\r
978         }\r
979 \r
980         /* Format the callback record. */\r
981         rej_status = __format_req_rec( p_port_cm, p_req, NULL, &req_rec );\r
982         if( rej_status )\r
983         {\r
984                 cm_res_release( p_conn );\r
985                 /* Release reference on p_conn obtained from __match_peer. */\r
986                 __deref_conn( p_conn );\r
987 \r
988                 /* The request is malformed.  Reject it. */\r
989                 __reject_req( p_port_cm, p_mad, rej_status );\r
990                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
991                         ("REJ sent for malformed REQ.\n") );\r
992                 return;\r
993         }\r
994 \r
995         /* Stop sending the REQ and change the state. */\r
996         status = ib_cancel_mad( p_conn->h_mad_svc, p_conn->p_send_mad );\r
997         p_conn->p_send_mad = NULL;\r
998         if( status == IB_NOT_FOUND )\r
999         {\r
1000                 cm_res_release( p_conn );\r
1001                 /* Release reference on p_conn obtained from __match_peer. */\r
1002                 __deref_conn( p_conn );\r
1003                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1004                         ("REQ in invalid state.\n") );\r
1005                 return;\r
1006         }\r
1007 \r
1008         /* update peer based rec handles and context values */\r
1009         req_rec.context = p_conn->h_qp->obj.context;\r
1010         req_rec.h_cm_req = p_conn;\r
1011         req_rec.h_cm_listen = NULL;\r
1012 \r
1013         __conn_save_wire_req(p_req, p_conn, &req_rec );\r
1014         cm_res_release( p_conn );\r
1015 \r
1016         /* Note that we're holding a reference on p_conn from __match_peer(). */\r
1017 \r
1018         /* Invoke the user's callback.  User must call ib_cm_rep or ib_cm_rej. */\r
1019         p_conn->p_req_info->pfn_cm_req_cb( &req_rec );\r
1020 \r
1021         /* Return the REQ to the mad pool */\r
1022         ib_put_mad( p_mad );\r
1023 \r
1024         AL_EXIT( AL_DBG_CM );\r
1025 }\r
1026 \r
1027 \r
1028 ib_api_status_t\r
1029 cm_conn_handoff(\r
1030         IN                              al_conn_t*       const                  p_conn,\r
1031         IN              const   net64_t                                         svc_id )\r
1032 {\r
1033         cl_list_item_t  *p_list_item;\r
1034         al_listen_t             *p_listen;\r
1035         ib_cm_req_rec_t req_rec;\r
1036         ib_rej_status_t rej_status;\r
1037         al_conn_t               *p_conn_handoff;\r
1038 \r
1039         AL_ENTER( AL_DBG_CM );\r
1040 \r
1041         CL_ASSERT( p_conn );\r
1042 \r
1043         cm_res_acquire( p_conn );\r
1044 \r
1045         /*\r
1046          * To do a successful handoff the current connection's attribs should be\r
1047          * validated against the service_id to be handed over to.\r
1048          * We change the service_id of the current connection to the one we want\r
1049          * to hand off to. The match routine will validate the rest of the handoff\r
1050          * process.\r
1051          */\r
1052         p_conn->p_req_info->svc_id = svc_id;\r
1053 \r
1054         cl_spinlock_acquire( &gp_cm->obj.lock );\r
1055         p_list_item = cl_qlist_find_from_head( &gp_cm->active_listen_list,\r
1056                 __match_conn_handoff, p_conn );\r
1057         if( p_list_item == cl_qlist_end( &gp_cm->active_listen_list ) )\r
1058         {\r
1059                 cl_spinlock_release( &gp_cm->obj.lock );\r
1060                 __conn_reject( p_conn, IB_REJ_INVALID_SID, NULL, 0, NULL );\r
1061                 cm_res_release( p_conn );\r
1062                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
1063                         ("Handoff failed on svc_id!\n") );\r
1064                 return IB_INVALID_PARAMETER;\r
1065         }\r
1066         cl_spinlock_release( &gp_cm->obj.lock );\r
1067 \r
1068         /* A listen for handoff was found. Now transfer details from old conn */\r
1069         p_listen = PARENT_STRUCT( p_list_item, al_listen_t, list_item );\r
1070 \r
1071         /* Format the callback record. */\r
1072         rej_status = __format_req_rec( p_conn->p_port_cm, &p_conn->mads.req,\r
1073                 p_listen, &req_rec );\r
1074         if( rej_status )\r
1075         {\r
1076                 /* The request does not conform to the handoff process service. */\r
1077                 __conn_reject( p_conn, rej_status, NULL, 0, NULL );\r
1078                 cm_res_release( p_conn );\r
1079                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
1080                         ("Handoff failed on svc_id info!\n") );\r
1081                 return IB_INVALID_PARAMETER;\r
1082         }\r
1083 \r
1084         /* Get a new connection object. */\r
1085         p_conn_handoff = __get_conn( (ib_al_handle_t)p_listen->obj.p_parent_obj,\r
1086                 req_rec.qp_type );\r
1087         if( !p_conn_handoff )\r
1088         {\r
1089                 /* Reject the request for insufficient resources. */\r
1090                 __conn_reject( p_conn, IB_REJ_INSUF_RESOURCES, NULL, 0, NULL );\r
1091                 cm_res_release( p_conn );\r
1092                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1093                         ("Handoff failed on insufficient resources.\n") );\r
1094                 return IB_INSUFFICIENT_MEMORY;\r
1095         }\r
1096 \r
1097         /* update p_conn from listen and req values. */\r
1098         p_conn_handoff->p_req_info->pfn_cm_req_cb = NULL;\r
1099         p_conn_handoff->pfn_cm_rej_cb = p_listen->info.pfn_cm_rej_cb;\r
1100         p_conn_handoff->p_req_info->pfn_cm_rep_cb = NULL;\r
1101         p_conn_handoff->pfn_cm_mra_cb = p_listen->info.pfn_cm_mra_cb;\r
1102 \r
1103         p_conn_handoff->p_port_cm = p_conn->p_port_cm;\r
1104 \r
1105         /* update listen based rec */\r
1106         req_rec.context = p_listen->obj.context;\r
1107         req_rec.h_cm_req = p_conn_handoff;\r
1108         req_rec.h_cm_listen = p_listen;\r
1109 \r
1110         /* save req info received */\r
1111         __conn_save_wire_req( &p_conn->mads.req, p_conn_handoff, &req_rec );\r
1112 \r
1113         /* Add the connection to the list of pending connections. */\r
1114         cl_spinlock_acquire( &gp_cm->obj.lock );\r
1115         cl_qlist_insert_tail( &gp_cm->pending_list,\r
1116                 (cl_list_item_t*)&p_conn_handoff->map_item );\r
1117         cl_spinlock_release( &gp_cm->obj.lock );\r
1118 \r
1119         /* Reference the connection object until the user calls REP or REJ. */\r
1120         __ref_conn( p_conn_handoff );\r
1121 \r
1122         /* Abort the original connection created when the REQ was received. */\r
1123         __conn_abort( p_conn );\r
1124         cm_res_release( p_conn );\r
1125 \r
1126         /* Invoke the user's callback. */\r
1127         p_listen->info.pfn_cm_req_cb( &req_rec );\r
1128 \r
1129         /* deref the listen object */\r
1130         deref_al_obj( &p_listen->obj );\r
1131 \r
1132         AL_EXIT( AL_DBG_CM );\r
1133         return IB_SUCCESS;\r
1134 }\r
1135 \r
1136 \r
1137 void\r
1138 __process_cm_req(\r
1139         IN                              cl_async_proc_item_t            *p_item )\r
1140 {\r
1141         cm_port_agent_t *p_port_cm;\r
1142         mad_cm_req_t    *p_req;\r
1143         cm_async_mad_t  *p_async_mad;\r
1144         cl_list_item_t  *p_list_item;\r
1145         al_conn_t               *p_conn;\r
1146         al_listen_t             *p_listen;\r
1147 \r
1148         AL_ENTER( AL_DBG_CM );\r
1149 \r
1150         p_async_mad = PARENT_STRUCT( p_item, cm_async_mad_t, item );\r
1151         p_req = (mad_cm_req_t*)p_async_mad->p_mad->p_mad_buf;\r
1152         p_port_cm = p_async_mad->p_port_cm;\r
1153 \r
1154         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, ("REQ: comm_id (x%x) received\n",\r
1155                 p_req->local_comm_id ) );\r
1156 \r
1157         /* Match against pending connections using remote comm ID and CA GUID. */\r
1158         cl_spinlock_acquire( &gp_cm->obj.lock );\r
1159         p_list_item = cl_qlist_find_from_head( &gp_cm->pending_list,\r
1160                 __req_match_pending, p_req );\r
1161         if( p_list_item != cl_qlist_end( &gp_cm->pending_list ) )\r
1162         {\r
1163                 /* Already received the REQ. */\r
1164                 cl_spinlock_release( &gp_cm->obj.lock );\r
1165                 p_conn = PARENT_STRUCT( p_list_item, al_conn_t, map_item );\r
1166                 __repeated_mad( p_port_cm, p_conn, p_async_mad->p_mad );\r
1167                 __deref_conn( p_conn );\r
1168                 cl_free( p_async_mad );\r
1169                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
1170                         ("Duplicate REQ received.\n") );\r
1171                 return;\r
1172         }\r
1173 \r
1174         /* Match against stale connections using remote comm ID and CA GUID. */\r
1175         p_list_item = cl_qlist_find_from_tail( &gp_cm->time_wait_list,\r
1176                 __match_timewait, p_req );\r
1177         if( p_list_item != cl_qlist_end( &gp_cm->time_wait_list ) )\r
1178         {\r
1179                 cl_spinlock_release( &gp_cm->obj.lock );\r
1180                 __reject_req( p_port_cm, p_async_mad->p_mad, IB_REJ_STALE_CONN );\r
1181                 cl_free( p_async_mad );\r
1182                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
1183                         ("REQ received for connection in TIME_WAIT state.\n") );\r
1184                 return;\r
1185         }\r
1186 \r
1187         /* Match against listens using SID and compare data. */\r
1188         p_list_item = cl_qlist_find_from_head( &gp_cm->active_listen_list,\r
1189                 __match_conn_listen, p_req );\r
1190         if( p_list_item != cl_qlist_end( &gp_cm->active_listen_list ) )\r
1191         {\r
1192                 cl_spinlock_release( &gp_cm->obj.lock );\r
1193                 p_listen = PARENT_STRUCT( p_list_item, al_listen_t, list_item );\r
1194                 __listen_req( p_port_cm, p_listen, p_async_mad->p_mad );\r
1195                 deref_al_obj( &p_listen->obj );\r
1196                 cl_free( p_async_mad );\r
1197                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
1198                         ("REQ matched a listen.\n") );\r
1199                 return;\r
1200         }\r
1201 \r
1202         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, ("No listens active!\n") );\r
1203 \r
1204         /* Match against peer-to-peer requests using SID and compare data. */\r
1205         p_list_item = cl_qlist_find_from_head( &gp_cm->pending_list,\r
1206                 __match_peer, p_req );\r
1207         if( p_list_item != cl_qlist_end( &gp_cm->pending_list ) )\r
1208         {\r
1209                 cl_spinlock_release( &gp_cm->obj.lock );\r
1210                 p_conn = PARENT_STRUCT( p_list_item, al_conn_t, map_item );\r
1211                 __peer_req( p_port_cm, p_conn, p_async_mad->p_mad );\r
1212                 cl_free( p_async_mad );\r
1213                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
1214                         ("REQ matched a peer-to-peer request.\n") );\r
1215                 return;\r
1216         }\r
1217 \r
1218         /* No match found.  Reject. */\r
1219         cl_spinlock_release( &gp_cm->obj.lock );\r
1220         __reject_req( p_port_cm, p_async_mad->p_mad, IB_REJ_INVALID_SID );\r
1221         cl_free( p_async_mad );\r
1222         AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
1223                 ("REQ received but no match found.\n") );\r
1224 }\r
1225 \r
1226 \r
1227 /*\r
1228  * Matches a connection by local (and remote if available) communication ID.\r
1229  */\r
1230 cl_status_t\r
1231 __mra_match(\r
1232         IN              const   cl_list_item_t* const           p_list_item,\r
1233         IN                              void                                            *context )\r
1234 {\r
1235         al_conn_t               *p_conn;\r
1236         mad_cm_mra_t    *p_mra;\r
1237 \r
1238         AL_ENTER( AL_DBG_CM );\r
1239 \r
1240         p_conn = PARENT_STRUCT( p_list_item, al_conn_t, map_item );\r
1241         p_mra = (mad_cm_mra_t*)context;\r
1242 \r
1243         if( p_conn->local_comm_id != p_mra->remote_comm_id )\r
1244         {\r
1245                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
1246                         ("Local conn ID mismatch.\n") );\r
1247                 return CL_NOT_FOUND;\r
1248         }\r
1249 \r
1250         if( p_conn->remote_comm_id &&\r
1251                 p_conn->remote_comm_id == p_mra->local_comm_id )\r
1252         {\r
1253                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
1254                         ("Remote conn ID mismatch.\n") );\r
1255                 return CL_NOT_FOUND;\r
1256         }\r
1257 \r
1258         AL_EXIT( AL_DBG_CM );\r
1259         return CL_SUCCESS;\r
1260 }\r
1261 \r
1262 \r
1263 void\r
1264 __start_mra_timer(\r
1265         IN                              al_conn_t* const                        p_conn,\r
1266         IN              const   mad_cm_mra_t* const                     p_mra )\r
1267 {\r
1268         uint32_t                timeout;\r
1269         uint8_t                 pkt_life;\r
1270 \r
1271         AL_ENTER( AL_DBG_CM );\r
1272 \r
1273         /* Cancel the send for the REQ, REP, or LAP. */\r
1274         ib_cancel_mad( p_conn->h_mad_svc, p_conn->p_send_mad );\r
1275         p_conn->p_send_mad = NULL;\r
1276 \r
1277         /*\r
1278          * Set the retry timer to the interval specified in the MRA.\r
1279          * All timeout values in micro seconds are expressed as 4.096 * 2^x,\r
1280          * where x is the timeout.  This approximates to 2^(x+2).\r
1281          * Since we want milliseconds, we can further approximate to 2^(x-8).\r
1282          * This results in a timeout that is roughly 5% on the low side, but\r
1283          * good enough.\r
1284          */\r
1285         if( conn_mra_get_svc_timeout( p_mra ) > 8 )\r
1286                 timeout = 1 << (conn_mra_get_svc_timeout( p_mra ) - 8);\r
1287         else\r
1288                 timeout = 0;\r
1289 \r
1290         pkt_life = ib_path_rec_pkt_life( &p_conn->path[p_conn->idx_primary] );\r
1291         if( pkt_life > 8 )\r
1292                 timeout += 1 << (pkt_life - 8);\r
1293 \r
1294         /*\r
1295          * Minimum 10 ms timeout - picked to match typical OS timer resolution.\r
1296          */\r
1297         if( timeout < 10 )\r
1298                 timeout = 10;\r
1299         if( p_conn->state != CM_CONN_REQ_MRA_RCVD &&\r
1300                 p_conn->state != CM_CONN_REP_MRA_RCVD &&\r
1301                 p_conn->state != CM_CONN_LAP_MRA_RCVD )\r
1302         {\r
1303                 /* Only reference the connection the first time we set the timer. */\r
1304                 __ref_conn( p_conn );\r
1305         }\r
1306 \r
1307         if( cl_timer_start( &p_conn->timer, timeout ) != CL_SUCCESS )\r
1308         {\r
1309                 __deref_conn( p_conn );\r
1310         }\r
1311 \r
1312         AL_EXIT( AL_DBG_CM );\r
1313 }\r
1314 \r
1315 \r
1316 void\r
1317 __do_mra_callback(\r
1318         IN                              al_conn_t* const                        p_conn,\r
1319         IN              const   mad_cm_mra_t* const                     p_mra )\r
1320 {\r
1321         ib_cm_mra_rec_t mra_rec;\r
1322 \r
1323         AL_ENTER( AL_DBG_CM );\r
1324 \r
1325         CL_ASSERT( p_conn->h_qp );\r
1326 \r
1327         /* Format the MRA callback record. */\r
1328         cl_memclr( &mra_rec, sizeof( ib_cm_mra_rec_t ) );\r
1329 \r
1330         mra_rec.h_qp = p_conn->h_qp;\r
1331         mra_rec.qp_context = p_conn->h_qp->obj.context;\r
1332         mra_rec.p_mra_pdata = p_mra->pdata;\r
1333 \r
1334         /*\r
1335          * Call the user back. Note that users will get a callback only\r
1336          * for the first MRA received in response to a REQ, REP, or LAP.\r
1337          */\r
1338         p_conn->pfn_cm_mra_cb( &mra_rec );\r
1339 \r
1340         AL_EXIT( AL_DBG_CM );\r
1341 }\r
1342 \r
1343 \r
1344 void\r
1345 __process_cm_mra(\r
1346         IN                              cl_async_proc_item_t            *p_item )\r
1347 {\r
1348         cm_port_agent_t *p_port_cm;\r
1349         mad_cm_mra_t    *p_mra;\r
1350         cm_async_mad_t  *p_async_mad;\r
1351         cl_map_item_t   *p_map_item;\r
1352         al_conn_t               *p_conn;\r
1353         boolean_t               do_callback = TRUE;\r
1354         uint64_t                key;\r
1355 \r
1356         AL_ENTER( AL_DBG_CM );\r
1357 \r
1358         p_async_mad = PARENT_STRUCT( p_item, cm_async_mad_t, item );\r
1359         p_port_cm = p_async_mad->p_port_cm;\r
1360         p_mra = (mad_cm_mra_t*)p_async_mad->p_mad->p_mad_buf;\r
1361 \r
1362         cl_spinlock_acquire( &gp_cm->obj.lock );\r
1363         if( conn_mra_get_msg_mraed( p_mra ) == 2 )\r
1364         {\r
1365                 key = ((uint64_t)p_mra->remote_comm_id << 32) |\r
1366                         ((uint64_t)p_mra->local_comm_id );\r
1367 \r
1368                 p_map_item = cl_qmap_get( &gp_cm->conn_map, key );\r
1369                 if( p_map_item == cl_qmap_end( &gp_cm->conn_map ) )\r
1370                 {\r
1371                         cl_spinlock_release( &gp_cm->obj.lock );\r
1372                         ib_put_mad( p_async_mad->p_mad );\r
1373                         cl_free( p_async_mad );\r
1374 \r
1375                         AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
1376                                 ("MRA received for LAP that could not be matched.\n") );\r
1377                         return;\r
1378                 }\r
1379         }\r
1380         else\r
1381         {\r
1382                 p_map_item = (cl_map_item_t*)cl_qlist_find_from_head(\r
1383                         &gp_cm->pending_list, __mra_match, p_mra );\r
1384                 if( p_map_item ==\r
1385                         (cl_map_item_t*)cl_qlist_end( &gp_cm->pending_list ) )\r
1386                 {\r
1387                         AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
1388                                 ("MRA received that could not be matched.\n") );\r
1389 \r
1390                         cl_spinlock_release( &gp_cm->obj.lock );\r
1391                         ib_put_mad( p_async_mad->p_mad );\r
1392                         cl_free( p_async_mad );\r
1393                         return;\r
1394                 }\r
1395         }\r
1396 \r
1397         p_conn = PARENT_STRUCT( p_map_item, al_conn_t, map_item );\r
1398 \r
1399         __ref_conn( p_conn );\r
1400         cl_spinlock_release( &gp_cm->obj.lock );\r
1401 \r
1402         cm_res_acquire( p_conn );\r
1403 \r
1404         switch( p_conn->state )\r
1405         {\r
1406         case CM_CONN_REQ_MRA_RCVD:\r
1407                 do_callback = FALSE;\r
1408         case CM_CONN_REQ_SENT:\r
1409                 /* MRA is not for the REQ. Drop it. */\r
1410                 if( conn_mra_get_msg_mraed( p_mra ) != 0 )\r
1411                 {\r
1412                         do_callback = FALSE;\r
1413                         break;\r
1414                 }\r
1415                 /* Store the remote communication ID. */\r
1416                 p_conn->remote_comm_id = p_mra->local_comm_id;\r
1417                 __start_mra_timer( p_conn, p_mra );\r
1418                 p_conn->state = CM_CONN_REQ_MRA_RCVD;\r
1419                 break;\r
1420 \r
1421         case CM_CONN_REP_MRA_RCVD:\r
1422                 do_callback = FALSE;\r
1423         case CM_CONN_REP_SENT:\r
1424                 /* MRA is not for the REP. Drop it. */\r
1425                 if( conn_mra_get_msg_mraed( p_mra ) != 1 )\r
1426                 {\r
1427                         do_callback = FALSE;\r
1428                         break;\r
1429                 }\r
1430                 __start_mra_timer( p_conn, p_mra );\r
1431                 p_conn->state = CM_CONN_REP_MRA_RCVD;\r
1432                 break;\r
1433 \r
1434         case CM_CONN_LAP_MRA_RCVD:\r
1435                 do_callback = FALSE;\r
1436         case CM_CONN_LAP_SENT:\r
1437                 /* MRA is not for the LAP. Drop it. */\r
1438                 if( conn_mra_get_msg_mraed( p_mra ) != 2 )\r
1439                 {\r
1440                         do_callback = FALSE;\r
1441                         break;\r
1442                 }\r
1443                 __start_mra_timer( p_conn, p_mra );\r
1444                 p_conn->state = CM_CONN_LAP_MRA_RCVD;\r
1445                 break;\r
1446 \r
1447         default:\r
1448                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM,\r
1449                         ("MRA received in invalid state.\n") );\r
1450                 do_callback = FALSE;\r
1451                 break;\r
1452         }\r
1453 \r
1454         cm_res_release( p_conn );\r
1455         if( do_callback )\r
1456                 __do_mra_callback( p_conn, p_mra );\r
1457         __deref_conn( p_conn );\r
1458 \r
1459         ib_put_mad( p_async_mad->p_mad );\r
1460         cl_free( p_async_mad );\r
1461 \r
1462         AL_EXIT( AL_DBG_CM );\r
1463 }\r
1464 \r
1465 \r
1466 void\r
1467 __do_rej_callback(\r
1468         IN                              al_conn_t* const                        p_conn,\r
1469         IN              const   mad_cm_rej_t* const                     p_rej )\r
1470 {\r
1471         ib_cm_rej_rec_t rej_rec;\r
1472 \r
1473         /* Format the REJ callback record. */\r
1474         cl_memclr( &rej_rec, sizeof( ib_cm_rej_rec_t ) );\r
1475 \r
1476         CL_ASSERT( p_conn->h_qp );\r
1477 \r
1478         rej_rec.h_qp = p_conn->h_qp;\r
1479         rej_rec.qp_context = p_conn->h_qp->obj.context;\r
1480 \r
1481         rej_rec.p_rej_pdata = p_rej->pdata;\r
1482         rej_rec.p_ari = p_rej->ari;\r
1483         rej_rec.ari_length = conn_rej_get_ari_len( p_rej );\r
1484         rej_rec.rej_status = p_rej->reason;\r
1485 \r
1486         /*\r
1487          * Unbind the QP from the connection object.  This allows the QP to\r
1488          * be immediately reused in another connection request.\r
1489          */\r
1490         __cm_conn_unbind( p_conn, 0 );\r
1491 \r
1492         /* Call the user back. */\r
1493         p_conn->pfn_cm_rej_cb( &rej_rec );\r
1494 }\r
1495 \r
1496 \r
1497 /*\r
1498  * Matches a connection by CA GUID and communication ID.\r
1499  */\r
1500 cl_status_t\r
1501 __rej_match(\r
1502         IN              const   cl_list_item_t* const           p_list_item,\r
1503         IN                              void                                            *context )\r
1504 {\r
1505         al_conn_t                                       *p_conn;\r
1506         mad_cm_rej_t                            *p_rej;\r
1507         const ib_net64_t UNALIGNED      *p_ca_guid;\r
1508         uint8_t                                         ari_len;\r
1509 \r
1510         AL_ENTER( AL_DBG_CM );\r
1511 \r
1512         p_conn = PARENT_STRUCT( p_list_item, al_conn_t, map_item );\r
1513         p_rej = (mad_cm_rej_t*)context;\r
1514 \r
1515         /* Either one of the communication IDs must be set. */\r
1516         CL_ASSERT( p_rej->remote_comm_id || p_rej->local_comm_id );\r
1517 \r
1518         /* REJ remote comm ID can be zero if rejecting due to REP timeout. */\r
1519         if( p_rej->remote_comm_id &&\r
1520                 p_conn->local_comm_id != p_rej->remote_comm_id )\r
1521         {\r
1522                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
1523                         ("Local comm ID mismatch.\n") );\r
1524                 return CL_NOT_FOUND;\r
1525         }\r
1526 \r
1527         /* Only match on remote comm ID if set. */\r
1528         if( p_conn->remote_comm_id &&\r
1529                 p_conn->remote_comm_id != p_rej->local_comm_id )\r
1530         {\r
1531                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
1532                         ("Remote comm ID mismatch.\n") );\r
1533                 return CL_NOT_FOUND;\r
1534         }\r
1535 \r
1536         /* If rejection is due to a REP timeout, compare the CA GUID. */\r
1537         p_ca_guid = (const net64_t*)p_rej->ari;\r
1538         ari_len = conn_rej_get_ari_len( p_rej );\r
1539         if( p_rej->reason == IB_REJ_TIMEOUT &&\r
1540                 ari_len == sizeof(ib_net64_t) )\r
1541         {\r
1542                 /* Only check if a connection req is started*/\r
1543                 if( ( p_conn->p_req_info->p_ca_attr ) &&\r
1544                         ( p_conn->p_req_info->p_ca_attr->ca_guid != *p_ca_guid ) )\r
1545                 {\r
1546                         AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
1547                                 ("Local CA GUID mismatch.\n") );\r
1548                         return CL_NOT_FOUND;\r
1549                 }\r
1550         }\r
1551 \r
1552         /* We reached here with a comm id match which is good enough for me */\r
1553 \r
1554         __ref_conn( p_conn );\r
1555         AL_EXIT( AL_DBG_CM );\r
1556         return CL_SUCCESS;\r
1557 }\r
1558 \r
1559 \r
1560 void\r
1561 __process_cm_rej(\r
1562         IN                              cl_async_proc_item_t            *p_item )\r
1563 {\r
1564         cm_port_agent_t *p_port_cm;\r
1565         mad_cm_rej_t    *p_rej;\r
1566         cm_async_mad_t  *p_async_mad;\r
1567         cl_map_item_t   *p_map_item;\r
1568         al_conn_t               *p_conn;\r
1569         uint64_t                key;\r
1570 \r
1571         AL_ENTER( AL_DBG_CM );\r
1572 \r
1573         p_async_mad = PARENT_STRUCT( p_item, cm_async_mad_t, item );\r
1574         p_port_cm = p_async_mad->p_port_cm;\r
1575         p_rej = (mad_cm_rej_t*)p_async_mad->p_mad->p_mad_buf;\r
1576 \r
1577         /* Check the pending list by the remote CA GUID and connection ID. */\r
1578         cl_spinlock_acquire( &gp_cm->obj.lock );\r
1579         p_map_item = (cl_map_item_t*)cl_qlist_find_from_head( &gp_cm->pending_list,\r
1580                 __rej_match, p_rej );\r
1581         if( p_map_item == (cl_map_item_t*)cl_qlist_end( &gp_cm->pending_list ) )\r
1582         {\r
1583                 /* Not in the pending list, check the connection map. */\r
1584                 key = ((uint64_t)p_rej->remote_comm_id << 32) |\r
1585                         ((uint64_t)p_rej->local_comm_id );\r
1586 \r
1587                 p_map_item = cl_qmap_get( &gp_cm->conn_map, key );\r
1588                 if( p_map_item == cl_qmap_end( &gp_cm->conn_map ) )\r
1589                 {\r
1590                         cl_spinlock_release( &gp_cm->obj.lock );\r
1591                         ib_put_mad( p_async_mad->p_mad );\r
1592                         cl_free( p_async_mad );\r
1593 \r
1594                         AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
1595                                 ("REJ received that could not be matched.\n") );\r
1596                         return;\r
1597                 }\r
1598                 p_conn = PARENT_STRUCT( p_map_item, al_conn_t, map_item );\r
1599                 __ref_conn( p_conn );\r
1600         }\r
1601         else\r
1602         {\r
1603                 p_conn = PARENT_STRUCT( p_map_item, al_conn_t, map_item );\r
1604         }\r
1605 \r
1606         cl_spinlock_release( &gp_cm->obj.lock );\r
1607         cm_res_acquire( p_conn );\r
1608 \r
1609         switch( p_conn->state )\r
1610         {\r
1611         case CM_CONN_REQ_SENT:\r
1612                 /*\r
1613                  * Ignore rejects with the status set to IB_REJ_INVALID_SID.  We will\r
1614                  * continue to retry (up to max_cm_retries) to connect to the remote\r
1615                  * side.  This is required to support peer-to-peer connections and\r
1616                  * clients that try to connect before the server comes up.\r
1617                  */\r
1618                 if( (p_rej->reason == IB_REJ_INVALID_SID) &&\r
1619                         p_conn->max_cm_retries )\r
1620                 {\r
1621                         p_conn->max_cm_retries--;\r
1622                         /* Deref the connection to match the reference taken when matching. */\r
1623                         cm_res_release( p_conn );\r
1624                         __deref_conn( p_conn );\r
1625                         ib_put_mad( p_async_mad->p_mad );\r
1626                         cl_free( p_async_mad );\r
1627                         AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
1628                                 ("Request rejected (invalid SID) - retrying.\n") );\r
1629                         return;\r
1630                 }\r
1631 \r
1632                 /* Fall through */\r
1633         case CM_CONN_REP_SENT:\r
1634                 /* Cancel any outstanding MAD. */\r
1635                 ib_cancel_mad( p_conn->h_mad_svc, p_conn->p_send_mad );\r
1636                 p_conn->p_send_mad = NULL;\r
1637 \r
1638                 /* Fall through */\r
1639 \r
1640         case CM_CONN_REQ_RCVD:\r
1641         case CM_CONN_REP_RCVD:\r
1642         case CM_CONN_REQ_MRA_RCVD:\r
1643         case CM_CONN_REQ_MRA_SENT:\r
1644         case CM_CONN_REP_MRA_RCVD:\r
1645         case CM_CONN_REP_MRA_SENT:\r
1646         case CM_CONN_ESTABLISHED:\r
1647                 /* Notify the user only for a valid CEP. */\r
1648                 /* TODO: Can this IF go away? */\r
1649                 if( p_conn->h_qp )\r
1650                         __do_rej_callback( p_conn, p_rej );\r
1651 \r
1652                 /* Abort connection establishment. No transition to timewait. */\r
1653                 __conn_abort( p_conn );\r
1654 \r
1655                 cm_res_release( p_conn );\r
1656                 break;\r
1657 \r
1658         default:\r
1659                 /* Ignore the REJ. */\r
1660                 cm_res_release( p_conn );\r
1661 \r
1662                 /* Deref the connection to match the reference taken when matching. */\r
1663                 __deref_conn( p_conn );\r
1664                 ib_put_mad( p_async_mad->p_mad );\r
1665                 cl_free( p_async_mad );\r
1666                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
1667                         ("REJ received in invalid state.\n") );\r
1668                 return;\r
1669         }\r
1670 \r
1671         /* Deref the connection to match the reference taken when matching. */\r
1672         __deref_conn( p_conn );\r
1673         ib_put_mad( p_async_mad->p_mad );\r
1674         cl_free( p_async_mad );\r
1675 \r
1676         AL_EXIT( AL_DBG_CM );\r
1677 }\r
1678 \r
1679 \r
1680 /*\r
1681  * Function invoked to send a REJ.\r
1682  */\r
1683 void\r
1684 __conn_reject(\r
1685         IN                              al_conn_t* const                        p_conn,\r
1686         IN              const   ib_rej_status_t                         reason,\r
1687         IN              const   ib_ari_t* const                         p_ari OPTIONAL,\r
1688         IN              const   uint8_t                                         ari_length,\r
1689         IN              const   ib_rej_pdata_t* const           p_rej_pdata OPTIONAL )\r
1690 {\r
1691         cm_port_agent_t         *p_port_cm;\r
1692         ib_api_status_t         status;\r
1693 \r
1694         AL_ENTER( AL_DBG_CM );\r
1695         UNUSED_PARAM( p_rej_pdata );\r
1696 \r
1697         /*\r
1698          * Format the reject information.\r
1699          */\r
1700         p_conn->mads.rej.hdr.attr_id = CM_REJ_ATTR_ID;\r
1701         p_conn->mads.rej.remote_comm_id = p_conn->remote_comm_id;\r
1702         p_conn->mads.rej.local_comm_id = p_conn->local_comm_id;\r
1703         switch( p_conn->state )\r
1704         {\r
1705         case CM_CONN_REQ_RCVD:\r
1706                 conn_rej_set_msg_rejected( 0, &p_conn->mads.rej );\r
1707                 break;\r
1708 \r
1709         case CM_CONN_REP_RCVD:\r
1710                 conn_rej_set_msg_rejected( 1, &p_conn->mads.rej );\r
1711                 break;\r
1712 \r
1713         default:\r
1714                 conn_rej_set_msg_rejected( 2, &p_conn->mads.rej );\r
1715                 break;\r
1716         }\r
1717 \r
1718         p_conn->mads.rej.reason = reason;\r
1719 \r
1720         /* Copy ARI data, if any. */\r
1721         if( reason == IB_REJ_TIMEOUT )\r
1722         {\r
1723                 /* ARI contains CA GUID. */\r
1724                 /* Copy the local CA GUID into the ARI. */\r
1725                 conn_rej_set_ari( (uint8_t*)&p_conn->p_req_info->p_ca_attr->ca_guid,\r
1726                         sizeof(ib_net64_t), &p_conn->mads.rej );\r
1727         }\r
1728         else if( p_ari )\r
1729         {\r
1730                 conn_rej_set_ari( p_ari->data, ari_length, &p_conn->mads.rej );\r
1731         }\r
1732         else\r
1733         {\r
1734                 conn_rej_set_ari( NULL, 0, &p_conn->mads.rej );\r
1735         }\r
1736 \r
1737         /* Copy private data, if any. */\r
1738         conn_rej_set_pdata( NULL, 0, &p_conn->mads.rej );\r
1739 \r
1740         conn_rej_clr_rsvd_fields( &p_conn->mads.rej );\r
1741 \r
1742         status = __get_port_attr( &p_conn->path[0].sgid, p_conn->path[0].slid,\r
1743                 &p_port_cm, NULL );\r
1744         if( status != IB_SUCCESS )\r
1745         {\r
1746                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1747                         ("__get_port_attr returned %s\n", ib_get_err_str(status)) );\r
1748                 return;\r
1749         }\r
1750 \r
1751         /* Cancel any outstanding sends. */\r
1752         if( p_conn->p_send_mad )\r
1753         {\r
1754                 ib_cancel_mad( p_conn->h_mad_svc, p_conn->p_send_mad );\r
1755                 p_conn->p_send_mad = NULL;\r
1756         }\r
1757 \r
1758         __cm_send( p_port_cm, p_conn );\r
1759         __conn_abort( p_conn );\r
1760 \r
1761         AL_EXIT( AL_DBG_CM );\r
1762 }\r
1763 \r
1764 \r
1765 /*\r
1766  * Matches a connection given a REP.\r
1767  */\r
1768 cl_status_t\r
1769 __rep_match(\r
1770         IN              const   cl_list_item_t* const           p_list_item,\r
1771         IN                              void                                            *context )\r
1772 {\r
1773         al_conn_t               *p_conn;\r
1774         mad_cm_rep_t    *p_rep;\r
1775 \r
1776         AL_ENTER( AL_DBG_CM );\r
1777 \r
1778         p_conn = PARENT_STRUCT( p_list_item, al_conn_t, map_item );\r
1779         p_rep = (mad_cm_rep_t*)context;\r
1780 \r
1781         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM,\r
1782                 ("p_conn:: local_comm_id (x%x) remote_comm_id (x%x)\n"\r
1783                 "p_rep:: local_comm_id (x%x) remote_comm_id (x%x)\n",\r
1784                 p_conn->local_comm_id,\r
1785                 p_conn->remote_comm_id,\r
1786                 p_rep->local_comm_id,\r
1787                 p_rep->remote_comm_id ) );\r
1788 \r
1789         if( p_conn->local_comm_id != p_rep->remote_comm_id )\r
1790         {\r
1791                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
1792                         ("Local comm ID mismatch.\n") );\r
1793                 return CL_NOT_FOUND;\r
1794         }\r
1795 \r
1796         __ref_conn( p_conn );\r
1797         AL_EXIT( AL_DBG_CM );\r
1798         return CL_SUCCESS;\r
1799 }\r
1800 \r
1801 \r
1802 \r
1803 void\r
1804 __format_rep_rec(\r
1805         IN              const   mad_cm_rep_t*           const   p_rep,\r
1806         IN              const   al_conn_t*                      const   p_conn,\r
1807                 OUT                     ib_cm_rep_rec_t*        const   p_rep_rec )\r
1808 {\r
1809         AL_ENTER( AL_DBG_CM );\r
1810 \r
1811         cl_memclr( p_rep_rec, sizeof(ib_cm_rep_rec_t) );\r
1812 \r
1813         /* fill the rec callback data */\r
1814         p_rep_rec->p_rep_pdata = p_rep->pdata;\r
1815         p_rep_rec->qp_type = p_conn->qp_type;\r
1816 \r
1817         p_rep_rec->h_cm_rep = (ib_cm_handle_t)p_conn;\r
1818         p_rep_rec->qp_context = p_conn->h_qp->obj.context;\r
1819         p_rep_rec->resp_res = p_rep->resp_resources;\r
1820         p_rep_rec->flow_ctrl = conn_rep_get_e2e_flow_ctl( p_rep );\r
1821         p_rep_rec->apr_status = conn_rep_get_failover( p_rep );\r
1822 \r
1823         AL_EXIT( AL_DBG_CM );\r
1824 }\r
1825 \r
1826 void\r
1827 __conn_save_wire_rep(\r
1828         IN              const   mad_cm_rep_t*           const   p_rep,\r
1829                 OUT                     al_conn_t*                      const   p_conn )\r
1830 {\r
1831         struct _qp_rtr          *p_rtr;\r
1832         struct _qp_rts          *p_rts;\r
1833 \r
1834         AL_ENTER( AL_DBG_CM );\r
1835 \r
1836         /* The send should have been cancelled during MRA processing. */\r
1837         p_conn->state = CM_CONN_REP_RCVD;\r
1838 \r
1839         /* Store pertinent information in the connection. */\r
1840         p_conn->remote_comm_id = p_rep->local_comm_id;\r
1841         p_conn->remote_ca_guid = p_rep->remote_comm_id;\r
1842 \r
1843         p_conn->remote_qpn = conn_rep_get_lcl_qpn( p_rep );\r
1844 \r
1845         /*\r
1846          * Store the target ack delay.  This is used to calculate the\r
1847          * ack timeouts when setting up address vectors for alternate paths.\r
1848          */\r
1849         p_conn->target_ack_delay = conn_rep_get_target_ack_delay( p_rep );\r
1850 \r
1851         /* Setup the QP modify structures for the RTR and RTS transitions */\r
1852         p_rtr = &p_conn->p_req_info->qp_mod_rtr.state.rtr;\r
1853         p_rts = &p_conn->p_req_info->qp_mod_rts.state.rts;\r
1854 \r
1855         /* Save RTR info */\r
1856         p_rtr->dest_qp = conn_rep_get_lcl_qpn( p_rep );\r
1857 \r
1858         p_rtr->primary_av.conn.rnr_retry_cnt = conn_rep_get_rnr_retry_cnt( p_rep );\r
1859 \r
1860         p_rtr->primary_av.conn.local_ack_timeout = cm_local_ack_timeout(\r
1861                 ib_path_rec_pkt_life( &p_conn->path[0] ), p_conn->target_ack_delay );\r
1862         if( p_conn->path[1].slid )\r
1863         {\r
1864                 p_rtr->alternate_av.conn.rnr_retry_cnt =\r
1865                         conn_rep_get_rnr_retry_cnt( p_rep );\r
1866                 p_rtr->alternate_av.conn.local_ack_timeout = cm_local_ack_timeout(\r
1867                         ib_path_rec_pkt_life( &p_conn->path[1] ),\r
1868                         p_conn->target_ack_delay );\r
1869         }\r
1870 \r
1871         /* Saved in a REQ and/or passed back to user in rep_rec callback\r
1872         p_rtr->resp_res;\r
1873         p_rtr->qkey;\r
1874         p_rtr->sq_depth;\r
1875         p_rtr->rq_depth;\r
1876         p_rtr->rq_psn;\r
1877         */\r
1878 \r
1879         /* Save RTS info */\r
1880         p_rts->rnr_retry_cnt = conn_rep_get_rnr_retry_cnt( p_rep );\r
1881 \r
1882         /* Responder resources and initiator depth are only for RC QPs. */\r
1883         if( p_conn->p_req_info->xport_type == IB_QPT_RELIABLE_CONN )\r
1884         {\r
1885                 p_rtr->resp_res = p_rep->initiator_depth;\r
1886                 p_rts->init_depth = p_rep->resp_resources;\r
1887         }\r
1888 \r
1889         /* Set the APM state. */\r
1890         if( conn_rep_get_failover( p_rep ) == IB_AP_SUCCESS )\r
1891         {\r
1892                 p_rts->opts |= IB_MOD_QP_APM_STATE;\r
1893                 p_rts->apm_state = IB_APM_REARM;\r
1894         }\r
1895 \r
1896         p_rts->sq_psn = conn_rep_get_starting_psn( p_rep );\r
1897 \r
1898         /* Saved in REQ and/or passed back in rep_rec callback\r
1899         p_rts->retry_cnt;\r
1900         p_rts->rnr_nak_timeout;\r
1901         p_rts->local_ack_timeout;\r
1902         p_rts->access_ctrl;\r
1903         p_rts->sq_depth;\r
1904         p_rts->rq_depth;\r
1905         p_rts->primary_port;\r
1906         p_rts->opts;\r
1907         p_rts->qkey = p_rep->local_qkey;\r
1908         */\r
1909 \r
1910         AL_EXIT( AL_DBG_CM );\r
1911 }\r
1912 \r
1913 void\r
1914 __process_cm_rep(\r
1915         IN                              cl_async_proc_item_t            *p_item )\r
1916 {\r
1917         mad_cm_rep_t            *p_rep;\r
1918         cm_async_mad_t          *p_async_mad;\r
1919         cl_map_item_t           *p_map_item;\r
1920         al_conn_t                       *p_conn;\r
1921         ib_cm_rep_rec_t         rep_rec;\r
1922         uint64_t                        key;\r
1923 \r
1924         AL_ENTER( AL_DBG_CM );\r
1925 \r
1926         p_async_mad = PARENT_STRUCT( p_item, cm_async_mad_t, item );\r
1927         p_rep = (mad_cm_rep_t*)p_async_mad->p_mad->p_mad_buf;\r
1928 \r
1929         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, ("REP: comm_id (x%x) received\n",\r
1930                 p_rep->local_comm_id ) );\r
1931 \r
1932         /* Check the pending list by the local connection ID. */\r
1933         cl_spinlock_acquire( &gp_cm->obj.lock );\r
1934         p_map_item = (cl_map_item_t*)cl_qlist_find_from_head( &gp_cm->pending_list,\r
1935                 __rep_match, p_rep );\r
1936         if( p_map_item == (cl_map_item_t*)cl_qlist_end( &gp_cm->pending_list ) )\r
1937         {\r
1938                 /* Not in the pending list, check the connection map. */\r
1939                 key = ((uint64_t)p_rep->remote_comm_id << 32) |\r
1940                         ((uint64_t)p_rep->local_comm_id );\r
1941 \r
1942                 p_map_item = cl_qmap_get( &gp_cm->conn_map, key );\r
1943                 if( p_map_item == cl_qmap_end( &gp_cm->conn_map ) )\r
1944                 {\r
1945                         cl_spinlock_release( &gp_cm->obj.lock );\r
1946                         ib_put_mad( p_async_mad->p_mad );\r
1947                         cl_free( p_async_mad );\r
1948 \r
1949                         AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
1950                                 ("REP received that could not be matched.\n") );\r
1951                         return;\r
1952                 }\r
1953                 p_conn = PARENT_STRUCT( p_map_item, al_conn_t, map_item );\r
1954                 __ref_conn( p_conn );\r
1955         }\r
1956         else\r
1957         {\r
1958                 p_conn = PARENT_STRUCT( p_map_item, al_conn_t, map_item );\r
1959         }\r
1960 \r
1961         cl_spinlock_release( &gp_cm->obj.lock );\r
1962         cm_res_acquire( p_conn );\r
1963 \r
1964         switch( p_conn->state )\r
1965         {\r
1966         case CM_CONN_REQ_SENT:\r
1967                 /* Cancel any outstanding send. */\r
1968                 ib_cancel_mad( p_conn->h_mad_svc, p_conn->p_send_mad );\r
1969                 p_conn->p_send_mad = NULL;\r
1970 \r
1971                 /* Fall through. */\r
1972         case CM_CONN_REQ_MRA_RCVD:\r
1973                 if( p_conn->state == CM_CONN_REQ_MRA_RCVD )\r
1974                 {\r
1975                         /* Cancel the MRA timer and release its reference. */\r
1976                         cl_timer_stop( &p_conn->timer );\r
1977                         __deref_conn( p_conn );\r
1978                 }\r
1979 \r
1980                 __conn_save_wire_rep( p_rep, p_conn );\r
1981                 __format_rep_rec( p_rep, p_conn, &rep_rec );\r
1982 \r
1983                 cm_res_release( p_conn );\r
1984                 /* Reference the connection until the user calls REJ or RTU. */\r
1985                 __ref_conn( p_conn );\r
1986 \r
1987                 /* Notify the user of the reply. */\r
1988                 p_conn->p_req_info->pfn_cm_rep_cb( &rep_rec );\r
1989 \r
1990                 ib_put_mad( p_async_mad->p_mad );\r
1991                 break;\r
1992 \r
1993         case CM_CONN_ESTABLISHED:\r
1994                 cm_res_release( p_conn );\r
1995                 /* Repeate the RTU. */\r
1996                 __repeated_mad( p_async_mad->p_port_cm, p_conn, p_async_mad->p_mad );\r
1997                 break;\r
1998 \r
1999         default:\r
2000                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM,\r
2001                         ("REP received in invalid state.\n") );\r
2002                 cm_res_release( p_conn );\r
2003                 ib_put_mad( p_async_mad->p_mad );\r
2004                 break;\r
2005         }\r
2006         /* Release the reference acquired when matching the connection. */\r
2007         __deref_conn( p_conn );\r
2008         cl_free( p_async_mad );\r
2009 \r
2010         AL_EXIT( AL_DBG_CM );\r
2011 }\r
2012 \r
2013 \r
2014 /*\r
2015  * Matches a connection given an RTU.\r
2016  */\r
2017 cl_status_t\r
2018 __rtu_match(\r
2019         IN              const   cl_list_item_t* const           p_list_item,\r
2020         IN                              void                                            *context )\r
2021 {\r
2022         al_conn_t               *p_conn;\r
2023         mad_cm_rtu_t    *p_rtu;\r
2024 \r
2025         AL_ENTER( AL_DBG_CM );\r
2026 \r
2027         p_conn = PARENT_STRUCT( p_list_item, al_conn_t, map_item );\r
2028         p_rtu = (mad_cm_rtu_t*)context;\r
2029 \r
2030         if( p_conn->local_comm_id != p_rtu->remote_comm_id )\r
2031         {\r
2032                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
2033                         ("Local comm ID mismatch.\n") );\r
2034                 return CL_NOT_FOUND;\r
2035         }\r
2036 \r
2037         if( p_conn->remote_comm_id != p_rtu->local_comm_id )\r
2038         {\r
2039                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
2040                         ("Remote comm ID mismatch.\n") );\r
2041                 return CL_NOT_FOUND;\r
2042         }\r
2043 \r
2044         __ref_conn( p_conn );\r
2045         AL_EXIT( AL_DBG_CM );\r
2046         return CL_SUCCESS;\r
2047 }\r
2048 \r
2049 void\r
2050 __format_rtu_rec(\r
2051         IN      const   mad_cm_rtu_t*           const   p_rtu,\r
2052         IN      const   al_conn_t*                      const   p_conn,\r
2053                 OUT             ib_cm_rtu_rec_t*        const   p_rtu_rec )\r
2054 {\r
2055         AL_ENTER( AL_DBG_CM );\r
2056 \r
2057         cl_memclr( p_rtu_rec, sizeof(ib_cm_rtu_rec_t) );\r
2058 \r
2059         p_rtu_rec->p_rtu_pdata = p_rtu->pdata;\r
2060         p_rtu_rec->qp_type = p_conn->qp_type;\r
2061         p_rtu_rec->h_qp = p_conn->h_qp;\r
2062         p_rtu_rec->qp_context = p_conn->h_qp->obj.context;\r
2063 \r
2064         AL_EXIT( AL_DBG_CM );\r
2065 }\r
2066 \r
2067 void\r
2068 __process_cm_rtu(\r
2069         IN                              cl_async_proc_item_t            *p_item )\r
2070 {\r
2071         mad_cm_rtu_t                    *p_rtu;\r
2072         cm_async_mad_t                  *p_async_mad;\r
2073         cl_list_item_t                  *p_list_item;\r
2074         al_conn_t                               *p_conn;\r
2075         ib_pfn_cm_rtu_cb_t              pfn_rtu;\r
2076         ib_cm_rtu_rec_t                 rtu_rec;\r
2077 \r
2078         AL_ENTER( AL_DBG_CM );\r
2079 \r
2080         p_async_mad = PARENT_STRUCT( p_item, cm_async_mad_t, item );\r
2081         p_rtu = (mad_cm_rtu_t*)p_async_mad->p_mad->p_mad_buf;\r
2082 \r
2083         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM, ("RTU: comm_id (x%x) received\n",\r
2084                 p_rtu->local_comm_id ) );\r
2085 \r
2086         /* Find the connection by local connection ID. */\r
2087         cl_spinlock_acquire( &gp_cm->obj.lock );\r
2088         p_list_item = cl_qlist_find_from_head( &gp_cm->pending_list,\r
2089                 __rtu_match, p_rtu );\r
2090         cl_spinlock_release( &gp_cm->obj.lock );\r
2091         if( p_list_item == cl_qlist_end( &gp_cm->pending_list ) )\r
2092         {\r
2093                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
2094                         ("RTU received that could not be matched.\n") );\r
2095                 ib_put_mad( p_async_mad->p_mad );\r
2096                 cl_free( p_async_mad );\r
2097                 return;\r
2098         }\r
2099 \r
2100         p_conn = PARENT_STRUCT( p_list_item, al_conn_t, map_item );\r
2101         cm_res_acquire( p_conn );\r
2102 \r
2103         switch( p_conn->state )\r
2104         {\r
2105         case CM_CONN_REP_SENT:\r
2106                 /* Cancel any outstanding send. */\r
2107                 ib_cancel_mad( p_conn->h_mad_svc, p_conn->p_send_mad );\r
2108                 p_conn->p_send_mad = NULL;\r
2109 \r
2110                 /* Fall through. */\r
2111         case CM_CONN_REP_MRA_RCVD:\r
2112                 if( p_conn->state == CM_CONN_REP_MRA_RCVD )\r
2113                 {\r
2114                         /* Cancel the MRA timer and release its reference. */\r
2115                         cl_timer_stop( &p_conn->timer );\r
2116                         __deref_conn( p_conn );\r
2117                 }\r
2118 \r
2119                 /* The send should have been cancelled during MRA processing. */\r
2120                 p_conn->state = CM_CONN_ESTABLISHED;\r
2121 \r
2122                 /* Store the callback pointers. */\r
2123                 pfn_rtu = p_conn->p_req_info->pfn_cm_rtu_cb;\r
2124 \r
2125                 /* Move the connection from the pending list to the connection map. */\r
2126                 __migrate_conn_to_map( p_conn );\r
2127 \r
2128                 /* Release the request info. */\r
2129                 cm_res_release( p_conn );\r
2130 \r
2131                 /* callback user */\r
2132                 __format_rtu_rec( p_rtu, p_conn, &rtu_rec );\r
2133                 pfn_rtu( &rtu_rec );\r
2134 \r
2135                 break;\r
2136 \r
2137         default:\r
2138                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM,\r
2139                         ("RTU received in invalid state.\n") );\r
2140                 cm_res_release( p_conn );\r
2141                 break;\r
2142         }\r
2143 \r
2144         /* Release the reference acquired when matching the connection. */\r
2145         __deref_conn( p_conn );\r
2146         ib_put_mad( p_async_mad->p_mad );\r
2147         cl_free( p_async_mad );\r
2148 \r
2149         AL_EXIT( AL_DBG_CM );\r
2150 }\r
2151 \r
2152 \r
2153 /*\r
2154  * Matches a connection given a DREQ.\r
2155  */\r
2156 cl_status_t\r
2157 __dreq_match(\r
2158         IN              const   cl_list_item_t* const           p_list_item,\r
2159         IN                              void                                            *context )\r
2160 {\r
2161         al_conn_t               *p_conn;\r
2162         mad_cm_dreq_t   *p_dreq;\r
2163 \r
2164         AL_ENTER( AL_DBG_CM );\r
2165 \r
2166         p_conn = PARENT_STRUCT( p_list_item, al_conn_t, map_item );\r
2167         p_dreq = (mad_cm_dreq_t*)context;\r
2168 \r
2169         if( p_conn->local_comm_id != p_dreq->remote_comm_id )\r
2170         {\r
2171                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
2172                         ("Local comm ID mismatch.\n") );\r
2173                 return CL_NOT_FOUND;\r
2174         }\r
2175 \r
2176         if( p_conn->remote_comm_id != p_dreq->local_comm_id )\r
2177         {\r
2178                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
2179                         ("Remote comm ID mismatch.\n") );\r
2180                 return CL_NOT_FOUND;\r
2181         }\r
2182 \r
2183         if( p_conn->local_qpn != conn_dreq_get_remote_qpn( p_dreq ) )\r
2184         {\r
2185                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
2186                         ("local QPN mismatch.\n") );\r
2187                 return CL_NOT_FOUND;\r
2188         }\r
2189 \r
2190         AL_EXIT( AL_DBG_CM );\r
2191         return CL_SUCCESS;\r
2192 }\r
2193 \r
2194 void\r
2195 __format_dreq_rec(\r
2196         IN      const   mad_cm_dreq_t*          const   p_dreq,\r
2197         IN      const   al_conn_t*                      const   p_conn,\r
2198                 OUT             ib_cm_dreq_rec_t*       const   p_dreq_rec )\r
2199 {\r
2200         AL_ENTER( AL_DBG_CM );\r
2201 \r
2202         cl_memclr( p_dreq_rec, sizeof(ib_cm_dreq_rec_t) );\r
2203 \r
2204         p_dreq_rec->h_cm_dreq = (ib_cm_handle_t)p_conn;\r
2205         p_dreq_rec->p_dreq_pdata = p_dreq->pdata;\r
2206 \r
2207         p_dreq_rec->qp_type = p_conn->qp_type;\r
2208         p_dreq_rec->qp_context = p_conn->h_qp->obj.context;\r
2209 \r
2210         AL_EXIT( AL_DBG_CM );\r
2211 }\r
2212 \r
2213 \r
2214 \r
2215 void\r
2216 __process_cm_dreq(\r
2217         IN                              cl_async_proc_item_t            *p_item )\r
2218 {\r
2219         mad_cm_dreq_t           *p_dreq;\r
2220         cm_async_mad_t          *p_async_mad;\r
2221         cl_map_item_t           *p_map_item;\r
2222         al_conn_t                       *p_conn;\r
2223         uint64_t                        key;\r
2224         ib_cm_dreq_rec_t        dreq_rec;\r
2225 \r
2226         AL_ENTER( AL_DBG_CM );\r
2227 \r
2228         p_async_mad = PARENT_STRUCT( p_item, cm_async_mad_t, item );\r
2229         p_dreq = (mad_cm_dreq_t*)p_async_mad->p_mad->p_mad_buf;\r
2230 \r
2231         /* Find the connection by connection IDs. */\r
2232         key = ( (uint64_t)p_dreq->remote_comm_id ) << 32 |\r
2233                 ( (uint64_t)p_dreq->local_comm_id );\r
2234         cl_spinlock_acquire( &gp_cm->obj.lock );\r
2235         p_map_item = cl_qmap_get( &gp_cm->conn_map, key );\r
2236         if( p_map_item == cl_qmap_end( &gp_cm->conn_map ) )\r
2237         {\r
2238                 /* Look in the timewait list in order to repeat the final DREP. */\r
2239                 p_map_item = (cl_map_item_t*)cl_qlist_find_from_head(\r
2240                         &gp_cm->time_wait_list, __dreq_match, p_dreq );\r
2241                 if( p_map_item ==\r
2242                         (cl_map_item_t*)cl_qlist_end( &gp_cm->time_wait_list ) )\r
2243                 {\r
2244                         cl_spinlock_release( &gp_cm->obj.lock );\r
2245                         AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
2246                                 ("DREQ received that could not be matched.\n") );\r
2247                         ib_put_mad( p_async_mad->p_mad );\r
2248                         cl_free( p_async_mad );\r
2249                         return;\r
2250                 }\r
2251         }\r
2252 \r
2253         p_conn = PARENT_STRUCT( p_map_item, al_conn_t, map_item );\r
2254 \r
2255         /*\r
2256          * Reference the connection to sync with a destroy QP and prevent the\r
2257          * connection object from being destroyed while in a callback.\r
2258          */\r
2259         __ref_conn( p_conn );\r
2260 \r
2261         cl_spinlock_release( &gp_cm->obj.lock );\r
2262 \r
2263         cm_res_acquire( p_conn );\r
2264         /* Do the additional check as per spec. */\r
2265         if( p_conn->local_qpn != conn_dreq_get_remote_qpn( p_dreq ) )\r
2266         {\r
2267                 cm_res_release( p_conn );\r
2268 \r
2269                 __deref_conn( p_conn );\r
2270                 ib_put_mad( p_async_mad->p_mad );\r
2271                 cl_free( p_async_mad );\r
2272                 AL_EXIT( AL_DBG_CM );\r
2273                 return;\r
2274         }\r
2275 \r
2276         switch( p_conn->state )\r
2277         {\r
2278         case CM_CONN_REP_SENT:\r
2279         case CM_CONN_DREQ_SENT:\r
2280                 /* Cancel the outstanding MAD. */\r
2281                 ib_cancel_mad( p_conn->h_mad_svc, p_conn->p_send_mad );\r
2282                 p_conn->p_send_mad = NULL;\r
2283 \r
2284                 /* Fall through and process as DREQ received case. */\r
2285         case CM_CONN_ESTABLISHED:\r
2286                 /*\r
2287                  * The user must call ib_cm_drep.  Continue to hold the initial\r
2288                  * reference on p_conn until the user makes the call (or we give\r
2289                  * up waiting on them).\r
2290                  */\r
2291                 p_conn->state = CM_CONN_DREQ_RCVD;\r
2292 \r
2293                 __format_dreq_rec( p_dreq, p_conn, &dreq_rec );\r
2294 \r
2295                 cm_res_release( p_conn );\r
2296                 p_conn->pfn_cm_dreq_cb( &dreq_rec );\r
2297                 ib_put_mad( p_async_mad->p_mad );\r
2298                 break;\r
2299 \r
2300         case CM_CONN_DREP_SENT:\r
2301         case CM_CONN_TIMEWAIT:\r
2302                 cm_res_release( p_conn );\r
2303                 /* Repeat the DREP. */\r
2304                 __repeated_mad( p_async_mad->p_port_cm, p_conn, p_async_mad->p_mad );\r
2305                 break;\r
2306 \r
2307         default:\r
2308                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM,\r
2309                         ("DREQ received in invalid state.\n") );\r
2310                 cm_res_release( p_conn );\r
2311                 ib_put_mad( p_async_mad->p_mad );\r
2312                 break;\r
2313         }\r
2314 \r
2315         /* Release the reference taken above. */\r
2316         __deref_conn( p_conn );\r
2317         cl_free( p_async_mad );\r
2318 }\r
2319 \r
2320 \r
2321 \r
2322 void\r
2323 __format_drep_rec(\r
2324         IN              const   mad_cm_drep_t*          const   p_drep,\r
2325         IN              const   al_conn_t*                      const   p_conn,\r
2326                 OUT                     ib_cm_drep_rec_t*       const   p_drep_rec )\r
2327 {\r
2328         AL_ENTER( AL_DBG_CM );\r
2329 \r
2330         cl_memclr( p_drep_rec, sizeof(ib_cm_drep_rec_t) );\r
2331 \r
2332         /* Copy qp context before the connection is released */\r
2333         p_drep_rec->cm_status = IB_SUCCESS;\r
2334         p_drep_rec->p_drep_pdata = p_drep->pdata;\r
2335         p_drep_rec->qp_type = p_conn->qp_type;\r
2336         p_drep_rec->h_qp = p_conn->h_qp;\r
2337         p_drep_rec->qp_context = p_conn->h_qp->obj.context;\r
2338 \r
2339         AL_EXIT( AL_DBG_CM );\r
2340 }\r
2341 \r
2342 \r
2343 void\r
2344 __process_cm_drep(\r
2345         IN                              cl_async_proc_item_t            *p_item )\r
2346 {\r
2347         mad_cm_drep_t           *p_drep;\r
2348         cm_async_mad_t          *p_async_mad;\r
2349         cl_map_item_t           *p_map_item;\r
2350         uint64_t                        key;\r
2351         al_conn_t                       *p_conn;\r
2352         ib_cm_drep_rec_t        drep_rec;\r
2353 \r
2354         AL_ENTER( AL_DBG_CM );\r
2355 \r
2356         p_async_mad = PARENT_STRUCT( p_item, cm_async_mad_t, item );\r
2357         p_drep = (mad_cm_drep_t*)p_async_mad->p_mad->p_mad_buf;\r
2358 \r
2359         /* Find the connection by local connection ID. */\r
2360         cl_spinlock_acquire( &gp_cm->obj.lock );\r
2361         key = ( (uint64_t)p_drep->remote_comm_id << 32) |\r
2362                 ( (uint64_t)p_drep->local_comm_id );\r
2363         p_map_item = cl_qmap_get( &gp_cm->conn_map, key );\r
2364         if( p_map_item == cl_qmap_end( &gp_cm->conn_map ) )\r
2365         {\r
2366                 cl_spinlock_release( &gp_cm->obj.lock );\r
2367                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
2368                         ("DREP received that could not be matched.\n") );\r
2369                 ib_put_mad( p_async_mad->p_mad );\r
2370                 cl_free( p_async_mad );\r
2371                 return;\r
2372         }\r
2373 \r
2374         /*\r
2375          * Reference the connection to sync with a destroy QP and prevent the\r
2376          * connection object from being destroyed while in a callback.\r
2377          */\r
2378         p_conn = PARENT_STRUCT( p_map_item, al_conn_t, map_item );\r
2379 \r
2380         __ref_conn( p_conn );\r
2381         cl_spinlock_release( &gp_cm->obj.lock );\r
2382 \r
2383         cm_res_acquire( p_conn );\r
2384 \r
2385         switch( p_conn->state )\r
2386         {\r
2387         case CM_CONN_DREQ_SENT:\r
2388                 /* Cancel the DREQ. */\r
2389                 ib_cancel_mad( p_conn->h_mad_svc, p_conn->p_send_mad );\r
2390                 p_conn->p_send_mad = NULL;\r
2391 \r
2392                 __format_drep_rec( p_drep, p_conn, &drep_rec );\r
2393 \r
2394                 /*\r
2395                  * Release the connection. This puts the QP and connection object\r
2396                  * into the timewait state.\r
2397                  */\r
2398                 __conn_release( p_conn );\r
2399                 cm_res_release( p_conn );\r
2400 \r
2401                 p_conn->pfn_cm_drep_cb( &drep_rec );\r
2402                 break;\r
2403 \r
2404         default:\r
2405                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM,\r
2406                         ("DREP received in invalid state.\n") );\r
2407                 cm_res_release( p_conn );\r
2408         }\r
2409 \r
2410         /* Release the reference taken above. */\r
2411         __deref_conn( p_conn );\r
2412 \r
2413         ib_put_mad( p_async_mad->p_mad );\r
2414         cl_free( p_async_mad );\r
2415         AL_EXIT( AL_DBG_CM );\r
2416 }\r
2417 \r
2418 \r
2419 void\r
2420 __format_lap_path_rec(\r
2421         IN                              al_conn_t* const                        p_conn,\r
2422         IN              const   mad_cm_lap_t* const                     p_lap,\r
2423                 OUT                     ib_path_rec_t* const            p_path_rec )\r
2424 {\r
2425         const lap_path_info_t* const    p_path = &p_lap->alternate_path;\r
2426 \r
2427         AL_ENTER( AL_DBG_CM );\r
2428 \r
2429         CL_ASSERT( p_lap );\r
2430         CL_ASSERT( p_path_rec );\r
2431 \r
2432         /*\r
2433          * Format a local path record. The local ack timeout specified in the\r
2434          * REQ is twice the packet life plus the sender's CA ACK delay.  When\r
2435          * reporting the packet life, we divide the local ack timeout by 2 to\r
2436          * approach the path's packet lifetime.  Since local ack timeout is\r
2437          * expressed as 4.096 * 2^x, subtracting 1 is equivalent to dividing the\r
2438          * time in half.\r
2439          */\r
2440         ib_path_rec_init_local( p_path_rec,\r
2441                 &p_lap->alternate_path.local_gid,\r
2442                 &p_lap->alternate_path.remote_gid,\r
2443                 p_lap->alternate_path.local_lid,\r
2444                 p_lap->alternate_path.remote_lid,\r
2445                 1, p_conn->path[p_conn->idx_primary].pkey,\r
2446                 conn_lap_path_get_svc_lvl( p_path ),\r
2447                 IB_PATH_SELECTOR_EXACTLY,\r
2448                 ib_path_rec_mtu( &p_conn->path[p_conn->idx_primary] ),\r
2449                 IB_PATH_SELECTOR_EXACTLY,\r
2450                 conn_lap_path_get_pkt_rate( p_path ),\r
2451                 IB_PATH_SELECTOR_EXACTLY,\r
2452                 (uint8_t)( conn_lap_path_get_lcl_ack_timeout( p_path ) - 1 ),\r
2453                 0 );\r
2454 \r
2455         p_path_rec->hop_flow_raw.val = 0;\r
2456         /* Add global routing info as necessary. */\r
2457         if( !conn_lap_path_get_subn_lcl( p_path ) )\r
2458         {\r
2459                 ib_path_rec_set_hop_flow_raw( p_path_rec,\r
2460                         p_lap->alternate_path.hop_limit,\r
2461                         conn_lap_path_get_flow_lbl( p_path ),\r
2462                         FALSE );\r
2463                 p_path_rec->tclass = conn_lap_path_get_tclass( p_path );\r
2464         }\r
2465 \r
2466         AL_EXIT( AL_DBG_CM );\r
2467 }\r
2468 \r
2469 \r
2470 void\r
2471 __process_cm_lap(\r
2472         IN                              cl_async_proc_item_t            *p_item )\r
2473 {\r
2474         cm_port_agent_t *p_port_cm;\r
2475         mad_cm_lap_t    *p_lap;\r
2476         cm_async_mad_t  *p_async_mad;\r
2477         cl_map_item_t   *p_map_item;\r
2478         uint64_t                key;\r
2479         al_conn_t               *p_conn;\r
2480         ib_cm_lap_rec_t lap_rec;\r
2481 \r
2482         AL_ENTER( AL_DBG_CM );\r
2483 \r
2484         p_async_mad = PARENT_STRUCT( p_item, cm_async_mad_t, item );\r
2485         p_port_cm = p_async_mad->p_port_cm;\r
2486         p_lap = (mad_cm_lap_t*)p_async_mad->p_mad->p_mad_buf;\r
2487 \r
2488         key = ((uint64_t)p_lap->remote_comm_id << 32) |\r
2489                 ((uint64_t)p_lap->local_comm_id );\r
2490         /* Find the connection by local connection ID. */\r
2491         cl_spinlock_acquire( &gp_cm->obj.lock );\r
2492         p_map_item = cl_qmap_get( &gp_cm->conn_map, key );\r
2493         if( p_map_item == cl_qmap_end( &gp_cm->conn_map ) )\r
2494         {\r
2495                 cl_spinlock_release( &gp_cm->obj.lock );\r
2496                 ib_put_mad( p_async_mad->p_mad );\r
2497                 cl_free( p_async_mad );\r
2498 \r
2499                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
2500                         ("LAP received that could not be matched.\n") );\r
2501                 return;\r
2502         }\r
2503 \r
2504         p_conn = PARENT_STRUCT( p_map_item, al_conn_t, map_item );\r
2505         cl_spinlock_release( &gp_cm->obj.lock );\r
2506         cm_res_acquire( p_conn );\r
2507 \r
2508         switch( p_conn->state )\r
2509         {\r
2510         case CM_CONN_ESTABLISHED:\r
2511                 p_conn->state = CM_CONN_LAP_RCVD;\r
2512                 cl_memclr( &lap_rec, sizeof( ib_cm_lap_rec_t ) );\r
2513                 lap_rec.qp_context = p_conn->h_qp->obj.context;\r
2514                 lap_rec.h_cm_lap = p_conn;\r
2515                 /* Format the path record. */\r
2516                 __format_lap_path_rec( p_conn, p_lap, &lap_rec.alt_path );\r
2517 \r
2518                 lap_rec.p_lap_pdata = p_lap->pdata;\r
2519 \r
2520                 /*\r
2521                  * Copy the path record into the connection for use when\r
2522                  * sending the APR and loading the path.\r
2523                  */\r
2524                 cl_memcpy( &p_conn->new_alt_path, &lap_rec.alt_path,\r
2525                         sizeof(ib_path_rec_t) );\r
2526 \r
2527                 /* Hold on to the connection reference until the user responds. */\r
2528                 __ref_conn( p_conn );\r
2529                 cm_res_release( p_conn );\r
2530                 p_conn->pfn_cm_lap_cb( &lap_rec );\r
2531                 break;\r
2532 \r
2533         default:\r
2534                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM,\r
2535                         ("LAP received in invalid state.\n") );\r
2536                 cm_res_release( p_conn );\r
2537                 break;\r
2538         }\r
2539 \r
2540         ib_put_mad( p_async_mad->p_mad );\r
2541         cl_free( p_async_mad );\r
2542         AL_EXIT( AL_DBG_CM );\r
2543 }\r
2544 \r
2545 \r
2546 ib_api_status_t\r
2547 __cm_lap_qp(\r
2548         IN                              al_conn_t* const                        p_conn )\r
2549 {\r
2550         ib_api_status_t         status;\r
2551         cm_port_agent_t         *p_port_cm;\r
2552         ib_ca_attr_t            *p_ca_attr;\r
2553         ib_qp_mod_t                     qp_mod;\r
2554 \r
2555         AL_ENTER( AL_DBG_CM );\r
2556 \r
2557         status = __get_port_attr( &p_conn->new_alt_path.sgid,\r
2558                 p_conn->new_alt_path.slid, &p_port_cm, &p_ca_attr );\r
2559         if( status != IB_SUCCESS )\r
2560         {\r
2561                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
2562                         ("__get_port_attr returned %s.\n", ib_get_err_str(status)) );\r
2563                 return status;\r
2564         }\r
2565 \r
2566         /* Setup the alt address vector */\r
2567         cl_memclr( &qp_mod, sizeof( ib_qp_mod_t ) );\r
2568         qp_mod.state.rts.opts = IB_MOD_QP_ALTERNATE_AV | IB_MOD_QP_APM_STATE;\r
2569         cm_save_path_av( &p_ca_attr->p_port_attr[p_port_cm->port_idx],\r
2570                 &p_conn->new_alt_path, p_conn->p_req_info->qp_mod_rts.state.rts.retry_cnt,\r
2571                 p_conn->p_req_info->qp_mod_rts.state.rts.rnr_retry_cnt,\r
2572                 &qp_mod.state.rts.alternate_av );\r
2573 \r
2574         qp_mod.state.rts.apm_state = IB_APM_REARM;\r
2575         qp_mod.req_state = IB_QPS_RTS;\r
2576         status = ib_modify_qp( p_conn->h_qp, &qp_mod );\r
2577         if( status != IB_SUCCESS )\r
2578         {\r
2579                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
2580                         ("ib_modify_qp for LAP returned %s.\n", ib_get_err_str(status)) );\r
2581                 return status;\r
2582         }\r
2583 \r
2584         cl_memcpy( &p_conn->path[(p_conn->idx_primary + 1) & 0x1],\r
2585                 &p_conn->new_alt_path, sizeof(ib_path_rec_t) );\r
2586         AL_EXIT( AL_DBG_CM );\r
2587         return IB_SUCCESS;\r
2588 }\r
2589 \r
2590 \r
2591 void\r
2592 __process_cm_apr(\r
2593         IN                              cl_async_proc_item_t            *p_item )\r
2594 {\r
2595         cm_port_agent_t *p_port_cm;\r
2596         mad_cm_apr_t    *p_apr;\r
2597         cm_async_mad_t  *p_async_mad;\r
2598         cl_map_item_t   *p_map_item;\r
2599         al_conn_t               *p_conn;\r
2600         uint64_t                key;\r
2601         ib_cm_apr_rec_t apr_rec;\r
2602 \r
2603         AL_ENTER( AL_DBG_CM );\r
2604 \r
2605         p_async_mad = PARENT_STRUCT( p_item, cm_async_mad_t, item );\r
2606         p_port_cm = p_async_mad->p_port_cm;\r
2607         p_apr = (mad_cm_apr_t*)p_async_mad->p_mad->p_mad_buf;\r
2608 \r
2609         key = ((uint64_t)p_apr->remote_comm_id << 32) |\r
2610                 ((uint64_t)p_apr->local_comm_id );\r
2611         /* Find the connection by local connection ID. */\r
2612         cl_spinlock_acquire( &gp_cm->obj.lock );\r
2613         p_map_item = cl_qmap_get( &gp_cm->conn_map, key );\r
2614         if( p_map_item == cl_qmap_end( &gp_cm->conn_map ) )\r
2615         {\r
2616                 cl_spinlock_release( &gp_cm->obj.lock );\r
2617                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_CM,\r
2618                         ("APR received that could not be matched.\n") );\r
2619                 ib_put_mad( p_async_mad->p_mad );\r
2620                 cl_free( p_async_mad );\r
2621                 return;\r
2622         }\r
2623 \r
2624         p_conn = PARENT_STRUCT( p_map_item, al_conn_t, map_item );\r
2625 \r
2626         __ref_conn( p_conn );\r
2627         cl_spinlock_release( &gp_cm->obj.lock );\r
2628 \r
2629         cm_res_acquire( p_conn );\r
2630 \r
2631         switch( p_conn->state )\r
2632         {\r
2633         case CM_CONN_LAP_SENT:\r
2634                 /* Cancel sending the LAP. */\r
2635                 ib_cancel_mad( p_conn->h_mad_svc, p_conn->p_send_mad );\r
2636                 p_conn->p_send_mad = NULL;\r
2637 \r
2638                 /* Fall through to handle the callback. */\r
2639         case CM_CONN_LAP_MRA_RCVD:\r
2640                 cl_memclr( &apr_rec, sizeof( ib_cm_apr_rec_t ) );\r
2641                 apr_rec.h_qp = p_conn->h_qp;\r
2642                 apr_rec.qp_context = p_conn->h_qp->obj.context;\r
2643                 apr_rec.p_info = (const uint8_t*)&p_apr->info;\r
2644                 apr_rec.info_length = p_apr->info_len;\r
2645                 apr_rec.p_apr_pdata = p_apr->pdata;\r
2646                 apr_rec.apr_status = p_apr->status;\r
2647 \r
2648                 if( apr_rec.apr_status == IB_AP_SUCCESS )\r
2649                 {\r
2650                         apr_rec.cm_status = __cm_lap_qp( p_conn );\r
2651                 }\r
2652                 else\r
2653                 {\r
2654                         apr_rec.cm_status = IB_ERROR;\r
2655                 }\r
2656                 cm_res_release( p_conn );\r
2657                 p_conn->pfn_cm_apr_cb( &apr_rec );\r
2658                 break;\r
2659 \r
2660         default:\r
2661                 cm_res_release( p_conn );\r
2662                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_CM,\r
2663                         ("APR received in invalid state.\n") );\r
2664                 break;\r
2665         }\r
2666         __deref_conn( p_conn );\r
2667         ib_put_mad( p_async_mad->p_mad );\r
2668         cl_free( p_async_mad );\r
2669 }\r
2670 \r
2671 \r
2672 /*\r
2673  * Callback to process a disconnection timeout due to not receiving the DREP\r
2674  * within allowable time.\r
2675  */\r
2676 void\r
2677 __proc_dconn_timeout(\r
2678         IN                              cl_async_proc_item_t*           p_item )\r
2679 {\r
2680         al_conn_t                       *p_conn;\r
2681         ib_cm_drep_rec_t        drep_rec;\r
2682         ib_cm_drep_t            cm_drep;\r
2683 \r
2684         AL_ENTER( AL_DBG_CM );\r
2685 \r
2686         p_conn = PARENT_STRUCT( p_item, al_conn_t, timeout_item );\r
2687 \r
2688         cm_res_acquire( p_conn );\r
2689 \r
2690         switch( p_conn->state )\r
2691         {\r
2692         case CM_CONN_DREQ_SENT:\r
2693                 /* No response.  We're done.  Deliver a DREP callback. */\r
2694                 cl_memclr( &drep_rec, sizeof( ib_cm_drep_rec_t ) );\r
2695                 drep_rec.h_qp = p_conn->h_qp;\r
2696                 drep_rec.qp_context = p_conn->h_qp->obj.context;\r
2697                 drep_rec.cm_status = IB_TIMEOUT;\r
2698 \r
2699                 /*\r
2700                  * Format a DREP message in case a DREQ is received while\r
2701                  * the connection is in the timewait state.\r
2702                  */\r
2703                 cl_memclr( &cm_drep, sizeof( ib_cm_drep_t ) );\r
2704                 __format_mad_drep( &cm_drep, p_conn );\r
2705 \r
2706                 /*\r
2707                  * Release the connection now.  Note that we still hold a reference\r
2708                  * on p_conn from trying to send the DREQ.\r
2709                  */\r
2710                 __conn_release( p_conn );\r
2711                 cm_res_release( p_conn );\r
2712 \r
2713                 /* Call the user back. */\r
2714                 p_conn->pfn_cm_drep_cb( &drep_rec );\r
2715                 break;\r
2716 \r
2717         default:\r
2718                 /*\r
2719                  * Something changed the state.  The DREP was likely received\r
2720                  * after timing out, but before we could process the timeout.\r
2721                  */\r
2722                 cm_res_release( p_conn );\r
2723                 break;\r
2724         }\r
2725 \r
2726         /* Release the reference taken when sending. */\r
2727         __deref_conn( p_conn );\r
2728         AL_EXIT( AL_DBG_CM );\r
2729 }\r
2730 \r
2731 \r
2732 /*\r
2733  * Formats a REQ mad's path information given a path record.\r
2734  */\r
2735 ib_api_status_t\r
2736 __format_mad_req_path(\r
2737         IN              const   ib_path_rec_t* const            p_path_rec,\r
2738         IN              const   uint8_t                                         ack_delay,\r
2739                 OUT                     req_path_info_t* const          p_req_path )\r
2740 {\r
2741         AL_ENTER( AL_DBG_CM );\r
2742 \r
2743         p_req_path->local_lid = p_path_rec->slid;\r
2744         p_req_path->remote_lid = p_path_rec->dlid;\r
2745         p_req_path->local_gid = p_path_rec->sgid;\r
2746         p_req_path->remote_gid = p_path_rec->dgid;\r
2747 \r
2748         conn_req_path_set_flow_lbl( ib_path_rec_flow_lbl( p_path_rec ),\r
2749                 p_req_path );\r
2750         conn_req_path_set_pkt_rate( ib_path_rec_rate( p_path_rec ),\r
2751                 p_req_path );\r
2752 \r
2753         /* Traffic class & hop limit */\r
2754         p_req_path->traffic_class = p_path_rec->tclass;\r
2755         p_req_path->hop_limit = ib_path_rec_hop_limit( p_path_rec );\r
2756 \r
2757         /* SL & Subnet Local fields */\r
2758         conn_req_path_set_svc_lvl( ib_path_rec_sl( p_path_rec ),\r
2759                 p_req_path );\r
2760         conn_req_path_set_subn_lcl(\r
2761                 ib_gid_is_link_local( &p_path_rec->dgid ), p_req_path );\r
2762 \r
2763         conn_req_path_set_lcl_ack_timeout( cm_local_ack_timeout(\r
2764                 ib_path_rec_pkt_life( p_path_rec ), ack_delay ), p_req_path );\r
2765 \r
2766         conn_req_path_clr_rsvd_fields( p_req_path );\r
2767 \r
2768         AL_EXIT( AL_DBG_CM );\r
2769         return IB_SUCCESS;\r
2770 }\r
2771 \r
2772 \r
2773 ib_api_status_t\r
2774 __format_mad_req(\r
2775         IN              const   ib_cm_req_t* const                      p_cm_req,\r
2776         IN      OUT                     al_conn_t* const                        p_conn )\r
2777 {\r
2778         ib_api_status_t status;\r
2779 \r
2780         AL_ENTER( AL_DBG_CM );\r
2781 \r
2782         if( p_cm_req->p_alt_path )\r
2783         {\r
2784                 /* MTUs must match since they are specified only once. */\r
2785                 if( ib_path_rec_mtu( p_cm_req->p_primary_path ) !=\r
2786                         ib_path_rec_mtu( p_cm_req->p_alt_path ) )\r
2787                 {\r
2788                         AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
2789                                 ("Mismatched primary and alternate path MTUs.\n") );\r
2790                         return IB_INVALID_SETTING;\r
2791                 }\r
2792 \r
2793                 /* Format the alternate path. */\r
2794                 status = __format_mad_req_path( p_cm_req->p_alt_path,\r
2795                         p_conn->p_req_info->p_ca_attr->local_ack_delay,\r
2796                         &p_conn->mads.req.alternate_path );\r
2797 \r
2798                 if( status != IB_SUCCESS )\r
2799                 {\r
2800                         AL_EXIT( AL_DBG_ERROR );\r
2801                         return status;\r
2802                 }\r
2803         }\r
2804         else\r
2805         {\r
2806                 cl_memclr( &p_conn->mads.req.alternate_path,\r
2807                         sizeof( req_path_info_t ) );\r
2808         }\r
2809 \r
2810         /* Format the primary path. */\r
2811         status = __format_mad_req_path( p_cm_req->p_primary_path,\r
2812                 p_conn->p_req_info->p_ca_attr->local_ack_delay,\r
2813                 &p_conn->mads.req.primary_path );\r
2814 \r
2815         if( status != IB_SUCCESS )\r
2816         {\r
2817                 AL_EXIT( AL_DBG_ERROR );\r
2818                 return status;\r
2819         }\r
2820 \r
2821         /* Format the rest of the REQ. */\r
2822         p_conn->mads.req.hdr.attr_id = CM_REQ_ATTR_ID;\r
2823         p_conn->mads.req.local_comm_id = p_conn->local_comm_id;\r
2824         p_conn->mads.req.sid = p_cm_req->svc_id;\r
2825         p_conn->mads.req.local_ca_guid = p_cm_req->h_qp->obj.p_ci_ca->verbs.guid;\r
2826 \r
2827         conn_req_set_lcl_qpn( p_conn->p_req_info->local_qpn, &p_conn->mads.req );\r
2828         conn_req_set_resp_res( p_cm_req->resp_res, &p_conn->mads.req );\r
2829         conn_req_set_init_depth( p_cm_req->init_depth, &p_conn->mads.req );\r
2830         conn_req_set_remote_resp_timeout( p_cm_req->remote_resp_timeout,\r
2831                 &p_conn->mads.req );\r
2832         conn_req_set_qp_type( p_cm_req->h_qp->type, &p_conn->mads.req );\r
2833         conn_req_set_flow_ctrl( p_cm_req->flow_ctrl, &p_conn->mads.req );\r
2834         conn_req_set_starting_psn( p_conn->p_req_info->local_qpn,\r
2835                 &p_conn->mads.req );\r
2836 \r
2837         conn_req_set_lcl_resp_timeout( p_cm_req->local_resp_timeout,\r
2838                 &p_conn->mads.req );\r
2839         conn_req_set_retry_cnt( p_cm_req->retry_cnt, &p_conn->mads.req );\r
2840 \r
2841         p_conn->mads.req.pkey = p_cm_req->p_primary_path->pkey;\r
2842 \r
2843         conn_req_set_mtu( ib_path_rec_mtu( p_cm_req->p_primary_path ),\r
2844                 &p_conn->mads.req );\r
2845         conn_req_set_rnr_retry_cnt( p_cm_req->rnr_retry_cnt,\r
2846                 &p_conn->mads.req );\r
2847 \r
2848         conn_req_set_max_cm_retries( p_cm_req->max_cm_retries, &p_conn->mads.req );\r
2849         conn_req_set_pdata(p_cm_req->p_req_pdata, p_cm_req->req_length,\r
2850                 &p_conn->mads.req );\r
2851 \r
2852         conn_req_clr_rsvd_fields( &p_conn->mads.req );\r
2853 \r
2854         AL_EXIT( AL_DBG_CM );\r
2855         return IB_SUCCESS;\r
2856 }\r
2857 \r
2858 \r
2859 ib_api_status_t\r
2860 __format_mad_rep(\r
2861         IN              const   ib_cm_rep_t* const                      p_cm_rep,\r
2862         IN      OUT                     al_conn_t* const                        p_conn )\r
2863 {\r
2864         AL_ENTER( AL_DBG_CM );\r
2865 \r
2866         p_conn->mads.rep.hdr.attr_id = CM_REP_ATTR_ID;\r
2867         p_conn->mads.rep.local_comm_id = p_conn->local_comm_id;\r
2868         p_conn->mads.rep.remote_comm_id = p_conn->remote_comm_id;\r
2869         conn_rep_set_lcl_qpn( p_conn->p_req_info->local_qpn, &p_conn->mads.rep );\r
2870         conn_rep_set_starting_psn( p_conn->p_req_info->local_qpn,\r
2871                 &p_conn->mads.rep );\r
2872 \r
2873         /* Check the CA's responder resource max and trim if necessary. */\r
2874         if( (p_conn->p_req_info->p_ca_attr->max_qp_resp_res <\r
2875                 p_conn->p_req_info->qp_mod_rtr.state.rtr.resp_res) )\r
2876         {\r
2877                 /*\r
2878                  * The CA cannot handle the requested responder resources.\r
2879                  * Set the response to the CA's maximum.\r
2880                  */\r
2881                 p_conn->mads.rep.resp_resources = \r
2882                         p_conn->p_req_info->p_ca_attr->max_qp_resp_res;\r
2883         }\r
2884         else\r
2885         {\r
2886                 /* The CA supports the requested responder resources. */\r
2887                 p_conn->mads.rep.resp_resources = \r
2888                         p_conn->p_req_info->qp_mod_rtr.state.rtr.resp_res;\r
2889         }\r
2890 \r
2891         p_conn->mads.rep.initiator_depth = p_cm_rep->init_depth;\r
2892 \r
2893         conn_rep_set_target_ack_delay( p_cm_rep->target_ack_delay,\r
2894                 &p_conn->mads.rep );\r
2895         conn_rep_set_failover( p_cm_rep->failover_accepted, &p_conn->mads.rep );\r
2896         conn_rep_set_e2e_flow_ctl( p_cm_rep->flow_ctrl, &p_conn->mads.rep );\r
2897 \r
2898         conn_rep_set_rnr_retry_cnt( (uint8_t)(p_cm_rep->rnr_retry_cnt & 0x07),\r
2899                 &p_conn->mads.rep );\r
2900 \r
2901         p_conn->mads.rep.local_ca_guid = p_conn->p_req_info->p_ca_attr->ca_guid;\r
2902 \r
2903         conn_rep_set_pdata( p_cm_rep->p_rep_pdata, p_cm_rep->rep_length,\r
2904                 &p_conn->mads.rep );\r
2905 \r
2906         conn_rep_clr_rsvd_fields( &p_conn->mads.rep );\r
2907 \r
2908         AL_EXIT( AL_DBG_CM );\r
2909         return IB_SUCCESS;\r
2910 }\r
2911 \r
2912 \r
2913 void\r
2914 __format_mad_rtu(\r
2915         IN              const   ib_cm_rtu_t* const                      p_cm_rtu,\r
2916         IN      OUT                     al_conn_t* const                        p_conn )\r
2917 {\r
2918         AL_ENTER( AL_DBG_CM );\r
2919 \r
2920         p_conn->mads.rtu.hdr.attr_id = CM_RTU_ATTR_ID;\r
2921 \r
2922         p_conn->mads.rtu.local_comm_id = p_conn->local_comm_id;\r
2923         p_conn->mads.rtu.remote_comm_id = p_conn->remote_comm_id;\r
2924 \r
2925         /* copy optional data */\r
2926         conn_rtu_set_pdata( p_cm_rtu->p_rtu_pdata, p_cm_rtu->rtu_length,\r
2927                 &p_conn->mads.rtu );\r
2928 \r
2929         AL_EXIT( AL_DBG_CM );\r
2930 }\r
2931 \r
2932 \r
2933 \r
2934 ib_rej_status_t\r
2935 __conn_save_user_rep(\r
2936         IN              const   ib_cm_rep_t* const                      p_cm_rep,\r
2937         IN      OUT                     al_conn_t*       const                  p_conn,\r
2938                 OUT                     cm_port_agent_t** const         pp_port_cm )\r
2939 {\r
2940         ib_api_status_t         status;\r
2941 \r
2942         AL_ENTER( AL_DBG_CM );\r
2943 \r
2944         /* Cache the local QPN. */\r
2945         p_conn->p_req_info->local_qpn = p_conn->h_qp->num;\r
2946 \r
2947         /* Validate the primary path.  This must be done after binding. */\r
2948         status = __validate_primary_path( p_conn, pp_port_cm );\r
2949         if( status != IB_SUCCESS )\r
2950         {\r
2951                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
2952                         ("Primary path validation failed: %s.\n", ib_get_err_str(status)) );\r
2953 \r
2954                 /* Reject and abort the connection. */\r
2955                 return IB_REJ_INVALID_GID;\r
2956         }\r
2957 \r
2958         if( p_cm_rep->failover_accepted == IB_FAILOVER_ACCEPT_SUCCESS )\r
2959         {\r
2960                 status = __validate_alt_path( p_conn );\r
2961                 if( status != IB_SUCCESS )\r
2962                 {\r
2963                         AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
2964                                 ("Alternate path validation failed: %s.\n",\r
2965                                 ib_get_err_str(status)) );\r
2966 \r
2967                         return IB_REJ_INVALID_ALT_GID;\r
2968                 }\r
2969         }\r
2970 \r
2971         /* Update conn info */\r
2972         p_conn->p_req_info->pfn_cm_rtu_cb = p_cm_rep->pfn_cm_rtu_cb;\r
2973         p_conn->pfn_cm_lap_cb = p_cm_rep->pfn_cm_lap_cb;\r
2974         p_conn->pfn_cm_dreq_cb = p_cm_rep->pfn_cm_dreq_cb;\r
2975 \r
2976         if( p_cm_rep->qp_type != p_conn->p_req_info->xport_type )\r
2977         {\r
2978                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,      ("qp_type mistach!\n") );\r
2979                 return IB_REJ_INVALID_XPORT;\r
2980         }\r
2981 \r
2982         cm_save_rep_qp_attr( p_cm_rep,\r
2983                 &p_conn->p_req_info->p_ca_attr->p_port_attr[\r
2984                 p_conn->p_req_info->port_idx], &p_conn->path[0],\r
2985                 &p_conn->path[1], &p_conn->p_req_info->qp_mod_rtr,\r
2986                 &p_conn->p_req_info->qp_mod_rts );\r
2987 \r
2988         /* Update the QP destruction timeout = timeout x retries + 2 seconds. */\r
2989         set_al_obj_timeout( &p_cm_rep->h_qp->obj,\r
2990                 p_conn->retry_timeout * p_conn->max_cm_retries + 2000 );\r
2991 \r
2992         AL_EXIT( AL_DBG_CM );\r
2993         return 0;\r
2994 }\r
2995 \r
2996 \r
2997 \r
2998 ib_api_status_t\r
2999 __conn_save_user_rtu(\r
3000         IN              const   ib_cm_rtu_t* const                      p_cm_rtu,\r
3001         IN      OUT                     al_conn_t*       const                  p_conn,\r
3002                 OUT                     cm_port_agent_t** const         pp_port_cm )\r
3003 {\r
3004         ib_api_status_t         status;\r
3005 \r
3006         AL_ENTER( AL_DBG_CM );\r
3007 \r
3008         status = __get_port_attr( &p_conn->path[0].sgid, p_conn->path[0].slid,\r
3009                 pp_port_cm, NULL );\r
3010         if( status != IB_SUCCESS )\r
3011         {\r
3012                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
3013                         ("__get_port_attr returned %s.\n", ib_get_err_str(status)) );\r
3014                 /*\r
3015                  * Don't fail the connection since the remote side will repeat\r
3016                  * the REP perhaps with better luck.\r
3017                  */\r
3018                 return status;\r
3019         }\r
3020 \r
3021         p_conn->pfn_cm_apr_cb = p_cm_rtu->pfn_cm_apr_cb;\r
3022         p_conn->pfn_cm_dreq_cb = p_cm_rtu->pfn_cm_dreq_cb;\r
3023 \r
3024         cm_save_rtu_qp_attr( p_cm_rtu, &p_conn->p_req_info->qp_mod_rtr );\r
3025 \r
3026         AL_EXIT( AL_DBG_CM );\r
3027         return IB_SUCCESS;\r
3028 }\r
3029 \r
3030 \r
3031 \r
3032 /*\r
3033  * Formats a LAP mad's path information given a path record.\r
3034  */\r
3035 ib_api_status_t\r
3036 __format_mad_lap_path(\r
3037         IN              const   ib_path_rec_t* const            p_path_rec,\r
3038         IN              const   uint8_t                                         ack_delay,\r
3039                 OUT                     lap_path_info_t* const          p_lap_path )\r
3040 {\r
3041         AL_ENTER( AL_DBG_CM );\r
3042 \r
3043         p_lap_path->local_lid = p_path_rec->slid;\r
3044         p_lap_path->remote_lid = p_path_rec->dlid;\r
3045         p_lap_path->local_gid = p_path_rec->sgid;\r
3046         p_lap_path->remote_gid = p_path_rec->dgid;\r
3047 \r
3048         /* Set Flow Label and Packet Rate */\r
3049         conn_lap_path_set_flow_lbl( ib_path_rec_flow_lbl( p_path_rec ),\r
3050                 p_lap_path );\r
3051         conn_lap_path_set_tclass( p_path_rec->tclass, p_lap_path );\r
3052 \r
3053         p_lap_path->hop_limit = ib_path_rec_hop_limit( p_path_rec );\r
3054         conn_lap_path_set_pkt_rate( ib_path_rec_rate( p_path_rec ),\r
3055                 p_lap_path );\r
3056 \r
3057         /* Set SL and Subnet Local */\r
3058         conn_lap_path_set_svc_lvl( ib_path_rec_sl( p_path_rec ),\r
3059                 p_lap_path );\r
3060         conn_lap_path_set_subn_lcl(\r
3061                 ib_gid_is_link_local( &p_path_rec->dgid ), p_lap_path );\r
3062 \r
3063         conn_lap_path_set_lcl_ack_timeout(\r
3064                 cm_local_ack_timeout( ib_path_rec_pkt_life( p_path_rec ),\r
3065                 ack_delay ), p_lap_path );\r
3066 \r
3067         conn_lap_path_clr_rsvd_fields( p_lap_path );\r
3068 \r
3069         AL_EXIT( AL_DBG_CM );\r
3070         return IB_SUCCESS;\r
3071 }\r
3072 \r
3073 \r
3074 \r
3075 /*\r
3076  * Validates the primary path specified for a connection, and stores\r
3077  * the assocated CA attributes and port index.\r
3078  */\r
3079 ib_api_status_t\r
3080 __validate_lap_path(\r
3081         IN                              al_conn_t* const                        p_conn,\r
3082                 OUT                     cm_port_agent_t** const         pp_port_cm,\r
3083                 OUT                     uint8_t* const                          p_ack_delay )\r
3084 {\r
3085         ib_api_status_t         status;\r
3086         cm_port_agent_t         *p_port_cm;\r
3087         ib_ca_attr_t            *p_ca_attr, *p_alt_ca_attr;\r
3088 \r
3089         AL_ENTER( AL_DBG_CM );\r
3090 \r
3091         CL_ASSERT( p_conn );\r
3092         CL_ASSERT( pp_port_cm );\r
3093         CL_ASSERT( p_ack_delay );\r
3094 \r
3095         status = __get_port_attr( &p_conn->path[p_conn->idx_primary].sgid,\r
3096                 p_conn->path[p_conn->idx_primary].slid, &p_port_cm, &p_ca_attr );\r
3097         if( status != IB_SUCCESS )\r
3098         {\r
3099                 /* Primary path invalid.  Should have received a path migration. */\r
3100                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
3101                         ("Primary connection path invalid!\n") );\r
3102                 return IB_INVALID_SETTING;\r
3103         }\r
3104 \r
3105         status = __get_port_attr( &p_conn->new_alt_path.sgid,\r
3106                 p_conn->new_alt_path.slid, NULL, &p_alt_ca_attr );\r
3107         if( status != IB_SUCCESS )\r
3108         {\r
3109                 /* Alternate path invalid. */\r
3110                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
3111                         ("Alternate path invalid!\n") );\r
3112                 return status;\r
3113         }\r
3114 \r
3115         /*\r
3116          * The primary path and alternate path are both valid individually.\r
3117          * Check that they are valid as a pair.\r
3118          */\r
3119         if( p_ca_attr->ca_guid != p_alt_ca_attr->ca_guid )\r
3120         {\r
3121                 /* Paths are not on the same CA. */\r
3122                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
3123                         ("Primary and alternate paths must be on the same CA.\n") );\r
3124                 return IB_INVALID_SETTING;\r
3125         }\r
3126 \r
3127         *p_ack_delay = p_ca_attr->local_ack_delay;\r
3128         *pp_port_cm = p_port_cm;\r
3129         AL_EXIT( AL_DBG_CM );\r
3130         return IB_SUCCESS;\r
3131 }\r
3132 \r
3133 \r
3134 void\r
3135 __format_mad_dreq(\r
3136         IN              const   ib_cm_dreq_t* const                     p_cm_dreq,\r
3137                 OUT                     al_conn_t*              const           p_conn )\r
3138 {\r
3139         AL_ENTER( AL_DBG_CM );\r
3140 \r
3141         p_conn->mads.dreq.hdr.attr_id = CM_DREQ_ATTR_ID;\r
3142         p_conn->mads.dreq.local_comm_id = p_conn->local_comm_id;\r
3143         p_conn->mads.dreq.remote_comm_id = p_conn->remote_comm_id;\r
3144         conn_dreq_set_remote_qpn( p_conn->remote_qpn, &p_conn->mads.dreq );\r
3145         conn_dreq_set_pdata( p_cm_dreq->p_dreq_pdata, p_cm_dreq->dreq_length,\r
3146                 &p_conn->mads.dreq );\r
3147         conn_dreq_clr_rsvd_fields( &p_conn->mads.dreq );\r
3148 \r
3149         AL_EXIT( AL_DBG_CM );\r
3150 }\r
3151 \r
3152 void\r
3153 __format_mad_drep(\r
3154         IN              const   ib_cm_drep_t*   const           p_cm_drep,\r
3155                 OUT                     al_conn_t*              const           p_conn )\r
3156 {\r
3157         AL_ENTER( AL_DBG_CM );\r
3158 \r
3159         p_conn->mads.drep.hdr.attr_id = CM_DREP_ATTR_ID;\r
3160         p_conn->mads.drep.local_comm_id = p_conn->local_comm_id;\r
3161         p_conn->mads.drep.remote_comm_id = p_conn->remote_comm_id;\r
3162         conn_drep_set_pdata( p_cm_drep->p_drep_pdata, p_cm_drep->drep_length,\r
3163                 &p_conn->mads.drep );\r
3164 \r
3165         AL_EXIT( AL_DBG_CM );\r
3166 }\r
3167 \r
3168 \r
3169 ib_api_status_t\r
3170 cm_conn_mra(\r