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