693de6d11737befd1371c736883da29bc08422a2
[mirror/winof/.git] / core / al / al_mad.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 <complib/cl_byteswap.h>\r
35 #include <complib/cl_timer.h>\r
36 \r
37 #include "al.h"\r
38 #include "al_debug.h"\r
39 \r
40 #if defined(EVENT_TRACING)\r
41 #ifdef offsetof\r
42 #undef offsetof\r
43 #endif\r
44 #include "al_mad.tmh"\r
45 #endif\r
46 \r
47 #include "al_cq.h"\r
48 #include "al_mad.h"\r
49 #include "al_qp.h"\r
50 #include "al_res_mgr.h"\r
51 #include "al_verbs.h"\r
52 \r
53 #include "ib_common.h"\r
54 \r
55 \r
56 #define MAX_TIME                                CL_CONST64(0xFFFFFFFFFFFFFFFF)\r
57 #define MAD_VECTOR_SIZE                 8\r
58 #define MAX_METHOD                              127\r
59 #define DEFAULT_RMPP_VERSION    1\r
60 \r
61 #define AL_RMPP_WINDOW                  16                              /* Max size of RMPP window */\r
62 #define AL_REASSEMBLY_TIMEOUT   5000                    /* 5 seconds */\r
63 \r
64 static void\r
65 __cleanup_mad_disp(\r
66         IN                              al_obj_t                                        *p_obj );\r
67 \r
68 static void\r
69 __free_mad_disp(\r
70         IN                              al_obj_t                                        *p_obj );\r
71 \r
72 static cl_status_t\r
73 __init_mad_reg(\r
74         IN                              void* const                                     p_element,\r
75         IN                              void*                                           context );\r
76 \r
77 static cl_status_t\r
78 __init_version_entry(\r
79         IN                              void* const                                     p_element,\r
80         IN                              void*                                           context );\r
81 \r
82 static void\r
83 __destroy_version_entry(\r
84         IN                              void* const                                     p_element,\r
85         IN                              void*                                           context );\r
86 \r
87 static cl_status_t\r
88 __init_class_entry(\r
89         IN                              void* const                                     p_element,\r
90         IN                              void*                                           context );\r
91 \r
92 static void\r
93 __destroy_class_entry(\r
94         IN                              void* const                                     p_element,\r
95         IN                              void*                                           context );\r
96 \r
97 static __inline uint8_t\r
98 __mgmt_class_index(\r
99         IN              const   uint8_t                                         mgmt_class );\r
100 \r
101 static __inline uint8_t\r
102 __mgmt_version_index(\r
103         IN              const   uint8_t                                         mgmt_version );\r
104 \r
105 static boolean_t\r
106 __mad_disp_reg_unsol(\r
107         IN              const   al_mad_disp_handle_t            h_mad_disp,\r
108         IN              const   al_mad_reg_handle_t                     h_mad_reg,\r
109         IN              const   ib_mad_svc_t                            *p_mad_svc );\r
110 \r
111 static boolean_t\r
112 __use_tid_routing(\r
113         IN              const   ib_mad_t* const                         p_mad_hdr,\r
114         IN              const   boolean_t                                       are_we_sender );\r
115 \r
116 /*\r
117  * Issue a send request to the MAD dispatcher.\r
118  */\r
119 static void\r
120 __mad_disp_queue_send(\r
121         IN              const   al_mad_reg_handle_t                     h_mad_reg,\r
122         IN                              al_mad_wr_t* const                      p_mad_wr );\r
123 \r
124 static inline void\r
125 __mad_disp_resume_send(\r
126         IN              const   al_mad_reg_handle_t                     h_mad_reg );\r
127 \r
128 static void\r
129 __destroying_mad_svc(\r
130         IN                              struct _al_obj                          *p_obj );\r
131 \r
132 static void\r
133 __cleanup_mad_svc(\r
134         IN                              struct _al_obj                          *p_obj );\r
135 \r
136 static void\r
137 __send_timer_cb(\r
138         IN                              void                                            *context );\r
139 \r
140 static void\r
141 __check_send_queue(\r
142         IN                              ib_mad_svc_handle_t                     h_mad_svc );\r
143 \r
144 static void\r
145 __recv_timer_cb(\r
146         IN                              void                                            *context );\r
147 \r
148 static ib_api_status_t\r
149 __init_send_mad(\r
150         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
151         IN              const   ib_mad_send_handle_t            h_send,\r
152         IN                              ib_mad_element_t* const         p_mad_element );\r
153 \r
154 static boolean_t\r
155 __does_send_req_rmpp(\r
156         IN              const   ib_mad_svc_type_t                       mad_svc_type,\r
157         IN              const   ib_mad_element_t* const         p_mad_element,\r
158                 OUT                     uint8_t                                         *p_rmpp_version );\r
159 \r
160 static void\r
161 __queue_mad_wr(\r
162         IN              const   al_mad_reg_handle_t                     h_mad_reg,\r
163         IN              const   ib_mad_send_handle_t            h_send );\r
164 \r
165 static void\r
166 __queue_rmpp_seg(\r
167         IN              const   al_mad_reg_handle_t                     h_mad_reg,\r
168         IN                              ib_mad_send_handle_t            h_send );\r
169 \r
170 static ib_api_status_t\r
171 __create_send_av(\r
172         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
173         IN                              ib_mad_send_handle_t            h_send );\r
174 \r
175 static void\r
176 __cleanup_mad_send(\r
177         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
178         IN                              ib_mad_send_handle_t            h_send );\r
179 \r
180 static __inline void\r
181 __set_retry_time(\r
182         IN                              ib_mad_send_handle_t            h_send );\r
183 \r
184 static void\r
185 __mad_svc_send_done(\r
186         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
187         IN                              al_mad_wr_t                                     *p_mad_wr,\r
188         IN                              ib_wc_t                                         *p_wc );\r
189 \r
190 static boolean_t\r
191 __is_send_mad_done(\r
192         IN                              ib_mad_send_handle_t            h_send,\r
193         IN                              ib_wc_t                                         *p_wc );\r
194 \r
195 static void\r
196 __notify_send_comp(\r
197         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
198         IN                              ib_mad_send_handle_t            h_send,\r
199         IN                              ib_wc_status_t                          wc_status );\r
200 \r
201 static void\r
202 __mad_svc_recv_done(\r
203         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
204         IN                              ib_mad_element_t                        *p_mad_element );\r
205 \r
206 static void\r
207 __process_recv_resp(\r
208         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
209         IN                              ib_mad_element_t                        *p_mad_element );\r
210 \r
211 static cl_status_t\r
212 __do_rmpp_recv(\r
213         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
214         IN      OUT                     ib_mad_element_t                        **pp_mad_element );\r
215 \r
216 static __inline boolean_t\r
217 __recv_requires_rmpp(\r
218         IN              const   ib_mad_svc_type_t                       mad_svc_type,\r
219         IN              const   ib_mad_element_t* const         p_mad_element );\r
220 \r
221 static __inline boolean_t\r
222 __is_internal_send(\r
223         IN              const   ib_mad_svc_type_t                       mad_svc_type,\r
224         IN              const   ib_mad_element_t* const         p_mad_element );\r
225 \r
226 static cl_status_t\r
227 __process_rmpp_data(\r
228         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
229         IN      OUT                     ib_mad_element_t                        **pp_mad_element );\r
230 \r
231 static void\r
232 __process_rmpp_ack(\r
233         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
234         IN                              ib_mad_element_t                        *p_mad_element );\r
235 \r
236 static void\r
237 __process_rmpp_nack(\r
238         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
239         IN                              ib_mad_element_t                        *p_mad_element );\r
240 \r
241 static cl_status_t\r
242 __process_segment(\r
243         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
244         IN                              al_mad_rmpp_t                           *p_rmpp,\r
245         IN      OUT                     ib_mad_element_t                        **pp_mad_element,\r
246                 OUT                     ib_mad_element_t                        **pp_rmpp_resp_mad );\r
247 \r
248 static al_mad_rmpp_t*\r
249 __find_rmpp(\r
250         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
251         IN      OUT                     ib_mad_element_t                        *p_mad_element );\r
252 \r
253 static al_mad_rmpp_t*\r
254 __get_mad_rmpp(\r
255         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
256         IN                              ib_mad_element_t                        *p_mad_element );\r
257 \r
258 static void\r
259 __put_mad_rmpp(\r
260         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
261         IN                              al_mad_rmpp_t                           *p_rmpp );\r
262 \r
263 static void\r
264 __init_reply_element(\r
265         IN                              ib_mad_element_t                        *p_dst_element,\r
266         IN                              ib_mad_element_t                        *p_src_element );\r
267 \r
268 static ib_mad_element_t*\r
269 __get_rmpp_ack(\r
270         IN                              al_mad_rmpp_t                           *p_rmpp );\r
271 \r
272 ib_net64_t\r
273 __get_send_tid(\r
274         IN                              ib_mad_send_handle_t            h_send )\r
275 {\r
276         return ((ib_mad_t*)ib_get_mad_buf( h_send->p_send_mad ))->trans_id;\r
277 }\r
278 \r
279 \r
280 ib_mad_t*\r
281 get_mad_hdr_from_wr(\r
282         IN                              al_mad_wr_t* const                      p_mad_wr )\r
283 {\r
284         ib_mad_send_handle_t    h_send;\r
285 \r
286         CL_ASSERT( p_mad_wr );\r
287 \r
288         h_send = PARENT_STRUCT( p_mad_wr, al_mad_send_t, mad_wr );\r
289         return h_send->p_send_mad->p_mad_buf;\r
290 }\r
291 \r
292 \r
293 \r
294 /*\r
295  * Construct a MAD element from a receive work completion.\r
296  */\r
297 void\r
298 build_mad_recv(\r
299         IN                              ib_mad_element_t*                       p_mad_element,\r
300         IN                              ib_wc_t*                                        p_wc )\r
301 {\r
302         AL_ENTER( AL_DBG_SMI );\r
303 \r
304         CL_ASSERT( p_mad_element );\r
305         CL_ASSERT( p_wc );\r
306 \r
307         /* Build the MAD element from the work completion. */\r
308         p_mad_element->status           = p_wc->status;\r
309         p_mad_element->remote_qp        = p_wc->recv.ud.remote_qp;\r
310 \r
311         /*\r
312          * We assume all communicating managers using MAD services use\r
313          * the same QKEY.\r
314          */\r
315 \r
316         /*\r
317          * Mellanox workaround:\r
318          * The Q_KEY from the QP context must be used if the high bit is\r
319          * set in the Q_KEY part of the work request. See section 10.2.5\r
320          * on Q_KEYS Compliance Statement C10-15.\r
321          * This must be enabled to permit future non special QP's to have\r
322          * MAD level service capability. To use SAR in a generic way.\r
323          */\r
324 \r
325         /*\r
326          * p_mad_element->remote_qkey = IB_QP_PRIVILEGED_Q_KEY;\r
327          */\r
328 \r
329         p_mad_element->remote_qkey      = IB_QP1_WELL_KNOWN_Q_KEY;\r
330         p_mad_element->remote_lid       = p_wc->recv.ud.remote_lid;\r
331         p_mad_element->remote_sl        = p_wc->recv.ud.remote_sl;\r
332         p_mad_element->pkey_index       = p_wc->recv.ud.pkey_index;\r
333         p_mad_element->path_bits        = p_wc->recv.ud.path_bits;\r
334         p_mad_element->recv_opt         = p_wc->recv.ud.recv_opt;\r
335         p_mad_element->grh_valid        = p_wc->recv.ud.recv_opt & IB_RECV_OPT_GRH_VALID;\r
336 \r
337         if( p_wc->recv.ud.recv_opt & IB_RECV_OPT_IMMEDIATE )\r
338                 p_mad_element->immediate_data = p_wc->recv.ud.immediate_data;\r
339 \r
340         AL_EXIT( AL_DBG_SMI );\r
341 }\r
342 \r
343 \r
344 \r
345 /*\r
346  *\r
347  * MAD Dispatcher.\r
348  *\r
349  */\r
350 \r
351 \r
352 ib_api_status_t\r
353 create_mad_disp(\r
354         IN                              al_obj_t* const                         p_parent_obj,\r
355         IN              const   ib_qp_handle_t                          h_qp,\r
356         IN                              al_mad_disp_handle_t* const     ph_mad_disp )\r
357 {\r
358         al_mad_disp_handle_t    h_mad_disp;\r
359         ib_api_status_t                 status;\r
360         cl_status_t                             cl_status;\r
361 \r
362         AL_ENTER( AL_DBG_MAD_SVC );\r
363         h_mad_disp = cl_zalloc( sizeof( al_mad_disp_t ) );\r
364         if( !h_mad_disp )\r
365         {\r
366                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("insufficient memory\n") );\r
367                 return IB_INSUFFICIENT_MEMORY;\r
368         }\r
369 \r
370         /* Initialize the MAD dispatcher. */\r
371         cl_vector_construct( &h_mad_disp->client_vector );\r
372         cl_vector_construct( &h_mad_disp->version_vector );\r
373         construct_al_obj( &h_mad_disp->obj, AL_OBJ_TYPE_MAD_DISP );\r
374         status = init_al_obj( &h_mad_disp->obj, h_mad_disp, TRUE,\r
375                 NULL, __cleanup_mad_disp, __free_mad_disp );\r
376         if( status != IB_SUCCESS )\r
377         {\r
378                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("init obj: %s\n",\r
379                         ib_get_err_str(status)) );\r
380                 __free_mad_disp( &h_mad_disp->obj );\r
381                 return status;\r
382         }\r
383         status = attach_al_obj( p_parent_obj, &h_mad_disp->obj );\r
384         if( status != IB_SUCCESS )\r
385         {\r
386                 h_mad_disp->obj.pfn_destroy( &h_mad_disp->obj, NULL );\r
387                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
388                         ("attach_al_obj returned %s.\n", ib_get_err_str(status)) );\r
389                 return status;\r
390         }\r
391 \r
392         /* Obtain a reference to the QP to post sends to. */\r
393         h_mad_disp->h_qp = h_qp;\r
394         ref_al_obj( &h_qp->obj );\r
395 \r
396         /* Create the client vector. */\r
397         cl_status = cl_vector_init( &h_mad_disp->client_vector, 1, MAD_VECTOR_SIZE,\r
398                 sizeof( al_mad_disp_reg_t ), __init_mad_reg, NULL, h_mad_disp );\r
399         if( cl_status != CL_SUCCESS )\r
400         {\r
401                 h_mad_disp->obj.pfn_destroy( &h_mad_disp->obj, NULL );\r
402                 return ib_convert_cl_status( cl_status );\r
403         }\r
404 \r
405         /* Create the version vector. */\r
406         cl_status = cl_vector_init( &h_mad_disp->version_vector,\r
407                 1, 1, sizeof( cl_vector_t ), __init_version_entry,\r
408                 __destroy_version_entry, &h_mad_disp->version_vector );\r
409         if( cl_status != CL_SUCCESS )\r
410         {\r
411                 h_mad_disp->obj.pfn_destroy( &h_mad_disp->obj, NULL );\r
412                 return ib_convert_cl_status( cl_status );\r
413         }\r
414 \r
415         *ph_mad_disp = h_mad_disp;\r
416 \r
417         /* Release the reference taken in init_al_obj. */\r
418         deref_al_obj( &h_mad_disp->obj );\r
419 \r
420         AL_EXIT( AL_DBG_MAD_SVC );\r
421         return IB_SUCCESS;\r
422 }\r
423 \r
424 \r
425 \r
426 static void\r
427 __cleanup_mad_disp(\r
428         IN                              al_obj_t                                        *p_obj )\r
429 {\r
430         al_mad_disp_handle_t    h_mad_disp;\r
431 \r
432         AL_ENTER( AL_DBG_MAD_SVC );\r
433         CL_ASSERT( p_obj );\r
434         h_mad_disp = PARENT_STRUCT( p_obj, al_mad_disp_t, obj );\r
435 \r
436         /* Detach from the QP that we were using. */\r
437         if( h_mad_disp->h_qp )\r
438                 deref_al_obj( &h_mad_disp->h_qp->obj );\r
439 \r
440         AL_EXIT( AL_DBG_MAD_SVC );\r
441 }\r
442 \r
443 \r
444 \r
445 static void\r
446 __free_mad_disp(\r
447         IN                              al_obj_t                                        *p_obj )\r
448 {\r
449         al_mad_disp_handle_t    h_mad_disp;\r
450 \r
451         AL_ENTER( AL_DBG_MAD_SVC );\r
452         CL_ASSERT( p_obj );\r
453         h_mad_disp = PARENT_STRUCT( p_obj, al_mad_disp_t, obj );\r
454 \r
455         cl_vector_destroy( &h_mad_disp->client_vector );\r
456         cl_vector_destroy( &h_mad_disp->version_vector );\r
457         destroy_al_obj( p_obj );\r
458         cl_free( h_mad_disp );\r
459         AL_EXIT( AL_DBG_MAD_SVC );\r
460 }\r
461 \r
462 \r
463 \r
464 static al_mad_reg_handle_t\r
465 __mad_disp_reg(\r
466         IN              const   al_mad_disp_handle_t            h_mad_disp,\r
467         IN              const   ib_mad_svc_handle_t                     h_mad_svc,\r
468         IN              const   ib_mad_svc_t                            *p_mad_svc,\r
469         IN              const   pfn_mad_svc_send_done_t         pfn_send_done,\r
470         IN              const   pfn_mad_svc_recv_done_t         pfn_recv_done )\r
471 {\r
472         al_mad_reg_handle_t             h_mad_reg;\r
473         size_t                                  i;\r
474         cl_status_t                             cl_status;\r
475 \r
476         AL_ENTER( AL_DBG_MAD_SVC );\r
477         cl_spinlock_acquire( &h_mad_disp->obj.lock );\r
478 \r
479         /* Find an empty slot in the client vector for the registration. */\r
480         for( i = 0; i < cl_vector_get_size( &h_mad_disp->client_vector ); i++ )\r
481         {\r
482                 h_mad_reg = cl_vector_get_ptr( &h_mad_disp->client_vector, i );\r
483                 if( !h_mad_reg->ref_cnt )\r
484                         break;\r
485         }\r
486         /* Trap for ClientID overflow. */\r
487         if( i >= 0xFFFFFFFF )\r
488         {\r
489                 cl_spinlock_release( &h_mad_disp->obj.lock );\r
490                 return NULL;\r
491         }\r
492         cl_status = cl_vector_set_min_size( &h_mad_disp->client_vector, i+1 );\r
493         if( cl_status != CL_SUCCESS )\r
494         {\r
495                 cl_spinlock_release( &h_mad_disp->obj.lock );\r
496                 return NULL;\r
497         }\r
498         h_mad_reg = cl_vector_get_ptr( &h_mad_disp->client_vector, i );\r
499 \r
500         /* Record the registration. */\r
501         h_mad_reg->client_id = (uint32_t)i;\r
502         h_mad_reg->support_unsol = p_mad_svc->support_unsol;\r
503         h_mad_reg->mgmt_class = p_mad_svc->mgmt_class;\r
504         h_mad_reg->mgmt_version = p_mad_svc->mgmt_version;\r
505         h_mad_reg->pfn_recv_done = pfn_recv_done;\r
506         h_mad_reg->pfn_send_done = pfn_send_done;\r
507 \r
508         /* If the client requires support for unsolicited MADs, add tracking. */\r
509         if( p_mad_svc->support_unsol )\r
510         {\r
511                 if( !__mad_disp_reg_unsol( h_mad_disp, h_mad_reg, p_mad_svc ) )\r
512                 {\r
513                         cl_spinlock_release( &h_mad_disp->obj.lock );\r
514                         AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("reg unsol failed\n") );\r
515                         return NULL;\r
516                 }\r
517         }\r
518 \r
519         /* Record that the registration was successful. */\r
520         h_mad_reg->h_mad_svc = h_mad_svc;\r
521         h_mad_reg->ref_cnt = 1;\r
522         cl_spinlock_release( &h_mad_disp->obj.lock );\r
523 \r
524         /* The MAD service needs to take a reference on the dispatcher. */\r
525         ref_al_obj( &h_mad_disp->obj );\r
526 \r
527         AL_EXIT( AL_DBG_MAD_SVC );\r
528         return h_mad_reg;\r
529 }\r
530 \r
531 \r
532 static cl_status_t\r
533 __init_mad_reg(\r
534         IN                              void* const                                     p_element,\r
535         IN                              void*                                           context )\r
536 {\r
537         al_mad_reg_handle_t                     h_mad_reg;\r
538 \r
539         /* Record the MAD dispatcher for the registration structure. */\r
540         h_mad_reg = p_element;\r
541         h_mad_reg->h_mad_disp = context;\r
542         h_mad_reg->ref_cnt = 0;\r
543 \r
544         return CL_SUCCESS;\r
545 }\r
546 \r
547 \r
548 /*\r
549  * Initialize an entry in the version vector.  Each entry is a vector of\r
550  * classes.\r
551  */\r
552 static cl_status_t\r
553 __init_version_entry(\r
554         IN                              void* const                                     p_element,\r
555         IN                              void*                                           context )\r
556 {\r
557         cl_vector_t             *p_vector;\r
558 \r
559         p_vector = p_element;\r
560         UNUSED_PARAM( context );\r
561 \r
562         cl_vector_construct( p_vector );\r
563         return cl_vector_init( p_vector, MAD_VECTOR_SIZE, MAD_VECTOR_SIZE,\r
564                 sizeof( cl_ptr_vector_t ), __init_class_entry, __destroy_class_entry,\r
565                 p_vector );\r
566 }\r
567 \r
568 \r
569 static void\r
570 __destroy_version_entry(\r
571         IN                              void* const                                     p_element,\r
572         IN                              void*                                           context )\r
573 {\r
574         cl_vector_t             *p_vector;\r
575 \r
576         p_vector = p_element;\r
577         UNUSED_PARAM( context );\r
578 \r
579         cl_vector_destroy( p_vector );\r
580 }\r
581 \r
582 \r
583 /*\r
584  * Initialize an entry in the class vector.  Each entry is a pointer vector\r
585  * of methods.\r
586  */\r
587 static cl_status_t\r
588 __init_class_entry(\r
589         IN                              void* const                                     p_element,\r
590         IN                              void*                                           context )\r
591 {\r
592         cl_ptr_vector_t         *p_ptr_vector;\r
593 \r
594         p_ptr_vector = p_element;\r
595         UNUSED_PARAM( context );\r
596 \r
597         cl_ptr_vector_construct( p_ptr_vector );\r
598         return cl_ptr_vector_init( p_ptr_vector,\r
599                 MAD_VECTOR_SIZE, MAD_VECTOR_SIZE );\r
600 }\r
601 \r
602 \r
603 static void\r
604 __destroy_class_entry(\r
605         IN                              void* const                                     p_element,\r
606         IN                              void*                                           context )\r
607 {\r
608         cl_ptr_vector_t         *p_ptr_vector;\r
609 \r
610         p_ptr_vector = p_element;\r
611         UNUSED_PARAM( context );\r
612 \r
613         cl_ptr_vector_destroy( p_ptr_vector );\r
614 }\r
615 \r
616 \r
617 /*\r
618  * Add support for unsolicited MADs for the given MAD service.\r
619  */\r
620 static boolean_t\r
621 __mad_disp_reg_unsol(\r
622         IN              const   al_mad_disp_handle_t            h_mad_disp,\r
623         IN              const   al_mad_reg_handle_t                     h_mad_reg,\r
624         IN              const   ib_mad_svc_t                            *p_mad_svc )\r
625 {\r
626         cl_status_t                     cl_status;\r
627         cl_vector_t                     *p_class_vector;\r
628         cl_ptr_vector_t         *p_method_ptr_vector;\r
629         uint8_t                         i;\r
630 \r
631         /* Ensure that we are ready to handle this version number. */\r
632         AL_ENTER( AL_DBG_MAD_SVC );\r
633         cl_status = cl_vector_set_min_size( &h_mad_disp->version_vector,\r
634                 __mgmt_version_index( p_mad_svc->mgmt_version ) + 1 );\r
635         if( cl_status != CL_SUCCESS )\r
636                 return FALSE;\r
637 \r
638         /* Get the list of classes in use for this version. */\r
639         p_class_vector = cl_vector_get_ptr( &h_mad_disp->version_vector,\r
640                 __mgmt_version_index( p_mad_svc->mgmt_version ) );\r
641 \r
642         /* Ensure that we are ready to handle the specified class. */\r
643         cl_status = cl_vector_set_min_size( p_class_vector,\r
644                 __mgmt_class_index( p_mad_svc->mgmt_class ) + 1 );\r
645         if( cl_status != CL_SUCCESS )\r
646                 return FALSE;\r
647 \r
648         /* Get the list of methods in use for this class. */\r
649         p_method_ptr_vector = cl_vector_get_ptr( p_class_vector,\r
650                 __mgmt_class_index( p_mad_svc->mgmt_class ) );\r
651 \r
652         /* Ensure that we can handle all requested methods. */\r
653         for( i = MAX_METHOD - 1; i > 0; i-- )\r
654         {\r
655                 if( p_mad_svc->method_array[i] )\r
656                 {\r
657                         cl_status = cl_ptr_vector_set_min_size( p_method_ptr_vector, i+1 );\r
658                         if( cl_status != CL_SUCCESS )\r
659                                 return FALSE;\r
660 \r
661                         /* No one else can be registered for this method. */\r
662                         if( cl_ptr_vector_get( p_method_ptr_vector, i ) )\r
663                         {\r
664                                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
665                                         ("Other client already registered for Un-Solicited Method "\r
666                                         "%u for version %u of class %u.\n", i, p_mad_svc->mgmt_version,\r
667                                         p_mad_svc->mgmt_class ) );\r
668                                 return FALSE;\r
669                         }\r
670                 }\r
671         }\r
672 \r
673         /* We can support the request.  Record the methods. */\r
674         for( i = 0; i < MAX_METHOD; i++ )\r
675         {\r
676                 if( p_mad_svc->method_array[i] )\r
677                 {\r
678                         cl_ptr_vector_set( p_method_ptr_vector, i, h_mad_reg );\r
679 \r
680                         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC,\r
681                                 ("Register version:%u (%u) class:0x%02X(%u) method:0x%02X Hdl:%016I64x\n",\r
682                                 p_mad_svc->mgmt_version,\r
683                                 __mgmt_version_index( p_mad_svc->mgmt_version ),\r
684                                 p_mad_svc->mgmt_class,\r
685                                 __mgmt_class_index( p_mad_svc->mgmt_class ),\r
686                                 i,\r
687                                 (LONG_PTR)h_mad_reg) );\r
688                 }\r
689         }\r
690 \r
691         AL_EXIT( AL_DBG_MAD_SVC );\r
692         return TRUE;\r
693 }\r
694 \r
695 \r
696 static __inline uint8_t\r
697 __mgmt_version_index(\r
698         IN              const   uint8_t                                         mgmt_version )\r
699 {\r
700         return (uint8_t)(mgmt_version - 1);\r
701 }\r
702 \r
703 \r
704 static __inline uint8_t\r
705 __mgmt_class_index(\r
706         IN              const   uint8_t                                         mgmt_class )\r
707 {\r
708         /* Map class 0x81 to 0 to remove empty class values. */\r
709         if( mgmt_class == IB_MCLASS_SUBN_DIR )\r
710                 return IB_MCLASS_SUBN_LID;\r
711         else\r
712                 return mgmt_class;\r
713 }\r
714 \r
715 \r
716 \r
717 /*\r
718  * Deregister a MAD service from the dispatcher.\r
719  */\r
720 static void\r
721 __mad_disp_dereg(\r
722         IN              const   al_mad_reg_handle_t                     h_mad_reg )\r
723 {\r
724         al_mad_disp_handle_t    h_mad_disp;\r
725         cl_vector_t                             *p_class_vector;\r
726         cl_ptr_vector_t                 *p_method_ptr_vector;\r
727         size_t                                  i;\r
728 \r
729         AL_ENTER( AL_DBG_MAD_SVC );\r
730         h_mad_disp = h_mad_reg->h_mad_disp;\r
731 \r
732         cl_spinlock_acquire( &h_mad_disp->obj.lock );\r
733 \r
734         if( h_mad_reg->support_unsol )\r
735         {\r
736                 /* Deregister the service from receiving unsolicited MADs. */\r
737                 p_class_vector = cl_vector_get_ptr( &h_mad_disp->version_vector,\r
738                         __mgmt_version_index( h_mad_reg->mgmt_version ) );\r
739 \r
740                 p_method_ptr_vector = cl_vector_get_ptr( p_class_vector,\r
741                         __mgmt_class_index( h_mad_reg->mgmt_class ) );\r
742 \r
743                 /* Deregister all methods registered to the client. */\r
744                 for( i = 0; i < cl_ptr_vector_get_size( p_method_ptr_vector ); i++ )\r
745                 {\r
746                         if( cl_ptr_vector_get( p_method_ptr_vector, i ) == h_mad_reg )\r
747                         {\r
748                                 cl_ptr_vector_set( p_method_ptr_vector, i, NULL );\r
749                         }\r
750                 }\r
751         }\r
752 \r
753         cl_spinlock_release( &h_mad_disp->obj.lock );\r
754 \r
755         /* Decrement the reference count in the registration table. */\r
756         cl_atomic_dec( &h_mad_reg->ref_cnt );\r
757 \r
758         /* The MAD service no longer requires access to the MAD dispatcher. */\r
759         deref_al_obj( &h_mad_disp->obj );\r
760         AL_EXIT( AL_DBG_MAD_SVC );\r
761 }\r
762 \r
763 \r
764 \r
765 static void\r
766 __mad_disp_queue_send(\r
767         IN              const   al_mad_reg_handle_t                     h_mad_reg,\r
768         IN                              al_mad_wr_t* const                      p_mad_wr )\r
769 {\r
770         ib_mad_t                                *p_mad_hdr;\r
771 \r
772         /*\r
773          * Increment the reference count on the registration to ensure that\r
774          * the MAD service does not go away until the send completes.\r
775          */\r
776         AL_ENTER( AL_DBG_MAD_SVC );\r
777         cl_atomic_inc( &h_mad_reg->ref_cnt );\r
778         ref_al_obj( &h_mad_reg->h_mad_svc->obj );\r
779 \r
780         /* Get the MAD header. */\r
781         p_mad_hdr = get_mad_hdr_from_wr( p_mad_wr );\r
782         CL_ASSERT( !p_mad_wr->send_wr.wr_id );\r
783         p_mad_wr->send_wr.wr_id = (uintn_t)p_mad_wr;\r
784 \r
785         /*\r
786          * If we are the originator of the transaction, we need to modify the\r
787          * TID to ensure that duplicate TIDs are not used by multiple clients.\r
788          */\r
789         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("dispatching TID: 0x%I64x\n",\r
790                 p_mad_hdr->trans_id) );\r
791         p_mad_wr->client_tid = p_mad_hdr->trans_id;\r
792         if( __use_tid_routing( p_mad_hdr, TRUE ) )\r
793         {\r
794                 /* Clear the AL portion of the TID before setting. */\r
795                 ((al_tid_t*)&p_mad_hdr->trans_id)->tid32.al_tid = 0;\r
796 \r
797 #pragma warning( push, 3 )\r
798                 al_set_al_tid( &p_mad_hdr->trans_id, h_mad_reg->client_id );\r
799 #pragma warning( pop )\r
800 \r
801                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC,\r
802                         ("modified TID to: 0x%0I64x\n", p_mad_hdr->trans_id) );\r
803         }\r
804 \r
805         /* Post the work request to the QP. */\r
806         p_mad_wr->client_id = h_mad_reg->client_id;\r
807         h_mad_reg->h_mad_disp->h_qp->pfn_queue_mad(\r
808                 h_mad_reg->h_mad_disp->h_qp, p_mad_wr );\r
809 \r
810         AL_EXIT( AL_DBG_MAD_SVC );\r
811 }\r
812 \r
813 \r
814 static inline void\r
815 __mad_disp_resume_send(\r
816         IN              const   al_mad_reg_handle_t                     h_mad_reg )\r
817 {\r
818         AL_ENTER( AL_DBG_MAD_SVC );\r
819 \r
820         h_mad_reg->h_mad_disp->h_qp->pfn_resume_mad(\r
821                 h_mad_reg->h_mad_disp->h_qp );\r
822 \r
823         AL_EXIT( AL_DBG_MAD_SVC );\r
824 }\r
825 \r
826 \r
827 /*\r
828  * Complete a sent MAD.  Route the completion to the correct MAD service.\r
829  */\r
830 void\r
831 mad_disp_send_done(\r
832         IN                              al_mad_disp_handle_t            h_mad_disp,\r
833         IN                              al_mad_wr_t                                     *p_mad_wr,\r
834         IN                              ib_wc_t                                         *p_wc )\r
835 {\r
836         al_mad_reg_handle_t             h_mad_reg;\r
837         ib_mad_t                                *p_mad_hdr;\r
838 \r
839         AL_ENTER( AL_DBG_MAD_SVC );\r
840 \r
841         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC,\r
842                 ("p_mad_wr 0x%016I64x\n", (LONG_PTR)p_mad_wr ) );\r
843 \r
844         /* Get the MAD header. */\r
845         p_mad_hdr = get_mad_hdr_from_wr( p_mad_wr );\r
846 \r
847         /* Get the MAD service that issued the send. */\r
848         cl_spinlock_acquire( &h_mad_disp->obj.lock );\r
849         h_mad_reg = cl_vector_get_ptr( &h_mad_disp->client_vector,\r
850                 p_mad_wr->client_id );\r
851         cl_spinlock_release( &h_mad_disp->obj.lock );\r
852         CL_ASSERT( h_mad_reg && (h_mad_reg->client_id == p_mad_wr->client_id) );\r
853 \r
854         /* Reset the TID and WR ID. */\r
855         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("send done TID: 0x%I64x\n",\r
856                 p_mad_hdr->trans_id) );\r
857         p_mad_hdr->trans_id = p_mad_wr->client_tid;\r
858         p_mad_wr->send_wr.wr_id = 0;\r
859 \r
860         /* Return the completed request to the MAD service. */\r
861         CL_ASSERT( h_mad_reg->h_mad_svc );\r
862         h_mad_reg->pfn_send_done( h_mad_reg->h_mad_svc, p_mad_wr, p_wc );\r
863 \r
864         /* The MAD service is no longer referenced once the send completes. */\r
865         deref_al_obj( &h_mad_reg->h_mad_svc->obj );\r
866         cl_atomic_dec( &h_mad_reg->ref_cnt );\r
867 \r
868         AL_EXIT( AL_DBG_MAD_SVC );\r
869 }\r
870 \r
871 \r
872 \r
873 /*\r
874  * Process a received MAD.  Route the completion to the correct MAD service.\r
875  */\r
876 ib_api_status_t\r
877 mad_disp_recv_done(\r
878         IN                              al_mad_disp_handle_t            h_mad_disp,\r
879         IN                              ib_mad_element_t                        *p_mad_element )\r
880 {\r
881         ib_mad_t                                *p_mad_hdr;\r
882         al_mad_reg_handle_t             h_mad_reg;\r
883         ib_al_handle_t                  h_al;\r
884         ib_mad_svc_handle_t             h_mad_svc;\r
885 \r
886         cl_vector_t                             *p_class_vector;\r
887         cl_ptr_vector_t                 *p_method_ptr_vector;\r
888         uint8_t                                 method;\r
889 \r
890         AL_ENTER( AL_DBG_MAD_SVC );\r
891         p_mad_hdr = ib_get_mad_buf( p_mad_element );\r
892 \r
893         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC,\r
894                 ("TID = 0x%I64x\n"\r
895                  "class = 0x%x.\n"\r
896                  "version = 0x%x.\n"\r
897                  "method = 0x%x.\n",\r
898                 p_mad_hdr->trans_id,\r
899                 p_mad_hdr->mgmt_class,\r
900                 p_mad_hdr->class_ver,\r
901                 p_mad_hdr->method) );\r
902 \r
903         /* Get the client to route the receive to. */\r
904         cl_spinlock_acquire( &h_mad_disp->obj.lock );\r
905         if( __use_tid_routing( p_mad_hdr, FALSE ) )\r
906         {\r
907                 /* The MAD was received in response to a send. */\r
908                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("routing based on TID\n"));\r
909 \r
910                 /* Verify that we have a registration entry. */\r
911                 if( al_get_al_tid( p_mad_hdr->trans_id ) >=\r
912                         cl_vector_get_size( &h_mad_disp->client_vector ) )\r
913                 {\r
914                         /* No clients for this version-class-method. */\r
915                         cl_spinlock_release( &h_mad_disp->obj.lock );\r
916                         AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC,\r
917                                 ("invalid client ID\n") );\r
918                         return IB_NOT_FOUND;\r
919                 }\r
920 \r
921                 h_mad_reg = cl_vector_get_ptr( &h_mad_disp->client_vector,\r
922                         al_get_al_tid( p_mad_hdr->trans_id ) );\r
923 \r
924 /*\r
925  * Disable warning about passing unaligned 64-bit value.\r
926  * The value is always aligned given how buffers are allocated\r
927  * and given the layout of a MAD.\r
928  */\r
929 #pragma warning( push, 3 )\r
930                 al_set_al_tid( &p_mad_hdr->trans_id, 0 );\r
931 #pragma warning( pop )\r
932         }\r
933         else\r
934         {\r
935                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC,\r
936                         ("routing based on version, class, method\n"));\r
937 \r
938                 /* The receive is unsolicited.  Find the client. */\r
939                 if( __mgmt_version_index( p_mad_hdr->class_ver ) >=\r
940                         cl_vector_get_size( &h_mad_disp->version_vector ) )\r
941                 {\r
942                         /* No clients for this version of MADs. */\r
943                         cl_spinlock_release( &h_mad_disp->obj.lock );\r
944                         AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC,\r
945                                 ("no clients registered for this class version\n") );\r
946                         return IB_NOT_FOUND;\r
947                 }\r
948 \r
949                 /* See if we have a client for this class of MADs. */\r
950                 p_class_vector = cl_vector_get_ptr( &h_mad_disp->version_vector,\r
951                         __mgmt_version_index( p_mad_hdr->class_ver ) );\r
952 \r
953                 if( __mgmt_class_index( p_mad_hdr->mgmt_class ) >=\r
954                         cl_vector_get_size( p_class_vector ) )\r
955                 {\r
956                         /* No clients for this version-class. */\r
957                         cl_spinlock_release( &h_mad_disp->obj.lock );\r
958                         AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC,\r
959                                 ("no clients registered for this class\n") );\r
960                         return IB_NOT_FOUND;\r
961                 }\r
962 \r
963                 /* See if we have a client for this method. */\r
964                 p_method_ptr_vector = cl_vector_get_ptr( p_class_vector,\r
965                         __mgmt_class_index( p_mad_hdr->mgmt_class ) );\r
966                 method = (uint8_t)(p_mad_hdr->method & (~IB_MAD_METHOD_RESP_MASK));\r
967 \r
968                 if( method >= cl_ptr_vector_get_size( p_method_ptr_vector ) )\r
969                 {\r
970                         /* No clients for this version-class-method. */\r
971                         cl_spinlock_release( &h_mad_disp->obj.lock );\r
972                         AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC,\r
973                                 ("no clients registered for this method-out of range\n") );\r
974                         return IB_NOT_FOUND;\r
975                 }\r
976 \r
977                 h_mad_reg = cl_ptr_vector_get( p_method_ptr_vector, method );\r
978                 if( !h_mad_reg )\r
979                 {\r
980                         /* No clients for this version-class-method. */\r
981                         cl_spinlock_release( &h_mad_disp->obj.lock );\r
982                         AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC,\r
983                                 ("no clients registered for method %u of class %u(%u) version %u(%u)\n",\r
984                                  method,\r
985                                  p_mad_hdr->mgmt_class,\r
986                                  __mgmt_class_index( p_mad_hdr->mgmt_class ),\r
987                                  p_mad_hdr->class_ver,\r
988                                  __mgmt_version_index( p_mad_hdr->class_ver )\r
989                                  ) );\r
990                         return IB_NOT_FOUND;\r
991                 }\r
992         }\r
993 \r
994         /* Verify that the registration is still valid. */\r
995         if( !h_mad_reg->ref_cnt )\r
996         {\r
997                 cl_spinlock_release( &h_mad_disp->obj.lock );\r
998                 AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC,\r
999                         ("no client registered\n") );\r
1000                 return IB_NOT_FOUND;\r
1001         }\r
1002 \r
1003         /* Take a reference on the MAD service in case it deregisters. */\r
1004         h_mad_svc = h_mad_reg->h_mad_svc;\r
1005         ref_al_obj( &h_mad_svc->obj );\r
1006         cl_spinlock_release( &h_mad_disp->obj.lock );\r
1007 \r
1008         /* Handoff the MAD to the correct AL instance. */\r
1009         h_al = qp_get_al( (ib_qp_handle_t)(h_mad_svc->obj.p_parent_obj) );\r
1010         al_handoff_mad( h_al, p_mad_element );\r
1011 \r
1012         h_mad_reg->pfn_recv_done( h_mad_svc, p_mad_element );\r
1013         deref_al_obj( &h_mad_svc->obj );\r
1014         AL_EXIT( AL_DBG_MAD_SVC );\r
1015         return IB_SUCCESS;\r
1016 }\r
1017 \r
1018 \r
1019 \r
1020 /*\r
1021  * Return TRUE if we should route the MAD to the recipient based on the TID.\r
1022  */\r
1023 static boolean_t\r
1024 __use_tid_routing(\r
1025         IN              const   ib_mad_t* const                         p_mad_hdr,\r
1026         IN              const   boolean_t                                       are_we_sender )\r
1027 {\r
1028         ib_rmpp_mad_t           *p_rmpp_mad;\r
1029         boolean_t                       is_orig;\r
1030 \r
1031         AL_ENTER( AL_DBG_MAD_SVC );\r
1032 \r
1033         /* CM MADs are never TID routed. */\r
1034         if( p_mad_hdr->mgmt_class == IB_MCLASS_COMM_MGMT )\r
1035         {\r
1036                 AL_EXIT( AL_DBG_MAD_SVC );\r
1037                 return FALSE;\r
1038         }\r
1039 \r
1040         /*\r
1041          * Determine originator for a sent MAD.  Received MADs are just the\r
1042          * opposite.\r
1043          */\r
1044 \r
1045         /* Non-DATA RMPP MADs are handled differently. */\r
1046         p_rmpp_mad = (ib_rmpp_mad_t*)p_mad_hdr;\r
1047         if( (p_mad_hdr->mgmt_class == IB_MCLASS_SUBN_ADM) &&\r
1048                 ( ib_rmpp_is_flag_set( p_rmpp_mad, IB_RMPP_FLAG_ACTIVE ) &&\r
1049                 (p_rmpp_mad->rmpp_type != IB_RMPP_TYPE_DATA) ) )\r
1050         {\r
1051                 /*\r
1052                  * We need to distinguish between ACKs sent after receiving\r
1053                  * a request, versus ACKs sent after receiving a response.  ACKs\r
1054                  * to a request are from the responder.  ACKs to a response are\r
1055                  * from the originator.\r
1056 \r
1057                  * Note that we assume STOP and ABORT packets are initiated by\r
1058                  * receivers.  If both senders and receivers can\r
1059                  * initiate STOP and ABORT MADs, then we can't distinguish which\r
1060                  * transaction is associated with the MAD.  The TID for a\r
1061                  * send and receive can be the same.\r
1062                  */\r
1063                 is_orig = !ib_mad_is_response( p_mad_hdr );\r
1064         }\r
1065         else\r
1066         {\r
1067                 /*\r
1068                  * See if the MAD is being sent in response to a previous MAD.  If\r
1069                  * it is, then we're NOT the originator.  Note that trap repress\r
1070                  * MADs are responses, even though the response bit isn't set.\r
1071                  */\r
1072                 is_orig = !( ib_mad_is_response( p_mad_hdr ) ||\r
1073                         (p_mad_hdr->method == IB_MAD_METHOD_TRAP_REPRESS) );\r
1074         }\r
1075 \r
1076         /* If we're the receiver, toggle the result. */\r
1077         if( !are_we_sender )\r
1078                 is_orig = !is_orig;\r
1079 \r
1080         AL_EXIT( AL_DBG_MAD_SVC );\r
1081         return is_orig;\r
1082 }\r
1083 \r
1084 \r
1085 \r
1086 /*\r
1087  *\r
1088  * MAD Service.\r
1089  *\r
1090  */\r
1091 \r
1092 \r
1093 \r
1094 /*\r
1095  * Create and initialize a MAD service for use.\r
1096  */\r
1097 ib_api_status_t\r
1098 reg_mad_svc(\r
1099         IN              const   ib_qp_handle_t                          h_qp,\r
1100         IN              const   ib_mad_svc_t* const                     p_mad_svc,\r
1101                 OUT                     ib_mad_svc_handle_t* const      ph_mad_svc )\r
1102 {\r
1103         ib_api_status_t         status;\r
1104         cl_status_t                     cl_status;\r
1105         ib_mad_svc_handle_t     h_mad_svc;\r
1106         al_qp_alias_t           *p_qp_alias;\r
1107         ib_qp_attr_t            qp_attr;\r
1108 \r
1109         AL_ENTER( AL_DBG_MAD_SVC );\r
1110         CL_ASSERT( h_qp );\r
1111 \r
1112         switch( h_qp->type )\r
1113         {\r
1114         case IB_QPT_QP0:\r
1115         case IB_QPT_QP1:\r
1116         case IB_QPT_QP0_ALIAS:\r
1117         case IB_QPT_QP1_ALIAS:\r
1118         case IB_QPT_MAD:\r
1119                 break;\r
1120 \r
1121         default:\r
1122                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
1123                 return IB_INVALID_PARAMETER;\r
1124         }\r
1125 \r
1126         if( !p_mad_svc || !ph_mad_svc )\r
1127         {\r
1128                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
1129                 return IB_INVALID_PARAMETER;\r
1130         }\r
1131 \r
1132         h_mad_svc = cl_zalloc( sizeof( al_mad_svc_t) );\r
1133         if( !h_mad_svc )\r
1134         {\r
1135                 return IB_INSUFFICIENT_MEMORY;\r
1136         }\r
1137 \r
1138         /* Construct the MAD service. */\r
1139         construct_al_obj( &h_mad_svc->obj, AL_OBJ_TYPE_H_MAD_SVC );\r
1140         cl_timer_construct( &h_mad_svc->send_timer );\r
1141         cl_timer_construct( &h_mad_svc->recv_timer );\r
1142         cl_qlist_init( &h_mad_svc->send_list );\r
1143         cl_qlist_init( &h_mad_svc->recv_list );\r
1144 \r
1145         p_qp_alias = PARENT_STRUCT( h_qp, al_qp_alias_t, qp );\r
1146         h_mad_svc->svc_type = p_mad_svc->svc_type;\r
1147         h_mad_svc->obj.context = p_mad_svc->mad_svc_context;\r
1148         h_mad_svc->pfn_user_recv_cb = p_mad_svc->pfn_mad_recv_cb;\r
1149         h_mad_svc->pfn_user_send_cb = p_mad_svc->pfn_mad_send_cb;\r
1150 \r
1151         /* Initialize the MAD service. */\r
1152         status = init_al_obj( &h_mad_svc->obj, p_mad_svc->mad_svc_context,\r
1153                 TRUE, __destroying_mad_svc, __cleanup_mad_svc, free_mad_svc );\r
1154         if( status != IB_SUCCESS )\r
1155         {\r
1156                 free_mad_svc( &h_mad_svc->obj );\r
1157                 return status;\r
1158         }\r
1159         status = attach_al_obj( &h_qp->obj, &h_mad_svc->obj );\r
1160         if( status != IB_SUCCESS )\r
1161         {\r
1162                 h_mad_svc->obj.pfn_destroy( &h_mad_svc->obj, NULL );\r
1163                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1164                         ("attach_al_obj returned %s.\n", ib_get_err_str(status)) );\r
1165                 return status;\r
1166         }\r
1167 \r
1168         h_mad_svc->h_mad_reg = __mad_disp_reg( p_qp_alias->h_mad_disp,\r
1169                 h_mad_svc, p_mad_svc, __mad_svc_send_done, __mad_svc_recv_done );\r
1170         if( !h_mad_svc->h_mad_reg )\r
1171         {\r
1172                 h_mad_svc->obj.pfn_destroy( &h_mad_svc->obj, NULL );\r
1173                 return IB_INSUFFICIENT_MEMORY;\r
1174         }\r
1175 \r
1176         /* Record which port this MAD service uses, to use when creating AVs. */\r
1177         status = ib_query_qp( h_qp, &qp_attr );\r
1178         if( status != IB_SUCCESS )\r
1179         {\r
1180                 h_mad_svc->obj.pfn_destroy( &h_mad_svc->obj, NULL );\r
1181                 return status;\r
1182         }\r
1183         h_mad_svc->h_pd = qp_attr.h_pd;\r
1184         h_mad_svc->port_num = qp_attr.primary_port;\r
1185 \r
1186         cl_status = cl_timer_init( &h_mad_svc->send_timer,\r
1187                 __send_timer_cb, h_mad_svc );\r
1188         if( cl_status != CL_SUCCESS )\r
1189         {\r
1190                 h_mad_svc->obj.pfn_destroy( &h_mad_svc->obj, NULL );\r
1191                 return ib_convert_cl_status( cl_status );\r
1192         }\r
1193 \r
1194         cl_status = cl_timer_init( &h_mad_svc->recv_timer,\r
1195                 __recv_timer_cb, h_mad_svc );\r
1196         if( cl_status != CL_SUCCESS )\r
1197         {\r
1198                 h_mad_svc->obj.pfn_destroy( &h_mad_svc->obj, NULL );\r
1199                 return ib_convert_cl_status( cl_status );\r
1200         }\r
1201 \r
1202         *ph_mad_svc = h_mad_svc;\r
1203 \r
1204         AL_EXIT( AL_DBG_MAD_SVC );\r
1205         return IB_SUCCESS;\r
1206 }\r
1207 \r
1208 \r
1209 \r
1210 static void\r
1211 __destroying_mad_svc(\r
1212         IN                              struct _al_obj                          *p_obj )\r
1213 {\r
1214         ib_qp_handle_t                  h_qp;\r
1215         ib_mad_svc_handle_t             h_mad_svc;\r
1216         ib_mad_send_handle_t    h_send;\r
1217         cl_list_item_t                  *p_list_item;\r
1218         int32_t                                 timeout_ms;\r
1219 #ifdef CL_KERNEL\r
1220         KIRQL                                   old_irql;\r
1221 #endif\r
1222 \r
1223         AL_ENTER( AL_DBG_MAD_SVC );\r
1224         CL_ASSERT( p_obj );\r
1225         h_mad_svc = PARENT_STRUCT( p_obj, al_mad_svc_t, obj );\r
1226 \r
1227         /* Deregister the MAD service. */\r
1228         h_qp = (ib_qp_handle_t)p_obj->p_parent_obj;\r
1229         if( h_qp->pfn_dereg_mad_svc )\r
1230                 h_qp->pfn_dereg_mad_svc( h_mad_svc );\r
1231 \r
1232         /* Wait here until the MAD service is no longer in use. */\r
1233         timeout_ms = (int32_t)h_mad_svc->obj.timeout_ms;\r
1234         while( h_mad_svc->ref_cnt && timeout_ms > 0 )\r
1235         {\r
1236                 /* Use a timeout to avoid waiting forever - just in case. */\r
1237                 cl_thread_suspend( 10 );\r
1238                 timeout_ms -= 10;\r
1239         }\r
1240 \r
1241         /*\r
1242          * Deregister from the MAD dispatcher.  The MAD dispatcher holds\r
1243          * a reference on the MAD service when invoking callbacks.  Since we\r
1244          * issue sends, we know how many callbacks are expected for send\r
1245          * completions.  With receive completions, we need to wait until all\r
1246          * receive callbacks have completed before cleaning up receives.\r
1247          */\r
1248         if( h_mad_svc->h_mad_reg )\r
1249                 __mad_disp_dereg( h_mad_svc->h_mad_reg );\r
1250 \r
1251         /* Cancel all outstanding send requests. */\r
1252         cl_spinlock_acquire( &h_mad_svc->obj.lock );\r
1253         for( p_list_item = cl_qlist_head( &h_mad_svc->send_list );\r
1254                  p_list_item != cl_qlist_end( &h_mad_svc->send_list );\r
1255                  p_list_item = cl_qlist_next( p_list_item ) )\r
1256         {\r
1257                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("canceling MAD\n") );\r
1258                 h_send = PARENT_STRUCT( p_list_item, al_mad_send_t, pool_item );\r
1259                 h_send->canceled = TRUE;\r
1260         }\r
1261         cl_spinlock_release( &h_mad_svc->obj.lock );\r
1262 \r
1263         /*\r
1264          * Invoke the timer callback to return the canceled MADs to the user.\r
1265          * Since the MAD service is being destroyed, the user cannot be issuing\r
1266          * sends.\r
1267          */\r
1268         if( h_mad_svc->h_mad_reg )\r
1269         {\r
1270 #ifdef CL_KERNEL\r
1271                 old_irql = KeRaiseIrqlToDpcLevel();\r
1272 #endif\r
1273                 __check_send_queue( h_mad_svc );\r
1274 #ifdef CL_KERNEL\r
1275                 KeLowerIrql( old_irql );\r
1276 #endif\r
1277         }\r
1278 \r
1279         cl_timer_destroy( &h_mad_svc->send_timer );\r
1280 \r
1281 #ifdef CL_KERNEL\r
1282         /*\r
1283          * Reclaim any pending receives sent to the proxy for UAL.\r
1284          */\r
1285         if( h_mad_svc->obj.h_al->p_context )\r
1286         {\r
1287                 cl_qlist_t                                      *p_cblist;\r
1288                 al_proxy_cb_info_t                      *p_cb_info;\r
1289 \r
1290                 cl_spinlock_acquire( &h_mad_svc->obj.h_al->p_context->cb_lock );\r
1291                 p_cblist = &h_mad_svc->obj.h_al->p_context->misc_cb_list;\r
1292                 p_list_item = cl_qlist_head( p_cblist );\r
1293                 while( p_list_item != cl_qlist_end( p_cblist ) )\r
1294                 {\r
1295                         p_cb_info = (al_proxy_cb_info_t*)p_list_item;\r
1296                         p_list_item = cl_qlist_next( p_list_item );\r
1297 \r
1298                         if( p_cb_info->p_al_obj && p_cb_info->p_al_obj == &h_mad_svc->obj )\r
1299                         {\r
1300                                 cl_qlist_remove_item( p_cblist, &p_cb_info->pool_item.list_item );\r
1301                                 deref_al_obj( p_cb_info->p_al_obj );\r
1302                                 proxy_cb_put( p_cb_info );\r
1303                         }\r
1304                 }\r
1305                 cl_spinlock_release( &h_mad_svc->obj.h_al->p_context->cb_lock );\r
1306         }\r
1307 #endif\r
1308 \r
1309         AL_EXIT( AL_DBG_MAD_SVC );\r
1310 }\r
1311 \r
1312 \r
1313 \r
1314 static void\r
1315 __cleanup_mad_svc(\r
1316         IN                              struct _al_obj                          *p_obj )\r
1317 {\r
1318         ib_mad_svc_handle_t             h_mad_svc;\r
1319         al_mad_rmpp_t                   *p_rmpp;\r
1320         cl_list_item_t                  *p_list_item;\r
1321 \r
1322         CL_ASSERT( p_obj );\r
1323         h_mad_svc = PARENT_STRUCT( p_obj, al_mad_svc_t, obj );\r
1324 \r
1325         /*\r
1326          * There are no more callbacks from the MAD dispatcher that are active.\r
1327          * Cleanup any receives that may still be lying around.  Stop the receive\r
1328          * timer to avoid synchronizing with it.\r
1329          */\r
1330         cl_timer_destroy( &h_mad_svc->recv_timer );\r
1331         for( p_list_item = cl_qlist_head( &h_mad_svc->recv_list );\r
1332                  p_list_item != cl_qlist_end( &h_mad_svc->recv_list );\r
1333                  p_list_item = cl_qlist_next( p_list_item ) )\r
1334         {\r
1335                 p_rmpp = PARENT_STRUCT( p_list_item, al_mad_rmpp_t, pool_item );\r
1336                 p_rmpp->inactive = TRUE;\r
1337         }\r
1338         __recv_timer_cb( h_mad_svc );\r
1339 \r
1340         CL_ASSERT( cl_is_qlist_empty( &h_mad_svc->send_list ) );\r
1341         CL_ASSERT( cl_is_qlist_empty( &h_mad_svc->recv_list ) );\r
1342 }\r
1343 \r
1344 \r
1345 \r
1346 void\r
1347 free_mad_svc(\r
1348         IN                              al_obj_t                                        *p_obj )\r
1349 {\r
1350         ib_mad_svc_handle_t     h_mad_svc;\r
1351 \r
1352         CL_ASSERT( p_obj );\r
1353         h_mad_svc = PARENT_STRUCT( p_obj, al_mad_svc_t, obj );\r
1354 \r
1355         destroy_al_obj( p_obj );\r
1356         cl_free( h_mad_svc );\r
1357 }\r
1358 \r
1359 \r
1360 \r
1361 ib_api_status_t\r
1362 ib_send_mad(\r
1363         IN              const   ib_mad_svc_handle_t                     h_mad_svc,\r
1364         IN                              ib_mad_element_t* const         p_mad_element_list,\r
1365                 OUT                     ib_mad_element_t                        **pp_mad_failure OPTIONAL )\r
1366 {\r
1367         ib_api_status_t                         status = IB_SUCCESS;\r
1368 #ifdef CL_KERNEL\r
1369         ib_mad_send_handle_t            h_send;\r
1370         ib_mad_element_t                        *p_cur_mad, *p_next_mad;\r
1371 #endif\r
1372 \r
1373         AL_ENTER( AL_DBG_MAD_SVC );\r
1374 \r
1375         if( AL_OBJ_INVALID_HANDLE( h_mad_svc, AL_OBJ_TYPE_H_MAD_SVC ) )\r
1376         {\r
1377                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") );\r
1378                 return IB_INVALID_HANDLE;\r
1379         }\r
1380         if( !p_mad_element_list ||\r
1381                 ( p_mad_element_list->p_next && !pp_mad_failure ) )\r
1382         {\r
1383                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
1384                 return IB_INVALID_PARAMETER;\r
1385         }\r
1386 \r
1387 #ifndef CL_KERNEL\r
1388         /* This is a send from user mode using special QP alias */\r
1389         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC,\r
1390                 ("ib_send_mad: ual_context non-zero, TID = 0x%I64x.\n",\r
1391                 ((ib_mad_t*)(ib_get_mad_buf( p_mad_element_list )))->trans_id ));\r
1392         status = spl_qp_mad_send( h_mad_svc, p_mad_element_list,\r
1393                 pp_mad_failure );\r
1394         AL_EXIT( AL_DBG_MAD_SVC );\r
1395         return status;\r
1396 #else\r
1397         /* Post each send on the list. */\r
1398         p_cur_mad = p_mad_element_list;\r
1399         while( p_cur_mad )\r
1400         {\r
1401                 p_next_mad = p_cur_mad->p_next;\r
1402 \r
1403                 /* Get an element to track the send. */\r
1404                 h_send = get_mad_send( PARENT_STRUCT( p_cur_mad,\r
1405                         al_mad_element_t, element ) );\r
1406                 if( !h_send )\r
1407                 {\r
1408                         AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("unable to get mad_send\n") );\r
1409                         if( pp_mad_failure )\r
1410                                 *pp_mad_failure = p_cur_mad;\r
1411                         return IB_INSUFFICIENT_RESOURCES;\r
1412                 }\r
1413 \r
1414                 /* Initialize the MAD for sending. */\r
1415                 status = __init_send_mad( h_mad_svc, h_send, p_cur_mad );\r
1416                 if( status != IB_SUCCESS )\r
1417                 {\r
1418                         AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("init_send_mad failed: %s\n",\r
1419                                 ib_get_err_str(status)) );\r
1420                         put_mad_send( h_send );\r
1421                         if( pp_mad_failure )\r
1422                                 *pp_mad_failure = p_cur_mad;\r
1423                         return status;\r
1424                 }\r
1425 \r
1426                 /* Add the MADs to our list. */\r
1427                 cl_spinlock_acquire( &h_mad_svc->obj.lock );\r
1428                 cl_qlist_insert_tail( &h_mad_svc->send_list,\r
1429                         (cl_list_item_t*)&h_send->pool_item );\r
1430 \r
1431                 /* Post the MAD to the dispatcher, and check for failures. */\r
1432                 ref_al_obj( &h_mad_svc->obj );\r
1433                 p_cur_mad->p_next = NULL;\r
1434                 if( h_send->uses_rmpp )\r
1435                         __queue_rmpp_seg( h_mad_svc->h_mad_reg, h_send );\r
1436                 else\r
1437                         __queue_mad_wr( h_mad_svc->h_mad_reg, h_send );\r
1438                 cl_spinlock_release( &h_mad_svc->obj.lock );\r
1439 \r
1440                 p_cur_mad = p_next_mad;\r
1441         }\r
1442 \r
1443         /*\r
1444          * Resume any sends that can now be sent without holding\r
1445          * the mad service lock.\r
1446          */\r
1447         __mad_disp_resume_send( h_mad_svc->h_mad_reg );\r
1448 \r
1449         AL_EXIT( AL_DBG_MAD_SVC );\r
1450         return status;\r
1451 #endif\r
1452 }\r
1453 \r
1454 \r
1455 \r
1456 static ib_api_status_t\r
1457 __init_send_mad(\r
1458         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
1459         IN              const   ib_mad_send_handle_t            h_send,\r
1460         IN                              ib_mad_element_t* const         p_mad_element )\r
1461 {\r
1462         ib_rmpp_mad_t           *p_rmpp_hdr;\r
1463         uint8_t                         rmpp_version;\r
1464         ib_api_status_t         status;\r
1465 \r
1466         AL_ENTER( AL_DBG_MAD_SVC );\r
1467 \r
1468         /* Initialize tracking the send. */\r
1469         h_send->p_send_mad = p_mad_element;\r
1470         h_send->retry_time = MAX_TIME;\r
1471         h_send->retry_cnt = p_mad_element->retry_cnt;\r
1472 \r
1473         /* See if the send uses RMPP. */\r
1474         h_send->uses_rmpp = __does_send_req_rmpp( h_mad_svc->svc_type,\r
1475                 p_mad_element, &rmpp_version );\r
1476         if( h_send->uses_rmpp )\r
1477         {\r
1478                 /* The RMPP header is present. */\r
1479                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("RMPP is activated\n") );\r
1480                 p_rmpp_hdr = (ib_rmpp_mad_t*)p_mad_element->p_mad_buf;\r
1481 \r
1482                 /* We only support version 1. */\r
1483                 if( rmpp_version != DEFAULT_RMPP_VERSION )\r
1484                 {\r
1485                         AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("unsupported version\n") );\r
1486                         return IB_INVALID_SETTING;\r
1487                 }\r
1488 \r
1489                 p_rmpp_hdr->rmpp_version = rmpp_version;\r
1490                 p_rmpp_hdr->rmpp_type = IB_RMPP_TYPE_DATA;\r
1491                 ib_rmpp_set_resp_time( p_rmpp_hdr, IB_RMPP_NO_RESP_TIME );\r
1492                 p_rmpp_hdr->rmpp_status = IB_RMPP_STATUS_SUCCESS;\r
1493                 /*\r
1494                  * The segment number, flags, and payload size are set when\r
1495                  * sending, so that they are set correctly when issuing retries.\r
1496                  */\r
1497 \r
1498                 h_send->ack_seg = 0;\r
1499                 h_send->seg_limit = 1;\r
1500                 h_send->cur_seg = 1;\r
1501                 /* For SA RMPP MADS we need different data size and header size */\r
1502                 if( p_mad_element->p_mad_buf->mgmt_class == IB_MCLASS_SUBN_ADM )\r
1503                 {\r
1504                         h_send->total_seg = ( (p_mad_element->size - IB_SA_MAD_HDR_SIZE) +\r
1505                                 (IB_SA_DATA_SIZE - 1) ) / IB_SA_DATA_SIZE;\r
1506                 } \r
1507                 else \r
1508                 {\r
1509                         h_send->total_seg = ( (p_mad_element->size - MAD_RMPP_HDR_SIZE) +\r
1510                                 (MAD_RMPP_DATA_SIZE - 1) ) / MAD_RMPP_DATA_SIZE;\r
1511                 }\r
1512         }\r
1513 \r
1514         /* See if we need to create the address vector for the user. */\r
1515         if( !p_mad_element->h_av &&\r
1516                 !( p_mad_element->send_opt & IB_SEND_OPT_LOCAL ) )\r
1517         {\r
1518                 status = __create_send_av( h_mad_svc, h_send );\r
1519                 if( status != IB_SUCCESS )\r
1520                 {\r
1521                         return status;\r
1522                 }\r
1523         }\r
1524 \r
1525         AL_EXIT( AL_DBG_MAD_SVC );\r
1526         return IB_SUCCESS;\r
1527 }\r
1528 \r
1529 \r
1530 \r
1531 static ib_api_status_t\r
1532 __create_send_av(\r
1533         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
1534         IN                              ib_mad_send_handle_t            h_send )\r
1535 {\r
1536         ib_av_attr_t            av_attr;\r
1537         ib_mad_element_t        *p_mad_element;\r
1538 \r
1539         p_mad_element = h_send->p_send_mad;\r
1540 \r
1541         av_attr.port_num = h_mad_svc->port_num;\r
1542 \r
1543         av_attr.sl = p_mad_element->remote_sl;\r
1544         av_attr.dlid = p_mad_element->remote_lid;\r
1545 \r
1546         av_attr.grh_valid = p_mad_element->grh_valid;\r
1547         if( av_attr.grh_valid )\r
1548                 av_attr.grh = *p_mad_element->p_grh;\r
1549 \r
1550         av_attr.static_rate = IB_PATH_RECORD_RATE_10_GBS;\r
1551         av_attr.path_bits = p_mad_element->path_bits;\r
1552 \r
1553         return ib_create_av( h_mad_svc->h_pd, &av_attr, &h_send->h_av );\r
1554 }\r
1555 \r
1556 \r
1557 \r
1558 static boolean_t\r
1559 __does_send_req_rmpp(\r
1560         IN              const   ib_mad_svc_type_t                       mad_svc_type,\r
1561         IN              const   ib_mad_element_t* const         p_mad_element,\r
1562                 OUT                     uint8_t                                         *p_rmpp_version )\r
1563 {\r
1564         switch( mad_svc_type )\r
1565         {\r
1566         case IB_MAD_SVC_DEFAULT:\r
1567         case IB_MAD_SVC_RMPP:\r
1568                 /* Internally generated MADs do not use RMPP. */\r
1569                 if( __is_internal_send( mad_svc_type, p_mad_element ) )\r
1570                         return FALSE;\r
1571 \r
1572                 /* If the MAD has the version number set, just return it. */\r
1573                 if( p_mad_element->rmpp_version )\r
1574                 {\r
1575                         *p_rmpp_version = p_mad_element->rmpp_version;\r
1576                         return TRUE;\r
1577                 }\r
1578 \r
1579                 /* If the class is well known and uses RMPP, use the default version. */\r
1580                 if( p_mad_element->p_mad_buf->mgmt_class == IB_MCLASS_SUBN_ADM )\r
1581                 {\r
1582                         switch( p_mad_element->p_mad_buf->method )\r
1583                         {\r
1584                         case IB_MAD_METHOD_GETTABLE_RESP:\r
1585                         case IB_MAD_METHOD_GETMULTI:\r
1586                         case IB_MAD_METHOD_GETMULTI_RESP:\r
1587                                 *p_rmpp_version = DEFAULT_RMPP_VERSION;\r
1588                                 return TRUE;\r
1589 \r
1590                         default:\r
1591                                 return FALSE;\r
1592                         }\r
1593                 }\r
1594 \r
1595                 /* The RMPP is not active. */\r
1596                 return FALSE;\r
1597 \r
1598         default:\r
1599                 return FALSE;\r
1600         }\r
1601 }\r
1602 \r
1603 \r
1604 \r
1605 /*\r
1606  * Sends the next RMPP segment of an RMPP transfer.\r
1607  */\r
1608 static void\r
1609 __queue_rmpp_seg(\r
1610         IN              const   al_mad_reg_handle_t                     h_mad_reg,\r
1611         IN                              ib_mad_send_handle_t            h_send )\r
1612 {\r
1613         ib_rmpp_mad_t           *p_rmpp_hdr;\r
1614 \r
1615         AL_ENTER( AL_DBG_MAD_SVC );\r
1616 \r
1617         CL_ASSERT( h_mad_reg && h_send );\r
1618         CL_ASSERT( h_send->cur_seg <= h_send->seg_limit );\r
1619 \r
1620         /* Reset information to track the send. */\r
1621         h_send->retry_time = MAX_TIME;\r
1622 \r
1623         /* Set the RMPP header information. */\r
1624         p_rmpp_hdr = (ib_rmpp_mad_t*)h_send->p_send_mad->p_mad_buf;\r
1625         p_rmpp_hdr->seg_num = cl_hton32( h_send->cur_seg );\r
1626         p_rmpp_hdr->rmpp_flags = IB_RMPP_FLAG_ACTIVE;\r
1627         p_rmpp_hdr->paylen_newwin = 0;\r
1628 \r
1629         /* See if this is the first segment that needs to be sent. */\r
1630         if( h_send->cur_seg == 1 )\r
1631         {\r
1632                 p_rmpp_hdr->rmpp_flags |= IB_RMPP_FLAG_FIRST;\r
1633 \r
1634                 /*\r
1635                  * Since the RMPP layer is the one to support SA MADs by duplicating\r
1636                  * the SA header. The actual Payload Length should include the\r
1637                  * original mad size + NumSegs * SA-extra-header.\r
1638                  */\r
1639                 if( h_send->p_send_mad->p_mad_buf->mgmt_class == IB_MCLASS_SUBN_ADM )\r
1640                 {\r
1641                         /* Add sa_ext_hdr to each segment over the first one. */\r
1642                         p_rmpp_hdr->paylen_newwin = cl_hton32(\r
1643                                 h_send->p_send_mad->size - MAD_RMPP_HDR_SIZE +\r
1644                                 (h_send->total_seg - 1) * \r
1645                                 (IB_SA_MAD_HDR_SIZE - MAD_RMPP_HDR_SIZE) );\r
1646                 }\r
1647                 else \r
1648                 {\r
1649                         /* For other RMPP packets we simply use the given MAD */\r
1650                         p_rmpp_hdr->paylen_newwin = cl_hton32( h_send->p_send_mad->size -\r
1651                                 MAD_RMPP_HDR_SIZE );\r
1652                 }\r
1653         }\r
1654 \r
1655         /* See if this is the last segment that needs to be sent. */\r
1656         if( h_send->cur_seg == h_send->total_seg )\r
1657         {\r
1658                 p_rmpp_hdr->rmpp_flags |= IB_RMPP_FLAG_LAST;\r
1659 \r
1660                 /* But for SA MADs we need extra header size */\r
1661                 if( h_send->p_send_mad->p_mad_buf->mgmt_class == IB_MCLASS_SUBN_ADM )\r
1662                 {\r
1663                         p_rmpp_hdr->paylen_newwin = cl_hton32( h_send->p_send_mad->size -\r
1664                                 (h_send->cur_seg -1)*IB_SA_DATA_SIZE - MAD_RMPP_HDR_SIZE );\r
1665                 }\r
1666                 else\r
1667                 {\r
1668                         p_rmpp_hdr->paylen_newwin = cl_hton32( h_send->p_send_mad->size -\r
1669                                 (h_send->cur_seg -1)*MAD_RMPP_DATA_SIZE );\r
1670                 }\r
1671         }\r
1672 \r
1673         /* Set the current segment to the next one. */\r
1674         h_send->cur_seg++;\r
1675 \r
1676         /* Send the MAD. */\r
1677         __queue_mad_wr( h_mad_reg, h_send );\r
1678 \r
1679         AL_EXIT( AL_DBG_MAD_SVC );\r
1680 }\r
1681 \r
1682 \r
1683 \r
1684 /*\r
1685  * Posts a send work request to the dispatcher for a MAD send.\r
1686  */\r
1687 static void\r
1688 __queue_mad_wr(\r
1689         IN              const   al_mad_reg_handle_t                     h_mad_reg,\r
1690         IN              const   ib_mad_send_handle_t            h_send )\r
1691 {\r
1692         ib_send_wr_t            *p_send_wr;\r
1693         al_mad_element_t        *p_al_element;\r
1694         ib_rmpp_mad_t           *p_rmpp_hdr;\r
1695         uint8_t                         *p_rmpp_src, *p_rmpp_dst;\r
1696         uintn_t                         hdr_len, offset, max_len;\r
1697 \r
1698         AL_ENTER( AL_DBG_MAD_SVC );\r
1699         p_send_wr = &h_send->mad_wr.send_wr;\r
1700 \r
1701         cl_memclr( p_send_wr, sizeof( ib_send_wr_t ) );\r
1702 \r
1703         p_send_wr->wr_type = WR_SEND;\r
1704         p_send_wr->send_opt = h_send->p_send_mad->send_opt;\r
1705 \r
1706         p_al_element = PARENT_STRUCT( h_send->p_send_mad,\r
1707                 al_mad_element_t, element );\r
1708 \r
1709         /* See if the MAD requires RMPP support. */\r
1710         if( h_send->uses_rmpp && p_al_element->p_al_mad_buf )\r
1711         {\r
1712 #if defined( CL_KERNEL )\r
1713                 p_rmpp_dst = p_al_element->mad_buf + sizeof(ib_grh_t);\r
1714 #else\r
1715                 p_rmpp_dst = (uint8_t*)(uintn_t)p_al_element->mad_ds.vaddr;\r
1716 #endif\r
1717                 p_rmpp_src = (uint8_t* __ptr64)h_send->p_send_mad->p_mad_buf;\r
1718                 p_rmpp_hdr = (ib_rmpp_mad_t*)p_rmpp_src;\r
1719 \r
1720                 if( h_send->p_send_mad->p_mad_buf->mgmt_class == IB_MCLASS_SUBN_ADM )\r
1721                         hdr_len = IB_SA_MAD_HDR_SIZE;\r
1722                 else\r
1723                         hdr_len = MAD_RMPP_HDR_SIZE;\r
1724 \r
1725                 max_len = MAD_BLOCK_SIZE - hdr_len;\r
1726 \r
1727                 offset = hdr_len + (max_len * (cl_ntoh32( p_rmpp_hdr->seg_num ) - 1));\r
1728 \r
1729                 /* Copy the header into the registered send buffer. */\r
1730                 cl_memcpy( p_rmpp_dst, p_rmpp_src, hdr_len );\r
1731 \r
1732                 /* Copy this segment's payload into the registered send buffer. */\r
1733                 CL_ASSERT( h_send->p_send_mad->size != offset );\r
1734                 if( (h_send->p_send_mad->size - offset) < max_len )\r
1735                 {\r
1736                         max_len = h_send->p_send_mad->size - offset;\r
1737                         /* Clear unused payload. */\r
1738                         cl_memclr( p_rmpp_dst + hdr_len + max_len,\r
1739                                 MAD_BLOCK_SIZE - hdr_len - max_len );\r
1740                 }\r
1741 \r
1742                 cl_memcpy(\r
1743                         p_rmpp_dst + hdr_len, p_rmpp_src + offset, max_len );\r
1744         }\r
1745 \r
1746         p_send_wr->num_ds = 1;\r
1747         p_send_wr->ds_array = &p_al_element->mad_ds;\r
1748 \r
1749         p_send_wr->dgrm.ud.remote_qp = h_send->p_send_mad->remote_qp;\r
1750         p_send_wr->dgrm.ud.remote_qkey = h_send->p_send_mad->remote_qkey;\r
1751         p_send_wr->dgrm.ud.pkey_index = h_send->p_send_mad->pkey_index;\r
1752 \r
1753         /* See if we created the address vector on behalf of the user. */\r
1754         if( h_send->p_send_mad->h_av )\r
1755                 p_send_wr->dgrm.ud.h_av = h_send->p_send_mad->h_av;\r
1756         else\r
1757                 p_send_wr->dgrm.ud.h_av = h_send->h_av;\r
1758 \r
1759         __mad_disp_queue_send( h_mad_reg, &h_send->mad_wr );\r
1760 \r
1761         AL_EXIT( AL_DBG_MAD_SVC );\r
1762 }\r
1763 \r
1764 \r
1765 \r
1766 static cl_status_t\r
1767 __mad_svc_find_send(\r
1768         IN              const   cl_list_item_t* const           p_list_item,\r
1769         IN                              void*                                           context )\r
1770 {\r
1771         ib_mad_send_handle_t    h_send;\r
1772 \r
1773         h_send = PARENT_STRUCT( p_list_item, al_mad_send_t, pool_item );\r
1774 \r
1775         if( h_send->p_send_mad == context )\r
1776                 return CL_SUCCESS;\r
1777         else\r
1778                 return CL_NOT_FOUND;\r
1779 }\r
1780 \r
1781 \r
1782 \r
1783 ib_api_status_t\r
1784 ib_cancel_mad(\r
1785         IN              const   ib_mad_svc_handle_t                     h_mad_svc,\r
1786         IN                              ib_mad_element_t* const         p_mad_element )\r
1787 {\r
1788 #ifdef CL_KERNEL\r
1789         cl_list_item_t                  *p_list_item;\r
1790         ib_mad_send_handle_t    h_send;\r
1791 #else\r
1792         ib_api_status_t                 status;\r
1793 #endif\r
1794 \r
1795         AL_ENTER( AL_DBG_MAD_SVC );\r
1796 \r
1797         if( AL_OBJ_INVALID_HANDLE( h_mad_svc, AL_OBJ_TYPE_H_MAD_SVC ) )\r
1798         {\r
1799                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") );\r
1800                 return IB_INVALID_HANDLE;\r
1801         }\r
1802         if( !p_mad_element )\r
1803         {\r
1804                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
1805                 return IB_INVALID_PARAMETER;\r
1806         }\r
1807 \r
1808 #ifndef CL_KERNEL\r
1809         /* This is a send from user mode using special QP alias */\r
1810         status = spl_qp_cancel_mad( h_mad_svc, p_mad_element );\r
1811         AL_EXIT( AL_DBG_MAD_SVC );\r
1812         return status;\r
1813 #else\r
1814         /* Search for the MAD in our MAD list.  It may have already completed. */\r
1815         cl_spinlock_acquire( &h_mad_svc->obj.lock );\r
1816         p_list_item = cl_qlist_find_from_head( &h_mad_svc->send_list,\r
1817                 __mad_svc_find_send, p_mad_element );\r
1818 \r
1819         if( p_list_item == cl_qlist_end( &h_mad_svc->send_list ) )\r
1820         {\r
1821                 cl_spinlock_release( &h_mad_svc->obj.lock );\r
1822                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("mad not found\n") );\r
1823                 return IB_NOT_FOUND;\r
1824         }\r
1825 \r
1826         /* Mark the MAD as having been canceled. */\r
1827         h_send = PARENT_STRUCT( p_list_item, al_mad_send_t, pool_item );\r
1828         h_send->canceled = TRUE;\r
1829 \r
1830         /* If the MAD is active, process it in the send callback. */\r
1831         if( h_send->retry_time != MAX_TIME )\r
1832         {\r
1833                 /* Process the canceled MAD using the timer thread. */\r
1834                 cl_timer_trim( &h_mad_svc->send_timer, 0 );\r
1835         }\r
1836 \r
1837         cl_spinlock_release( &h_mad_svc->obj.lock );\r
1838         AL_EXIT( AL_DBG_MAD_SVC );\r
1839         return IB_SUCCESS;\r
1840 #endif\r
1841 }\r
1842 \r
1843 \r
1844 ib_api_status_t\r
1845 ib_delay_mad(\r
1846         IN              const   ib_mad_svc_handle_t                     h_mad_svc,\r
1847         IN                              ib_mad_element_t* const         p_mad_element,\r
1848         IN              const   uint32_t                                        delay_ms )\r
1849 {\r
1850 #ifdef CL_KERNEL\r
1851         cl_list_item_t                  *p_list_item;\r
1852         ib_mad_send_handle_t    h_send;\r
1853 #endif\r
1854 \r
1855         AL_ENTER( AL_DBG_MAD_SVC );\r
1856 \r
1857         if( AL_OBJ_INVALID_HANDLE( h_mad_svc, AL_OBJ_TYPE_H_MAD_SVC ) )\r
1858         {\r
1859                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_HANDLE\n") );\r
1860                 return IB_INVALID_HANDLE;\r
1861         }\r
1862         if( !p_mad_element )\r
1863         {\r
1864                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
1865                 return IB_INVALID_PARAMETER;\r
1866         }\r
1867 \r
1868 #ifndef CL_KERNEL\r
1869         UNUSED_PARAM( p_mad_element );\r
1870         UNUSED_PARAM( delay_ms );\r
1871         /* TODO: support for user-mode MAD QP's. */\r
1872         AL_EXIT( AL_DBG_MAD_SVC );\r
1873         return IB_UNSUPPORTED;\r
1874 #else\r
1875         /* Search for the MAD in our MAD list.  It may have already completed. */\r
1876         cl_spinlock_acquire( &h_mad_svc->obj.lock );\r
1877         p_list_item = cl_qlist_find_from_head( &h_mad_svc->send_list,\r
1878                 __mad_svc_find_send, p_mad_element );\r
1879 \r
1880         if( p_list_item == cl_qlist_end( &h_mad_svc->send_list ) )\r
1881         {\r
1882                 cl_spinlock_release( &h_mad_svc->obj.lock );\r
1883                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("MAD not found\n") );\r
1884                 return IB_NOT_FOUND;\r
1885         }\r
1886 \r
1887         /* Mark the MAD as having been canceled. */\r
1888         h_send = PARENT_STRUCT( p_list_item, al_mad_send_t, pool_item );\r
1889 \r
1890         if( h_send->retry_time == MAX_TIME )\r
1891                 h_send->delay = delay_ms;\r
1892         else\r
1893                 h_send->retry_time += ((uint64_t)delay_ms * 1000Ui64);\r
1894 \r
1895         cl_spinlock_release( &h_mad_svc->obj.lock );\r
1896         AL_EXIT( AL_DBG_MAD_SVC );\r
1897         return IB_SUCCESS;\r
1898 #endif\r
1899 }\r
1900 \r
1901 \r
1902 /*\r
1903  * Process a send completion.\r
1904  */\r
1905 static void\r
1906 __mad_svc_send_done(\r
1907         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
1908         IN                              al_mad_wr_t                                     *p_mad_wr,\r
1909         IN                              ib_wc_t                                         *p_wc )\r
1910 {\r
1911         ib_mad_send_handle_t    h_send;\r
1912 \r
1913         AL_ENTER( AL_DBG_MAD_SVC );\r
1914         CL_ASSERT( h_mad_svc && p_mad_wr && !p_wc->p_next );\r
1915 \r
1916         h_send = PARENT_STRUCT( p_mad_wr, al_mad_send_t, mad_wr );\r
1917         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("send callback TID:0x%I64x\n",\r
1918                 __get_send_tid( h_send )) );\r
1919 \r
1920         /* We need to synchronize access to the list as well as the MAD request. */\r
1921         cl_spinlock_acquire( &h_mad_svc->obj.lock );\r
1922 \r
1923         /* Complete internally sent MADs. */\r
1924         if( __is_internal_send( h_mad_svc->svc_type, h_send->p_send_mad ) )\r
1925         {\r
1926                 AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC, ("internal send\n") );\r
1927                 cl_qlist_remove_item( &h_mad_svc->send_list,\r
1928                         (cl_list_item_t*)&h_send->pool_item );\r
1929                 cl_spinlock_release( &h_mad_svc->obj.lock );\r
1930                 ib_put_mad( h_send->p_send_mad );\r
1931                 __cleanup_mad_send( h_mad_svc, h_send );\r
1932                 return;\r
1933         }\r
1934 \r
1935         /* See if the send request has completed. */\r
1936         if( __is_send_mad_done( h_send, p_wc ) )\r
1937         {\r
1938                 /* The send has completed. */\r
1939                 cl_qlist_remove_item( &h_mad_svc->send_list,\r
1940                         (cl_list_item_t*)&h_send->pool_item );\r
1941                 cl_spinlock_release( &h_mad_svc->obj.lock );\r
1942 \r
1943                 /* Report the send as canceled only if we don't have the response. */\r
1944                 if( h_send->canceled && !h_send->p_resp_mad )\r
1945                         __notify_send_comp( h_mad_svc, h_send, IB_WCS_CANCELED );\r
1946                 else\r
1947                         __notify_send_comp( h_mad_svc, h_send, p_wc->status );\r
1948         }\r
1949         else\r
1950         {\r
1951                 /* See if this is an RMPP MAD, and we should send more segments. */\r
1952                 if( h_send->uses_rmpp && (h_send->cur_seg <= h_send->seg_limit) )\r
1953                 {\r
1954                         /* Send the next segment. */\r
1955                         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC,\r
1956                                 ("sending next RMPP segment for TID:0x%I64x\n",\r
1957                                 __get_send_tid( h_send )) );\r
1958 \r
1959                         __queue_rmpp_seg( h_mad_svc->h_mad_reg, h_send );\r
1960                 }\r
1961                 else\r
1962                 {\r
1963                         /* Continue waiting for a response or ACK. */\r
1964                         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC,\r
1965                                 ("waiting for response for TID:0x%I64x\n",\r
1966                                 __get_send_tid( h_send )) );\r
1967 \r
1968                         __set_retry_time( h_send );\r
1969                         cl_timer_trim( &h_mad_svc->send_timer,\r
1970                                 h_send->p_send_mad->timeout_ms );\r
1971                 }\r
1972                 cl_spinlock_release( &h_mad_svc->obj.lock );\r
1973         }\r
1974 \r
1975         /*\r
1976          * Resume any sends that can now be sent without holding\r
1977          * the mad service lock.\r
1978          */\r
1979         __mad_disp_resume_send( h_mad_svc->h_mad_reg );\r
1980 \r
1981         AL_EXIT( AL_DBG_MAD_SVC );\r
1982 }\r
1983 \r
1984 \r
1985 \r
1986 /*\r
1987  * Notify the user of a completed send operation.\r
1988  */\r
1989 static void\r
1990 __notify_send_comp(\r
1991         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
1992         IN                              ib_mad_send_handle_t            h_send,\r
1993         IN                              ib_wc_status_t                          wc_status )\r
1994 {\r
1995         AL_ENTER( AL_DBG_MAD_SVC );\r
1996 \r
1997         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("completing TID:0x%I64x\n",\r
1998                 __get_send_tid( h_send )) );\r
1999 \r
2000         h_send->p_send_mad->status = wc_status;\r
2001 \r
2002         /* Notify the user of a received response, if one exists. */\r
2003         if( h_send->p_resp_mad )\r
2004         {\r
2005                 h_mad_svc->pfn_user_recv_cb( h_mad_svc, (void*)h_mad_svc->obj.context,\r
2006                         h_send->p_resp_mad );\r
2007         }\r
2008 \r
2009         /* The transaction has completed, return the send MADs. */\r
2010         h_mad_svc->pfn_user_send_cb( h_mad_svc, (void*)h_mad_svc->obj.context,\r
2011                 h_send->p_send_mad );\r
2012 \r
2013         __cleanup_mad_send( h_mad_svc, h_send );\r
2014 \r
2015         AL_EXIT( AL_DBG_MAD_SVC );\r
2016 }\r
2017 \r
2018 \r
2019 \r
2020 /*\r
2021  * Return a send MAD tracking structure to its pool and cleanup any resources\r
2022  * it may have allocated.\r
2023  */\r
2024 static void\r
2025 __cleanup_mad_send(\r
2026         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
2027         IN                              ib_mad_send_handle_t            h_send )\r
2028 {\r
2029         /* Release any address vectors that we may have created. */\r
2030         if( h_send->h_av )\r
2031         {\r
2032                 ib_destroy_av( h_send->h_av );\r
2033         }\r
2034 \r
2035         /* Return the send MAD tracking structure to its pool. */\r
2036         put_mad_send( h_send );\r
2037 \r
2038         /* We no longer need to reference the MAD service. */\r
2039         deref_al_obj( &h_mad_svc->obj );\r
2040 }\r
2041 \r
2042 \r
2043 \r
2044 static boolean_t\r
2045 __is_send_mad_done(\r
2046         IN                              ib_mad_send_handle_t            h_send,\r
2047         IN                              ib_wc_t                                         *p_wc )\r
2048 {\r
2049         AL_ENTER( AL_DBG_MAD_SVC );\r
2050 \r
2051         /* Complete the send if the request failed. */\r
2052         if( p_wc->status != IB_WCS_SUCCESS )\r
2053         {\r
2054                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("y-send failed\n" ) );\r
2055                 return TRUE;\r
2056         }\r
2057 \r
2058         /* Complete the send if it has been canceled. */\r
2059         if( h_send->canceled )\r
2060         {\r
2061                 AL_PRINT_EXIT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC,\r
2062                         ("y-send was canceled\n") );\r
2063                 return TRUE;\r
2064         }\r
2065 \r
2066         /* Complete the send if we have its response. */\r
2067         if( h_send->p_resp_mad )\r
2068         {\r
2069                 AL_PRINT_EXIT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC,\r
2070                         ("y-response received\n") );\r
2071                 return TRUE;\r
2072         }\r
2073 \r
2074         /* RMPP sends cannot complete until all segments have been acked. */\r
2075         if( h_send->uses_rmpp && (h_send->ack_seg < h_send->total_seg) )\r
2076         {\r
2077                 AL_PRINT_EXIT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC,\r
2078                         ("more RMPP segments to send\n") );\r
2079                 return FALSE;\r
2080         }\r
2081 \r
2082         /*\r
2083          * All segments of this send have been sent.\r
2084          * The send has completed if we are not waiting for a response.\r
2085          */\r
2086         if( h_send->p_send_mad->resp_expected )\r
2087         {\r
2088                 AL_PRINT_EXIT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC,\r
2089                         ("no-waiting on response\n") );\r
2090                 return FALSE;\r
2091         }\r
2092         else\r
2093         {\r
2094                 AL_PRINT_EXIT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC,\r
2095                         ("send completed\n") );\r
2096                 return TRUE;\r
2097         }\r
2098 }\r
2099 \r
2100 \r
2101 \r
2102 /*\r
2103  * Try to find a send that matches the received response.  This call must\r
2104  * be synchronized with access to the MAD service send_list.\r
2105  */\r
2106 static ib_mad_send_handle_t\r
2107 __mad_svc_match_recv(\r
2108         IN              const   ib_mad_svc_handle_t                     h_mad_svc,\r
2109         IN                              ib_mad_element_t* const         p_recv_mad )\r
2110 {\r
2111         ib_mad_t                                *p_recv_hdr;\r
2112         cl_list_item_t                  *p_list_item;\r
2113         ib_mad_send_handle_t    h_send;\r
2114 \r
2115         AL_ENTER( AL_DBG_MAD_SVC );\r
2116 \r
2117         p_recv_hdr = p_recv_mad->p_mad_buf;\r
2118 \r
2119         /* Search the send list for a matching request. */\r
2120         for( p_list_item = cl_qlist_head( &h_mad_svc->send_list );\r
2121                  p_list_item != cl_qlist_end( &h_mad_svc->send_list );\r
2122                  p_list_item = cl_qlist_next( p_list_item ) )\r
2123         {\r
2124                 h_send = PARENT_STRUCT( p_list_item, al_mad_send_t, pool_item );\r
2125 \r
2126                 /* Match on the transaction ID, ignoring internally generated sends. */\r
2127                 AL_EXIT( AL_DBG_MAD_SVC );\r
2128                 if( (p_recv_hdr->trans_id == h_send->mad_wr.client_tid) &&\r
2129                          !__is_internal_send( h_mad_svc->svc_type, h_send->p_send_mad ) )\r
2130                 {\r
2131                         return h_send;\r
2132                 }\r
2133         }\r
2134 \r
2135         return NULL;\r
2136 }\r
2137 \r
2138 \r
2139 \r
2140 static void\r
2141 __mad_svc_recv_done(\r
2142         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
2143         IN                              ib_mad_element_t                        *p_mad_element )\r
2144 {\r
2145         ib_mad_t                                *p_mad_hdr;\r
2146         ib_api_status_t                 cl_status;\r
2147 \r
2148         AL_ENTER( AL_DBG_MAD_SVC );\r
2149 \r
2150         p_mad_hdr = ib_get_mad_buf( p_mad_element );\r
2151         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("recv done TID:0x%I64x\n",\r
2152                 p_mad_hdr->trans_id) );\r
2153 \r
2154         /* Raw MAD services get all receives. */\r
2155         if( h_mad_svc->svc_type == IB_MAD_SVC_RAW )\r
2156         {\r
2157                 /* Report the receive. */\r
2158                 AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC,\r
2159                         ("recv TID:0x%I64x\n", p_mad_hdr->trans_id) );\r
2160                 h_mad_svc->pfn_user_recv_cb( h_mad_svc, (void*)h_mad_svc->obj.context,\r
2161                         p_mad_element );\r
2162                 return;\r
2163         }\r
2164 \r
2165         /* Fully reassemble received MADs before completing them. */\r
2166         if( __recv_requires_rmpp( h_mad_svc->svc_type, p_mad_element ) )\r
2167         {\r
2168                 /* Reassembling the receive. */\r
2169                 cl_status = __do_rmpp_recv( h_mad_svc, &p_mad_element );\r
2170                 if( cl_status != CL_SUCCESS )\r
2171                 {\r
2172                         /* The reassembly is not done. */\r
2173                         AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC,\r
2174                                 ("no RMPP receive to report\n") );\r
2175                         return;\r
2176                 }\r
2177 \r
2178                 /*\r
2179                  * Get the header to the MAD element to report to the user.  This\r
2180                  * will be a MAD element received earlier.\r
2181                  */\r
2182                 p_mad_hdr = ib_get_mad_buf( p_mad_element );\r
2183         }\r
2184 \r
2185         /*\r
2186          * If the response indicates that the responder was busy, continue\r
2187          * retrying the request.\r
2188          */\r
2189         if( p_mad_hdr->status & IB_MAD_STATUS_BUSY )\r
2190         {\r
2191                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
2192                         ("responder busy TID:0x%I64x\n", p_mad_hdr->trans_id) );\r
2193                 ib_put_mad( p_mad_element );\r
2194                 return;\r
2195         }\r
2196 \r
2197         /*\r
2198          * See if the MAD was sent in response to a previously sent MAD.  Note\r
2199          * that trap repress messages are responses, even though the response\r
2200          * bit isn't set.\r
2201          */\r
2202         if( ib_mad_is_response( p_mad_hdr ) ||\r
2203                 (p_mad_hdr->method == IB_MAD_METHOD_TRAP_REPRESS) )\r
2204         {\r
2205                 /* Process the received response. */\r
2206                 __process_recv_resp( h_mad_svc, p_mad_element );\r
2207         }\r
2208         else\r
2209         {\r
2210                 /* Report the receive. */\r
2211                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("unsol recv TID:0x%I64x\n",\r
2212                         p_mad_hdr->trans_id) );\r
2213                 h_mad_svc->pfn_user_recv_cb( h_mad_svc, (void*)h_mad_svc->obj.context,\r
2214                         p_mad_element );\r
2215         }\r
2216         AL_EXIT( AL_DBG_MAD_SVC );\r
2217 }\r
2218 \r
2219 \r
2220 \r
2221 /*\r
2222  * A MAD was received in response to a send.  Find the corresponding send\r
2223  * and process the receive completion.\r
2224  */\r
2225 static void\r
2226 __process_recv_resp(\r
2227         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
2228         IN                              ib_mad_element_t                        *p_mad_element )\r
2229 {\r
2230         ib_mad_t                                *p_mad_hdr;\r
2231         ib_mad_send_handle_t    h_send;\r
2232 \r
2233         /*\r
2234          * Try to find the send.  The send may have already timed out or\r
2235          * have been canceled, so we need to search for it.\r
2236          */\r
2237         AL_ENTER( AL_DBG_MAD_SVC );\r
2238         p_mad_hdr = ib_get_mad_buf( p_mad_element );\r
2239         cl_spinlock_acquire( &h_mad_svc->obj.lock );\r
2240 \r
2241         h_send = __mad_svc_match_recv( h_mad_svc, p_mad_element );\r
2242         if( !h_send )\r
2243         {\r
2244                 /* A matching send was not found. */\r
2245                 AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC,\r
2246                         ("unmatched resp TID:0x%I64x\n", p_mad_hdr->trans_id) );\r
2247                 cl_spinlock_release( &h_mad_svc->obj.lock );\r
2248                 ib_put_mad( p_mad_element );\r
2249                 return;\r
2250         }\r
2251 \r
2252         /* We've found the matching send. */\r
2253         h_send->p_send_mad->status = IB_WCS_SUCCESS;\r
2254 \r
2255         /* Record the send contexts with the receive. */\r
2256         p_mad_element->send_context1 = (void* __ptr64)h_send->p_send_mad->context1;\r
2257         p_mad_element->send_context2 = (void* __ptr64)h_send->p_send_mad->context2;\r
2258 \r
2259         if( h_send->retry_time == MAX_TIME )\r
2260         {\r
2261                 /* The send is currently active.  Do not report it. */\r
2262                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC,\r
2263                         ("resp send active TID:0x%I64x\n", p_mad_hdr->trans_id) );\r
2264                 /* Handle a duplicate receive happening before the send completion is processed. */\r
2265                 if( h_send->p_resp_mad )\r
2266                         ib_put_mad( h_send->p_resp_mad );\r
2267                 h_send->p_resp_mad = p_mad_element;\r
2268                 cl_spinlock_release( &h_mad_svc->obj.lock );\r
2269         }\r
2270         else\r
2271         {\r
2272                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC,\r
2273                         ("resp received TID:0x%I64x\n", p_mad_hdr->trans_id) );\r
2274 \r
2275                 /* Report the send completion below. */\r
2276                 cl_qlist_remove_item( &h_mad_svc->send_list,\r
2277                         (cl_list_item_t*)&h_send->pool_item );\r
2278                 cl_spinlock_release( &h_mad_svc->obj.lock );\r
2279 \r
2280                 /* Report the receive. */\r
2281                 h_mad_svc->pfn_user_recv_cb( h_mad_svc, (void*)h_mad_svc->obj.context,\r
2282                         p_mad_element );\r
2283 \r
2284                 /* Report the send completion. */\r
2285                 h_mad_svc->pfn_user_send_cb( h_mad_svc, (void*)h_mad_svc->obj.context,\r
2286                         h_send->p_send_mad );\r
2287                 __cleanup_mad_send( h_mad_svc, h_send );\r
2288         }\r
2289         AL_EXIT( AL_DBG_MAD_SVC );\r
2290 }\r
2291 \r
2292 \r
2293 \r
2294 /*\r
2295  * Return TRUE if a received MAD requires RMPP processing.\r
2296  */\r
2297 static __inline boolean_t\r
2298 __recv_requires_rmpp(\r
2299         IN              const   ib_mad_svc_type_t                       mad_svc_type,\r
2300         IN              const   ib_mad_element_t* const         p_mad_element )\r
2301 {\r
2302         ib_rmpp_mad_t                           *p_rmpp_mad;\r
2303 \r
2304         AL_ENTER( AL_DBG_MAD_SVC );\r
2305 \r
2306         p_rmpp_mad = (ib_rmpp_mad_t*)ib_get_mad_buf( p_mad_element );\r
2307 \r
2308         AL_EXIT( AL_DBG_MAD_SVC );\r
2309 \r
2310         switch( mad_svc_type )\r
2311         {\r
2312         case IB_MAD_SVC_DEFAULT:\r
2313                 /* Only subnet management receives require RMPP. */\r
2314                 return( (p_rmpp_mad->common_hdr.mgmt_class == IB_MCLASS_SUBN_ADM) &&\r
2315                         ib_rmpp_is_flag_set( p_rmpp_mad, IB_RMPP_FLAG_ACTIVE ) );\r
2316 \r
2317         case IB_MAD_SVC_RMPP:\r
2318                 return( ib_rmpp_is_flag_set( p_rmpp_mad, IB_RMPP_FLAG_ACTIVE ) );\r
2319 \r
2320         default:\r
2321                 return FALSE;\r
2322         }\r
2323 }\r
2324 \r
2325 \r
2326 \r
2327 /*\r
2328  * Return TRUE if the MAD was issued by AL itself.\r
2329  */\r
2330 static __inline boolean_t\r
2331 __is_internal_send(\r
2332         IN              const   ib_mad_svc_type_t                       mad_svc_type,\r
2333         IN              const   ib_mad_element_t* const         p_mad_element )\r
2334 {\r
2335         ib_rmpp_mad_t           *p_rmpp_mad;\r
2336 \r
2337         p_rmpp_mad = (ib_rmpp_mad_t*)ib_get_mad_buf( p_mad_element );\r
2338 \r
2339         /* See if the MAD service issues internal MADs. */\r
2340         switch( mad_svc_type )\r
2341         {\r
2342         case IB_MAD_SVC_DEFAULT:\r
2343                 /* Internal sends are non-RMPP data MADs. */\r
2344                 return( (p_rmpp_mad->common_hdr.mgmt_class == IB_MCLASS_SUBN_ADM) &&\r
2345                                 (p_rmpp_mad->rmpp_type &&\r
2346                                 (p_rmpp_mad->rmpp_type != IB_RMPP_TYPE_DATA) ) );\r
2347 \r
2348         case IB_MAD_SVC_RMPP:\r
2349                 /* The RMPP header is present.  Check its type. */\r
2350                 return( (p_rmpp_mad->rmpp_type) &&\r
2351                                 (p_rmpp_mad->rmpp_type != IB_RMPP_TYPE_DATA) );\r
2352 \r
2353         default:\r
2354                 return FALSE;\r
2355         }\r
2356 }\r
2357 \r
2358 \r
2359 \r
2360 /*\r
2361  * Fully reassemble a received MAD.  Return TRUE once all segments of the\r
2362  * MAD have been received.  Return the fully reassembled MAD.\r
2363  */\r
2364 static cl_status_t\r
2365 __do_rmpp_recv(\r
2366         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
2367         IN      OUT                     ib_mad_element_t                        **pp_mad_element )\r
2368 {\r
2369         ib_rmpp_mad_t           *p_rmpp_mad;\r
2370         cl_status_t                     cl_status;\r
2371 \r
2372         AL_ENTER( AL_DBG_MAD_SVC );\r
2373 \r
2374         p_rmpp_mad = ib_get_mad_buf( *pp_mad_element );\r
2375         CL_ASSERT( ib_rmpp_is_flag_set( p_rmpp_mad, IB_RMPP_FLAG_ACTIVE ) );\r
2376 \r
2377         /* Perform the correct operation base on the RMPP MAD type. */\r
2378         switch( p_rmpp_mad->rmpp_type )\r
2379         {\r
2380         case IB_RMPP_TYPE_DATA:\r
2381                 cl_status = __process_rmpp_data( h_mad_svc, pp_mad_element );\r
2382                 /* Return the received element back to its MAD pool if not needed. */\r
2383                 if( (cl_status != CL_SUCCESS) && (cl_status != CL_NOT_DONE) )\r
2384                 {\r
2385                         ib_put_mad( *pp_mad_element );\r
2386                 }\r
2387                 break;\r
2388 \r
2389         case IB_RMPP_TYPE_ACK:\r
2390                 /* Process the ACK. */\r
2391                 __process_rmpp_ack( h_mad_svc, *pp_mad_element );\r
2392                 ib_put_mad( *pp_mad_element );\r
2393                 cl_status = CL_COMPLETED;\r
2394                 break;\r
2395 \r
2396         case IB_RMPP_TYPE_STOP:\r
2397         case IB_RMPP_TYPE_ABORT:\r
2398         default:\r
2399                 /* Process the ABORT or STOP. */\r
2400                 __process_rmpp_nack( h_mad_svc, *pp_mad_element );\r
2401                 ib_put_mad( *pp_mad_element );\r
2402                 cl_status = CL_REJECT;\r
2403                 break;\r
2404         }\r
2405 \r
2406         AL_EXIT( AL_DBG_MAD_SVC );\r
2407         return cl_status;\r
2408 }\r
2409 \r
2410 \r
2411 \r
2412 /*\r
2413  * Process an RMPP DATA message.  Reassemble the received data.  If the\r
2414  * received MAD is fully reassembled, this call returns CL_SUCCESS.\r
2415  */\r
2416 static cl_status_t\r
2417 __process_rmpp_data(\r
2418         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
2419         IN      OUT                     ib_mad_element_t                        **pp_mad_element )\r
2420 {\r
2421         ib_mad_element_t        *p_rmpp_resp_mad = NULL;\r
2422         al_mad_rmpp_t           *p_rmpp;\r
2423         ib_rmpp_mad_t           *p_rmpp_hdr;\r
2424         uint32_t                        cur_seg;\r
2425         cl_status_t                     cl_status;\r
2426         ib_api_status_t         status;\r
2427 \r
2428         p_rmpp_hdr = ib_get_mad_buf( *pp_mad_element );\r
2429         CL_ASSERT( p_rmpp_hdr->rmpp_type == IB_RMPP_TYPE_DATA );\r
2430 \r
2431         /* Try to find a receive already being reassembled. */\r
2432         cl_spinlock_acquire( &h_mad_svc->obj.lock );\r
2433         p_rmpp = __find_rmpp( h_mad_svc, *pp_mad_element );\r
2434         if( !p_rmpp )\r
2435         {\r
2436                 /* This receive is not being reassembled. It should be the first seg. */\r
2437                 if( cl_ntoh32( p_rmpp_hdr->seg_num ) != 1 )\r
2438                 {\r
2439                         cl_spinlock_release( &h_mad_svc->obj.lock );\r
2440                         return CL_NOT_FOUND;\r
2441                 }\r
2442 \r
2443                 /* Start tracking the new reassembly. */\r
2444                 p_rmpp = __get_mad_rmpp( h_mad_svc, *pp_mad_element );\r
2445                 if( !p_rmpp )\r
2446                 {\r
2447                         cl_spinlock_release( &h_mad_svc->obj.lock );\r
2448                         return CL_INSUFFICIENT_MEMORY;\r
2449                 }\r
2450         }\r
2451 \r
2452         /* Verify that we just received the expected segment. */\r
2453         cur_seg = cl_ntoh32( p_rmpp_hdr->seg_num );\r
2454         if( cur_seg == p_rmpp->expected_seg )\r
2455         {\r
2456                 /* Copy the new segment's data into our reassembly buffer. */\r
2457                 cl_status = __process_segment( h_mad_svc, p_rmpp,\r
2458                         pp_mad_element, &p_rmpp_resp_mad );\r
2459 \r
2460                 /* See if the RMPP is done. */\r
2461                 if( cl_status == CL_SUCCESS )\r
2462                 {\r
2463                         /* Stop tracking the reassembly. */\r
2464                         __put_mad_rmpp( h_mad_svc, p_rmpp );\r
2465                 }\r
2466                 else if( cl_status == CL_NOT_DONE )\r
2467                 {\r
2468                         /* Start the reassembly timer. */\r
2469                         cl_timer_trim( &h_mad_svc->recv_timer, AL_REASSEMBLY_TIMEOUT );\r
2470                 }\r
2471         }\r
2472         else if( cur_seg < p_rmpp->expected_seg )\r
2473         {\r
2474                 /* We received an old segment.  Resend the last ACK. */\r
2475                 p_rmpp_resp_mad = __get_rmpp_ack( p_rmpp );\r
2476                 cl_status = CL_DUPLICATE;\r
2477         }\r
2478         else\r
2479         {\r
2480                 /* The sender is confused, ignore this MAD.  We could ABORT here. */\r
2481                 cl_status = CL_OVERRUN;\r
2482         }\r
2483 \r
2484         cl_spinlock_release( &h_mad_svc->obj.lock );\r
2485 \r
2486         /*\r
2487          * Send any response MAD (ACK, ABORT, etc.) to the sender.  Note that\r
2488          * we are currently in the callback from the MAD dispatcher.  The\r
2489          * dispatcher holds a reference on the MAD service while in the callback,\r
2490          * preventing the MAD service from being destroyed.  This allows the\r
2491          * call to ib_send_mad() to proceed even if the user tries to destroy\r
2492          * the MAD service.\r
2493          */\r
2494         if( p_rmpp_resp_mad )\r
2495         {\r
2496                 status = ib_send_mad( h_mad_svc, p_rmpp_resp_mad, NULL );\r
2497                 if( status != IB_SUCCESS )\r
2498                 {\r
2499                         /* Return the MAD.  The MAD is considered dropped. */\r
2500                         ib_put_mad( p_rmpp_resp_mad );\r
2501                 }\r
2502         }\r
2503 \r
2504         return cl_status;\r
2505 }\r
2506 \r
2507 \r
2508 \r
2509 /*\r
2510  * Locate an existing RMPP MAD being reassembled.  Return NULL if one is not\r
2511  * found.  This call assumes access to the recv_list is synchronized.\r
2512  */\r
2513 static al_mad_rmpp_t*\r
2514 __find_rmpp(\r
2515         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
2516         IN      OUT                     ib_mad_element_t                        *p_mad_element )\r
2517 {\r
2518         al_mad_rmpp_t                   *p_rmpp;\r
2519         cl_list_item_t                  *p_list_item;\r
2520         ib_mad_t                                *p_mad_hdr, *p_mad_hdr2;\r
2521         ib_mad_element_t                *p_mad_element2;\r
2522 \r
2523 \r
2524         p_mad_hdr = ib_get_mad_buf( p_mad_element );\r
2525 \r
2526         /* Search all MADs being reassembled. */\r
2527         for( p_list_item = cl_qlist_head( &h_mad_svc->recv_list );\r
2528                  p_list_item != cl_qlist_end( &h_mad_svc->recv_list );\r
2529                  p_list_item = cl_qlist_next( p_list_item ) )\r
2530         {\r
2531                 p_rmpp = PARENT_STRUCT( p_list_item, al_mad_rmpp_t, pool_item );\r
2532 \r
2533                 p_mad_element2 = p_rmpp->p_mad_element;\r
2534                 p_mad_hdr2 = ib_get_mad_buf( p_mad_element2 );\r
2535 \r
2536                 /* See if the incoming MAD matches - what a check. */\r
2537                 if( (p_mad_hdr->trans_id                == p_mad_hdr2->trans_id)                &&\r
2538                         (p_mad_hdr->class_ver           == p_mad_hdr2->class_ver)               &&\r
2539                         (p_mad_hdr->mgmt_class          == p_mad_hdr2->mgmt_class)              &&\r
2540                         (p_mad_hdr->method                      == p_mad_hdr2->method)                  &&\r
2541                         (p_mad_element->remote_lid      == p_mad_element2->remote_lid)  &&\r
2542                         (p_mad_element->remote_qp       == p_mad_element2->remote_qp) )\r
2543                 {\r
2544                         return p_rmpp;\r
2545                 }\r
2546         }\r
2547 \r
2548         return NULL;\r
2549 }\r
2550 \r
2551 \r
2552 \r
2553 /*\r
2554  * Acquire a new RMPP tracking structure.  This call assumes access to\r
2555  * the recv_list is synchronized.\r
2556  */\r
2557 static al_mad_rmpp_t*\r
2558 __get_mad_rmpp(\r
2559         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
2560         IN                              ib_mad_element_t                        *p_mad_element )\r
2561 {\r
2562         al_mad_rmpp_t           *p_rmpp;\r
2563         al_mad_element_t        *p_al_element;\r
2564 \r
2565         p_al_element = PARENT_STRUCT( p_mad_element, al_mad_element_t, element );\r
2566 \r
2567         /* Get an RMPP tracking structure. */\r
2568         p_rmpp = get_mad_rmpp( p_al_element );\r
2569         if( !p_rmpp )\r
2570                 return NULL;\r
2571 \r
2572         /* Initialize the tracking information. */\r
2573         p_rmpp->expected_seg = 1;\r
2574         p_rmpp->seg_limit = 1;\r
2575         p_rmpp->inactive = FALSE;\r
2576         p_rmpp->p_mad_element = p_mad_element;\r
2577 \r
2578         /* Insert the tracking structure into the reassembly list. */\r
2579         cl_qlist_insert_tail( &h_mad_svc->recv_list,\r
2580                 (cl_list_item_t*)&p_rmpp->pool_item );\r
2581 \r
2582         return p_rmpp;\r
2583 }\r
2584 \r
2585 \r
2586 \r
2587 /*\r
2588  * Return the RMPP tracking structure.  This call assumes access to\r
2589  * the recv_list is synchronized.\r
2590  */\r
2591 static void\r
2592 __put_mad_rmpp(\r
2593         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
2594         IN                              al_mad_rmpp_t                           *p_rmpp )\r
2595 {\r
2596         /* Remove the tracking structure from the reassembly list. */\r
2597         cl_qlist_remove_item( &h_mad_svc->recv_list,\r
2598                 (cl_list_item_t*)&p_rmpp->pool_item );\r
2599 \r
2600         /* Return the RMPP tracking structure. */\r
2601         put_mad_rmpp( p_rmpp );\r
2602 }\r
2603 \r
2604 \r
2605 \r
2606 /*\r
2607  * Process a received RMPP segment.  Copy the data into our receive buffer,\r
2608  * update the expected segment, and send an ACK if needed.\r
2609  */\r
2610 static cl_status_t\r
2611 __process_segment(\r
2612         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
2613         IN                              al_mad_rmpp_t                           *p_rmpp,\r
2614         IN      OUT                     ib_mad_element_t                        **pp_mad_element,\r
2615                 OUT                     ib_mad_element_t                        **pp_rmpp_resp_mad )\r
2616 {\r
2617         ib_rmpp_mad_t                   *p_rmpp_hdr;\r
2618         uint32_t                                cur_seg;\r
2619         ib_api_status_t                 status;\r
2620         cl_status_t                             cl_status;\r
2621         uint8_t                                 *p_dst_seg, *p_src_seg;\r
2622         uint32_t                                paylen;\r
2623 \r
2624         CL_ASSERT( h_mad_svc && p_rmpp && pp_mad_element && *pp_mad_element );\r
2625 \r
2626         p_rmpp_hdr = (ib_rmpp_mad_t*)(*pp_mad_element)->p_mad_buf;\r
2627         cur_seg = cl_ntoh32( p_rmpp_hdr->seg_num );\r
2628         CL_ASSERT( cur_seg == p_rmpp->expected_seg );\r
2629         CL_ASSERT( cur_seg <= p_rmpp->seg_limit );\r
2630 \r
2631         /* See if the receive has been fully reassembled. */\r
2632         if( ib_rmpp_is_flag_set( p_rmpp_hdr, IB_RMPP_FLAG_LAST ) )\r
2633                 cl_status = CL_SUCCESS;\r
2634         else\r
2635                 cl_status = CL_NOT_DONE;\r
2636         \r
2637         /* Save the payload length for later use. */\r
2638         paylen = cl_ntoh32(p_rmpp_hdr->paylen_newwin);\r
2639 \r
2640         /* The element of the first segment starts the reasembly. */\r
2641         if( *pp_mad_element != p_rmpp->p_mad_element )\r
2642         {\r
2643                 /* SA MADs require extra header size ... */\r
2644                 if( (*pp_mad_element)->p_mad_buf->mgmt_class == IB_MCLASS_SUBN_ADM )\r
2645                 {\r
2646                         /* Copy the received data into our reassembly buffer. */\r
2647                         p_src_seg = ((uint8_t* __ptr64)(*pp_mad_element)->p_mad_buf) +\r
2648                                 IB_SA_MAD_HDR_SIZE;\r
2649                         p_dst_seg = ((uint8_t* __ptr64)p_rmpp->p_mad_element->p_mad_buf) +\r
2650                                 IB_SA_MAD_HDR_SIZE + IB_SA_DATA_SIZE * (cur_seg - 1);\r
2651                         cl_memcpy( p_dst_seg, p_src_seg, IB_SA_DATA_SIZE );\r
2652                 }\r
2653                 else \r
2654                 {\r
2655                         /* Copy the received data into our reassembly buffer. */\r
2656                         p_src_seg = ((uint8_t* __ptr64)(*pp_mad_element)->p_mad_buf) +\r
2657                                 MAD_RMPP_HDR_SIZE;\r
2658                         p_dst_seg = ((uint8_t* __ptr64)p_rmpp->p_mad_element->p_mad_buf) +\r
2659                                 MAD_RMPP_HDR_SIZE + MAD_RMPP_DATA_SIZE * (cur_seg - 1);\r
2660                         cl_memcpy( p_dst_seg, p_src_seg, MAD_RMPP_DATA_SIZE );\r
2661                 }\r
2662                 /* This MAD is no longer needed. */\r
2663                 ib_put_mad( *pp_mad_element );\r
2664         }\r
2665 \r
2666         /* Update the size of the mad if the last segment */\r
2667         if ( cl_status == CL_SUCCESS )\r
2668         {\r
2669                 if (p_rmpp->p_mad_element->p_mad_buf->mgmt_class == IB_MCLASS_SUBN_ADM )\r
2670                 {\r
2671                         /*\r
2672                          * Note we will get one extra SA Hdr size in the paylen, \r
2673                          * so we only take the rmpp header size of the first segment.\r
2674                          */\r
2675                         p_rmpp->p_mad_element->size = \r
2676                                 MAD_RMPP_HDR_SIZE + IB_SA_DATA_SIZE *(cur_seg - 1) + paylen;\r
2677                 }\r
2678                 else\r
2679                 {\r
2680                          p_rmpp->p_mad_element->size = \r
2681                                 MAD_RMPP_HDR_SIZE + MAD_RMPP_DATA_SIZE * (cur_seg - 1) + paylen;\r
2682                 }\r
2683         }\r
2684 \r
2685         /*\r
2686          * We are ready to accept the next segment.  We increment expected segment\r
2687          * even if we're done, so that ACKs correctly report the last segment.\r
2688          */\r
2689         p_rmpp->expected_seg++;\r
2690 \r
2691         /* Mark the RMPP as active if we're not destroying the MAD service. */\r
2692         p_rmpp->inactive = (h_mad_svc->obj.state == CL_DESTROYING);\r
2693 \r
2694         /* See if the receive has been fully reassembled. */\r
2695         if( cl_status == CL_NOT_DONE && cur_seg == p_rmpp->seg_limit )\r
2696         {\r
2697                 /* Allocate more segments for the incoming receive. */\r
2698                 status = al_resize_mad( p_rmpp->p_mad_element,\r
2699                         p_rmpp->p_mad_element->size + AL_RMPP_WINDOW * MAD_RMPP_DATA_SIZE );\r
2700 \r
2701                 /* If we couldn't allocate a new buffer, just drop the MAD. */\r
2702                 if( status == IB_SUCCESS )\r
2703                 {\r
2704                         /* Send an ACK indicating that more space is available. */\r
2705                         p_rmpp->seg_limit += AL_RMPP_WINDOW;\r
2706                         *pp_rmpp_resp_mad = __get_rmpp_ack( p_rmpp );\r
2707                 }\r
2708         }\r
2709         else if( cl_status == CL_SUCCESS )\r
2710         {\r
2711                 /* Return the element referencing the reassembled MAD. */\r
2712                 *pp_mad_element = p_rmpp->p_mad_element;\r
2713                 *pp_rmpp_resp_mad = __get_rmpp_ack( p_rmpp );\r
2714         }\r
2715 \r
2716         return cl_status;\r
2717 }\r
2718 \r
2719 \r
2720 \r
2721 /*\r
2722  * Get an ACK message to return to the sender of an RMPP MAD.\r
2723  */\r
2724 static ib_mad_element_t*\r
2725 __get_rmpp_ack(\r
2726         IN                              al_mad_rmpp_t                           *p_rmpp )\r
2727 {\r
2728         ib_mad_element_t                *p_mad_element;\r
2729         al_mad_element_t                *p_al_element;\r
2730         ib_api_status_t                 status;\r
2731         ib_rmpp_mad_t                   *p_ack_rmpp_hdr, *p_data_rmpp_hdr;\r
2732 \r
2733         /* Get a MAD to carry the ACK. */\r
2734         p_al_element = PARENT_STRUCT( p_rmpp->p_mad_element,\r
2735                 al_mad_element_t, element );\r
2736         status = ib_get_mad( p_al_element->pool_key, MAD_BLOCK_SIZE,\r
2737                 &p_mad_element );\r
2738         if( status != IB_SUCCESS )\r
2739         {\r
2740                 /* Just return.  The ACK will be treated as being dropped. */\r
2741                 return NULL;\r
2742         }\r
2743 \r
2744         /* Format the ACK. */\r
2745         p_ack_rmpp_hdr = ib_get_mad_buf( p_mad_element );\r
2746         p_data_rmpp_hdr = ib_get_mad_buf( p_rmpp->p_mad_element );\r
2747 \r
2748         __init_reply_element( p_mad_element, p_rmpp->p_mad_element );\r
2749 \r
2750         /* Copy the MAD common header. */\r
2751         cl_memcpy( &p_ack_rmpp_hdr->common_hdr, &p_data_rmpp_hdr->common_hdr,\r
2752                 sizeof( ib_mad_t ) );\r
2753 \r
2754         /* Reset the status (in case the BUSY bit is set). */\r
2755         p_ack_rmpp_hdr->common_hdr.status = 0;\r
2756 \r
2757         /* Flip the response bit in the method */\r
2758         p_ack_rmpp_hdr->common_hdr.method ^= IB_MAD_METHOD_RESP_MASK;\r
2759 \r
2760         p_ack_rmpp_hdr->rmpp_version = p_data_rmpp_hdr->rmpp_version;\r
2761         p_ack_rmpp_hdr->rmpp_type = IB_RMPP_TYPE_ACK;\r
2762         ib_rmpp_set_resp_time( p_ack_rmpp_hdr, IB_RMPP_NO_RESP_TIME );\r
2763         p_ack_rmpp_hdr->rmpp_flags |= IB_RMPP_FLAG_ACTIVE;\r
2764         p_ack_rmpp_hdr->rmpp_status = IB_RMPP_STATUS_SUCCESS;\r
2765 \r
2766         p_ack_rmpp_hdr->seg_num = cl_hton32( p_rmpp->expected_seg - 1 );\r
2767 \r
2768         if (p_rmpp->seg_limit == p_rmpp->expected_seg - 1 &&\r
2769                 !ib_rmpp_is_flag_set( p_data_rmpp_hdr, IB_RMPP_FLAG_LAST ) )\r
2770         {\r
2771                 p_ack_rmpp_hdr->paylen_newwin = cl_hton32( 1 + p_rmpp->seg_limit);\r
2772         }\r
2773         else\r
2774         {\r
2775                 p_ack_rmpp_hdr->paylen_newwin = cl_hton32( p_rmpp->seg_limit );\r
2776         }\r
2777 \r
2778         return p_mad_element;\r
2779 }\r
2780 \r
2781 \r
2782 \r
2783 /*\r
2784  * Copy necessary data between MAD elements to allow the destination\r
2785  * element to be sent to the sender of the source element.\r
2786  */\r
2787 static void\r
2788 __init_reply_element(\r
2789         IN                              ib_mad_element_t                        *p_dst_element,\r
2790         IN                              ib_mad_element_t                        *p_src_element )\r
2791 {\r
2792         p_dst_element->remote_qp = p_src_element->remote_qp;\r
2793         p_dst_element->remote_qkey = p_src_element->remote_qkey;\r
2794 \r
2795         if( p_src_element->grh_valid )\r
2796         {\r
2797                 p_dst_element->grh_valid = p_src_element->grh_valid;\r
2798                 cl_memcpy( p_dst_element->p_grh, p_src_element->p_grh,\r
2799                         sizeof( ib_grh_t ) );\r
2800         }\r
2801 \r
2802         p_dst_element->remote_lid = p_src_element->remote_lid;\r
2803         p_dst_element->remote_sl = p_src_element->remote_sl;\r
2804         p_dst_element->pkey_index = p_src_element->pkey_index;\r
2805         p_dst_element->path_bits = p_src_element->path_bits;\r
2806 }\r
2807 \r
2808 \r
2809 \r
2810 /*\r
2811  * Process an RMPP ACK message.  Continue sending addition segments.\r
2812  */\r
2813 static void\r
2814 __process_rmpp_ack(\r
2815         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
2816         IN                              ib_mad_element_t                        *p_mad_element )\r
2817 {\r
2818         ib_mad_send_handle_t    h_send;\r
2819         ib_rmpp_mad_t                   *p_rmpp_mad;\r
2820         boolean_t                               send_done = FALSE;\r
2821         ib_wc_status_t                  wc_status = IB_WCS_SUCCESS;\r
2822 \r
2823         AL_ENTER( AL_DBG_MAD_SVC );\r
2824         p_rmpp_mad = (ib_rmpp_mad_t*)ib_get_mad_buf( p_mad_element );\r
2825 \r
2826         /*\r
2827          * Search for the send.  The send may have timed out, been canceled,\r
2828          * or received a response.\r
2829          */\r
2830         cl_spinlock_acquire( &h_mad_svc->obj.lock );\r
2831         h_send = __mad_svc_match_recv( h_mad_svc, p_mad_element );\r
2832         if( !h_send )\r
2833         {\r
2834                 cl_spinlock_release( &h_mad_svc->obj.lock );\r
2835                 AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC,\r
2836                         ("ACK cannot find a matching send\n") );\r
2837                 return;\r
2838         }\r
2839 \r
2840         /* Drop old ACKs. */\r
2841         if( cl_ntoh32( p_rmpp_mad->seg_num ) < h_send->ack_seg )\r
2842         {\r
2843                 cl_spinlock_release( &h_mad_svc->obj.lock );\r
2844                 AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC,\r
2845                         ("old ACK - being dropped\n") );\r
2846                 return;\r
2847         }\r
2848 \r
2849         /* Update the acknowledged segment and segment limit. */\r
2850         h_send->ack_seg = cl_ntoh32( p_rmpp_mad->seg_num );\r
2851 \r
2852         /* Keep seg_limit <= total_seg to simplify checks. */\r
2853         if( cl_ntoh32( p_rmpp_mad->paylen_newwin ) > h_send->total_seg )\r
2854                 h_send->seg_limit = h_send->total_seg;\r
2855         else\r
2856                 h_send->seg_limit = cl_ntoh32( p_rmpp_mad->paylen_newwin );\r
2857 \r
2858         /* Reset the current segment to start resending from the ACK. */\r
2859         h_send->cur_seg = h_send->ack_seg + 1;\r
2860 \r
2861         /* If the send is active, we will finish processing it once it completes. */\r
2862         if( h_send->retry_time == MAX_TIME )\r
2863         {\r
2864                 cl_spinlock_release( &h_mad_svc->obj.lock );\r
2865                 AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC,\r
2866                         ("ACK processed, waiting for send to complete\n") );\r
2867                 return;\r
2868         }\r
2869 \r
2870         /*\r
2871          * Complete the send if all segments have been ack'ed and no\r
2872          * response is expected.  (If the response for a send had already been\r
2873          * received, we would have reported the completion regardless of the\r
2874          * send having been ack'ed.)\r
2875          */\r
2876         CL_ASSERT( !h_send->p_send_mad->resp_expected || !h_send->p_resp_mad );\r
2877         if( (h_send->ack_seg == h_send->total_seg) &&\r
2878                 !h_send->p_send_mad->resp_expected )\r
2879         {\r
2880                 /* The send is done.  All segments have been ack'ed. */\r
2881                 send_done = TRUE;\r
2882         }\r
2883         else if( h_send->ack_seg < h_send->seg_limit )\r
2884         {\r
2885                 /* Send the next segment. */\r
2886                 __queue_rmpp_seg( h_mad_svc->h_mad_reg, h_send );\r
2887         }\r
2888 \r
2889         if( send_done )\r
2890         {\r
2891                 /* Notify the user of a send completion or error. */\r
2892                 cl_qlist_remove_item( &h_mad_svc->send_list,\r
2893                         (cl_list_item_t*)&h_send->pool_item );\r
2894                 cl_spinlock_release( &h_mad_svc->obj.lock );\r
2895                 __notify_send_comp( h_mad_svc, h_send, wc_status );\r
2896         }\r
2897         else\r
2898         {\r
2899                 /* Continue waiting for a response or a larger send window. */\r
2900                 cl_spinlock_release( &h_mad_svc->obj.lock );\r
2901         }\r
2902 \r
2903         /*\r
2904          * Resume any sends that can now be sent without holding\r
2905          * the mad service lock.\r
2906          */\r
2907         __mad_disp_resume_send( h_mad_svc->h_mad_reg );\r
2908 \r
2909         AL_EXIT( AL_DBG_MAD_SVC );\r
2910 }\r
2911 \r
2912 \r
2913 \r
2914 /*\r
2915  * Process an RMPP STOP or ABORT message.\r
2916  */\r
2917 static void\r
2918 __process_rmpp_nack(\r
2919         IN                              ib_mad_svc_handle_t                     h_mad_svc,\r
2920         IN                              ib_mad_element_t                        *p_mad_element )\r
2921 {\r
2922         ib_mad_send_handle_t    h_send;\r
2923         ib_rmpp_mad_t                   *p_rmpp_mad;\r
2924 \r
2925         AL_ENTER( AL_DBG_MAD_SVC );\r
2926         p_rmpp_mad = (ib_rmpp_mad_t*)ib_get_mad_buf( p_mad_element );\r
2927 \r
2928         /* Search for the send.  The send may have timed out or been canceled. */\r
2929         cl_spinlock_acquire( &h_mad_svc->obj.lock );\r
2930         h_send = __mad_svc_match_recv( h_mad_svc, p_mad_element );\r
2931         if( !h_send )\r
2932         {\r
2933                 cl_spinlock_release( &h_mad_svc->obj.lock );\r
2934                 return;\r
2935         }\r
2936 \r
2937         /* If the send is active, we will finish processing it once it completes. */\r
2938         if( h_send->retry_time == MAX_TIME )\r
2939         {\r
2940                 h_send->canceled = TRUE;\r
2941                 cl_spinlock_release( &h_mad_svc->obj.lock );\r
2942                 AL_EXIT( AL_DBG_MAD_SVC );\r
2943                 return;\r
2944         }\r
2945 \r
2946         /* Fail the send operation. */\r
2947         cl_qlist_remove_item( &h_mad_svc->send_list,\r
2948                 (cl_list_item_t*)&h_send->pool_item );\r
2949         cl_spinlock_release( &h_mad_svc->obj.lock );\r
2950         __notify_send_comp( h_mad_svc, h_send, IB_WCS_CANCELED );\r
2951 \r
2952         AL_EXIT( AL_DBG_MAD_SVC );\r
2953 }\r
2954 \r
2955 \r
2956 \r
2957 static __inline void\r
2958 __set_retry_time(\r
2959         IN                              ib_mad_send_handle_t            h_send )\r
2960 {\r
2961         h_send->retry_time =\r
2962                 (uint64_t)(h_send->p_send_mad->timeout_ms + h_send->delay) * 1000Ui64 +\r
2963                 cl_get_time_stamp();\r
2964         h_send->delay = 0;\r
2965 }\r
2966 \r
2967 \r
2968 \r
2969 static void\r
2970 __send_timer_cb(\r
2971         IN                              void                                            *context )\r
2972 {\r
2973         AL_ENTER( AL_DBG_MAD_SVC );\r
2974 \r
2975         __check_send_queue( (ib_mad_svc_handle_t)context );\r
2976 \r
2977         AL_EXIT( AL_DBG_MAD_SVC );\r
2978 }\r
2979 \r
2980 \r
2981 \r
2982 /*\r
2983  * Check the send queue for any sends that have timed out or were canceled\r
2984  * by the user.\r
2985  */\r
2986 static void\r
2987 __check_send_queue(\r
2988         IN                              ib_mad_svc_handle_t                     h_mad_svc )\r
2989 {\r
2990         ib_mad_send_handle_t    h_send;\r
2991         cl_list_item_t                  *p_list_item, *p_next_item;\r
2992         uint64_t                                cur_time;\r
2993         cl_qlist_t                              timeout_list;\r
2994 \r
2995         AL_ENTER( AL_DBG_MAD_SVC );\r
2996 \r
2997         /*\r
2998          * The timeout out list is used to call the user back without\r
2999          * holding the lock on the MAD service.\r
3000          */\r
3001         cl_qlist_init( &timeout_list );\r
3002         cur_time = cl_get_time_stamp();\r
3003 \r
3004         cl_spinlock_acquire( &h_mad_svc->obj.lock );\r
3005 \r
3006         /* Check all outstanding sends. */\r
3007         for( p_list_item = cl_qlist_head( &h_mad_svc->send_list );\r
3008                  p_list_item != cl_qlist_end( &h_mad_svc->send_list );\r
3009                  p_list_item = p_next_item )\r
3010         {\r
3011                 p_next_item = cl_qlist_next( p_list_item );\r
3012                 h_send = PARENT_STRUCT( p_list_item, al_mad_send_t, pool_item );\r
3013 \r
3014                 /* See if the request is active. */\r
3015                 if( h_send->retry_time == MAX_TIME )\r
3016                 {\r
3017                         /* The request is still active. */\r
3018                         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("active TID:0x%I64x\n",\r
3019                                 __get_send_tid( h_send )) );\r
3020                         continue;\r
3021                 }\r
3022 \r
3023                 /* The request is not active. */\r
3024                 /* See if the request has been canceled. */\r
3025                 if( h_send->canceled )\r
3026                 {\r
3027                         /* The request has been canceled. */\r
3028                         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("canceling TID:0x%I64x\n",\r
3029                                 __get_send_tid( h_send )) );\r
3030 \r
3031                         h_send->p_send_mad->status = IB_WCS_CANCELED;\r
3032                         cl_qlist_remove_item( &h_mad_svc->send_list, p_list_item );\r
3033                         cl_qlist_insert_tail( &timeout_list, p_list_item );\r
3034                         continue;\r
3035                 }\r
3036 \r
3037                 /* Skip requests that have not timed out. */\r
3038                 if( cur_time < h_send->retry_time )\r
3039                 {\r
3040                         /* The request has not timed out. */\r
3041                         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("waiting on TID:0x%I64x\n",\r
3042                                 __get_send_tid( h_send )) );\r
3043 \r
3044                         /* Set the retry timer to the minimum needed time, in ms. */\r
3045                         cl_timer_trim( &h_mad_svc->send_timer,\r
3046                                 ((uint32_t)(h_send->retry_time - cur_time) / 1000) );\r
3047                         continue;\r
3048                 }\r
3049 \r
3050                 /* See if we need to retry the send operation. */\r
3051                 if( h_send->retry_cnt )\r
3052                 {\r
3053                         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_MAD_SVC, ("retrying TID:0x%I64x\n",\r
3054                                 __get_send_tid( h_send )) );\r
3055 \r
3056                         /* Retry the send. */\r
3057                         h_send->retry_time = MAX_TIME;\r
3058                         h_send->retry_cnt--;\r
3059 \r
3060                         if( h_send->uses_rmpp )\r
3061                         {\r
3062                                 if( h_send->ack_seg < h_send->seg_limit )\r
3063                                 {\r
3064                                         /* Resend all unacknowledged segments. */\r
3065                                         h_send->cur_seg = h_send->ack_seg + 1;\r
3066                                         __queue_rmpp_seg( h_mad_svc->h_mad_reg, h_send );\r
3067                                 }\r
3068                                 else\r
3069                                 {\r
3070                                         /* The send was delivered.  Continue waiting. */\r
3071                                         __set_retry_time( h_send );\r
3072                                         cl_timer_trim( &h_mad_svc->send_timer,\r
3073                                                 ((uint32_t)(h_send->retry_time - cur_time) / 1000) );\r
3074                                 }\r
3075                         }\r
3076                         else\r
3077                         {\r
3078                                 /* The work request should already be formatted properly. */\r
3079                                 __mad_disp_queue_send( h_mad_svc->h_mad_reg,\r
3080                                         &h_send->mad_wr );\r
3081                         }\r
3082                         continue;\r
3083                 }\r
3084                 /* The request has timed out or failed to be retried. */\r
3085                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_MAD_SVC,\r
3086                         ("timing out TID:0x%I64x\n", __get_send_tid( h_send )) );\r
3087 \r
3088                 h_send->p_send_mad->status = IB_WCS_TIMEOUT_RETRY_ERR;\r
3089                 cl_qlist_remove_item( &h_mad_svc->send_list, p_list_item );\r
3090                 cl_qlist_insert_tail( &timeout_list, p_list_item );\r
3091         }\r
3092 \r
3093         cl_spinlock_release( &h_mad_svc->obj.lock );\r
3094 \r
3095         /*\r
3096          * Resume any sends that can now be sent without holding\r
3097          * the mad service lock.\r
3098          */\r
3099         __mad_disp_resume_send( h_mad_svc->h_mad_reg );\r
3100 \r
3101         /* Report all timed out sends to the user. */\r
3102         p_list_item = cl_qlist_remove_head( &timeout_list );\r
3103         while( p_list_item != cl_qlist_end( &timeout_list ) )\r
3104         {\r
3105                 h_send = PARENT_STRUCT( p_list_item, al_mad_send_t, pool_item );\r
3106 \r
3107                 h_mad_svc->pfn_user_send_cb( h_mad_svc, (void*)h_mad_svc->obj.context,\r
3108                         h_send->p_send_mad );\r
3109                 __cleanup_mad_send( h_mad_svc, h_send );\r
3110                 p_list_item = cl_qlist_remove_head( &timeout_list );\r
3111         }\r
3112         AL_EXIT( AL_DBG_MAD_SVC );\r
3113 }\r
3114 \r
3115 \r
3116 \r
3117 static void\r
3118 __recv_timer_cb(\r
3119         IN                              void                                            *context )\r
3120 {\r
3121         ib_mad_svc_handle_t             h_mad_svc;\r
3122         al_mad_rmpp_t                   *p_rmpp;\r
3123         cl_list_item_t                  *p_list_item, *p_next_item;\r
3124         boolean_t                               restart_timer;\r
3125 \r
3126         AL_ENTER( AL_DBG_MAD_SVC );\r
3127 \r
3128         h_mad_svc = (ib_mad_svc_handle_t)context;\r
3129 \r
3130         cl_spinlock_acquire( &h_mad_svc->obj.lock );\r
3131 \r
3132         /* Check all outstanding receives. */\r
3133         for( p_list_item = cl_qlist_head( &h_mad_svc->recv_list );\r
3134                  p_list_item != cl_qlist_end( &h_mad_svc->recv_list );\r
3135                  p_list_item = p_next_item )\r
3136         {\r
3137                 p_next_item = cl_qlist_next( p_list_item );\r
3138                 p_rmpp = PARENT_STRUCT( p_list_item, al_mad_rmpp_t, pool_item );\r
3139 \r
3140                 /* Fail all RMPP MADs that have remained inactive. */\r
3141                 if( p_rmpp->inactive )\r
3142                 {\r
3143                         ib_put_mad( p_rmpp->p_mad_element );\r
3144                         __put_mad_rmpp( h_mad_svc, p_rmpp );\r
3145                 }\r
3146                 else\r
3147                 {\r
3148                         /* Mark the RMPP as inactive. */\r
3149                          p_rmpp->inactive = TRUE;\r
3150                 }\r
3151         }\r
3152 \r
3153         restart_timer = !cl_is_qlist_empty( &h_mad_svc->recv_list );\r
3154         cl_spinlock_release( &h_mad_svc->obj.lock );\r
3155 \r
3156         if( restart_timer )\r
3157                 cl_timer_start( &h_mad_svc->recv_timer, AL_REASSEMBLY_TIMEOUT );\r
3158         AL_EXIT( AL_DBG_MAD_SVC );\r
3159 }\r
3160 \r
3161 \r
3162 \r
3163 ib_api_status_t\r
3164 ib_local_mad(\r
3165         IN              const   ib_ca_handle_t                          h_ca,\r
3166         IN              const   uint8_t                                         port_num,\r
3167         IN              const   void* const                                     p_mad_in,\r
3168         IN                              void*                                           p_mad_out )\r
3169 {\r
3170         ib_api_status_t                 status;\r
3171 \r
3172         AL_ENTER( AL_DBG_MAD_SVC );\r
3173 \r
3174         if( AL_OBJ_INVALID_HANDLE( h_ca, AL_OBJ_TYPE_H_CA ) )\r
3175         {\r
3176                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_CA_HANDLE\n") );\r
3177                 return IB_INVALID_CA_HANDLE;\r
3178         }\r
3179         if( !p_mad_in || !p_mad_out )\r
3180         {\r
3181                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
3182                 return IB_INVALID_PARAMETER;\r
3183         }\r
3184 \r
3185         status = verbs_local_mad( h_ca, port_num, p_mad_in, p_mad_out );\r
3186 \r
3187         AL_EXIT( AL_DBG_MAD_SVC );\r
3188         return status;\r
3189 }\r
3190 \r
3191 \r
3192 \r
3193 ib_net32_t\r
3194 al_get_user_tid(\r
3195         IN              const   ib_net64_t                                              tid64 )\r
3196 {\r
3197         al_tid_t                al_tid;\r
3198 \r
3199         al_tid.tid64 = tid64;\r
3200         return( al_tid.tid32.user_tid );\r
3201 }\r
3202 \r
3203 uint32_t\r
3204 al_get_al_tid(\r
3205         IN              const   ib_net64_t                                              tid64 )\r
3206 {\r
3207         al_tid_t                al_tid;\r
3208 \r
3209         al_tid.tid64 = tid64;\r
3210         return( cl_ntoh32( al_tid.tid32.al_tid ) );\r
3211 }\r
3212 \r
3213 void\r
3214 al_set_al_tid(\r
3215         IN                              ib_net64_t*             const                   p_tid64,\r
3216         IN              const   uint32_t                                                tid32 )\r
3217 {\r
3218         al_tid_t                *p_al_tid;\r
3219 \r
3220         p_al_tid = (al_tid_t*)p_tid64;\r
3221 \r
3222         if( tid32 )\r
3223         {\r
3224                 CL_ASSERT( !p_al_tid->tid32.al_tid );\r
3225         }\r
3226 \r
3227         p_al_tid->tid32.al_tid = cl_hton32( tid32 );\r
3228 }\r