[IPoIB NDIS 6.0 CM]
[mirror/winof/.git] / ulp / ipoib_NDIS6_CM / kernel / ipoib_endpoint.cpp
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  * Copyright (c) 2006 Mellanox Technologies.  All rights reserved.\r
4  * Portions Copyright (c) 2008 Microsoft Corporation.  All rights reserved.\r
5  *\r
6  * This software is available to you under the OpenIB.org BSD license\r
7  * below:\r
8  *\r
9  *     Redistribution and use in source and binary forms, with or\r
10  *     without modification, are permitted provided that the following\r
11  *     conditions are met:\r
12  *\r
13  *      - Redistributions of source code must retain the above\r
14  *        copyright notice, this list of conditions and the following\r
15  *        disclaimer.\r
16  *\r
17  *      - Redistributions in binary form must reproduce the above\r
18  *        copyright notice, this list of conditions and the following\r
19  *        disclaimer in the documentation and/or other materials\r
20  *        provided with the distribution.\r
21  *\r
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
23  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
25  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
26  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
27  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
28  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
29  * SOFTWARE.\r
30  *\r
31  * $Id: ipoib_endpoint.c 4226 2009-04-06 06:01:03Z xalex $\r
32  */\r
33 \r
34 \r
35 \r
36 #include "ipoib_endpoint.h"\r
37 #include "ipoib_port.h"\r
38 #include "ipoib_debug.h"\r
39 #if defined(EVENT_TRACING)\r
40 #ifdef offsetof\r
41 #undef offsetof\r
42 #endif\r
43 #include "ipoib_endpoint.tmh"\r
44 #endif\r
45 #include <complib/cl_atomic.h>\r
46 #include <complib/cl_math.h>\r
47 \r
48 \r
49 static void\r
50 __endpt_destroying(\r
51         IN                              cl_obj_t*                                       p_obj );\r
52 \r
53 static void\r
54 __endpt_cleanup(\r
55         IN                              cl_obj_t*                                       p_obj );\r
56 \r
57 static void\r
58 __endpt_free(\r
59         IN                              cl_obj_t*                                       p_obj );\r
60 \r
61 static ib_api_status_t\r
62 __create_mcast_av(\r
63         IN                              ib_pd_handle_t                          h_pd,\r
64         IN                              uint8_t                                         port_num,\r
65         IN                              ib_member_rec_t* const          p_member_rec,\r
66                 OUT                     ib_av_handle_t* const           ph_av );\r
67 \r
68 static inline ipoib_port_t*\r
69 __endpt_parent(\r
70         IN                              ipoib_endpt_t* const            p_endpt );\r
71 \r
72 static void\r
73 __path_query_cb(\r
74         IN                              ib_query_rec_t                          *p_query_rec );\r
75 \r
76 static void\r
77 __endpt_resolve(\r
78         IN                              ipoib_endpt_t* const            p_endpt );\r
79 \r
80 static void\r
81 __endpt_cm_send_cb(\r
82         IN              const   ib_cq_handle_t                  h_cq,\r
83         IN                              void                                    *cq_context );\r
84 static void\r
85 __endpt_cm_recv_cb(\r
86         IN              const   ib_cq_handle_t                  h_cq,\r
87         IN                              void                                    *cq_context );\r
88 \r
89 static void\r
90 __endpt_cm_buf_mgr_construct(\r
91         IN              endpt_buf_mgr_t * const         p_buf_mgr );\r
92 static void\r
93 __conn_reply_cb(\r
94         IN              ib_cm_rep_rec_t                 *p_cm_rep );\r
95 \r
96 static void\r
97 __conn_mra_cb(\r
98         IN              ib_cm_mra_rec_t                 *p_mra_rec );\r
99 \r
100 static void\r
101 __conn_rej_cb(\r
102         IN              ib_cm_rej_rec_t                 *p_rej_rec );\r
103 \r
104 static void\r
105 __conn_dreq_cb(\r
106          IN     ib_cm_dreq_rec_t                        *p_dreq_rec );\r
107 \r
108 #if 0 //CM\r
109 static cl_status_t\r
110 __cm_recv_desc_ctor(\r
111         IN              void* const                                     p_object,\r
112         IN              void*                                           context,\r
113         OUT             cl_pool_item_t** const          pp_pool_item );\r
114 \r
115 static void\r
116 __cm_recv_desc_dtor(\r
117         IN              const   cl_pool_item_t* const           p_pool_item,\r
118         IN                              void                                            *context );\r
119 \r
120 static NDIS_PACKET*\r
121 __endpt_cm_get_ndis_pkt(\r
122         IN              ipoib_port_t* const                     p_port,\r
123         IN              ipoib_cm_desc_t* const          p_desc );\r
124 \r
125 static inline ipoib_cm_desc_t*\r
126 __endpt_cm_buf_mgr_get_recv(\r
127         IN              endpt_buf_mgr_t * const         p_buf_mgr );\r
128 \r
129 static boolean_t\r
130 __cm_recv_is_dhcp(\r
131         IN              const ipoib_pkt_t* const        p_ipoib );\r
132 \r
133 static ib_api_status_t\r
134 __endpt_cm_recv_arp(\r
135         IN              ipoib_port_t* const                     p_port,\r
136         IN              const   ipoib_pkt_t* const      p_ipoib,\r
137         OUT             eth_pkt_t* const                        p_eth,\r
138         IN              ipoib_endpt_t* const            p_src_endpt );\r
139 \r
140 static ib_api_status_t\r
141 __endpt_cm_recv_udp(\r
142         IN              ipoib_port_t* const                     p_port,\r
143         IN              ib_wc_t* const                          p_wc,\r
144         IN              const   ipoib_pkt_t* const      p_ipoib,\r
145         OUT             eth_pkt_t* const                        p_eth,\r
146         IN              ipoib_endpt_t* const            p_src_endpt );\r
147 #endif\r
148 \r
149 ipoib_endpt_t*\r
150 ipoib_endpt_create(\r
151         IN              const   ib_gid_t* const                         p_dgid,\r
152         IN              const   net16_t                                         dlid,\r
153         IN              const   net32_t                                         qpn )\r
154 {\r
155         ipoib_endpt_t   *p_endpt;\r
156         cl_status_t             status;\r
157 \r
158         IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
159 \r
160         p_endpt = (ipoib_endpt_t *) cl_zalloc( sizeof(ipoib_endpt_t) );\r
161         if( !p_endpt )\r
162         {\r
163                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
164                         ("Failed to allocate endpoint (%d bytes)\n",\r
165                         sizeof(ipoib_endpt_t)) );\r
166                 return NULL;\r
167         }\r
168 \r
169         cl_obj_construct( &p_endpt->obj, IPOIB_OBJ_ENDPOINT );\r
170 \r
171         status = cl_obj_init( &p_endpt->obj, CL_DESTROY_ASYNC,\r
172                 __endpt_destroying, __endpt_cleanup, __endpt_free );\r
173 \r
174         IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT,\r
175                 ("Created endpoint: [ %p ] DLID: %#x QPN: %#x \n", \r
176                 p_endpt, cl_ntoh16(dlid), cl_ntoh32(qpn) ) );\r
177 \r
178         p_endpt->dgid = *p_dgid;\r
179         p_endpt->dlid = dlid;\r
180         p_endpt->qpn = qpn;\r
181 \r
182         IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
183         return p_endpt;\r
184 }\r
185 \r
186 \r
187 static ib_api_status_t\r
188 __create_mcast_av(\r
189         IN                              ib_pd_handle_t                          h_pd,\r
190         IN                              uint8_t                                         port_num,\r
191         IN                              ib_member_rec_t* const          p_member_rec,\r
192                 OUT                     ib_av_handle_t* const           ph_av )\r
193 {\r
194         ib_av_attr_t    av_attr;\r
195         uint32_t                flow_lbl;\r
196         uint8_t                 hop_lmt;\r
197         ib_api_status_t status;\r
198         ipoib_endpt_t   *p_endpt;\r
199 \r
200         IPOIB_ENTER( IPOIB_DBG_MCAST );\r
201 \r
202         p_endpt = PARENT_STRUCT(ph_av, ipoib_endpt_t, h_av );\r
203 \r
204         cl_memclr( &av_attr, sizeof(ib_av_attr_t) );\r
205         av_attr.port_num = port_num;\r
206         ib_member_get_sl_flow_hop( p_member_rec->sl_flow_hop,\r
207                 &av_attr.sl, &flow_lbl, &hop_lmt );\r
208         av_attr.dlid = p_member_rec->mlid;\r
209         av_attr.grh_valid = TRUE;\r
210         av_attr.grh.hop_limit = hop_lmt;\r
211         av_attr.grh.dest_gid = p_member_rec->mgid;\r
212         av_attr.grh.src_gid = p_member_rec->port_gid;\r
213         av_attr.grh.ver_class_flow =\r
214                 ib_grh_set_ver_class_flow( 6, p_member_rec->tclass, flow_lbl );\r
215         av_attr.static_rate = p_member_rec->rate & IB_PATH_REC_BASE_MASK;\r
216         av_attr.path_bits = 0;\r
217         /* port is not attached to endpoint at this point, so use endpt ifc reference */\r
218         status = p_endpt->p_ifc->create_av( h_pd, &av_attr, ph_av );\r
219 \r
220         if( status != IB_SUCCESS )\r
221         {\r
222                 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
223                         ("ib_create_av returned %s\n",\r
224                         p_endpt->p_ifc->get_err_str( status )) );\r
225         }\r
226 \r
227         IPOIB_EXIT( IPOIB_DBG_MCAST );\r
228         return status;\r
229 }\r
230 \r
231 \r
232 ib_api_status_t\r
233 ipoib_endpt_set_mcast(\r
234         IN                              ipoib_endpt_t* const            p_endpt,\r
235         IN                              ib_pd_handle_t                          h_pd,\r
236         IN                              uint8_t                                         port_num,\r
237         IN                              ib_mcast_rec_t* const           p_mcast_rec )\r
238 {\r
239         ib_api_status_t status;\r
240 \r
241         IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
242 \r
243         IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT,\r
244                 ("Create av for MAC: %02X-%02X-%02X-%02X-%02X-%02X\n",\r
245                 p_endpt->mac.addr[0], p_endpt->mac.addr[1],\r
246                 p_endpt->mac.addr[2], p_endpt->mac.addr[3],\r
247                 p_endpt->mac.addr[4], p_endpt->mac.addr[5]) );\r
248                 \r
249         status = __create_mcast_av( h_pd, port_num, p_mcast_rec->p_member_rec,\r
250                 &p_endpt->h_av );\r
251         if( status != IB_SUCCESS )\r
252         {\r
253                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
254                         ("__create_mcast_av returned %s\n", \r
255                         p_endpt->p_ifc->get_err_str( status )) );\r
256                 return status;\r
257         }\r
258         p_endpt->h_mcast = p_mcast_rec->h_mcast;\r
259         CL_ASSERT(p_endpt->dlid == 0);\r
260 \r
261         IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
262         return IB_SUCCESS;\r
263 }\r
264 \r
265 \r
266 static void\r
267 __endpt_destroying(\r
268         IN                              cl_obj_t*                                       p_obj )\r
269 {\r
270         ipoib_endpt_t   *p_endpt;\r
271         ipoib_port_t    *p_port;\r
272 \r
273         IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
274 \r
275         p_endpt = PARENT_STRUCT( p_obj, ipoib_endpt_t, obj );\r
276         p_port = __endpt_parent( p_endpt );\r
277 \r
278         cl_obj_lock( p_obj );\r
279         if( p_endpt->h_query )\r
280         {\r
281                 p_port->p_adapter->p_ifc->cancel_query(\r
282                         p_port->p_adapter->h_al, p_endpt->h_query );\r
283                 p_endpt->h_query = NULL;\r
284         }\r
285 \r
286         /* Leave the multicast group if it exists. */\r
287         if( p_endpt->h_mcast )\r
288         {\r
289                 IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT,\r
290                         ("Leaving MCast group\n") );\r
291                 ipoib_port_ref(p_port, ref_leave_mcast);\r
292                 p_port->p_adapter->p_ifc->leave_mcast( p_endpt->h_mcast, ipoib_leave_mcast_cb );\r
293         }\r
294 #if 0\r
295         else if( p_port->p_adapter->params.cm_enabled )\r
296         {\r
297                 p_endpt->cm_flag = 0;\r
298                 CL_ASSERT( endpt_cm_get_state( p_endpt ) == IPOIB_CM_DISCONNECTED );\r
299         }\r
300 #endif\r
301 \r
302         cl_obj_unlock( p_obj );\r
303         \r
304         IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
305 }\r
306 \r
307 \r
308 static void\r
309 __endpt_cleanup(\r
310         IN                              cl_obj_t*                                       p_obj )\r
311 {\r
312         ipoib_endpt_t   *p_endpt;\r
313         ipoib_port_t    *p_port;\r
314 \r
315         IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
316 \r
317         p_endpt = PARENT_STRUCT( p_obj, ipoib_endpt_t, obj );\r
318         p_port = __endpt_parent( p_endpt );\r
319 \r
320         /* Destroy the AV if it exists. */\r
321         if( p_endpt->h_av )\r
322                 p_port->p_adapter->p_ifc->destroy_av( p_endpt->h_av );\r
323 \r
324         IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
325 }\r
326 \r
327 \r
328 static void\r
329 __endpt_free(\r
330         IN                              cl_obj_t*                                       p_obj )\r
331 {\r
332         ipoib_endpt_t   *p_endpt;\r
333 \r
334         IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
335 \r
336         p_endpt = PARENT_STRUCT( p_obj, ipoib_endpt_t, obj );\r
337 \r
338         cl_obj_deinit( p_obj );\r
339         cl_free( p_endpt );\r
340 \r
341         IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
342 }\r
343 \r
344 \r
345 static inline ipoib_port_t*\r
346 __endpt_parent(\r
347         IN                              ipoib_endpt_t* const            p_endpt )\r
348 {\r
349         return PARENT_STRUCT( p_endpt->rel.p_parent_obj, ipoib_port_t, obj );\r
350 }\r
351 \r
352 ipoib_port_t*\r
353 ipoib_endpt_parent(\r
354         IN                              ipoib_endpt_t* const            p_endpt )\r
355 {\r
356         return __endpt_parent( p_endpt );\r
357 }\r
358 \r
359 /*\r
360  * This function is called with the port object's send lock held and\r
361  * a reference held on the endpoint.  If we fail, we release the reference.\r
362  */\r
363 NDIS_STATUS\r
364 ipoib_endpt_queue(\r
365         IN                              ipoib_endpt_t* const            p_endpt )\r
366 {\r
367         ib_api_status_t status;\r
368         ipoib_port_t    *p_port;\r
369         ib_av_attr_t    av_attr;\r
370         net32_t                 flow_lbl;\r
371 \r
372         IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
373 \r
374         if( p_endpt->h_av )\r
375         {\r
376                 IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
377                 return NDIS_STATUS_SUCCESS;\r
378         }\r
379 \r
380         if( p_endpt->qpn == CL_HTON32(0x00FFFFFF) )\r
381         {\r
382                 /*\r
383                  * Handle a race between the mcast callback and a receive/send.  The QP\r
384                  * is joined to the MC group before the MC callback is received, so it\r
385                  * can receive packets, and NDIS can try to respond.  We need to delay\r
386                  * a response until the MC callback runs and sets the AV.\r
387                  */\r
388                 ipoib_endpt_deref( p_endpt );\r
389                 IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
390                 return NDIS_STATUS_PENDING;\r
391         }\r
392 \r
393         /* This is the first packet for this endpoint.  Create the AV. */\r
394         p_port = __endpt_parent( p_endpt );\r
395 \r
396         cl_memclr( &av_attr, sizeof(ib_av_attr_t) );\r
397 \r
398         av_attr.port_num = p_port->port_num;\r
399 \r
400         ib_member_get_sl_flow_hop(\r
401                 p_port->ib_mgr.bcast_rec.sl_flow_hop,\r
402                 &av_attr.sl,\r
403                 &flow_lbl,\r
404                 &av_attr.grh.hop_limit\r
405                 );\r
406 \r
407         av_attr.dlid = p_endpt->dlid;\r
408 \r
409         /*\r
410          * We always send the GRH so that we preferably lookup endpoints\r
411          * by GID rather than by LID.  This allows certain WHQL tests\r
412          * such as the 2c_MediaCheck test to succeed since they don't use\r
413          * IP.  This allows endpoints to be created on the fly for requests\r
414          * for which there is no match, something that doesn't work when\r
415          * using LIDs only.\r
416          */\r
417         av_attr.grh_valid = TRUE;\r
418         av_attr.grh.ver_class_flow = ib_grh_set_ver_class_flow(\r
419                 6, p_port->ib_mgr.bcast_rec.tclass, flow_lbl );\r
420         av_attr.grh.resv1 = 0;\r
421         av_attr.grh.resv2 = 0;\r
422         ib_gid_set_default( &av_attr.grh.src_gid, p_port->p_adapter->guids.port_guid.guid );\r
423         av_attr.grh.dest_gid = p_endpt->dgid;\r
424 \r
425         av_attr.static_rate = p_port->ib_mgr.bcast_rec.rate;\r
426         av_attr.path_bits = 0;\r
427 \r
428         /* Create the AV. */\r
429         status = p_port->p_adapter->p_ifc->create_av(\r
430                 p_port->ib_mgr.h_pd, &av_attr, &p_endpt->h_av );\r
431         if( status != IB_SUCCESS )\r
432         {\r
433                 p_port->p_adapter->hung = TRUE;\r
434                 ipoib_endpt_deref( p_endpt );\r
435                 cl_obj_unlock( &p_endpt->obj );\r
436                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
437                         ("ib_create_av failed with %s\n", \r
438                         p_port->p_adapter->p_ifc->get_err_str( status )) );\r
439                 return NDIS_STATUS_FAILURE;\r
440         }\r
441 \r
442         IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
443         return NDIS_STATUS_SUCCESS;\r
444 }\r
445 \r
446 #if 0\r
447 \r
448 static void\r
449 __endpt_cm_buf_mgr_construct(\r
450         IN              endpt_buf_mgr_t * const         p_buf_mgr )\r
451 {\r
452         IPOIB_ENTER( IPOIB_DBG_INIT );\r
453 \r
454         cl_qpool_construct( &p_buf_mgr->recv_pool );\r
455 \r
456         p_buf_mgr->h_packet_pool = NULL;\r
457         p_buf_mgr->h_buffer_pool = NULL;\r
458 \r
459         IPOIB_EXIT( IPOIB_DBG_INIT );\r
460 }\r
461 \r
462 ib_api_status_t\r
463 endpt_cm_buf_mgr_init(\r
464         IN                              ipoib_port_t* const                             p_port )\r
465 {\r
466         cl_status_t             cl_status;\r
467         NDIS_STATUS             ndis_status;\r
468         ib_api_status_t ib_status = IB_SUCCESS;\r
469 \r
470         IPOIB_ENTER( IPOIB_DBG_INIT );\r
471 \r
472         if( p_port->cm_buf_mgr.pool_init )\r
473                 return ib_status;\r
474 \r
475         cl_qlist_init( &p_port->cm_buf_mgr.posted_list );\r
476 \r
477         __endpt_cm_buf_mgr_construct( &p_port->cm_buf_mgr );\r
478         p_port->cm_recv_mgr.rq_depth = \r
479                 min( (uint32_t)p_port->p_adapter->params.rq_depth * 8,\r
480                                 p_port->p_ca_attrs->max_srq_wrs/2 );\r
481         p_port->cm_recv_mgr.depth = 0;\r
482         /* Allocate the receive descriptors pool */\r
483         cl_status = cl_qpool_init( &p_port->cm_buf_mgr.recv_pool,\r
484                 p_port->cm_recv_mgr.rq_depth ,\r
485                 0,\r
486                 0,\r
487                 sizeof( ipoib_cm_desc_t ),\r
488                 __cm_recv_desc_ctor,\r
489                 __cm_recv_desc_dtor,\r
490                 p_port );\r
491 \r
492         if( cl_status != CL_SUCCESS )\r
493         {\r
494                 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
495                         EVENT_IPOIB_RECV_POOL, 1, cl_status );\r
496                 \r
497                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
498                         ("cl_qpool_init for cm recvs returned %#x\n", cl_status) );\r
499                 \r
500                 return IB_INSUFFICIENT_MEMORY;\r
501         }\r
502 \r
503         /* Allocate the NDIS buffer and packet pools for receive indication. */\r
504         NdisAllocatePacketPool( &ndis_status, \r
505                                                         &p_port->cm_buf_mgr.h_packet_pool,\r
506                                                         p_port->cm_recv_mgr.rq_depth, \r
507                                                         PROTOCOL_RESERVED_SIZE_IN_PACKET );\r
508         if( ndis_status != NDIS_STATUS_SUCCESS )\r
509         {\r
510                 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
511                         EVENT_IPOIB_RECV_PKT_POOL, 1, ndis_status );\r
512 \r
513                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
514                         ("NdisAllocatePacketPool returned %08X\n", ndis_status) );\r
515                 \r
516                 ib_status = IB_INSUFFICIENT_RESOURCES;\r
517                 goto pkt_pool_failed;\r
518         }\r
519 \r
520         NdisAllocateBufferPool( &ndis_status, \r
521                                                         &p_port->cm_buf_mgr.h_buffer_pool,\r
522                                                         p_port->cm_recv_mgr.rq_depth );\r
523         if( ndis_status != NDIS_STATUS_SUCCESS )\r
524         {\r
525                 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
526                         EVENT_IPOIB_RECV_BUF_POOL, 1, ndis_status );\r
527                 \r
528                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
529                         ("NdisAllocateBufferPool returned %08X\n", ndis_status) );\r
530                 \r
531                 ib_status = IB_INSUFFICIENT_RESOURCES;\r
532                 goto buf_pool_failed;\r
533         }\r
534         //NDIS60\r
535         //p_port->cm_recv_mgr.recv_pkt_array = \r
536                 //cl_zalloc( sizeof(NDIS_PACKET*) * p_port->cm_recv_mgr.rq_depth );\r
537         p_port->cm_recv_mgr.recv_lst_array = \r
538                 cl_zalloc( sizeof(NET_BUFFER_LIST*) * p_port->cm_recv_mgr.rq_depth );\r
539         \r
540                 \r
541 \r
542         if( !p_port->cm_recv_mgr.recv_pkt_array )\r
543         {\r
544                 //NDIS60\r
545                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
546                         ("cl_zalloc for NET_BUFFER_LIST array failed.\n") );\r
547                 \r
548                 ib_status = IB_INSUFFICIENT_MEMORY;\r
549                 goto pkt_array_failed;\r
550         }\r
551 \r
552         p_port->cm_buf_mgr.pool_init = TRUE;\r
553         return IB_SUCCESS;\r
554 \r
555 pkt_array_failed:\r
556         if( p_port->cm_buf_mgr.h_buffer_pool )\r
557                 NdisFreeBufferPool( p_port->cm_buf_mgr.h_buffer_pool );\r
558 buf_pool_failed:\r
559         if( p_port->cm_buf_mgr.h_packet_pool )\r
560                 NdisFreePacketPool( p_port->cm_buf_mgr.h_packet_pool );\r
561 pkt_pool_failed:\r
562                 cl_qpool_destroy( &p_port->cm_buf_mgr.recv_pool );\r
563 \r
564         IPOIB_EXIT( IPOIB_DBG_INIT );\r
565         return ib_status;\r
566 }\r
567 \r
568 void\r
569 endpt_cm_buf_mgr_reset(\r
570         IN              ipoib_port_t* const             p_port )\r
571 {\r
572         cl_list_item_t          *p_item;\r
573 \r
574         if( !p_port->cm_buf_mgr.pool_init )\r
575                 return;\r
576 \r
577         if( cl_qlist_count( &p_port->cm_buf_mgr.posted_list ) )\r
578         {\r
579                 for( p_item = cl_qlist_remove_head( &p_port->cm_buf_mgr.posted_list );\r
580                         p_item != cl_qlist_end( &p_port->cm_buf_mgr.posted_list );\r
581                         p_item =  cl_qlist_remove_head( &p_port->cm_buf_mgr.posted_list ) )\r
582                 {\r
583                         cl_qpool_put( &p_port->cm_buf_mgr.recv_pool, \r
584                                 &( PARENT_STRUCT( p_item, ipoib_cm_desc_t, list_item ))->item );\r
585                 }\r
586         }\r
587 }\r
588 \r
589 void\r
590 endpt_cm_buf_mgr_destroy(\r
591         IN              ipoib_port_t* const             p_port )\r
592 {\r
593 \r
594         IPOIB_ENTER(IPOIB_DBG_INIT );\r
595 \r
596         CL_ASSERT( p_port );\r
597         \r
598         /* Free the receive descriptors. */\r
599         if( !p_port->cm_buf_mgr.pool_init )\r
600                 return;\r
601 \r
602         endpt_cm_buf_mgr_reset( p_port );\r
603 \r
604         p_port->cm_buf_mgr.pool_init = FALSE;\r
605         \r
606         if( p_port->cm_recv_mgr.recv_pkt_array )\r
607         {\r
608                 cl_free( p_port->cm_recv_mgr.recv_pkt_array );\r
609         }\r
610 \r
611         /* Destroy the receive packet and buffer pools. */\r
612         if( p_port->cm_buf_mgr.h_buffer_pool )\r
613                 NdisFreeBufferPool( p_port->cm_buf_mgr.h_buffer_pool );\r
614         if( p_port->cm_buf_mgr.h_packet_pool )\r
615                 NdisFreePacketPool( p_port->cm_buf_mgr.h_packet_pool );\r
616 \r
617         cl_qpool_destroy( &p_port->cm_buf_mgr.recv_pool );\r
618         \r
619         IPOIB_EXIT(  IPOIB_DBG_INIT );\r
620 }\r
621 \r
622 static cl_status_t\r
623 __cm_recv_desc_ctor(\r
624         IN                              void* const                                     p_object,\r
625         IN                              void*                                           context,\r
626                 OUT                     cl_pool_item_t** const          pp_pool_item )\r
627 {\r
628         ipoib_cm_desc_t*        p_desc;\r
629         ipoib_port_t*           p_port;\r
630         ib_mr_create_t          create_mr;\r
631         net32_t                         rkey;\r
632 \r
633         CL_ASSERT( p_object );\r
634         CL_ASSERT( context );\r
635 \r
636         p_desc = (ipoib_cm_desc_t*)p_object;\r
637         p_port = (ipoib_port_t*)context;\r
638 \r
639 #define BUF_ALIGN               (16)\r
640 \r
641         p_desc->alloc_buf_size = \r
642                 ROUNDUP( p_port->p_adapter->params.cm_xfer_block_size, BUF_ALIGN );\r
643         \r
644         p_desc->p_alloc_buf = (uint8_t *)ExAllocatePoolWithTag( \r
645                 NonPagedPool, p_desc->alloc_buf_size, 'DOMC' );\r
646 \r
647         if( p_desc->p_alloc_buf == NULL )\r
648         {\r
649                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
650                         ("Failed to allocate receive buffer size %d bytes.\n", p_desc->alloc_buf_size ) );\r
651                 return CL_INSUFFICIENT_MEMORY;\r
652         }\r
653 \r
654         create_mr.vaddr  = p_desc->p_alloc_buf;\r
655         create_mr.length  = p_desc->alloc_buf_size;\r
656         create_mr.access_ctrl = IB_AC_LOCAL_WRITE;\r
657 \r
658         \r
659         if( p_port->p_adapter->p_ifc->reg_mem( \r
660                                                         p_port->ib_mgr.h_pd,\r
661                                                         &create_mr,\r
662                                                         &p_desc->lkey,\r
663                                                         &rkey,\r
664                                                         &p_desc->h_mr ) != IB_SUCCESS )\r
665         {\r
666                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
667                         ("Failed to create Memory Region size %d bytes.\n", p_desc->alloc_buf_size ) );\r
668                 goto ctor_failed;\r
669         }\r
670         p_desc->p_buf = p_desc->p_alloc_buf + (BUF_ALIGN - sizeof( ipoib_hdr_t));\r
671         p_desc->buf_size = p_desc->alloc_buf_size - (BUF_ALIGN - sizeof( ipoib_hdr_t));\r
672 \r
673         /* Setup the local data segment. */\r
674         p_desc->local_ds[0].vaddr = (uint64_t)(uintn_t)p_desc->p_buf;\r
675         p_desc->local_ds[0].length = p_desc->buf_size;\r
676         p_desc->local_ds[0].lkey = p_desc->lkey;\r
677 \r
678         /* Setup the work request. */\r
679         p_desc->wr.wr_id = (uintn_t)p_desc;\r
680         p_desc->wr.ds_array = p_desc->local_ds;\r
681         p_desc->wr.num_ds = 1;\r
682         p_desc->type = PKT_TYPE_CM_UCAST;\r
683         \r
684         *pp_pool_item = &p_desc->item;\r
685         return CL_SUCCESS;\r
686 \r
687 ctor_failed:\r
688         ExFreePoolWithTag( p_desc->p_alloc_buf, 'DOMC' );\r
689         return CL_INSUFFICIENT_MEMORY;\r
690 }\r
691 \r
692 static void\r
693 __cm_recv_desc_dtor(\r
694         IN              const   cl_pool_item_t* const           p_pool_item,\r
695         IN                              void                                            *context )\r
696 {\r
697         ipoib_cm_desc_t *p_desc;\r
698         ipoib_port_t*   p_port;\r
699 \r
700         if( p_pool_item == NULL || context == NULL )\r
701                 return;\r
702 \r
703         p_port = (ipoib_port_t*)context;\r
704         p_desc = PARENT_STRUCT( p_pool_item, ipoib_cm_desc_t, item );\r
705 \r
706         if( p_desc->h_mr )\r
707                 p_port->p_adapter->p_ifc->dereg_mr( p_desc->h_mr );\r
708 \r
709         if( p_desc->p_alloc_buf )\r
710                 ExFreePoolWithTag( p_desc->p_alloc_buf, 'DOMC' );\r
711 }\r
712 \r
713 \r
714 static NDIS_PACKET*\r
715 __endpt_cm_get_ndis_pkt(\r
716         IN              ipoib_port_t* const                     p_port,\r
717         IN              ipoib_cm_desc_t* const  p_desc )\r
718 {\r
719         NDIS_STATUS                             status;\r
720         NDIS_PACKET                             *p_packet;\r
721         NDIS_BUFFER                             *p_buffer;\r
722         \r
723         IPOIB_ENTER(  IPOIB_DBG_RECV );\r
724 \r
725         NdisDprAllocatePacketNonInterlocked( &status, &p_packet,\r
726                         p_port->cm_buf_mgr.h_packet_pool );\r
727         if( status != NDIS_STATUS_SUCCESS )\r
728         {\r
729                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
730                         ("Failed to allocate NDIS_PACKET: %08x\n", status) );\r
731                 return NULL;\r
732         }\r
733 \r
734         IPOIB_PORT_FROM_PACKET( p_packet ) = p_port;\r
735         IPOIB_RECV_FROM_PACKET( p_packet ) = p_desc;\r
736 \r
737         NdisAllocateBuffer( \r
738                         &status, \r
739                         &p_buffer,\r
740                         p_port->cm_buf_mgr.h_buffer_pool, \r
741                         (void *)(p_desc->p_buf - DATA_OFFSET),\r
742                         p_desc->len + DATA_OFFSET );\r
743 \r
744         if( status != NDIS_STATUS_SUCCESS )\r
745         {\r
746                 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
747                         ("Failed to allocate NDIS_BUFFER: %08x\n", status) );\r
748                 NdisDprFreePacketNonInterlocked( p_packet );\r
749                 return NULL;\r
750         }\r
751 \r
752         NdisChainBufferAtFront( p_packet, p_buffer );\r
753         NDIS_SET_PACKET_HEADER_SIZE( p_packet, sizeof(eth_hdr_t) );\r
754 \r
755         IPOIB_EXIT(  IPOIB_DBG_RECV );\r
756         return p_packet;\r
757 }\r
758 \r
759 static inline ipoib_cm_desc_t*\r
760 __endpt_cm_buf_mgr_get_recv(\r
761         IN              endpt_buf_mgr_t * const         p_buf_mgr )\r
762 {\r
763         ipoib_cm_desc_t *p_desc;\r
764 \r
765         p_desc = (ipoib_cm_desc_t*)cl_qpool_get( &p_buf_mgr->recv_pool );\r
766         if( p_desc )\r
767                 cl_qlist_insert_tail( &p_buf_mgr->posted_list, &p_desc->list_item );\r
768 \r
769         return p_desc;\r
770 }\r
771 \r
772 void\r
773 endpt_cm_buf_mgr_put_recv(\r
774         IN              endpt_buf_mgr_t * const         p_buf_mgr,\r
775         IN              ipoib_cm_desc_t* const  p_desc )\r
776 {\r
777 \r
778         IPOIB_ENTER(IPOIB_DBG_RECV );\r
779 \r
780         /* Return the descriptor to it's pool. */\r
781         cl_qlist_remove_item( &p_buf_mgr->posted_list, &p_desc->list_item );\r
782         cl_qpool_put( &p_buf_mgr->recv_pool, &p_desc->item );\r
783 \r
784         IPOIB_EXIT(  IPOIB_DBG_RECV );\r
785 }\r
786 \r
787 void\r
788 endpt_cm_buf_mgr_put_recv_list(\r
789         IN              endpt_buf_mgr_t * const         p_buf_mgr,\r
790         IN              cl_qlist_t* const                       p_list )\r
791 {\r
792         cl_qpool_put_list( &p_buf_mgr->recv_pool, p_list );\r
793 }\r
794 \r
795 uint32_t\r
796 endpt_cm_recv_mgr_build_pkt_array(\r
797         IN                      ipoib_port_t* const                     p_port,\r
798         IN                      ipoib_endpt_t* const            p_endpt,\r
799         IN                      cl_qlist_t* const                       p_done_list,\r
800         IN OUT          uint32_t*                                       p_bytes_recv )\r
801 {\r
802         cl_list_item_t                  *p_item;\r
803         ipoib_cm_desc_t         *p_desc;\r
804         uint32_t                                i = 0;\r
805         NDIS_PACKET                             *p_packet;\r
806         NDIS_TCP_IP_CHECKSUM_PACKET_INFO        chksum;\r
807 \r
808         IPOIB_ENTER( IPOIB_DBG_RECV );\r
809         UNUSED_PARAM( p_endpt );\r
810 \r
811         p_item = cl_qlist_remove_head( p_done_list );\r
812         \r
813         *p_bytes_recv = 0;\r
814 \r
815         for( p_item; p_item != cl_qlist_end( p_done_list );\r
816                 p_item = cl_qlist_remove_head( p_done_list ) )\r
817         {\r
818                 p_desc = (ipoib_cm_desc_t*)p_item;\r
819 \r
820                 p_packet = __endpt_cm_get_ndis_pkt( p_port, p_desc );\r
821                 if( !p_packet )\r
822                 {\r
823                         IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
824                                 ("Failed to get Packet from descriptor\n" ) );\r
825                         endpt_cm_buf_mgr_put_recv( &p_port->cm_buf_mgr, p_desc );\r
826                         p_port->cm_recv_mgr.depth--;\r
827                         continue;\r
828                 }\r
829                 chksum.Value = 0;\r
830                 switch( p_port->p_adapter->params.recv_chksum_offload )\r
831                 {\r
832                 default:\r
833                         CL_ASSERT( FALSE );\r
834                 case CSUM_DISABLED:\r
835                 case CSUM_ENABLED:\r
836                 NDIS_PER_PACKET_INFO_FROM_PACKET( p_packet, TcpIpChecksumPacketInfo ) =\r
837                                 (void*)(uintn_t)chksum.Value;\r
838                         break;\r
839                 case CSUM_BYPASS:\r
840                         /* Flag the checksums as having been calculated. */\r
841                         chksum.Receive.NdisPacketTcpChecksumSucceeded = TRUE;\r
842                         chksum.Receive.NdisPacketUdpChecksumSucceeded = TRUE;\r
843                         chksum.Receive.NdisPacketIpChecksumSucceeded = TRUE;\r
844                         NDIS_PER_PACKET_INFO_FROM_PACKET( p_packet, TcpIpChecksumPacketInfo ) =\r
845                                 (void*)(uintn_t)chksum.Value;\r
846                         break;\r
847                 }\r
848 \r
849                 NDIS_SET_PACKET_STATUS( p_packet, NDIS_STATUS_SUCCESS );\r
850                 p_port->cm_recv_mgr.recv_pkt_array[i] = p_packet;\r
851                 i++;            \r
852                 *p_bytes_recv += p_desc->len;\r
853         }\r
854 \r
855         IPOIB_EXIT( IPOIB_DBG_RECV );\r
856         return i;\r
857 }\r
858 void\r
859 endpt_cm_flush_recv(\r
860         IN                              ipoib_port_t* const             p_port,\r
861         IN                              ipoib_endpt_t* const    p_endpt )\r
862 {\r
863         ib_api_status_t         ib_status = IB_SUCCESS;\r
864         ib_qp_mod_t                     mod_attr;\r
865         ib_wc_t                         wc[MAX_RECV_WC];\r
866         ib_wc_t                         *p_free_wc;\r
867         ib_wc_t                         *p_done_wc;\r
868         ib_wc_t                         *p_wc;\r
869         ipoib_cm_desc_t         *p_desc;\r
870         size_t                          i;\r
871 \r
872         IPOIB_ENTER( IPOIB_DBG_RECV );\r
873 \r
874         CL_ASSERT( p_endpt );\r
875 \r
876         if( p_endpt->conn.h_recv_qp )\r
877         {\r
878                 cl_memclr( &mod_attr, sizeof( mod_attr ) );\r
879                 mod_attr.req_state = IB_QPS_ERROR;\r
880                 p_port->p_adapter->p_ifc->modify_qp( p_endpt->conn.h_send_qp, &mod_attr );\r
881                 p_port->p_adapter->p_ifc->modify_qp( p_endpt->conn.h_recv_qp, &mod_attr );\r
882 \r
883                 for( i = 0; i < MAX_RECV_WC; i++ )\r
884                         wc[i].p_next = &wc[i + 1];\r
885                 wc[MAX_RECV_WC - 1].p_next = NULL;\r
886 \r
887                 do\r
888                 {\r
889                         p_free_wc = wc;\r
890                         ib_status = \r
891                                 p_port->p_adapter->p_ifc->poll_cq( p_endpt->conn.h_recv_cq, \r
892                                 &p_free_wc, &p_done_wc );\r
893                         if( ib_status != IB_SUCCESS && \r
894                                 ib_status != IB_NOT_FOUND )\r
895                         {\r
896                                 /* connection CQ failed */\r
897                                 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
898                                         ("Poll Recv CQ failed status %#x\n", ib_status ) );\r
899                                 break;\r
900                         }\r
901                         cl_spinlock_acquire( &p_port->recv_lock );\r
902                         for( p_wc = p_done_wc; p_wc; p_wc = p_wc->p_next )\r
903                         {\r
904                                 p_desc = (ipoib_cm_desc_t *)(uintn_t)p_wc->wr_id;\r
905                                 endpt_cm_buf_mgr_put_recv( &p_port->cm_buf_mgr, p_desc );\r
906                                 p_port->cm_recv_mgr.depth--;\r
907                         }\r
908                         cl_spinlock_release( &p_port->recv_lock );\r
909                 } while( !p_free_wc );\r
910 \r
911                 ib_status = p_port->p_adapter->p_ifc->destroy_qp( p_endpt->conn.h_recv_qp, NULL );\r
912                 if( ib_status != IB_SUCCESS )\r
913                 {\r
914                         IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
915                                 ("Destroy Recv QP failed status %#x\n", ib_status ) );\r
916                 }\r
917                 p_endpt->conn.h_recv_qp = NULL;\r
918         }\r
919 \r
920         if( p_endpt->conn.h_send_qp )\r
921         {\r
922                 ib_status = p_port->p_adapter->p_ifc->destroy_qp( p_endpt->conn.h_send_qp, NULL );\r
923                 if( ib_status != IB_SUCCESS )\r
924                 {\r
925                         IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
926                                 ("Destroy Send QP failed status %#x\n", ib_status ) );\r
927                 }\r
928                 p_endpt->conn.h_send_qp = NULL;\r
929         }\r
930 \r
931         IPOIB_EXIT( IPOIB_DBG_RECV );\r
932 }\r
933 \r
934 int32_t\r
935 endpt_cm_recv_mgr_filter(\r
936         IN              ipoib_endpt_t* const            p_endpt,\r
937         IN              ib_wc_t* const                          p_done_wc_list,\r
938         OUT             cl_qlist_t* const                       p_done_list,\r
939         OUT             cl_qlist_t* const                       p_bad_list )\r
940 {\r
941         ib_api_status_t                 ib_status;\r
942         ipoib_cm_desc_t                 *p_desc;\r
943         ib_wc_t                                 *p_wc;\r
944         ipoib_pkt_t                             *p_ipoib;\r
945         eth_pkt_t                               *p_eth;\r
946         ipoib_port_t*                   p_port;\r
947         int32_t                                 recv_cnt;\r
948 \r
949         IPOIB_ENTER( IPOIB_DBG_RECV );\r
950 \r
951         p_port = ipoib_endpt_parent( p_endpt );\r
952 \r
953         for( p_wc = p_done_wc_list, recv_cnt = 0; p_wc; p_wc = p_wc->p_next )\r
954         {\r
955                 p_desc = (ipoib_cm_desc_t *)(uintn_t)p_wc->wr_id;\r
956                 recv_cnt++;\r
957                 if(  p_wc->status != IB_WCS_SUCCESS )\r
958                 {\r
959                         if( p_wc->status != IB_WCS_WR_FLUSHED_ERR )\r
960                         {\r
961                                 \r
962                                 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
963                                         ("Failed completion %s  (vendor specific %#x)\n",\r
964                                         p_port->p_adapter->p_ifc->get_wc_status_str( p_wc->status ),\r
965                                         (int)p_wc->vendor_specific) );\r
966                         }\r
967                         else\r
968                         {\r
969                                 IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV,\r
970                                         ("Flushed completion %s\n",\r
971                                         p_port->p_adapter->p_ifc->get_wc_status_str( p_wc->status )) );\r
972                         }\r
973                         \r
974                         ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0, 0 );\r
975 \r
976                         cl_qlist_remove_item( &p_port->cm_buf_mgr.posted_list,&p_desc->list_item );\r
977                         cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item );\r
978                         continue;\r
979                 }\r
980 \r
981                 /* Successful completion                \r
982                  Setup the ethernet/ip/arp header and queue descriptor for report. */\r
983                 ib_status = IB_SUCCESS;\r
984                 p_ipoib = (ipoib_pkt_t *)((uint8_t*)p_desc->p_buf );\r
985                 p_eth = (eth_pkt_t *)((uint8_t*)p_desc->p_buf - DATA_OFFSET );\r
986                 \r
987                 switch( p_ipoib->hdr.type )\r
988                 {\r
989                 case ETH_PROT_TYPE_ARP:\r
990                         if( p_wc->length < (sizeof(ipoib_hdr_t) + sizeof(ipoib_arp_pkt_t)) )\r
991                         {\r
992                                 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
993                                 ("Received ARP packet too short\n") );\r
994                                 ib_status = IB_ERROR;\r
995                                 break;\r
996                         }\r
997                         ib_status = \r
998                                 __endpt_cm_recv_arp( p_port, p_ipoib, p_eth, p_endpt );\r
999                         break;\r
1000                 case ETH_PROT_TYPE_IP:\r
1001                         if( p_wc->length < (sizeof(ipoib_hdr_t) + sizeof(ip_hdr_t)) )\r
1002                         {\r
1003                                 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1004                                         ("Received IP packet too short\n") );\r
1005                                 ib_status = IB_ERROR;\r
1006                                 break;\r
1007                         }\r
1008                         if( p_ipoib->type.ip.hdr.prot == IP_PROT_UDP )\r
1009                         {\r
1010                                 ib_status = \r
1011                                         __endpt_cm_recv_udp( p_port, p_wc, p_ipoib, p_eth, p_endpt );\r
1012                         }\r
1013                 \r
1014                         break;\r
1015                 }\r
1016 \r
1017                 if( ib_status != IB_SUCCESS )\r
1018                 {\r
1019                         ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0, 0 );\r
1020                         cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item );\r
1021                         continue;\r
1022                 }\r
1023 \r
1024                 p_eth->hdr.type = p_ipoib->hdr.type;\r
1025                 p_eth->hdr.src = p_endpt->mac;\r
1026                 p_eth->hdr.dst = p_port->p_adapter->mac;\r
1027 \r
1028                 /* save payload length */\r
1029                 p_desc->len = p_wc->length;\r
1030                 \r
1031                 cl_qlist_insert_tail( p_done_list, &p_desc->item.list_item );\r
1032         }\r
1033 \r
1034         IPOIB_EXIT( IPOIB_DBG_RECV );\r
1035         return recv_cnt;\r
1036 }\r
1037 \r
1038 ib_api_status_t\r
1039 endpt_cm_post_recv(\r
1040         IN              ipoib_port_t* const                     p_port )\r
1041 {\r
1042         ib_api_status_t         ib_status = IB_SUCCESS;\r
1043         ipoib_cm_desc_t         *p_head_desc = NULL;\r
1044         ipoib_cm_desc_t         *p_tail_desc = NULL;\r
1045         ipoib_cm_desc_t         *p_next_desc;\r
1046         ib_recv_wr_t            *p_failed_wc = NULL;\r
1047 \r
1048         IPOIB_ENTER( IPOIB_DBG_RECV );\r
1049 \r
1050         while( cl_qpool_count( &p_port->cm_buf_mgr.recv_pool )  > 1  )\r
1051         {\r
1052                         /* Pull receives out of the pool and chain them up. */\r
1053                 p_next_desc = __endpt_cm_buf_mgr_get_recv( \r
1054                                                                         &p_port->cm_buf_mgr );\r
1055                 if( !p_next_desc )\r
1056                 {\r
1057                         IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV,\r
1058                                 ("Out of receive descriptors! Endpt recv queue depth 0x%x\n",\r
1059                                 p_port->cm_recv_mgr.depth ) );\r
1060                         break;\r
1061                 }\r
1062 \r
1063                 if( !p_tail_desc )\r
1064                 {\r
1065                         p_tail_desc = p_next_desc;\r
1066                         p_next_desc->wr.p_next = NULL;\r
1067                 }\r
1068                 else\r
1069                 {\r
1070                         p_next_desc->wr.p_next = &p_head_desc->wr;\r
1071                 }\r
1072 \r
1073                 p_head_desc = p_next_desc;\r
1074 \r
1075                 p_port->cm_recv_mgr.depth++;\r
1076         }\r
1077 \r
1078         if( p_head_desc )\r
1079         {\r
1080                 ib_status = p_port->p_adapter->p_ifc->post_srq_recv(\r
1081                         p_port->ib_mgr.h_srq, &p_head_desc->wr, &p_failed_wc );\r
1082 \r
1083                 if( ib_status != IB_SUCCESS )\r
1084                 {\r
1085                         IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1086                                 ("ip_post_recv returned %s\n", \r
1087                                 p_port->p_adapter->p_ifc->get_err_str( ib_status )) );\r
1088                         \r
1089                         /* put descriptors back to the pool */\r
1090                         while( p_failed_wc )\r
1091                         {\r
1092                                 p_head_desc = PARENT_STRUCT( p_failed_wc, ipoib_cm_desc_t, wr );\r
1093                                 p_failed_wc = p_failed_wc->p_next;\r
1094                                 endpt_cm_buf_mgr_put_recv( &p_port->cm_buf_mgr, p_head_desc );\r
1095                                 p_port->cm_recv_mgr.depth--;\r
1096                         }\r
1097                 }\r
1098         }\r
1099 \r
1100 \r
1101         IPOIB_EXIT( IPOIB_DBG_RECV );\r
1102         return( ib_status );\r
1103 }\r
1104 \r
1105 static ib_api_status_t\r
1106 __endpt_cm_recv_arp(\r
1107         IN              ipoib_port_t* const                             p_port,\r
1108         IN              const   ipoib_pkt_t* const              p_ipoib,\r
1109         OUT             eth_pkt_t* const                                p_eth,\r
1110         IN              ipoib_endpt_t* const                    p_src_endpt )\r
1111 {\r
1112         const ipoib_arp_pkt_t   *p_ib_arp;\r
1113         arp_pkt_t                               *p_arp;\r
1114         \r
1115         p_ib_arp = &p_ipoib->type.arp;\r
1116         p_arp = &p_eth->type.arp;\r
1117         \r
1118         if( p_ib_arp->hw_type != ARP_HW_TYPE_IB ||\r
1119                 p_ib_arp->hw_size != sizeof(ipoib_hw_addr_t) ||\r
1120                 p_ib_arp->prot_type != ETH_PROT_TYPE_IP )\r
1121         {\r
1122                 return IB_ERROR;\r
1123         }\r
1124         \r
1125         p_arp->hw_type = ARP_HW_TYPE_ETH;\r
1126         p_arp->hw_size = sizeof(mac_addr_t);\r
1127         p_arp->src_hw = p_src_endpt->mac;\r
1128         p_arp->src_ip = p_ib_arp->src_ip;\r
1129         p_arp->dst_hw = p_port->p_local_endpt->mac;\r
1130         p_arp->dst_ip = p_ib_arp->dst_ip;\r
1131 \r
1132         return IB_SUCCESS;      \r
1133 }\r
1134 \r
1135 static ib_api_status_t\r
1136 __endpt_cm_recv_udp(\r
1137         IN      ipoib_port_t* const     p_port,\r
1138         IN                      ib_wc_t* const                          p_wc,\r
1139         IN              const   ipoib_pkt_t* const              p_ipoib,\r
1140         OUT                     eth_pkt_t* const                        p_eth,\r
1141         IN                      ipoib_endpt_t* const            p_src_endpt )\r
1142 {\r
1143         ib_api_status_t                 ib_status = IB_SUCCESS;\r
1144 \r
1145         if( p_wc->length <\r
1146                 (sizeof(ipoib_hdr_t) + sizeof(ip_hdr_t) + sizeof(udp_hdr_t)) )\r
1147         {\r
1148                 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1149                         ("Received UDP packet too short\n") );\r
1150                 return IB_ERROR;\r
1151         }\r
1152         if( __cm_recv_is_dhcp( p_ipoib ) )\r
1153         {\r
1154                 ib_status = ipoib_recv_dhcp(\r
1155                         p_port, p_ipoib, p_eth, p_src_endpt, p_port->p_local_endpt );\r
1156         }\r
1157 \r
1158         return ib_status;\r
1159 }\r
1160 \r
1161 static boolean_t\r
1162 __cm_recv_is_dhcp(\r
1163         IN      const ipoib_pkt_t* const        p_ipoib )\r
1164 {\r
1165         return( (p_ipoib->type.ip.prot.udp.hdr.dst_port == DHCP_PORT_SERVER &&\r
1166                                 p_ipoib->type.ip.prot.udp.hdr.src_port == DHCP_PORT_CLIENT) ||\r
1167                                 (p_ipoib->type.ip.prot.udp.hdr.dst_port == DHCP_PORT_CLIENT &&\r
1168                                 p_ipoib->type.ip.prot.udp.hdr.src_port == DHCP_PORT_SERVER) );\r
1169 }\r
1170 #endif\r