89e1a0c0d5dd77591086d25bd0e27205127fd79b
[mirror/winof/.git] / ulp / ipoib_NDIS6_CM / kernel / ipoib_port.c
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_port.c 4506 2009-06-23 14:40:54Z 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_adapter.h"\r
39 #include "ipoib_debug.h"\r
40 #if defined(EVENT_TRACING)\r
41 #ifdef offsetof\r
42 #undef offsetof\r
43 #endif\r
44 #include "ipoib_port.tmh"\r
45 #endif\r
46 #include <offload.h>\r
47 \r
48 #include "wdm.h"\r
49 #include <ntddk.h>\r
50 \r
51 \r
52 \r
53 ib_gid_t        bcast_mgid_template = {\r
54         0xff,                                                           /* multicast field */\r
55         0x12,                                                           /* scope (to be filled in) */\r
56         0x40, 0x1b,                                                     /* IPv4 signature */\r
57         0xff, 0xff,                                                     /* 16 bits of P_Key (to be filled in) */\r
58         0x00, 0x00, 0x00, 0x00, 0x00, 0x00,     /* 48 bits of zeros */\r
59         0xff, 0xff, 0xff, 0xff,                         /* 32 bit IPv4 broadcast address */\r
60 };\r
61 \r
62 \r
63 #ifdef _DEBUG_\r
64 /* Handy pointer for debug use. */\r
65 ipoib_port_t    *gp_ipoib_port;\r
66 #endif\r
67 \r
68 static void __port_mcast_garbage_dpc(KDPC *p_gc_dpc,void *context,void *s_arg1, void *s_arg2);\r
69 static void __port_do_mcast_garbage(ipoib_port_t* const p_port );\r
70 \r
71 \r
72 static void __recv_cb_dpc(KDPC *p_gc_dpc,void *context,void *s_arg1, void *s_arg2);\r
73 \r
74 \r
75 /******************************************************************************\r
76 *\r
77 * Declarations\r
78 *\r
79 ******************************************************************************/\r
80 static void\r
81 __port_construct(\r
82         IN                              ipoib_port_t* const                     p_port );\r
83 \r
84 static ib_api_status_t\r
85 __port_init(\r
86         IN                              ipoib_port_t* const                     p_port,\r
87         IN                              ipoib_adapter_t* const          p_adapter,\r
88         IN                              ib_pnp_port_rec_t* const        p_pnp_rec );\r
89 \r
90 static void\r
91 __port_destroying(\r
92         IN                              cl_obj_t* const                         p_obj );\r
93 \r
94 static void\r
95 __port_cleanup(\r
96         IN                              cl_obj_t* const                         p_obj );\r
97 \r
98 static void\r
99 __port_free(\r
100         IN                              cl_obj_t* const                         p_obj );\r
101 \r
102 static ib_api_status_t\r
103 __port_query_ca_attrs( \r
104         IN              ipoib_port_t* const                                     p_port,\r
105         IN              ib_ca_attr_t**                                          pp_ca_attrs );\r
106 \r
107 static void\r
108 __srq_async_event_cb(\r
109 IN                      ib_async_event_rec_t            *p_event_rec );\r
110 \r
111 /******************************************************************************\r
112 *\r
113 * IB resource manager operations\r
114 *\r
115 ******************************************************************************/\r
116 static void\r
117 __ib_mgr_construct(\r
118         IN                              ipoib_port_t* const                     p_port );\r
119 \r
120 static ib_api_status_t\r
121 __ib_mgr_init(\r
122         IN                              ipoib_port_t* const                     p_port );\r
123 \r
124 static void\r
125 __ib_mgr_destroy(\r
126         IN                              ipoib_port_t* const                     p_port );\r
127 \r
128 static void\r
129 __qp_event(\r
130         IN                              ib_async_event_rec_t            *p_event_rec );\r
131 \r
132 static void\r
133 __cq_event(\r
134         IN                              ib_async_event_rec_t            *p_event_rec );\r
135 \r
136 static ib_api_status_t\r
137 __ib_mgr_activate(\r
138         IN                              ipoib_port_t* const                     p_port );\r
139 \r
140 /******************************************************************************\r
141 *\r
142 * Buffer manager operations.\r
143 *\r
144 ******************************************************************************/\r
145 static void\r
146 __buf_mgr_construct(\r
147         IN                              ipoib_port_t* const                     p_port );\r
148 \r
149 static ib_api_status_t\r
150 __buf_mgr_init(\r
151         IN                              ipoib_port_t* const                     p_port );\r
152 \r
153 static void\r
154 __buf_mgr_destroy(\r
155         IN                              ipoib_port_t* const                     p_port );\r
156 \r
157 static cl_status_t\r
158 __recv_ctor(\r
159         IN                              void* const                                     p_object,\r
160         IN                              void*                                           context,\r
161                 OUT                     cl_pool_item_t** const          pp_pool_item );\r
162 \r
163 #if !IPOIB_INLINE_RECV\r
164 static void\r
165 __recv_dtor(\r
166         IN              const   cl_pool_item_t* const           p_pool_item,\r
167         IN                              void                                            *context );\r
168 #endif  /* IPOIB_INLINE_RECV */\r
169 \r
170 static inline ipoib_send_desc_t*\r
171 __buf_mgr_get_send(\r
172         IN                              ipoib_port_t* const                     p_port );\r
173 \r
174 static inline void\r
175 __buf_mgr_put_send(\r
176         IN                              ipoib_port_t* const                     p_port,\r
177         IN                              ipoib_send_desc_t* const        p_desc );\r
178 \r
179 static inline ipoib_recv_desc_t*\r
180 __buf_mgr_get_recv(\r
181         IN                              ipoib_port_t* const                     p_port );\r
182 \r
183 static inline void\r
184 __buf_mgr_put_recv(\r
185         IN                              ipoib_port_t* const                     p_port,\r
186         IN                              ipoib_recv_desc_t* const        p_desc,\r
187         IN                              NET_BUFFER_LIST* const          p_net_buffer_list OPTIONAL );\r
188 \r
189 static inline void\r
190 __buf_mgr_put_recv_list(\r
191         IN                              ipoib_port_t* const                     p_port,\r
192         IN                              cl_qlist_t* const                       p_list );\r
193 \r
194 //NDIS60\r
195 static inline NET_BUFFER_LIST*\r
196 __buf_mgr_get_ndis_pkt(\r
197         IN                              ipoib_port_t* const                     p_port,\r
198         IN                              ipoib_recv_desc_t* const        p_desc );\r
199 \r
200 \r
201 /******************************************************************************\r
202 *\r
203 * Receive manager operations.\r
204 *\r
205 ******************************************************************************/\r
206 static void\r
207 __recv_mgr_construct(\r
208         IN                              ipoib_port_t* const                     p_port );\r
209 \r
210 static ib_api_status_t\r
211 __recv_mgr_init(\r
212         IN                              ipoib_port_t* const                     p_port );\r
213 \r
214 static void\r
215 __recv_mgr_destroy(\r
216         IN                              ipoib_port_t* const                     p_port );\r
217 \r
218 /* Posts receive buffers to the receive queue. */\r
219 static ib_api_status_t\r
220 __recv_mgr_repost(\r
221         IN                              ipoib_port_t* const                     p_port );\r
222 \r
223 static void\r
224 __recv_cb(\r
225         IN              const   ib_cq_handle_t                          h_cq,\r
226         IN                              void                                            *cq_context );\r
227 \r
228 static void\r
229 __recv_get_endpts(\r
230         IN                              ipoib_port_t* const                     p_port,\r
231         IN                              ipoib_recv_desc_t* const        p_desc,\r
232         IN                              ib_wc_t* const                          p_wc,\r
233                 OUT                     ipoib_endpt_t** const           pp_src,\r
234                 OUT                     ipoib_endpt_t** const           pp_dst );\r
235 \r
236 static int32_t\r
237 __recv_mgr_filter(\r
238         IN                              ipoib_port_t* const                     p_port,\r
239         IN                              ib_wc_t* const                          p_done_wc_list,\r
240                 OUT                     cl_qlist_t* const                       p_done_list,\r
241                 OUT                     cl_qlist_t* const                       p_bad_list );\r
242 \r
243 static ib_api_status_t\r
244 __recv_gen(\r
245         IN              const   ipoib_pkt_t* const                      p_ipoib,\r
246                 OUT                     eth_pkt_t* const                        p_eth,\r
247         IN                              ipoib_endpt_t* const            p_src,\r
248         IN                              ipoib_endpt_t* const            p_dst );\r
249 \r
250 static ib_api_status_t\r
251 __recv_dhcp(\r
252         IN                              ipoib_port_t* const                     p_port,\r
253         IN              const   ipoib_pkt_t* const                      p_ipoib,\r
254                 OUT                     eth_pkt_t* const                        p_eth,\r
255         IN                              ipoib_endpt_t* const            p_src,\r
256         IN                              ipoib_endpt_t* const            p_dst );\r
257 \r
258 static ib_api_status_t\r
259 __recv_arp(\r
260         IN                              ipoib_port_t* const                     p_port,\r
261         IN                              ib_wc_t* const                          p_wc,\r
262         IN              const   ipoib_pkt_t* const                      p_ipoib,\r
263                 OUT                     eth_pkt_t* const                        p_eth,\r
264         IN                              ipoib_endpt_t** const           p_src,\r
265         IN                              ipoib_endpt_t* const            p_dst );\r
266 \r
267 static ib_api_status_t\r
268 __recv_mgr_prepare_pkt(\r
269         IN                              ipoib_port_t* const                     p_port,\r
270         IN                              ipoib_recv_desc_t* const        p_desc,\r
271                 OUT                     NET_BUFFER_LIST** const         pp_net_buffer_list );\r
272 \r
273 static uint32_t\r
274 __recv_mgr_build_pkt_array(\r
275         IN                              ipoib_port_t* const                     p_port,\r
276         IN                              int32_t                                         shortage,\r
277                 OUT                     cl_qlist_t* const                       p_done_list,\r
278                 OUT                     int32_t* const                          p_discarded );\r
279 \r
280 /******************************************************************************\r
281 *\r
282 * Send manager operations.\r
283 *\r
284 ******************************************************************************/\r
285 static void\r
286 __send_mgr_construct(\r
287         IN                              ipoib_port_t* const                     p_port );\r
288 \r
289 static void\r
290 __send_mgr_destroy(\r
291         IN                              ipoib_port_t* const                     p_port );\r
292 \r
293 static NDIS_STATUS\r
294 __send_gen(\r
295         IN                              ipoib_port_t* const                     p_port,\r
296         IN                              ipoib_send_desc_t* const        p_desc,\r
297         IN                              SCATTER_GATHER_LIST                     *p_sgl,\r
298         IN                              INT                                             lso_data_index);\r
299 \r
300 static NDIS_STATUS\r
301 __send_mgr_filter_ip(\r
302         IN                              ipoib_port_t* const                     p_port,\r
303         IN              const   eth_hdr_t* const                        p_eth_hdr,\r
304         IN                              MDL*                                            p_mdl,\r
305         IN                              size_t                                          buf_len,\r
306         IN                              SCATTER_GATHER_LIST                     *p_sgl,\r
307         IN      OUT                     ipoib_send_desc_t* const        p_desc );\r
308 \r
309 static NDIS_STATUS\r
310 __send_mgr_filter_igmp_v2(\r
311         IN                              ipoib_port_t* const                     p_port,\r
312     IN          const   ip_hdr_t* const                         p_ip_hdr,\r
313         IN                              size_t                                          iph_options_size,\r
314         IN                              MDL*                                            p_mdl,\r
315         IN                              size_t                                          buf_len );\r
316 \r
317 static NDIS_STATUS\r
318 __send_mgr_filter_udp(\r
319         IN                              ipoib_port_t* const                     p_port,\r
320         IN              const   ip_hdr_t* const                         p_ip_hdr,\r
321         IN                              MDL*                                            p_mdl,\r
322         IN                              size_t                                          buf_len,\r
323         IN                              SCATTER_GATHER_LIST                     *p_sgl,\r
324         IN      OUT                     ipoib_send_desc_t* const        p_desc );\r
325 \r
326 static NDIS_STATUS\r
327 __send_mgr_filter_dhcp(\r
328         IN                              ipoib_port_t* const                     p_port,\r
329         IN              const   udp_hdr_t* const                        p_udp_hdr,\r
330         IN                              MDL*                                            p_mdl,\r
331         IN                              size_t                                          buf_len,\r
332         IN      OUT                     ipoib_send_desc_t* const        p_desc );\r
333 \r
334 static NDIS_STATUS\r
335 __send_mgr_filter_arp(\r
336         IN                              ipoib_port_t* const                     p_port,\r
337         IN              const   eth_hdr_t* const                        p_eth_hdr,\r
338         IN                              MDL*                                            p_mdl,\r
339         IN                              size_t                                          buf_len,\r
340         IN      OUT                     ipoib_send_desc_t* const        p_desc );\r
341 \r
342 static void\r
343 __process_failed_send(\r
344         IN                              ipoib_port_t* const                     p_port,\r
345         IN                              ipoib_send_desc_t* const        p_desc,\r
346         IN              const   NDIS_STATUS                                     status,\r
347         IN              ULONG                                           send_complete_flags );\r
348 \r
349 static inline NDIS_STATUS\r
350 __send_mgr_queue(\r
351         IN                              ipoib_port_t* const                     p_port,\r
352         IN                              eth_hdr_t* const                        p_eth_hdr,\r
353                 OUT                     ipoib_endpt_t** const           pp_endpt );\r
354 \r
355 static NDIS_STATUS\r
356 __build_send_desc(\r
357         IN                              ipoib_port_t* const                     p_port,\r
358         IN                              eth_hdr_t* const                        p_eth_hdr,\r
359         IN                              MDL* const                                      p_mdl,\r
360         IN              const   size_t                                          mdl_len,\r
361         IN                              SCATTER_GATHER_LIST                     *p_sgl,\r
362         IN      OUT                     ipoib_send_desc_t* const        p_desc );\r
363 \r
364 \r
365 static void\r
366 __send_cb(\r
367         IN              const   ib_cq_handle_t                          h_cq,\r
368         IN                              void                                            *cq_context );\r
369 \r
370 static NDIS_STATUS \r
371 GetLsoHeaderSize(\r
372         IN              PNET_BUFFER             pNetBuffer,\r
373         IN              LsoData                 *pLsoData,\r
374         OUT     UINT                    *IndexOfData,\r
375         IN              ipoib_hdr_t *ipoib_hdr );\r
376 \r
377 \r
378 static NDIS_STATUS\r
379 __build_lso_desc(\r
380         IN                              ipoib_port_t* const                     p_port,\r
381         IN      OUT                     ipoib_send_desc_t* const        p_desc,\r
382         IN                              ULONG                                           mss,\r
383         IN                              SCATTER_GATHER_LIST                     *p_sgl,\r
384         IN                              int32_t                                         hdr_idx,\r
385         IN PNDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO p_lso_info );\r
386 \r
387 static NDIS_STATUS\r
388 __send_fragments(\r
389         IN              ipoib_port_t* const                                     p_port,\r
390         IN              ipoib_send_desc_t* const                        p_desc,\r
391         IN              eth_hdr_t* const                                        p_eth_hdr,\r
392         IN              ip_hdr_t* const                                         p_ip_hdr,\r
393         IN              uint32_t                                                        buf_len,\r
394         IN              NDIS_BUFFER*                                            p_ndis_buf );\r
395 \r
396 static void\r
397 __update_fragment_ip_hdr(\r
398 IN              ip_hdr_t* const         p_ip_hdr,\r
399 IN              uint16_t                        fragment_size, \r
400 IN              uint16_t                        fragment_offset, \r
401 IN              BOOLEAN                         more_fragments );\r
402 \r
403 static void\r
404 __copy_ip_options(\r
405 IN              uint8_t*                        p_buf,\r
406 IN              uint8_t*                        p_options,\r
407 IN              uint32_t                        options_len,\r
408 IN              BOOLEAN                         copy_all );\r
409 /******************************************************************************\r
410 *\r
411 * Endpoint manager operations\r
412 *\r
413 ******************************************************************************/\r
414 static void\r
415 __endpt_mgr_construct(\r
416         IN                              ipoib_port_t* const                     p_port );\r
417 \r
418 static ib_api_status_t\r
419 __endpt_mgr_init(\r
420         IN                              ipoib_port_t* const                     p_port );\r
421 \r
422 static void\r
423 __endpt_mgr_destroy(\r
424         IN                              ipoib_port_t* const                     p_port );\r
425 \r
426 /****f* IPoIB/__endpt_mgr_remove_all\r
427 * NAME\r
428 *       __endpt_mgr_remove_all\r
429 *\r
430 * DESCRIPTION\r
431 *       Removes all enpoints from the port, dereferencing them to initiate\r
432 *       destruction.\r
433 *\r
434 * SYNOPSIS\r
435 */\r
436 static void\r
437 __endpt_mgr_remove_all(\r
438         IN                              ipoib_port_t* const                     p_port );\r
439 /*\r
440 ********/\r
441 \r
442 static void\r
443 __endpt_mgr_remove(\r
444         IN                              ipoib_port_t* const                     p_port,\r
445         IN                              ipoib_endpt_t* const            p_endpt );\r
446 \r
447 static void\r
448 __endpt_mgr_reset_all(\r
449         IN                              ipoib_port_t* const                     p_port );\r
450 \r
451 static inline NDIS_STATUS\r
452 __endpt_mgr_ref(\r
453         IN                              ipoib_port_t* const                     p_port,\r
454         IN              const   mac_addr_t                                      mac,\r
455                 OUT                     ipoib_endpt_t** const           pp_endpt );\r
456 \r
457 static inline NDIS_STATUS\r
458 __endpt_mgr_get_gid_qpn(\r
459         IN                              ipoib_port_t* const                     p_port,\r
460         IN              const   mac_addr_t                                      mac,\r
461                 OUT                     ib_gid_t* const                         p_gid,\r
462                 OUT                     UNALIGNED net32_t* const        p_qpn );\r
463 \r
464 static inline ipoib_endpt_t*\r
465 __endpt_mgr_get_by_gid(\r
466         IN                              ipoib_port_t* const                     p_port,\r
467         IN              const   ib_gid_t* const                         p_gid );\r
468 \r
469 static inline ipoib_endpt_t*\r
470 __endpt_mgr_get_by_lid(\r
471         IN                              ipoib_port_t* const                     p_port,\r
472         IN              const   net16_t                                         lid );\r
473 \r
474 static inline ib_api_status_t\r
475 __endpt_mgr_insert_locked(\r
476         IN                              ipoib_port_t* const                     p_port,\r
477         IN              const   mac_addr_t                                      mac,\r
478         IN                              ipoib_endpt_t* const            p_endpt );\r
479 \r
480 static inline ib_api_status_t\r
481 __endpt_mgr_insert(\r
482         IN                              ipoib_port_t* const                     p_port,\r
483         IN              const   mac_addr_t                                      mac,\r
484         IN                              ipoib_endpt_t* const            p_endpt );\r
485 \r
486 static ib_api_status_t\r
487 __endpt_mgr_add_local(\r
488         IN                              ipoib_port_t* const                     p_port,\r
489         IN                              ib_port_info_t* const           p_port_info );\r
490 \r
491 static ib_api_status_t\r
492 __endpt_mgr_add_bcast(\r
493         IN                              ipoib_port_t* const                     p_port,\r
494         IN                              ib_mcast_rec_t                          *p_mcast_rec );\r
495 \r
496 /******************************************************************************\r
497 *\r
498 * MCast operations.\r
499 *\r
500 ******************************************************************************/\r
501 static ib_api_status_t\r
502 __port_get_bcast(\r
503         IN                              ipoib_port_t* const                     p_port );\r
504 \r
505 static ib_api_status_t\r
506 __port_join_bcast(\r
507         IN                              ipoib_port_t* const                     p_port,\r
508         IN                              ib_member_rec_t* const          p_member_rec );\r
509 \r
510 static ib_api_status_t\r
511 __port_create_bcast(\r
512         IN                              ipoib_port_t* const                     p_port );\r
513 \r
514 \r
515 \r
516 static void\r
517 __bcast_get_cb(\r
518         IN                              ib_query_rec_t                          *p_query_rec );\r
519 \r
520 \r
521 static void\r
522 __bcast_cb(\r
523         IN                              ib_mcast_rec_t                          *p_mcast_rec );\r
524 \r
525 \r
526 static void\r
527 __mcast_cb(\r
528         IN                              ib_mcast_rec_t                          *p_mcast_rec );\r
529 \r
530 void\r
531 __leave_error_mcast_cb(\r
532         IN                              void                            *context );\r
533 \r
534 \r
535 static intn_t\r
536 __gid_cmp(\r
537         IN              const   void* const                                     p_key1,\r
538         IN              const   void* const                                     p_key2 )\r
539 {\r
540         return cl_memcmp( p_key1, p_key2, sizeof(ib_gid_t) );\r
541 }\r
542 \r
543 \r
544 inline void ipoib_port_ref( ipoib_port_t * p_port, int type )\r
545 {\r
546         cl_obj_ref( &p_port->obj );\r
547 #if DBG\r
548         cl_atomic_inc( &p_port->ref[type % ref_mask] );\r
549         if ((p_port->obj.ref_cnt % 20)==0)\r
550         IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ,\r
551                 ("ref type %d ref_cnt %d\n", type, p_port->obj.ref_cnt) );\r
552         //TODO remove\r
553         //ASSERT (p_port->obj.ref_cnt < 100);\r
554 #else\r
555         UNREFERENCED_PARAMETER(type);\r
556 #endif\r
557 }\r
558 \r
559 \r
560 inline void ipoib_port_deref(ipoib_port_t * p_port, int type)\r
561 {\r
562 #if DBG\r
563         cl_atomic_dec( &p_port->ref[type % ref_mask] );\r
564         if ((p_port->obj.ref_cnt % 20) == 0)\r
565         IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ,\r
566                 ("deref type %d ref_cnt %d\n", type, p_port->obj.ref_cnt) );\r
567 #else\r
568         UNREFERENCED_PARAMETER(type);\r
569 #endif\r
570         cl_obj_deref( &p_port->obj );\r
571 \r
572 }\r
573 \r
574 /* function returns pointer to payload that is going after IP header.\r
575 *  asssuming that payload and IP header are in the same buffer\r
576 */\r
577 static void* GetIpPayloadPtr(const      ip_hdr_t* const p_ip_hdr)\r
578 {\r
579         return (void*)((uint8_t*)p_ip_hdr + IP_HEADER_LENGTH(p_ip_hdr));\r
580 }\r
581 \r
582 /******************************************************************************\r
583 *\r
584 * Implementation\r
585 *\r
586 ******************************************************************************/\r
587 ib_api_status_t\r
588 ipoib_create_port(\r
589         IN                              ipoib_adapter_t* const          p_adapter,\r
590         IN                              ib_pnp_port_rec_t* const        p_pnp_rec,\r
591                 OUT                     ipoib_port_t** const            pp_port )\r
592 {\r
593         ib_api_status_t         status;\r
594         ipoib_port_t            *p_port;\r
595 \r
596         IPOIB_ENTER( IPOIB_DBG_INIT );\r
597 \r
598         CL_ASSERT( !p_adapter->p_port );\r
599 \r
600         p_port = cl_zalloc( sizeof(ipoib_port_t) +\r
601                 (sizeof(ipoib_hdr_t) * (p_adapter->params.sq_depth - 1)) );\r
602         if( !p_port )\r
603         {\r
604                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
605                         ("Failed to allocate ipoib_port_t (%d bytes)\n",\r
606                         sizeof(ipoib_port_t)) );\r
607                 return IB_INSUFFICIENT_MEMORY;\r
608         }\r
609 \r
610 #ifdef _DEBUG_\r
611         gp_ipoib_port = p_port;\r
612 #endif\r
613 \r
614         __port_construct( p_port );\r
615 \r
616         status = __port_init( p_port, p_adapter, p_pnp_rec );\r
617         if( status != IB_SUCCESS )\r
618         {\r
619                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
620                         ("ipoib_port_init returned %s.\n", \r
621                         p_adapter->p_ifc->get_err_str( status )) );\r
622                 __port_cleanup( &p_port->obj );\r
623                 __port_free( &p_port->obj );\r
624                 return status;\r
625         }\r
626 \r
627         *pp_port = p_port;\r
628         IPOIB_EXIT( IPOIB_DBG_INIT );\r
629         return IB_SUCCESS;\r
630 }\r
631 \r
632 \r
633 void\r
634 ipoib_port_destroy(\r
635         IN                              ipoib_port_t* const                     p_port )\r
636 {\r
637         IPOIB_ENTER( IPOIB_DBG_INIT );\r
638 \r
639         CL_ASSERT( p_port );\r
640         CL_ASSERT( p_port->p_adapter );\r
641         CL_ASSERT( !p_port->p_adapter->p_port );\r
642 \r
643         cl_obj_destroy( &p_port->obj );\r
644 \r
645         IPOIB_EXIT( IPOIB_DBG_INIT );\r
646 }\r
647 \r
648 \r
649 static void\r
650 __port_construct(\r
651         IN                              ipoib_port_t* const                     p_port )\r
652 {\r
653         IPOIB_ENTER( IPOIB_DBG_INIT );\r
654 \r
655         p_port->state = IB_QPS_RESET;\r
656 \r
657         cl_obj_construct( &p_port->obj, IPOIB_OBJ_PORT );\r
658         cl_spinlock_construct( &p_port->send_lock );\r
659         cl_spinlock_construct( &p_port->recv_lock );\r
660         __ib_mgr_construct( p_port );\r
661         __buf_mgr_construct( p_port );\r
662 \r
663         __recv_mgr_construct( p_port );\r
664         __send_mgr_construct( p_port );\r
665 \r
666         __endpt_mgr_construct( p_port );\r
667 \r
668         KeInitializeEvent( &p_port->sa_event, NotificationEvent, TRUE );\r
669         KeInitializeEvent( &p_port->leave_mcast_event, NotificationEvent, TRUE );\r
670         \r
671         IPOIB_EXIT( IPOIB_DBG_INIT );\r
672 }\r
673 \r
674 \r
675 static ib_api_status_t\r
676 __port_init(\r
677         IN                              ipoib_port_t* const                     p_port,\r
678         IN                              ipoib_adapter_t* const          p_adapter,\r
679         IN                              ib_pnp_port_rec_t* const        p_pnp_rec )\r
680 {\r
681         cl_status_t                     cl_status;\r
682         ib_api_status_t         status;\r
683 \r
684         IPOIB_ENTER( IPOIB_DBG_INIT );\r
685 \r
686         p_port->port_num = p_pnp_rec->p_port_attr->port_num;\r
687         p_port->p_adapter = p_adapter;\r
688 \r
689         cl_status = cl_spinlock_init( &p_port->send_lock );\r
690         if( cl_status != CL_SUCCESS )\r
691         {\r
692                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
693                         ("cl_spinlock_init returned %#x\n", cl_status) );\r
694                 return IB_ERROR;\r
695         }\r
696 \r
697         cl_status = cl_spinlock_init( &p_port->recv_lock );\r
698         if( cl_status != CL_SUCCESS )\r
699         {\r
700                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
701                         ("cl_spinlock_init returned %#x\n", cl_status) );\r
702                 return IB_ERROR;\r
703         }\r
704 \r
705         /* Initialize the IB resource manager. */\r
706         status = __ib_mgr_init( p_port );\r
707         if( status != IB_SUCCESS )\r
708         {\r
709                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
710                         ("__ib_mgr_init returned %s\n", \r
711                         p_adapter->p_ifc->get_err_str( status )) );\r
712                 return status;\r
713         }\r
714 \r
715         /* Initialize the buffer manager. */\r
716         status = __buf_mgr_init( p_port );\r
717         if( status != IB_SUCCESS )\r
718         {\r
719                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
720                         ("__buf_mgr_init returned %s\n", \r
721                         p_adapter->p_ifc->get_err_str( status )) );\r
722                 return status;\r
723         }\r
724 \r
725         /* Initialize the receive manager. */\r
726         status = __recv_mgr_init( p_port );\r
727         if( status != IB_SUCCESS )\r
728         {\r
729                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
730                         ("__recv_mgr_init returned %s\n", \r
731                         p_adapter->p_ifc->get_err_str( status )) );\r
732                 return status;\r
733         }\r
734 \r
735         /* Initialize the endpoint manager. */\r
736         status = __endpt_mgr_init( p_port );\r
737         if( status != IB_SUCCESS )\r
738         {\r
739                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
740                         ("__endpt_mgr_init returned %s\n", \r
741                         p_adapter->p_ifc->get_err_str( status )) );\r
742                 return status;\r
743         }\r
744 \r
745          KeInitializeDpc(&p_port->recv_dpc,(PKDEFERRED_ROUTINE)__recv_cb_dpc,p_port);\r
746 \r
747 \r
748          /* Initialize multicast garbage collector timer and DPC object */\r
749          KeInitializeDpc(&p_port->gc_dpc,(PKDEFERRED_ROUTINE)__port_mcast_garbage_dpc,p_port);\r
750          KeInitializeTimerEx(&p_port->gc_timer,SynchronizationTimer);\r
751 \r
752         /* We only ever destroy from the PnP callback thread. */\r
753         cl_status = cl_obj_init( &p_port->obj, CL_DESTROY_SYNC,\r
754                 __port_destroying, __port_cleanup, __port_free );\r
755 \r
756 #if DBG\r
757         cl_atomic_inc( &p_port->ref[ref_init] );\r
758         IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ,\r
759                 ("ref type %d ref_cnt %d\n", ref_init, p_port->obj.ref_cnt) );\r
760 #endif\r
761 \r
762         if( cl_status != CL_SUCCESS )\r
763         {\r
764                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
765                         ("cl_obj_init returned %#x\n", cl_status) );\r
766                 return IB_ERROR;\r
767         }\r
768 \r
769         cl_status = cl_obj_insert_rel( &p_port->rel, &p_adapter->obj, &p_port->obj );\r
770         if( cl_status != CL_SUCCESS )\r
771         {\r
772                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
773                         ("cl_obj_insert_rel returned %#x\n", cl_status) );\r
774                 cl_obj_destroy( &p_port->obj );\r
775                 return IB_ERROR;\r
776         }\r
777 \r
778 #if DBG\r
779         cl_atomic_inc( &p_port->ref[ref_init] );\r
780         IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_OBJ,\r
781                 ("ref type %d ref_cnt %d\n", ref_init, p_port->obj.ref_cnt) );\r
782 #endif\r
783 \r
784         IPOIB_EXIT( IPOIB_DBG_INIT );\r
785         return IB_SUCCESS;\r
786 }\r
787 \r
788 \r
789 static void\r
790 __port_destroying(\r
791         IN                              cl_obj_t* const                         p_obj )\r
792 {\r
793         ipoib_port_t    *p_port;\r
794 \r
795         IPOIB_ENTER( IPOIB_DBG_INIT );\r
796 \r
797         CL_ASSERT( p_obj );\r
798 \r
799         p_port = PARENT_STRUCT( p_obj, ipoib_port_t, obj );\r
800 \r
801         ipoib_port_down( p_port );\r
802 \r
803         __endpt_mgr_remove_all( p_port );\r
804 \r
805 #if 0\r
806         if( p_port->p_adapter->params.cm_enabled )\r
807         {\r
808                 endpt_cm_buf_mgr_destroy(  p_port );\r
809                 ipoib_port_srq_destroy( p_port );\r
810                 p_port->endpt_mgr.thread_is_done = 1;\r
811                 cl_event_signal( &p_port->endpt_mgr.event );\r
812         }\r
813 #endif\r
814         ASSERT(FALSE);\r
815         //TODO NDIS6.0\r
816         ipoib_port_resume( p_port, FALSE );\r
817 \r
818         IPOIB_EXIT( IPOIB_DBG_INIT );\r
819 }\r
820 \r
821 \r
822 static void\r
823 __port_cleanup(\r
824         IN                              cl_obj_t* const                         p_obj )\r
825 {\r
826         ipoib_port_t    *p_port;\r
827 \r
828         IPOIB_ENTER( IPOIB_DBG_INIT );\r
829 \r
830         CL_ASSERT( p_obj );\r
831 \r
832         p_port = PARENT_STRUCT( p_obj, ipoib_port_t, obj );\r
833 \r
834         /* Wait for all sends and receives to get flushed. */\r
835         while( p_port->send_mgr.depth || p_port->recv_mgr.depth )\r
836                 cl_thread_suspend( 0 );\r
837 \r
838         /* Destroy the send and receive managers before closing the CA. */\r
839         __ib_mgr_destroy( p_port );\r
840 \r
841         IPOIB_EXIT( IPOIB_DBG_INIT );\r
842 }\r
843 \r
844 \r
845 static void\r
846 __port_free(\r
847         IN                              cl_obj_t* const                         p_obj )\r
848 {\r
849         ipoib_port_t    *p_port;\r
850 \r
851         IPOIB_ENTER( IPOIB_DBG_INIT );\r
852 \r
853         CL_ASSERT( p_obj );\r
854 \r
855         p_port = PARENT_STRUCT( p_obj, ipoib_port_t, obj );\r
856 \r
857         KeCancelTimer(&p_port->gc_timer);\r
858         KeFlushQueuedDpcs();\r
859         __endpt_mgr_destroy( p_port );\r
860         __recv_mgr_destroy( p_port );\r
861         __send_mgr_destroy( p_port );\r
862         __buf_mgr_destroy( p_port );\r
863 \r
864         cl_spinlock_destroy( &p_port->send_lock );\r
865         cl_spinlock_destroy( &p_port->recv_lock );\r
866 \r
867         cl_obj_deinit( p_obj );\r
868         if( p_port->p_ca_attrs )\r
869         {\r
870                 cl_free ( p_port->p_ca_attrs );\r
871         }\r
872         cl_free( p_port );\r
873 \r
874         IPOIB_EXIT( IPOIB_DBG_INIT );\r
875 }\r
876 \r
877 \r
878 \r
879 /******************************************************************************\r
880 *\r
881 * IB resource manager implementation.\r
882 *\r
883 ******************************************************************************/\r
884 static void\r
885 __ib_mgr_construct(\r
886         IN                              ipoib_port_t* const                     p_port )\r
887 {\r
888         IPOIB_ENTER( IPOIB_DBG_INIT );\r
889 \r
890         cl_memclr( &p_port->ib_mgr, sizeof(ipoib_ib_mgr_t) );\r
891 \r
892         IPOIB_EXIT( IPOIB_DBG_INIT );\r
893 }\r
894 \r
895 \r
896 static ib_api_status_t\r
897 __ib_mgr_init(\r
898         IN                              ipoib_port_t* const                     p_port )\r
899 {\r
900         ib_api_status_t         status;\r
901         ib_cq_create_t          cq_create;\r
902         ib_qp_create_t          qp_create;\r
903         ib_phys_create_t        phys_create;\r
904         ib_phys_range_t         phys_range;\r
905         uint64_t                        vaddr;\r
906         net32_t                         rkey;\r
907         ib_qp_attr_t            qp_attr;\r
908 \r
909         IPOIB_ENTER( IPOIB_DBG_INIT );\r
910 \r
911         /* Open the CA. */\r
912         status = p_port->p_adapter->p_ifc->open_ca(\r
913                 p_port->p_adapter->h_al, p_port->p_adapter->guids.ca_guid,\r
914                 NULL, p_port, &p_port->ib_mgr.h_ca );\r
915         if( status != IB_SUCCESS )\r
916         {\r
917                 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
918                         EVENT_IPOIB_OPEN_CA, 1, status );\r
919                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
920                         ("ib_open_ca returned %s\n", \r
921                         p_port->p_adapter->p_ifc->get_err_str( status )) );\r
922                 return status;\r
923         }\r
924 \r
925         status = __port_query_ca_attrs( p_port, &p_port->p_ca_attrs );\r
926         if( status != IB_SUCCESS )\r
927         {\r
928                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
929                         ("Query CA attributes failed\n" ) );\r
930                 return status;\r
931         }\r
932 #if 0\r
933         if( p_port->p_adapter->params.cm_enabled )\r
934         {\r
935                 uint32_t payload_mtu = __port_attr_to_mtu_size( \r
936                         p_port->p_ca_attrs->p_port_attr[p_port->port_num - 1].mtu )\r
937                         - sizeof(ipoib_hdr_t);\r
938                 /* adjust ipoib UD payload MTU to actual port MTU size. */\r
939                 p_port->p_adapter->params.payload_mtu = \r
940                                 max( DEFAULT_PAYLOAD_MTU, payload_mtu );\r
941                 p_port->p_adapter->params.xfer_block_size = \r
942                         (sizeof(eth_hdr_t) + p_port->p_adapter->params.payload_mtu);\r
943         }\r
944 #endif\r
945 #if IPOIB_USE_DMA\r
946         /* init DMA only once while running MiniportInitialize */\r
947         if ( !p_port->p_adapter->reset )\r
948         {\r
949                 ULONG max_phys_mapping;\r
950                 if( p_port->p_adapter->params.cm_enabled )\r
951                 {\r
952                         max_phys_mapping = p_port->p_adapter->params.cm_xfer_block_size;\r
953                 }\r
954                 else if( p_port->p_adapter->params.lso )\r
955                 {\r
956                         max_phys_mapping = LARGE_SEND_OFFLOAD_SIZE;\r
957                 }\r
958                 else\r
959                 {\r
960                         max_phys_mapping = p_port->p_adapter->params.xfer_block_size;\r
961                 }\r
962                 /*if( NdisMInitializeScatterGatherDma( p_port->p_adapter->h_adapter,\r
963                                                         TRUE, max_phys_mapping )!= NDIS_STATUS_SUCCESS )\r
964                 {\r
965                         IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
966                                 ("NdisMInitializeScatterGatherDma failed\n" ) );\r
967                         return IB_INSUFFICIENT_RESOURCES;\r
968                 }*/\r
969         }\r
970 #endif\r
971 \r
972         /* Allocate the PD. */\r
973         status = p_port->p_adapter->p_ifc->alloc_pd(\r
974                 p_port->ib_mgr.h_ca, IB_PDT_UD, p_port, &p_port->ib_mgr.h_pd );\r
975         if( status != IB_SUCCESS )\r
976         {\r
977                 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
978                         EVENT_IPOIB_ALLOC_PD, 1, status );\r
979                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
980                         ("ib_alloc_pd returned %s\n", \r
981                         p_port->p_adapter->p_ifc->get_err_str( status )) );\r
982                 return status;\r
983         }\r
984 \r
985         /* Allocate receive CQ. */\r
986         cq_create.size = p_port->p_adapter->params.rq_depth;\r
987         cq_create.pfn_comp_cb = __recv_cb;\r
988         cq_create.h_wait_obj = NULL;\r
989 \r
990         status = p_port->p_adapter->p_ifc->create_cq(\r
991                 p_port->ib_mgr.h_ca, &cq_create, p_port,\r
992                 __cq_event, &p_port->ib_mgr.h_recv_cq );\r
993         if( status != IB_SUCCESS )\r
994         {\r
995                 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
996                         EVENT_IPOIB_CREATE_RECV_CQ, 1, status );\r
997                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
998                         ("ib_create_cq returned %s.\n", \r
999                         p_port->p_adapter->p_ifc->get_err_str( status )) );\r
1000                 return status;\r
1001         }\r
1002 \r
1003         /* Allocate send CQ. */\r
1004         cq_create.size = p_port->p_adapter->params.sq_depth;\r
1005         cq_create.pfn_comp_cb = __send_cb;\r
1006 \r
1007         status = p_port->p_adapter->p_ifc->create_cq(\r
1008                 p_port->ib_mgr.h_ca, &cq_create, p_port,\r
1009                 __cq_event, &p_port->ib_mgr.h_send_cq );\r
1010         if( status != IB_SUCCESS )\r
1011         {\r
1012                 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
1013                         EVENT_IPOIB_CREATE_SEND_CQ, 1, status );\r
1014                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1015                         ("ib_create_cq returned %s.\n", \r
1016                         p_port->p_adapter->p_ifc->get_err_str( status )) );\r
1017                 return status;\r
1018         }\r
1019         \r
1020         /* Allocate the QP. */\r
1021         cl_memclr( &qp_create, sizeof(qp_create) );\r
1022         qp_create.qp_type = IB_QPT_UNRELIABLE_DGRM;\r
1023         qp_create.rq_depth = p_port->p_adapter->params.rq_depth;\r
1024         qp_create.rq_sge = 2;   /* To support buffers spanning pages. */\r
1025         qp_create.h_rq_cq = p_port->ib_mgr.h_recv_cq;\r
1026         qp_create.sq_depth = p_port->p_adapter->params.sq_depth;\r
1027 \r
1028 #define UD_QP_USED_SGE 3\r
1029         qp_create.sq_sge = MAX_SEND_SGE < p_port->p_ca_attrs->max_sges ? \r
1030                         MAX_SEND_SGE  : ( p_port->p_ca_attrs->max_sges - UD_QP_USED_SGE );\r
1031         if ( !p_port->p_ca_attrs->ipoib_csum ) \r
1032         { \r
1033                 /* checksum is not supported by device\r
1034                 user must specify BYPASS to explicitly cancel checksum calculation */\r
1035                 if (p_port->p_adapter->params.send_chksum_offload == CSUM_ENABLED)\r
1036                         p_port->p_adapter->params.send_chksum_offload = CSUM_DISABLED;\r
1037                 if (p_port->p_adapter->params.recv_chksum_offload == CSUM_ENABLED)\r
1038                         p_port->p_adapter->params.recv_chksum_offload = CSUM_DISABLED;\r
1039         }\r
1040 \r
1041         qp_create.h_sq_cq = p_port->ib_mgr.h_send_cq;\r
1042         qp_create.sq_signaled = FALSE;\r
1043         status = p_port->p_adapter->p_ifc->create_qp(\r
1044                 p_port->ib_mgr.h_pd, &qp_create, p_port,\r
1045                 __qp_event, &p_port->ib_mgr.h_qp );\r
1046         if( status != IB_SUCCESS )\r
1047         {\r
1048                 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
1049                         EVENT_IPOIB_CREATE_QP, 1, status );\r
1050                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1051                         ("ib_create_qp returned %s\n", \r
1052                         p_port->p_adapter->p_ifc->get_err_str( status )) );\r
1053                 return status;\r
1054         }\r
1055         /* Query the QP so we can get our QPN. */\r
1056         status = p_port->p_adapter->p_ifc->query_qp(\r
1057                 p_port->ib_mgr.h_qp, &qp_attr );\r
1058         if( status != IB_SUCCESS )\r
1059         {\r
1060                 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
1061                         EVENT_IPOIB_QUERY_QP, 1, status );\r
1062                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1063                         ("ib_query_qp returned %s\n", \r
1064                         p_port->p_adapter->p_ifc->get_err_str( status )) );\r
1065                 return status;\r
1066         }\r
1067         p_port->ib_mgr.qpn = qp_attr.num;\r
1068 \r
1069         /* Register all of physical memory */\r
1070         phys_create.length = MEM_REG_SIZE;\r
1071         phys_create.num_ranges = 1;\r
1072         phys_create.range_array = &phys_range;\r
1073         phys_create.buf_offset = 0;\r
1074         phys_create.hca_page_size = PAGE_SIZE;\r
1075         phys_create.access_ctrl = IB_AC_LOCAL_WRITE;\r
1076         phys_range.base_addr = 0;\r
1077         phys_range.size = MEM_REG_SIZE;\r
1078         vaddr = 0;\r
1079         status = p_port->p_adapter->p_ifc->reg_phys(\r
1080                 p_port->ib_mgr.h_pd, &phys_create, &vaddr,\r
1081                 &p_port->ib_mgr.lkey, &rkey, &p_port->ib_mgr.h_mr );\r
1082         if( status != IB_SUCCESS )\r
1083         {\r
1084                 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
1085                         EVENT_IPOIB_REG_PHYS, 1, status );\r
1086                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1087                         ("ib_reg_phys returned %s\n", \r
1088                         p_port->p_adapter->p_ifc->get_err_str( status )) );\r
1089                 return status;\r
1090         }\r
1091 \r
1092         status = ipoib_port_srq_init( p_port );\r
1093         if( status != IB_SUCCESS )\r
1094         {\r
1095                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1096                         ("ipoib_port_srq_init failed %s\n",\r
1097                         p_port->p_adapter->p_ifc->get_err_str( status )) );\r
1098                 /* disable further CM initialization */\r
1099                 p_port->p_adapter->params.cm_enabled = FALSE;\r
1100 \r
1101                 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
1102                                 EVENT_IPOIB_CONNECTED_MODE_ERR, 1, 0xbadc0de1 );\r
1103 \r
1104         }\r
1105 //CM\r
1106 #if 0\r
1107         if( p_port->p_adapter->params.cm_enabled )\r
1108         {\r
1109                 status = endpt_cm_buf_mgr_init( p_port );\r
1110                 if( status != IB_SUCCESS )\r
1111                 {\r
1112                         IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1113                                 ("CM Init buf mgr failed status %#x\n", status ) );\r
1114                         ipoib_port_srq_destroy( p_port );\r
1115                         p_port->p_adapter->params.cm_enabled = FALSE;\r
1116 \r
1117                         NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
1118                                 EVENT_IPOIB_CONNECTED_MODE_ERR, 1, 0xbadc0de2 );\r
1119                 }\r
1120                 else \r
1121                 {\r
1122                         if ( p_port->p_adapter->params.send_chksum_offload )\r
1123                         p_port->p_adapter->params.send_chksum_offload = CSUM_DISABLED;\r
1124                 }\r
1125         }\r
1126 #endif\r
1127         IPOIB_EXIT( IPOIB_DBG_INIT );\r
1128         return IB_SUCCESS;\r
1129 }\r
1130 \r
1131 static void\r
1132 __srq_async_event_cb(\r
1133 IN                      ib_async_event_rec_t            *p_event_rec )\r
1134 {\r
1135         ipoib_port_t* p_port = \r
1136                 (ipoib_port_t *)p_event_rec->context;\r
1137 \r
1138         switch( p_event_rec->code )\r
1139         {\r
1140         case IB_AE_SRQ_LIMIT_REACHED:\r
1141                                 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1142                         ("SRQ ASYNC EVENT CODE %d: %s\n", \r
1143                         p_event_rec->code, "IB_AE_SRQ_LIMIT_REACHED" ) );\r
1144                         break;\r
1145         case IB_AE_SRQ_CATAS_ERROR:\r
1146                         IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1147                                 ("SRQ ASYNC EVENT CODE %d: %s\n", \r
1148                                 p_event_rec->code, "IB_AE_SRQ_CATAS_ERROR" ) );\r
1149                         /*SRQ is in err state, must reinitialize */\r
1150                         p_port->p_adapter->hung = TRUE;\r
1151                         break;\r
1152         case IB_AE_SRQ_QP_LAST_WQE_REACHED:\r
1153                         IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1154                                 ("SRQ ASYNC EVENT CODE %d: %s\n", \r
1155                                 p_event_rec->code, "IB_AE_SRQ_QP_LAST_WQE_REACHED" ) );\r
1156                         /*SRQ is in err state, must reinitialize */\r
1157                         p_port->p_adapter->hung = TRUE;\r
1158                         break;\r
1159         default:\r
1160                         IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1161                                 ("ASYNC EVENT CODE ARRIVED %d(%#x)\n", \r
1162                                 p_event_rec->code, p_event_rec->code ) );\r
1163         }\r
1164 }\r
1165 \r
1166 ib_api_status_t\r
1167 ipoib_port_srq_init(\r
1168         IN                              ipoib_port_t* const                     p_port )\r
1169 {\r
1170         ib_api_status_t         ib_status;\r
1171         ib_srq_handle_t         h_srq;\r
1172         ib_srq_attr_t           srq_attr;\r
1173 \r
1174         IPOIB_ENTER( IPOIB_DBG_INIT );\r
1175         \r
1176         if( !p_port->p_adapter->params.cm_enabled )\r
1177                 return IB_SUCCESS;\r
1178 \r
1179         srq_attr.max_sge = min( 2, p_port->p_ca_attrs->max_srq_sges );\r
1180         srq_attr.srq_limit = 10;\r
1181         srq_attr.max_wr = \r
1182                 min( (uint32_t)p_port->p_adapter->params.rq_depth * 8,\r
1183                                 p_port->p_ca_attrs->max_srq_wrs/2 );\r
1184 \r
1185         ib_status = p_port->p_adapter->p_ifc->create_srq( \r
1186                                                                 p_port->ib_mgr.h_pd, \r
1187                                                                 &srq_attr, \r
1188                                                                 p_port, \r
1189                                                                 __srq_async_event_cb, \r
1190                                                                 &h_srq );\r
1191         if( ib_status != IB_SUCCESS )\r
1192         {\r
1193                 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
1194                         EVENT_IPOIB_CREATE_QP, 1, ib_status );\r
1195                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1196                         ("ib_create_srq failed status %s\n", \r
1197                         p_port->p_adapter->p_ifc->get_err_str( ib_status )) );\r
1198                 return ib_status;\r
1199         }\r
1200         p_port->ib_mgr.h_srq = h_srq;\r
1201 \r
1202         IPOIB_EXIT( IPOIB_DBG_INIT );\r
1203 \r
1204         return ib_status;\r
1205 }\r
1206 \r
1207 /*  __port_query_ca_attrs() \r
1208  *  returns a pointer to allocated memory.\r
1209  *  must be released by caller.\r
1210  */\r
1211 static ib_api_status_t\r
1212 __port_query_ca_attrs( \r
1213         IN              ipoib_port_t* const             p_port,\r
1214         IN              ib_ca_attr_t**                  pp_ca_attrs )\r
1215 {\r
1216         ib_api_status_t         ib_status;\r
1217         uint32_t                        attr_size;\r
1218         ib_ca_attr_t*           p_ca_attrs;\r
1219 \r
1220         *pp_ca_attrs = NULL;\r
1221 \r
1222         ib_status = \r
1223                 p_port->p_adapter->p_ifc->query_ca( p_port->ib_mgr.h_ca, NULL , &attr_size );\r
1224         if( ib_status != IB_INSUFFICIENT_MEMORY )\r
1225         {\r
1226                 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1227                         ("ib_query_ca failed status %s\n",\r
1228                         p_port->p_adapter->p_ifc->get_err_str( ib_status )) );\r
1229                 goto done;\r
1230         }\r
1231         CL_ASSERT( attr_size );\r
1232 \r
1233         p_ca_attrs = cl_zalloc( attr_size );\r
1234         if ( p_ca_attrs == NULL )\r
1235         {\r
1236                 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1237                         ("Allocate %d bytes failed for CA Attributes\n", attr_size ));\r
1238                 ib_status = IB_INSUFFICIENT_MEMORY;\r
1239                 goto done;\r
1240         }\r
1241 \r
1242         ib_status = \r
1243                 p_port->p_adapter->p_ifc->query_ca( p_port->ib_mgr.h_ca, p_ca_attrs , &attr_size );\r
1244         if ( ib_status != IB_SUCCESS )\r
1245         {\r
1246                 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1247                         ("CA attributes query failed\n") );\r
1248                 cl_free ( p_ca_attrs );\r
1249                 goto done;\r
1250         }\r
1251 \r
1252         *pp_ca_attrs = p_ca_attrs;\r
1253 done:\r
1254         return ib_status;\r
1255 }\r
1256 \r
1257 void\r
1258 ipoib_port_srq_destroy( \r
1259         IN                              ipoib_port_t* const                     p_port )\r
1260 {\r
1261         ib_api_status_t status;\r
1262 \r
1263         if( p_port->ib_mgr.h_srq )\r
1264         {\r
1265                 status =\r
1266                         p_port->p_adapter->p_ifc->destroy_srq( p_port->ib_mgr.h_srq, NULL );\r
1267                 CL_ASSERT( status == IB_SUCCESS );\r
1268                 p_port->ib_mgr.h_srq = NULL;\r
1269         }\r
1270 }\r
1271 \r
1272 static void\r
1273 __ib_mgr_destroy(\r
1274         IN                              ipoib_port_t* const                     p_port )\r
1275 {\r
1276         ib_api_status_t status;\r
1277 \r
1278         IPOIB_ENTER( IPOIB_DBG_INIT );\r
1279 \r
1280         if( p_port->ib_mgr.h_ca )\r
1281         {\r
1282                 status =\r
1283                         p_port->p_adapter->p_ifc->close_ca( p_port->ib_mgr.h_ca, NULL );\r
1284                 CL_ASSERT( status == IB_SUCCESS );\r
1285                 p_port->ib_mgr.h_ca = NULL;\r
1286         }\r
1287 \r
1288         IPOIB_EXIT( IPOIB_DBG_INIT );\r
1289 }\r
1290 \r
1291 \r
1292 \r
1293 /******************************************************************************\r
1294 *\r
1295 * Buffer manager implementation.\r
1296 *\r
1297 ******************************************************************************/\r
1298 static void\r
1299 __buf_mgr_construct(\r
1300         IN                              ipoib_port_t* const                     p_port )\r
1301 {\r
1302         IPOIB_ENTER( IPOIB_DBG_INIT );\r
1303 \r
1304         cl_qpool_construct( &p_port->buf_mgr.recv_pool );\r
1305 \r
1306         p_port->buf_mgr.h_packet_pool = NULL;\r
1307         p_port->buf_mgr.h_buffer_pool = NULL;\r
1308 \r
1309         NdisInitializeNPagedLookasideList( &p_port->buf_mgr.send_buf_list,\r
1310                 NULL, NULL, 0, MAX_XFER_BLOCK_SIZE, 'bipi', 0 );\r
1311 \r
1312         p_port->buf_mgr.h_send_pkt_pool = NULL;\r
1313         p_port->buf_mgr.h_send_buf_pool = NULL;\r
1314 \r
1315         IPOIB_EXIT( IPOIB_DBG_INIT );\r
1316 }\r
1317 \r
1318 \r
1319 static ib_api_status_t\r
1320 __buf_mgr_init(\r
1321         IN                              ipoib_port_t* const                     p_port )\r
1322 {\r
1323         cl_status_t             cl_status;\r
1324         ipoib_params_t  *p_params;\r
1325         NET_BUFFER_LIST_POOL_PARAMETERS pool_parameters;\r
1326         IPOIB_ENTER(IPOIB_DBG_INIT );\r
1327 \r
1328         CL_ASSERT( p_port );\r
1329         CL_ASSERT( p_port->p_adapter );\r
1330 \r
1331         p_params = &p_port->p_adapter->params;\r
1332 \r
1333         /* Allocate the receive descriptor pool */\r
1334         cl_status = cl_qpool_init( &p_port->buf_mgr.recv_pool,\r
1335                 p_params->rq_depth * p_params->recv_pool_ratio,\r
1336 #if IPOIB_INLINE_RECV\r
1337                 0, 0, sizeof(ipoib_recv_desc_t), __recv_ctor, NULL, p_port );\r
1338 #else   /* IPOIB_INLINE_RECV */\r
1339                 0, 0, sizeof(ipoib_recv_desc_t), __recv_ctor, __recv_dtor, p_port );\r
1340 #endif  /* IPOIB_INLINE_RECV */\r
1341         if( cl_status != CL_SUCCESS )\r
1342         {\r
1343                 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
1344                         EVENT_IPOIB_RECV_POOL, 1, cl_status );\r
1345                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1346                         ("cl_qpool_init for recvs returned %#x\n",\r
1347                         cl_status) );\r
1348                 return IB_INSUFFICIENT_MEMORY;\r
1349         }\r
1350 \r
1351         /* Allocate the NET BUFFER list pools for receive indication. */\r
1352         NdisZeroMemory(&pool_parameters, sizeof(NET_BUFFER_LIST_POOL_PARAMETERS));\r
1353     pool_parameters.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;\r
1354     pool_parameters.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;\r
1355     pool_parameters.Header.Size = sizeof(pool_parameters);\r
1356     pool_parameters.ProtocolId = 0;\r
1357     pool_parameters.ContextSize = 0;\r
1358     pool_parameters.fAllocateNetBuffer = TRUE;\r
1359     pool_parameters.PoolTag = 'CRPI';\r
1360 \r
1361     p_port->buf_mgr.h_packet_pool = NdisAllocateNetBufferListPool(\r
1362                 p_port->p_adapter->h_adapter,\r
1363                 &pool_parameters); \r
1364 \r
1365         if( !p_port->buf_mgr.h_packet_pool )\r
1366         {\r
1367                 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
1368                         EVENT_IPOIB_RECV_PKT_POOL, 1, NDIS_STATUS_RESOURCES  );\r
1369                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1370                         ("NdisAllocatePacketPool returned %08X\n", (UINT)NDIS_STATUS_RESOURCES) );\r
1371                 return IB_INSUFFICIENT_RESOURCES;\r
1372         }\r
1373 /*\r
1374         NdisAllocateBufferPool( &ndis_status, &p_port->buf_mgr.h_buffer_pool,\r
1375                 p_params->rq_depth );\r
1376         if( ndis_status != NDIS_STATUS_SUCCESS )\r
1377         {\r
1378                 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
1379                         EVENT_IPOIB_RECV_BUF_POOL, 1, ndis_status );\r
1380                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1381                         ("NdisAllocateBufferPool returned %08X\n", ndis_status) );\r
1382                 return IB_INSUFFICIENT_RESOURCES;\r
1383         }\r
1384 */\r
1385         /* Allocate the NET buffer list pool for send formatting. */\r
1386     pool_parameters.PoolTag = 'XTPI';\r
1387 \r
1388     p_port->buf_mgr.h_send_pkt_pool = NdisAllocateNetBufferListPool(\r
1389                 p_port->p_adapter->h_adapter,\r
1390                 &pool_parameters); \r
1391         if( !p_port->buf_mgr.h_send_pkt_pool)\r
1392         {\r
1393                 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
1394                         EVENT_IPOIB_SEND_PKT_POOL, 1, NDIS_STATUS_RESOURCES );\r
1395                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1396                         ("NdisAllocatePacketPool returned %08X\n", (UINT)NDIS_STATUS_RESOURCES) );\r
1397                 return IB_INSUFFICIENT_RESOURCES;\r
1398         }\r
1399 /*\r
1400         NdisAllocateBufferPool( &ndis_status,\r
1401                 &p_port->buf_mgr.h_send_buf_pool, 1 );\r
1402         if( ndis_status != NDIS_STATUS_SUCCESS )\r
1403         {\r
1404                 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
1405                         EVENT_IPOIB_SEND_BUF_POOL, 1, ndis_status );\r
1406                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1407                         ("NdisAllocateBufferPool returned %08X\n", ndis_status) );\r
1408                 return IB_INSUFFICIENT_RESOURCES;\r
1409         }\r
1410 */\r
1411         IPOIB_EXIT( IPOIB_DBG_INIT );\r
1412         return IB_SUCCESS;\r
1413 }\r
1414 \r
1415 \r
1416 static void\r
1417 __buf_mgr_destroy(\r
1418         IN                              ipoib_port_t* const                     p_port )\r
1419 {\r
1420         IPOIB_ENTER(IPOIB_DBG_INIT );\r
1421 \r
1422         CL_ASSERT( p_port );\r
1423 \r
1424         /* Destroy the send packet and buffer pools. \r
1425         if( p_port->buf_mgr.h_send_buf_pool )\r
1426                 NdisFreeBufferPool( p_port->buf_mgr.h_send_buf_pool );*/\r
1427         if( p_port->buf_mgr.h_send_pkt_pool )\r
1428                 NdisFreeNetBufferListPool ( p_port->buf_mgr.h_send_pkt_pool );\r
1429 \r
1430         /* Destroy the receive packet and buffer pools. \r
1431         if( p_port->buf_mgr.h_buffer_pool )\r
1432                 NdisFreeBufferPool( p_port->buf_mgr.h_buffer_pool );*/\r
1433         if( p_port->buf_mgr.h_packet_pool )\r
1434                 NdisFreeNetBufferListPool ( p_port->buf_mgr.h_packet_pool );\r
1435 \r
1436         /* Free the receive and send descriptors. */\r
1437         cl_qpool_destroy( &p_port->buf_mgr.recv_pool );\r
1438 \r
1439         /* Free the lookaside list of scratch buffers. */\r
1440         NdisDeleteNPagedLookasideList( &p_port->buf_mgr.send_buf_list );\r
1441 \r
1442         IPOIB_EXIT(  IPOIB_DBG_INIT );\r
1443 }\r
1444 \r
1445 \r
1446 static cl_status_t\r
1447 __recv_ctor(\r
1448         IN                              void* const                                     p_object,\r
1449         IN                              void*                                           context,\r
1450                 OUT                     cl_pool_item_t** const          pp_pool_item )\r
1451 {\r
1452         ipoib_recv_desc_t       *p_desc;\r
1453         ipoib_port_t            *p_port;\r
1454 \r
1455 #if IPOIB_INLINE_RECV\r
1456         uint32_t                        ds0_len;\r
1457 #endif\r
1458 \r
1459         IPOIB_ENTER( IPOIB_DBG_ALLOC );\r
1460 \r
1461         CL_ASSERT( p_object );\r
1462         CL_ASSERT( context );\r
1463 \r
1464         p_desc = (ipoib_recv_desc_t*)p_object;\r
1465         p_port = (ipoib_port_t*)context;\r
1466 \r
1467         /* Setup the work request. */\r
1468         p_desc->wr.ds_array = p_desc->local_ds;\r
1469         p_desc->wr.wr_id = (uintn_t)p_desc;\r
1470 \r
1471 #if IPOIB_INLINE_RECV\r
1472         /* Sanity check on the receive buffer layout */\r
1473         CL_ASSERT( (void*)&p_desc->buf.eth.pkt.type ==\r
1474                 (void*)&p_desc->buf.ib.pkt.type );\r
1475         CL_ASSERT( sizeof(recv_buf_t) == sizeof(ipoib_pkt_t) + sizeof(ib_grh_t) );\r
1476 \r
1477         /* Setup the local data segment. */\r
1478         p_desc->local_ds[0].vaddr = cl_get_physaddr( &p_desc->buf );\r
1479         p_desc->local_ds[0].lkey = p_port->ib_mgr.lkey;\r
1480         ds0_len =\r
1481                 PAGE_SIZE - ((uint32_t)p_desc->local_ds[0].vaddr & (PAGE_SIZE - 1));\r
1482         if( ds0_len >= sizeof(recv_buf_t) )\r
1483         {\r
1484                 /* The whole buffer is within a page. */\r
1485                 p_desc->local_ds[0].length = ds0_len;\r
1486                 p_desc->wr.num_ds = 1;\r
1487         }\r
1488         else\r
1489         {\r
1490                 /* The buffer crosses page boundaries. */\r
1491                 p_desc->local_ds[0].length = ds0_len;\r
1492                 p_desc->local_ds[1].vaddr = cl_get_physaddr( \r
1493                         ((uint8_t*)&p_desc->buf) + ds0_len );\r
1494                 p_desc->local_ds[1].lkey = p_port->ib_mgr.lkey;\r
1495                 p_desc->local_ds[1].length = sizeof(recv_buf_t) - ds0_len;\r
1496                 p_desc->wr.num_ds = 2;\r
1497         }\r
1498 #else   /* IPOIB_INLINE_RECV */\r
1499         /* Allocate the receive buffer. */\r
1500         p_desc->p_buf = (recv_buf_t*)cl_zalloc( sizeof(recv_buf_t) );\r
1501         if( !p_desc->p_buf )\r
1502         {\r
1503                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1504                         ("Failed to allocate receive buffer.\n") );\r
1505                 return CL_INSUFFICIENT_MEMORY;\r
1506         }\r
1507 \r
1508         /* Sanity check on the receive buffer layout */\r
1509         CL_ASSERT( (void*)&p_desc->p_buf->eth.pkt.type ==\r
1510                 (void*)&p_desc->p_buf->ib.pkt.type );\r
1511 \r
1512         /* Setup the local data segment. */\r
1513         p_desc->local_ds[0].vaddr = cl_get_physaddr( p_desc->p_buf );\r
1514         p_desc->local_ds[0].length = sizeof(ipoib_pkt_t) + sizeof(ib_grh_t);\r
1515         p_desc->local_ds[0].lkey = p_port->ib_mgr.lkey;\r
1516         p_desc->wr.num_ds = 1;\r
1517 #endif  /* IPOIB_INLINE_RECV */\r
1518 \r
1519         *pp_pool_item = &p_desc->item;\r
1520 \r
1521         IPOIB_EXIT( IPOIB_DBG_ALLOC );\r
1522         return CL_SUCCESS;\r
1523 }\r
1524 \r
1525 \r
1526 #if !IPOIB_INLINE_RECV\r
1527 static void\r
1528 __recv_dtor(\r
1529         IN              const   cl_pool_item_t* const           p_pool_item,\r
1530         IN                              void                                            *context )\r
1531 {\r
1532         ipoib_recv_desc_t       *p_desc;\r
1533 \r
1534         IPOIB_ENTER(  IPOIB_DBG_ALLOC );\r
1535 \r
1536         UNUSED_PARAM( context );\r
1537 \r
1538         p_desc = PARENT_STRUCT( p_pool_item, ipoib_recv_desc_t, item );\r
1539 \r
1540         if( p_desc->p_buf )\r
1541                 cl_free( p_desc->p_buf );\r
1542 \r
1543         IPOIB_EXIT( IPOIB_DBG_ALLOC );\r
1544 }\r
1545 #endif\r
1546 \r
1547 \r
1548 static inline ipoib_recv_desc_t*\r
1549 __buf_mgr_get_recv(\r
1550         IN                              ipoib_port_t* const                     p_port )\r
1551 {\r
1552         ipoib_recv_desc_t       *p_desc;\r
1553         IPOIB_ENTER( IPOIB_DBG_RECV );\r
1554         p_desc = (ipoib_recv_desc_t*)cl_qpool_get( &p_port->buf_mgr.recv_pool );\r
1555         /* Reference the port object for the send. */\r
1556         if( p_desc )\r
1557         {\r
1558                 ipoib_port_ref( p_port, ref_get_recv );\r
1559                 CL_ASSERT( p_desc->wr.wr_id == (uintn_t)p_desc );\r
1560 #if IPOIB_INLINE_RECV\r
1561                 CL_ASSERT( p_desc->local_ds[0].vaddr ==\r
1562                         cl_get_physaddr( &p_desc->buf ) );\r
1563 #else   /* IPOIB_INLINE_RECV */\r
1564                 CL_ASSERT( p_desc->local_ds[0].vaddr ==\r
1565                         cl_get_physaddr( p_desc->p_buf ) );\r
1566                 CL_ASSERT( p_desc->local_ds[0].length ==\r
1567                         (sizeof(ipoib_pkt_t) + sizeof(ib_grh_t)) );\r
1568 #endif  /* IPOIB_INLINE_RECV */\r
1569                 CL_ASSERT( p_desc->local_ds[0].lkey == p_port->ib_mgr.lkey );\r
1570         }\r
1571         IPOIB_EXIT( IPOIB_DBG_RECV );\r
1572         return p_desc;\r
1573 }\r
1574 \r
1575 \r
1576 //NDIS60\r
1577 static inline void\r
1578 __buf_mgr_put_recv(\r
1579         IN                              ipoib_port_t* const                     p_port,\r
1580         IN                              ipoib_recv_desc_t* const        p_desc,\r
1581         IN                              NET_BUFFER_LIST* const          p_net_buffer_list OPTIONAL )\r
1582 {\r
1583         NET_BUFFER              *p_buf = NULL;\r
1584         MDL                             *p_mdl = NULL;\r
1585         IPOIB_ENTER(IPOIB_DBG_RECV );\r
1586 \r
1587         if( p_net_buffer_list )\r
1588         {\r
1589                 NET_BUFFER_LIST_NEXT_NBL(p_net_buffer_list) = NULL;\r
1590                 p_buf = NET_BUFFER_LIST_FIRST_NB(p_net_buffer_list);\r
1591                 CL_ASSERT( p_buf );\r
1592                 p_mdl = NET_BUFFER_FIRST_MDL(p_buf);\r
1593                 CL_ASSERT( p_mdl );\r
1594                 NdisFreeMdl(p_mdl);\r
1595                 NdisFreeNetBufferList(p_net_buffer_list);\r
1596         }\r
1597 \r
1598         /* Return the descriptor to its pools. */\r
1599         cl_qpool_put( &p_port->buf_mgr.recv_pool, &p_desc->item );\r
1600 \r
1601         /*\r
1602          * Dereference the port object since the receive is no longer outstanding.\r
1603          */\r
1604         ipoib_port_deref( p_port, ref_get_recv );\r
1605         IPOIB_EXIT(  IPOIB_DBG_RECV );\r
1606 }\r
1607 \r
1608 \r
1609 static inline void\r
1610 __buf_mgr_put_recv_list(\r
1611         IN                              ipoib_port_t* const                     p_port,\r
1612         IN                              cl_qlist_t* const                       p_list )\r
1613 {\r
1614         //IPOIB_ENTER(  IPOIB_DBG_RECV );\r
1615         cl_qpool_put_list( &p_port->buf_mgr.recv_pool, p_list );\r
1616         //IPOIB_EXIT(  IPOIB_DBG_RECV );\r
1617 }\r
1618 \r
1619 \r
1620 static inline NET_BUFFER_LIST*\r
1621 __buf_mgr_get_ndis_pkt(\r
1622         IN                              ipoib_port_t* const                     p_port,\r
1623         IN                              ipoib_recv_desc_t* const        p_desc )\r
1624 {\r
1625         NET_BUFFER_LIST                 *p_net_buffer_list;\r
1626         MDL                                             *p_mdl;\r
1627 \r
1628         IPOIB_ENTER(  IPOIB_DBG_RECV );\r
1629 \r
1630         p_mdl = NdisAllocateMdl(p_port->p_adapter->h_adapter,\r
1631                                                         &p_desc->buf.eth.pkt,\r
1632                                                         p_desc->len );\r
1633         if( !p_mdl )\r
1634         {\r
1635                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1636                         ("Failed to allocate MDL\n") );\r
1637                 return NULL;\r
1638         }\r
1639 \r
1640         p_net_buffer_list = NdisAllocateNetBufferAndNetBufferList(\r
1641                                                 p_port->buf_mgr.h_packet_pool,\r
1642                                                 0,\r
1643                                                 0,\r
1644                                                 p_mdl,\r
1645                                                 0,\r
1646                                                 0);\r
1647 \r
1648         if( !p_net_buffer_list )\r
1649         {\r
1650                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1651                         ("Failed to allocate NET_BUFFER_LIST\n") );\r
1652                 NdisFreeMdl(p_mdl);\r
1653                 return NULL;\r
1654         }\r
1655 \r
1656         NET_BUFFER_LIST_NEXT_NBL(p_net_buffer_list) = NULL;\r
1657         IPOIB_PORT_FROM_PACKET( p_net_buffer_list ) = p_port;\r
1658         IPOIB_RECV_FROM_PACKET( p_net_buffer_list ) = p_desc;\r
1659         p_net_buffer_list->SourceHandle = p_port->p_adapter->h_adapter;\r
1660 \r
1661         IPOIB_EXIT(  IPOIB_DBG_RECV );\r
1662         return p_net_buffer_list;\r
1663 }\r
1664 \r
1665 \r
1666 /******************************************************************************\r
1667 *\r
1668 * Receive manager implementation.\r
1669 *\r
1670 ******************************************************************************/\r
1671 static void\r
1672 __recv_mgr_construct(\r
1673         IN                              ipoib_port_t* const                     p_port )\r
1674 {\r
1675         IPOIB_ENTER( IPOIB_DBG_INIT );\r
1676 \r
1677         cl_qlist_init( &p_port->recv_mgr.done_list );\r
1678 \r
1679         p_port->recv_mgr.recv_pkt_array = NULL;\r
1680 \r
1681         IPOIB_EXIT( IPOIB_DBG_INIT );\r
1682 }\r
1683 \r
1684 \r
1685 static ib_api_status_t\r
1686 __recv_mgr_init(\r
1687         IN                              ipoib_port_t* const                     p_port )\r
1688 {\r
1689         IPOIB_ENTER( IPOIB_DBG_INIT );\r
1690 \r
1691         /* Allocate the NDIS_PACKET pointer array for indicating receives. */\r
1692         p_port->recv_mgr.recv_pkt_array = cl_malloc(\r
1693                 sizeof(NET_BUFFER_LIST*) * p_port->p_adapter->params.rq_depth );\r
1694         if( !p_port->recv_mgr.recv_pkt_array )\r
1695         {\r
1696                 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,\r
1697                         EVENT_IPOIB_RECV_PKT_ARRAY, 0 );\r
1698                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1699                         ("cl_malloc for PNDIS_PACKET array failed.\n") );\r
1700                 return IB_INSUFFICIENT_MEMORY;\r
1701         }\r
1702 \r
1703         IPOIB_EXIT( IPOIB_DBG_INIT );\r
1704         return IB_SUCCESS;\r
1705 }\r
1706 \r
1707 \r
1708 static void\r
1709 __recv_mgr_destroy(\r
1710         IN                              ipoib_port_t* const                     p_port )\r
1711 {\r
1712         IPOIB_ENTER( IPOIB_DBG_INIT );\r
1713 \r
1714         CL_ASSERT( cl_is_qlist_empty( &p_port->recv_mgr.done_list ) );\r
1715         CL_ASSERT( !p_port->recv_mgr.depth );\r
1716 \r
1717         if( p_port->recv_mgr.recv_pkt_array )\r
1718                 cl_free( p_port->recv_mgr.recv_pkt_array );\r
1719 \r
1720         IPOIB_EXIT( IPOIB_DBG_INIT );\r
1721 }\r
1722 \r
1723 \r
1724 /*\r
1725  * Posts receive buffers to the receive queue and returns the number\r
1726  * of receives needed to bring the RQ to its low water mark.  Note\r
1727  * that the value is signed, and can go negative.  All tests must\r
1728  * be for > 0.\r
1729  */\r
1730 static int32_t\r
1731 __recv_mgr_repost(\r
1732         IN                              ipoib_port_t* const                     p_port )\r
1733 {\r
1734         ipoib_recv_desc_t       *p_head = NULL, *p_tail = NULL, *p_next;\r
1735         ib_api_status_t         status;\r
1736         ib_recv_wr_t            *p_failed;\r
1737         PERF_DECLARE( GetRecv );\r
1738         PERF_DECLARE( PostRecv );\r
1739 \r
1740         IPOIB_ENTER( IPOIB_DBG_RECV );\r
1741 \r
1742         CL_ASSERT( p_port );\r
1743         cl_obj_lock( &p_port->obj );\r
1744         if( p_port->state != IB_QPS_RTS )\r
1745         {\r
1746                 cl_obj_unlock( &p_port->obj );\r
1747                 IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV,\r
1748                         ("Port in invalid state.  Not reposting.\n") );\r
1749                 return 0;\r
1750         }\r
1751         ipoib_port_ref( p_port, ref_repost );\r
1752         cl_obj_unlock( &p_port->obj );\r
1753 \r
1754         while( p_port->recv_mgr.depth < p_port->p_adapter->params.rq_depth )\r
1755         {\r
1756                 /* Pull receives out of the pool and chain them up. */\r
1757                 cl_perf_start( GetRecv );\r
1758                 p_next = __buf_mgr_get_recv( p_port );\r
1759                 cl_perf_stop( &p_port->p_adapter->perf, GetRecv );\r
1760                 if( !p_next )\r
1761                 {\r
1762                         IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_RECV,\r
1763                                 ("Out of receive descriptors! recv queue depth 0x%x\n",p_port->recv_mgr.depth) );\r
1764                         break;\r
1765                 }\r
1766 \r
1767                 if( !p_tail )\r
1768                 {\r
1769                         p_tail = p_next;\r
1770                         p_next->wr.p_next = NULL;\r
1771                 }\r
1772                 else\r
1773                 {\r
1774                         p_next->wr.p_next = &p_head->wr;\r
1775                 }\r
1776 \r
1777                 p_head = p_next;\r
1778 \r
1779                 p_port->recv_mgr.depth++;\r
1780         }\r
1781 \r
1782         if( p_head )\r
1783         {\r
1784                 cl_perf_start( PostRecv );\r
1785                 status = p_port->p_adapter->p_ifc->post_recv(\r
1786                         p_port->ib_mgr.h_qp, &p_head->wr, &p_failed );\r
1787                 cl_perf_stop( &p_port->p_adapter->perf, PostRecv );\r
1788 \r
1789                 if( status != IB_SUCCESS )\r
1790                 {\r
1791                         IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1792                                 ("ip_post_recv returned %s\n", \r
1793                                 p_port->p_adapter->p_ifc->get_err_str( status )) );\r
1794                         /* return the descriptors to the pool */\r
1795                         while( p_failed )\r
1796                         {\r
1797                                 p_head = PARENT_STRUCT( p_failed, ipoib_recv_desc_t, wr );\r
1798                                 p_failed = p_failed->p_next;\r
1799 \r
1800                                 __buf_mgr_put_recv( p_port, p_head, NULL );\r
1801                                 p_port->recv_mgr.depth--;\r
1802                         }\r
1803                 }\r
1804         }\r
1805 \r
1806         ipoib_port_deref( p_port, ref_repost );\r
1807         IPOIB_EXIT( IPOIB_DBG_RECV );\r
1808         return p_port->p_adapter->params.rq_low_watermark - p_port->recv_mgr.depth;\r
1809 }\r
1810 \r
1811 void\r
1812 ipoib_return_net_buffer_list(\r
1813         IN                              NDIS_HANDLE                                     adapter_context,\r
1814         IN                              NET_BUFFER_LIST                         *p_net_buffer_lists,\r
1815         IN                              ULONG                                           return_flags)\r
1816 {\r
1817 //      cl_list_item_t          *p_item;\r
1818         ipoib_port_t            *p_port;\r
1819         ipoib_recv_desc_t       *p_desc;\r
1820         NET_BUFFER_LIST         *cur_net_buffer_list,*next_net_buffer_list;\r
1821 //      ib_api_status_t         status = IB_NOT_DONE;\r
1822 //      int32_t                         shortage;\r
1823 //      ULONG                           complete_flags = 0;\r
1824         PERF_DECLARE( ReturnPacket );\r
1825         PERF_DECLARE( ReturnPutRecv );\r
1826         PERF_DECLARE( ReturnRepostRecv );\r
1827         PERF_DECLARE( ReturnPreparePkt );\r
1828         PERF_DECLARE( ReturnNdisIndicate );\r
1829 \r
1830         IPOIB_ENTER( IPOIB_DBG_RECV );\r
1831 \r
1832         UNUSED_PARAM( return_flags );\r
1833 \r
1834         p_port = ((ipoib_adapter_t*)adapter_context)->p_port;\r
1835         CL_ASSERT( p_net_buffer_lists );\r
1836 \r
1837         cl_perf_start( ReturnPacket );\r
1838         cl_spinlock_acquire( &p_port->recv_lock );\r
1839         for (cur_net_buffer_list = p_net_buffer_lists;\r
1840                  cur_net_buffer_list != NULL;\r
1841                  cur_net_buffer_list = next_net_buffer_list)\r
1842         {\r
1843                 next_net_buffer_list = NET_BUFFER_LIST_NEXT_NBL(cur_net_buffer_list);\r
1844 \r
1845                 /* Get the port and descriptor from the packet. */\r
1846                 CL_ASSERT(p_port == IPOIB_PORT_FROM_PACKET( cur_net_buffer_list ));\r
1847                 p_desc = IPOIB_RECV_FROM_PACKET( cur_net_buffer_list );\r
1848 \r
1849                 \r
1850                 //TODO: NDIS60, rewrite this block\r
1851                 /* Get descriptor from the packet. */\r
1852 #if 0\r
1853                 if( p_desc->type == PKT_TYPE_CM_UCAST )\r
1854                 {\r
1855                         NDIS_BUFFER             *p_buf;\r
1856 \r
1857                         /* Unchain the NDIS buffer. */\r
1858                         NdisUnchainBufferAtFront( p_packet, &p_buf );\r
1859                         CL_ASSERT( p_buf );\r
1860                         /* Return the NDIS packet and NDIS buffer to their pools. */\r
1861                         NdisDprFreePacketNonInterlocked( p_packet );\r
1862                         NdisFreeBuffer( p_buf );\r
1863 \r
1864                         endpt_cm_buf_mgr_put_recv( &p_port->cm_buf_mgr, (ipoib_cm_desc_t *)p_desc );\r
1865                         status = endpt_cm_post_recv( p_port );\r
1866                         if(  status != IB_SUCCESS )\r
1867                         {\r
1868                                 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
1869                                         ("Post Recv QP failed\n" ) );\r
1870                         }\r
1871                         cl_spinlock_release( &p_port->recv_lock );\r
1872                         return;\r
1873                 }\r
1874 #endif\r
1875 \r
1876                 cl_perf_start( ReturnPutRecv );\r
1877                 __buf_mgr_put_recv( p_port, p_desc, cur_net_buffer_list );\r
1878                 cl_perf_stop( &p_port->p_adapter->perf, ReturnPutRecv );\r
1879         }\r
1880 #if 0            \r
1881         /* Repost buffers. */\r
1882         cl_perf_start( ReturnRepostRecv );\r
1883         shortage = __recv_mgr_repost( p_port );\r
1884         cl_perf_stop( &p_port->p_adapter->perf, ReturnRepostRecv );\r
1885 \r
1886         for( p_item = cl_qlist_remove_head( &p_port->recv_mgr.done_list );\r
1887                 p_item != cl_qlist_end( &p_port->recv_mgr.done_list );\r
1888                 p_item = cl_qlist_remove_head( &p_port->recv_mgr.done_list ) )\r
1889         {\r
1890                 p_desc = (ipoib_recv_desc_t*)p_item;\r
1891 \r
1892                 cl_perf_start( ReturnPreparePkt );\r
1893                 status = __recv_mgr_prepare_pkt( p_port, p_desc, &cur_net_buffer_list );\r
1894                 cl_perf_stop( &p_port->p_adapter->perf, ReturnPreparePkt );\r
1895                 if( status == IB_SUCCESS )\r
1896                 {\r
1897                         if( shortage > 0 )\r
1898                                 NET_BUFFER_LIST_STATUS( cur_net_buffer_list) = NDIS_STATUS_RESOURCES;\r
1899                         else\r
1900                                 NET_BUFFER_LIST_STATUS( cur_net_buffer_list) = NDIS_STATUS_SUCCESS;\r
1901 \r
1902                         cl_spinlock_release( &p_port->recv_lock );\r
1903                         NET_BUFFER_LIST_NEXT_NBL(cur_net_buffer_list) = NULL;\r
1904                         cl_perf_start( ReturnNdisIndicate );\r
1905                         NdisMRecvIndicate( p_port->p_adapter->h_adapter,\r
1906                                 cur_net_buffer_list, complete_flags );\r
1907                         cl_perf_stop( &p_port->p_adapter->perf, ReturnNdisIndicate );\r
1908                         cl_spinlock_acquire( &p_port->recv_lock );\r
1909 \r
1910                         if( shortage > 0 )\r
1911                         {\r
1912                                 cl_perf_start( ReturnPutRecv );\r
1913                                 __buf_mgr_put_recv( p_port, p_desc, cur_net_buffer_list );\r
1914                                 cl_perf_stop( &p_port->p_adapter->perf, ReturnPutRecv );\r
1915 \r
1916                                 /* Repost buffers. */\r
1917                                 cl_perf_start( ReturnRepostRecv );\r
1918                                 shortage = __recv_mgr_repost( p_port );\r
1919                                 cl_perf_stop( &p_port->p_adapter->perf, ReturnRepostRecv );\r
1920                         }\r
1921                 }\r
1922                 else if( status != IB_NOT_DONE )\r
1923                 {\r
1924                         IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV,\r
1925                                 ("__recv_mgr_prepare_pkt returned %s\n",\r
1926                                 p_port->p_adapter->p_ifc->get_err_str( status )) );\r
1927                         /* Return the item to the head of the list. */\r
1928                         cl_qlist_insert_head( &p_port->recv_mgr.done_list, p_item );\r
1929                         break;\r
1930                 }\r
1931         }\r
1932         #endif\r
1933         cl_spinlock_release( &p_port->recv_lock );\r
1934         cl_perf_stop( &p_port->p_adapter->perf, ReturnPacket );\r
1935 \r
1936         IPOIB_EXIT( IPOIB_DBG_RECV );\r
1937 }\r
1938 \r
1939 static void __recv_cb_dpc(KDPC *p_gc_dpc,void *context,void * s_arg1 , void * s_arg2)\r
1940 {\r
1941 \r
1942         ipoib_port_t *p_port = context;\r
1943 \r
1944         UNREFERENCED_PARAMETER(p_gc_dpc);\r
1945         UNREFERENCED_PARAMETER(s_arg1);\r
1946         UNREFERENCED_PARAMETER(s_arg2);\r
1947 \r
1948 \r
1949         __recv_cb(NULL, p_port);\r
1950         ipoib_port_deref( p_port, ref_recv_cb );\r
1951 \r
1952 \r
1953 }\r
1954 \r
1955 \r
1956 static void\r
1957 __recv_cb(\r
1958         IN              const   ib_cq_handle_t                          h_cq,\r
1959         IN                              void                                            *cq_context )\r
1960 {\r
1961         ipoib_port_t            *p_port;\r
1962         ib_api_status_t         status;\r
1963         ib_wc_t                         wc[MAX_RECV_WC], *p_free, *p_wc;\r
1964         int32_t                         pkt_cnt, recv_cnt = 0, shortage, discarded;\r
1965         cl_qlist_t                      done_list, bad_list;\r
1966         size_t                          i;\r
1967         ULONG                           recv_complete_flags = 0;\r
1968 \r
1969         PERF_DECLARE( RecvCompBundle );\r
1970         PERF_DECLARE( RecvCb );\r
1971         PERF_DECLARE( PollRecv );\r
1972         PERF_DECLARE( RepostRecv );\r
1973         PERF_DECLARE( FilterRecv );\r
1974         PERF_DECLARE( BuildPktArray );\r
1975         PERF_DECLARE( RecvNdisIndicate );\r
1976         PERF_DECLARE( RearmRecv );\r
1977         PERF_DECLARE( PutRecvList );\r
1978 \r
1979         IPOIB_ENTER( IPOIB_DBG_RECV );\r
1980 \r
1981         cl_perf_clr( RecvCompBundle );\r
1982 \r
1983         cl_perf_start( RecvCb );\r
1984 //return ;\r
1985         UNUSED_PARAM( h_cq );\r
1986 \r
1987         NDIS_SET_SEND_COMPLETE_FLAG(recv_complete_flags, NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL );\r
1988 \r
1989         p_port = (ipoib_port_t*)cq_context;\r
1990 \r
1991         cl_qlist_init( &done_list );\r
1992         cl_qlist_init( &bad_list );\r
1993 \r
1994         ipoib_port_ref( p_port, ref_recv_cb );\r
1995         for( i = 0; i < MAX_RECV_WC; i++ )\r
1996                 wc[i].p_next = &wc[i + 1];\r
1997         wc[MAX_RECV_WC - 1].p_next = NULL;\r
1998 \r
1999         /*\r
2000          * We'll be accessing the endpoint map so take a reference\r
2001          * on it to prevent modifications.\r
2002          */\r
2003         cl_obj_lock( &p_port->obj );\r
2004         cl_atomic_inc( &p_port->endpt_rdr );\r
2005         cl_obj_unlock( &p_port->obj );\r
2006 \r
2007         do\r
2008         {\r
2009                 /* If we get here, then the list of WCs is intact. */\r
2010                 p_free = wc;\r
2011 \r
2012                 cl_perf_start( PollRecv );\r
2013                 status = p_port->p_adapter->p_ifc->poll_cq(\r
2014                         p_port->ib_mgr.h_recv_cq, &p_free, &p_wc );\r
2015                 cl_perf_stop( &p_port->p_adapter->perf, PollRecv );\r
2016                 CL_ASSERT( status == IB_SUCCESS || status == IB_NOT_FOUND );\r
2017 \r
2018                 /* Look at the payload now and filter ARP and DHCP packets. */\r
2019                 cl_perf_start( FilterRecv );\r
2020                 recv_cnt += __recv_mgr_filter( p_port, p_wc, &done_list, &bad_list );\r
2021                 cl_perf_stop( &p_port->p_adapter->perf, FilterRecv );\r
2022 \r
2023         } while( (!p_free) && (recv_cnt < 128));\r
2024 \r
2025         /* We're done looking at the endpoint map, release the reference. */\r
2026         cl_atomic_dec( &p_port->endpt_rdr );\r
2027 \r
2028         cl_perf_log( &p_port->p_adapter->perf, RecvCompBundle, recv_cnt );\r
2029 \r
2030         cl_spinlock_acquire( &p_port->recv_lock );\r
2031 \r
2032         /* Update our posted depth. */\r
2033         p_port->recv_mgr.depth -= recv_cnt;\r
2034 \r
2035         /* Return any discarded receives to the pool */\r
2036         cl_perf_start( PutRecvList );\r
2037         __buf_mgr_put_recv_list( p_port, &bad_list );\r
2038         cl_perf_stop( &p_port->p_adapter->perf, PutRecvList );\r
2039 \r
2040         do\r
2041         {\r
2042                 int32_t cnt;\r
2043                 /* Repost ASAP so we don't starve the RQ. */\r
2044                 cl_perf_start( RepostRecv );\r
2045                 shortage = __recv_mgr_repost( p_port );\r
2046                 cl_perf_stop( &p_port->p_adapter->perf, RepostRecv );\r
2047 \r
2048                 cl_perf_start( BuildPktArray );\r
2049                 /* Notify NDIS of any and all possible receive buffers. */\r
2050                 pkt_cnt = __recv_mgr_build_pkt_array(\r
2051                         p_port, shortage, &done_list, &discarded );\r
2052                 cl_perf_stop( &p_port->p_adapter->perf, BuildPktArray );\r
2053 \r
2054                 /* Only indicate receives if we actually had any. */\r
2055                 if( discarded && shortage > 0 )\r
2056                 {\r
2057                         /* We may have thrown away packets, and have a shortage */\r
2058                         cl_perf_start( RepostRecv );\r
2059                         __recv_mgr_repost( p_port );\r
2060                         cl_perf_stop( &p_port->p_adapter->perf, RepostRecv );\r
2061                 }\r
2062 \r
2063                 if( !pkt_cnt )\r
2064                         break;\r
2065 \r
2066                 cl_spinlock_release( &p_port->recv_lock );\r
2067                 for( cnt = 0; cnt < pkt_cnt -1; cnt++)\r
2068                 {\r
2069                         NET_BUFFER_LIST_NEXT_NBL(p_port->recv_mgr.recv_pkt_array[cnt]) = \r
2070                                 p_port->recv_mgr.recv_pkt_array[cnt + 1];\r
2071                 }\r
2072                 cl_perf_start( RecvNdisIndicate );\r
2073 #ifndef NDIS_DEFAULT_PORT_NUMBER\r
2074 #define NDIS_DEFAULT_PORT_NUMBER 0\r
2075 #endif\r
2076                 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2077                                         ("Indicate NDIS with  %d received NBs\n",\r
2078                                         pkt_cnt) );\r
2079                 NdisMIndicateReceiveNetBufferLists(\r
2080                         p_port->p_adapter->h_adapter,\r
2081                         p_port->recv_mgr.recv_pkt_array[0],\r
2082                         NDIS_DEFAULT_PORT_NUMBER,\r
2083                         pkt_cnt,\r
2084                         recv_complete_flags);\r
2085 \r
2086                 cl_perf_stop( &p_port->p_adapter->perf, RecvNdisIndicate );\r
2087 \r
2088                 /*\r
2089                  * Cap the number of receives to put back to what we just indicated\r
2090                  * with NDIS_STATUS_RESOURCES.\r
2091                  */\r
2092                 if( shortage > 0 )\r
2093                 {\r
2094                         if( pkt_cnt < shortage )\r
2095                                 shortage = pkt_cnt;\r
2096 \r
2097                         /* Return all but the last packet to the pool. */\r
2098                         cl_spinlock_acquire( &p_port->recv_lock );\r
2099                         while( shortage-- > 1 )\r
2100                         {\r
2101                                 __buf_mgr_put_recv( p_port,\r
2102                                         (ipoib_recv_desc_t *)IPOIB_RECV_FROM_PACKET( p_port->recv_mgr.recv_pkt_array[shortage] ),\r
2103                                         p_port->recv_mgr.recv_pkt_array[shortage] );\r
2104                         }\r
2105                         cl_spinlock_release( &p_port->recv_lock );\r
2106 \r
2107                         /*\r
2108                          * Return the last packet as if NDIS returned it, so that we repost\r
2109                          * and report any other pending receives.\r
2110                          */\r
2111                         ipoib_return_net_buffer_list( NULL, p_port->recv_mgr.recv_pkt_array[0],recv_complete_flags );\r
2112                 }\r
2113                 cl_spinlock_acquire( &p_port->recv_lock );\r
2114 \r
2115         } while( pkt_cnt );\r
2116         cl_spinlock_release( &p_port->recv_lock );\r
2117 \r
2118         if (p_free ) {\r
2119                 /*\r
2120                  * Rearm after filtering to prevent contention on the enpoint maps\r
2121                  * and eliminate the possibility of having a call to\r
2122                  * __endpt_mgr_insert find a duplicate.\r
2123                  */\r
2124                 cl_perf_start( RearmRecv );\r
2125                 status = p_port->p_adapter->p_ifc->rearm_cq(\r
2126                         p_port->ib_mgr.h_recv_cq, FALSE );\r
2127                 cl_perf_stop( &p_port->p_adapter->perf, RearmRecv );\r
2128                 CL_ASSERT( status == IB_SUCCESS );\r
2129 \r
2130                 ipoib_port_deref( p_port, ref_recv_cb );\r
2131         } else {\r
2132                 // Please note the reference is still up\r
2133                 KeInsertQueueDpc(&p_port->recv_dpc, NULL, NULL);\r
2134         }\r
2135 \r
2136         cl_perf_stop( &p_port->p_adapter->perf, RecvCb );\r
2137 \r
2138         IPOIB_EXIT( IPOIB_DBG_RECV );\r
2139 }\r
2140 \r
2141 \r
2142 static void\r
2143 __recv_get_endpts(\r
2144         IN                              ipoib_port_t* const                     p_port,\r
2145         IN                              ipoib_recv_desc_t* const        p_desc,\r
2146         IN                              ib_wc_t* const                          p_wc,\r
2147                 OUT                     ipoib_endpt_t** const           pp_src,\r
2148                 OUT                     ipoib_endpt_t** const           pp_dst )\r
2149 {\r
2150         ib_api_status_t         status;\r
2151         mac_addr_t                      mac;\r
2152         PERF_DECLARE( GetEndptByGid );\r
2153         PERF_DECLARE( GetEndptByLid );\r
2154         PERF_DECLARE( EndptInsert );\r
2155 \r
2156         IPOIB_ENTER( IPOIB_DBG_RECV );\r
2157 \r
2158         /* Setup our shortcut pointers based on whether GRH is valid. */\r
2159         if( p_wc->recv.ud.recv_opt & IB_RECV_OPT_GRH_VALID )\r
2160         {\r
2161                 /* Lookup the source endpoints based on GID. */\r
2162                 cl_perf_start( GetEndptByGid );\r
2163                 *pp_src =\r
2164 #if IPOIB_INLINE_RECV\r
2165                         __endpt_mgr_get_by_gid( p_port, &p_desc->buf.ib.grh.src_gid );\r
2166 #else   /* IPOIB_INLINE_RECV */\r
2167                         __endpt_mgr_get_by_gid( p_port, &p_desc->p_buf->ib.grh.src_gid );\r
2168 #endif  /* IPOIB_INLINE_RECV */\r
2169                 cl_perf_stop( &p_port->p_adapter->perf, GetEndptByGid );\r
2170 \r
2171                 /*\r
2172                  * Lookup the destination endpoint based on GID.\r
2173                  * This is used along with the packet filter to determine\r
2174                  * whether to report this to NDIS.\r
2175                  */\r
2176                 cl_perf_start( GetEndptByGid );\r
2177                 *pp_dst =\r
2178 #if IPOIB_INLINE_RECV\r
2179                         __endpt_mgr_get_by_gid( p_port, &p_desc->buf.ib.grh.dest_gid );\r
2180 #else   /* IPOIB_INLINE_RECV */\r
2181                         __endpt_mgr_get_by_gid( p_port, &p_desc->p_buf->ib.grh.dest_gid );\r
2182 #endif  /* IPOIB_INLINE_RECV */\r
2183                 cl_perf_stop( &p_port->p_adapter->perf, GetEndptByGid );\r
2184 \r
2185                 /*\r
2186                  * Create the source endpoint if it does not exist.  Note that we\r
2187                  * can only do this for globally routed traffic since we need the\r
2188                  * information from the GRH to generate the MAC.\r
2189                  */\r
2190                 if( !*pp_src )\r
2191                 {\r
2192                         status = ipoib_mac_from_guid(\r
2193 #if IPOIB_INLINE_RECV\r
2194                                 p_desc->buf.ib.grh.src_gid.unicast.interface_id, p_port->p_adapter->params.guid_mask, &mac );\r
2195 #else   /* IPOIB_INLINE_RECV */\r
2196                                 p_desc->p_buf->ib.grh.src_gid.unicast.interface_id, p_port->p_adapter->params.guid_mask, &mac );\r
2197 #endif  /* IPOIB_INLINE_RECV */\r
2198                         if( status != IB_SUCCESS )\r
2199                         {\r
2200                                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2201                                         ("ipoib_mac_from_guid returned %s\n",\r
2202                                         p_port->p_adapter->p_ifc->get_err_str( status )) );\r
2203                                 return;\r
2204                         }\r
2205 \r
2206                         /* Create the endpoint. */\r
2207 #if IPOIB_INLINE_RECV\r
2208                         *pp_src = ipoib_endpt_create( &p_desc->buf.ib.grh.src_gid,\r
2209 #else   /* IPOIB_INLINE_RECV */\r
2210                         *pp_src = ipoib_endpt_create( &p_desc->p_buf->ib.grh.src_gid,\r
2211 #endif  /* IPOIB_INLINE_RECV */\r
2212                                 p_wc->recv.ud.remote_lid, p_wc->recv.ud.remote_qp );\r
2213                         if( !*pp_src )\r
2214                         {\r
2215                                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2216                                         ("ipoib_endpt_create failed\n") );\r
2217                                 return;\r
2218                         }\r
2219                         cl_perf_start( EndptInsert );\r
2220                         cl_obj_lock( &p_port->obj );\r
2221                         status = __endpt_mgr_insert( p_port, mac, *pp_src );\r
2222                         if( status != IB_SUCCESS )\r
2223                         {\r
2224                                 cl_obj_unlock( &p_port->obj );\r
2225                                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2226                                         ("__endpt_mgr_insert returned %s\n",\r
2227                                         p_port->p_adapter->p_ifc->get_err_str( status )) );\r
2228                                 *pp_src = NULL;\r
2229                                 return;\r
2230                         }\r
2231                         cl_obj_unlock( &p_port->obj );\r
2232                         cl_perf_stop( &p_port->p_adapter->perf, EndptInsert );\r
2233                 }\r
2234         }\r
2235         else\r
2236         {\r
2237                 /*\r
2238                  * Lookup the remote endpoint based on LID.  Note that only\r
2239                  * unicast traffic can be LID routed.\r
2240                  */\r
2241                 cl_perf_start( GetEndptByLid );\r
2242                 *pp_src = __endpt_mgr_get_by_lid( p_port, p_wc->recv.ud.remote_lid );\r
2243                 cl_perf_stop( &p_port->p_adapter->perf, GetEndptByLid );\r
2244                 *pp_dst = p_port->p_local_endpt;\r
2245                 CL_ASSERT( *pp_dst );\r
2246         }\r
2247 \r
2248         if( *pp_src && !ipoib_is_voltaire_router_gid( &(*pp_src)->dgid ) &&\r
2249                 (*pp_src)->qpn != p_wc->recv.ud.remote_qp )\r
2250         {\r
2251                 /* Update the QPN for the endpoint. */\r
2252                 IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV,\r
2253                         ("Updating QPN for MAC: %02X-%02X-%02X-%02X-%02X-%02X\n",\r
2254                         (*pp_src )->mac.addr[0], (*pp_src )->mac.addr[1],\r
2255                         (*pp_src )->mac.addr[2], (*pp_src )->mac.addr[3],\r
2256                         (*pp_src )->mac.addr[4], (*pp_src )->mac.addr[5]) );\r
2257 //              (*pp_src)->qpn = p_wc->recv.ud.remote_qp;\r
2258         }\r
2259 \r
2260         if( *pp_src && *pp_dst )\r
2261         {\r
2262                 IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_RECV,\r
2263                         ("Recv:\n"\r
2264                         "\tsrc MAC: %02X-%02X-%02X-%02X-%02X-%02X\n"\r
2265                         "\tdst MAC: %02X-%02X-%02X-%02X-%02X-%02X\n",\r
2266                         (*pp_src )->mac.addr[0], (*pp_src )->mac.addr[1],\r
2267                         (*pp_src )->mac.addr[2], (*pp_src )->mac.addr[3],\r
2268                         (*pp_src )->mac.addr[4], (*pp_src )->mac.addr[5],\r
2269                         (*pp_dst )->mac.addr[0], (*pp_dst )->mac.addr[1],\r
2270                         (*pp_dst )->mac.addr[2], (*pp_dst )->mac.addr[3],\r
2271                         (*pp_dst )->mac.addr[4], (*pp_dst )->mac.addr[5]) );\r
2272         }\r
2273 \r
2274         IPOIB_EXIT( IPOIB_DBG_RECV );\r
2275 }\r
2276 \r
2277 \r
2278 static int32_t\r
2279 __recv_mgr_filter(\r
2280         IN                              ipoib_port_t* const                     p_port,\r
2281         IN                              ib_wc_t* const                          p_done_wc_list,\r
2282                 OUT                     cl_qlist_t* const                       p_done_list,\r
2283                 OUT                     cl_qlist_t* const                       p_bad_list )\r
2284 {\r
2285         ipoib_recv_desc_t               *p_desc;\r
2286         ib_wc_t                                 *p_wc;\r
2287         ipoib_pkt_t                             *p_ipoib;\r
2288         eth_pkt_t                               *p_eth;\r
2289         ipoib_endpt_t                   *p_src, *p_dst;\r
2290         ib_api_status_t                 status;\r
2291         uint32_t                                len;\r
2292         int32_t                                 recv_cnt = 0;\r
2293         PERF_DECLARE( GetRecvEndpts );\r
2294         PERF_DECLARE( RecvGen );\r
2295         PERF_DECLARE( RecvTcp );\r
2296         PERF_DECLARE( RecvUdp );\r
2297         PERF_DECLARE( RecvDhcp );\r
2298         PERF_DECLARE( RecvArp );\r
2299 \r
2300         IPOIB_ENTER( IPOIB_DBG_RECV );\r
2301 \r
2302         for( p_wc = p_done_wc_list; p_wc; p_wc = p_wc->p_next )\r
2303         {\r
2304                 CL_ASSERT( p_wc->status != IB_WCS_SUCCESS || p_wc->wc_type == IB_WC_RECV );\r
2305                 p_desc = (ipoib_recv_desc_t*)(uintn_t)p_wc->wr_id;\r
2306                 recv_cnt++;\r
2307 \r
2308                 if( p_wc->status != IB_WCS_SUCCESS )\r
2309                 {\r
2310                         if( p_wc->status != IB_WCS_WR_FLUSHED_ERR )\r
2311                         {\r
2312                                 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2313                                         ("Failed completion %s  (vendor specific %#x)\n",\r
2314                                         p_port->p_adapter->p_ifc->get_wc_status_str( p_wc->status ),\r
2315                                         (int)p_wc->vendor_specific) );\r
2316                                 ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0, 0 );\r
2317                         }\r
2318                         else\r
2319                         {\r
2320                                 IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_RECV,\r
2321                                         ("Flushed completion %s\n",\r
2322                                         p_port->p_adapter->p_ifc->get_wc_status_str( p_wc->status )) );\r
2323                                 ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_DROPPED, 0, 0 );\r
2324                         }\r
2325                         cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item );\r
2326                         /* Dereference the port object on behalf of the failed receive. */\r
2327                         ipoib_port_deref( p_port, ref_failed_recv_wc );\r
2328                         continue;\r
2329                 }\r
2330 \r
2331                 len = p_wc->length - sizeof(ib_grh_t);\r
2332 \r
2333                 if( len < sizeof(ipoib_hdr_t) )\r
2334                 {\r
2335                         IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2336                                 ("Received ETH packet < min size\n") );\r
2337                         ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0, 0 );\r
2338                         cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item );\r
2339                         ipoib_port_deref( p_port, ref_recv_inv_len );\r
2340                         continue;\r
2341                 }\r
2342 \r
2343                 if((len - sizeof(ipoib_hdr_t)) > p_port->p_adapter->params.payload_mtu)\r
2344                 {\r
2345                         IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2346                                 ("Received ETH packet len %d > payload MTU (%d)\n",\r
2347                                 (len - sizeof(ipoib_hdr_t)),\r
2348                                 p_port->p_adapter->params.payload_mtu) );\r
2349                         ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0, 0 );\r
2350                         cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item );\r
2351                         ipoib_port_deref( p_port, ref_recv_inv_len );\r
2352                         continue;\r
2353                         \r
2354                 }\r
2355                 /* Successful completion.  Get the receive information. */\r
2356                 p_desc->ndis_csum.Value = ( ( p_wc->recv.ud.recv_opt & IB_RECV_OPT_CSUM_MASK ) >> 8 );\r
2357                 p_desc->len = len + 14 - 4 ;\r
2358                 cl_perf_start( GetRecvEndpts );\r
2359                 __recv_get_endpts( p_port, p_desc, p_wc, &p_src, &p_dst );\r
2360                 cl_perf_stop( &p_port->p_adapter->perf, GetRecvEndpts );\r
2361 \r
2362 #if IPOIB_INLINE_RECV\r
2363                 p_ipoib = &p_desc->buf.ib.pkt;\r
2364                 p_eth = &p_desc->buf.eth.pkt;\r
2365 #else   /* IPOIB_INLINE_RECV */\r
2366                 p_ipoib = &p_desc->p_buf->ib.pkt;\r
2367                 p_eth = &p_desc->p_buf->eth.pkt;\r
2368 #endif  /*IPOIB_INLINE_RECV */\r
2369 \r
2370                 if( p_src )\r
2371                 {\r
2372                         /* Don't report loopback traffic - we requested SW loopback. */\r
2373                         if( !cl_memcmp( &p_port->p_adapter->params.conf_mac,\r
2374                                 &p_src->mac, sizeof(p_port->p_adapter->params.conf_mac) ) )\r
2375                         {\r
2376                                 /*\r
2377                                  * "This is not the packet you're looking for" - don't update\r
2378                                  * receive statistics, the packet never happened.\r
2379                                  */\r
2380                                 cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item );\r
2381                                 /* Dereference the port object on behalf of the failed recv. */\r
2382                                 ipoib_port_deref( p_port, ref_recv_loopback );\r
2383                                 continue;\r
2384                         }\r
2385                 }\r
2386 \r
2387                 switch( p_ipoib->hdr.type )\r
2388                 {\r
2389                 case ETH_PROT_TYPE_IP:\r
2390                         if( len < (sizeof(ipoib_hdr_t) + sizeof(ip_hdr_t)) )\r
2391                         {\r
2392                                 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2393                                         ("Received IP packet < min size\n") );\r
2394                                 status = IB_INVALID_SETTING;\r
2395                                 break;\r
2396                         }\r
2397 \r
2398                         if( p_ipoib->type.ip.hdr.offset ||\r
2399                                 p_ipoib->type.ip.hdr.prot != IP_PROT_UDP )\r
2400                         {\r
2401                                 /* Unfiltered.  Setup the ethernet header and report. */\r
2402                                 cl_perf_start( RecvTcp );\r
2403                                 status = __recv_gen( p_ipoib, p_eth, p_src, p_dst );\r
2404                                 cl_perf_stop( &p_port->p_adapter->perf, RecvTcp );\r
2405                                 break;\r
2406                         }\r
2407 \r
2408                         /* First packet of a UDP transfer. */\r
2409                         if( len <\r
2410                                 (sizeof(ipoib_hdr_t) + sizeof(ip_hdr_t) + sizeof(udp_hdr_t)) )\r
2411                         {\r
2412                                 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2413                                         ("Received UDP packet < min size\n") );\r
2414                                 status = IB_INVALID_SETTING;\r
2415                                 break;\r
2416                         }\r
2417 \r
2418                         /* Check if DHCP conversion is required. */\r
2419                         if( (p_ipoib->type.ip.prot.udp.hdr.dst_port == DHCP_PORT_SERVER &&\r
2420                                 p_ipoib->type.ip.prot.udp.hdr.src_port == DHCP_PORT_CLIENT) ||\r
2421                                 (p_ipoib->type.ip.prot.udp.hdr.dst_port == DHCP_PORT_CLIENT &&\r
2422                                 p_ipoib->type.ip.prot.udp.hdr.src_port == DHCP_PORT_SERVER) )\r
2423                         {\r
2424                                 if( len < (sizeof(ipoib_hdr_t) + sizeof(ip_hdr_t) +\r
2425                                         sizeof(udp_hdr_t) + DHCP_MIN_SIZE) )\r
2426                                 {\r
2427                                         IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2428                                                 ("Received DHCP < min size\n") );\r
2429                                         status = IB_INVALID_SETTING;\r
2430                                         break;\r
2431                                 }\r
2432                                 if ((p_ipoib->type.ip.hdr.ver_hl & 0x0f) != 5 ) {\r
2433                                         // If there are IP options in this message, we are in trouble in any case\r
2434                                         status = IB_INVALID_SETTING;\r
2435                                         break;                                  \r
2436                                 }\r
2437                                 /* UDP packet with BOOTP ports in src/dst port numbers. */\r
2438                                 cl_perf_start( RecvDhcp );\r
2439                                 status = __recv_dhcp( p_port, p_ipoib, p_eth, p_src, p_dst );\r
2440                                 cl_perf_stop( &p_port->p_adapter->perf, RecvDhcp );\r
2441                         }\r
2442                         else\r
2443                         {\r
2444                                 /* Unfiltered.  Setup the ethernet header and report. */\r
2445                                 cl_perf_start( RecvUdp );\r
2446                                 status = __recv_gen( p_ipoib, p_eth, p_src, p_dst );\r
2447                                 cl_perf_stop( &p_port->p_adapter->perf, RecvUdp );\r
2448                         }\r
2449                         break;\r
2450 \r
2451                 case ETH_PROT_TYPE_ARP:\r
2452                         if( len < (sizeof(ipoib_hdr_t) + sizeof(ipoib_arp_pkt_t)) )\r
2453                         {\r
2454                                 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2455                                         ("Received ARP < min size\n") );\r
2456                                 status = IB_INVALID_SETTING;\r
2457                                 break;\r
2458                         }\r
2459                         cl_perf_start( RecvArp );\r
2460                         status = __recv_arp( p_port, p_wc, p_ipoib, p_eth, &p_src, p_dst );\r
2461                         cl_perf_stop( &p_port->p_adapter->perf, RecvArp );\r
2462                         len = sizeof(ipoib_hdr_t) + sizeof(arp_pkt_t);\r
2463                         break;\r
2464 \r
2465                 default:\r
2466                         /* Unfiltered.  Setup the ethernet header and report. */\r
2467                         cl_perf_start( RecvGen );\r
2468                         status = __recv_gen( p_ipoib, p_eth, p_src, p_dst );\r
2469                         cl_perf_stop( &p_port->p_adapter->perf, RecvGen );\r
2470                 }\r
2471 \r
2472                 if( status != IB_SUCCESS )\r
2473                 {\r
2474                         /* Update stats. */\r
2475                         ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0, 0 );\r
2476                         cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item );\r
2477                         /* Dereference the port object on behalf of the failed receive. */\r
2478                         ipoib_port_deref( p_port, ref_recv_filter );\r
2479                 }\r
2480                 else\r
2481                 {\r
2482                         ip_stat_sel_t               ip_stat;\r
2483                         p_desc->len =\r
2484                                 len + sizeof(eth_hdr_t) - sizeof(ipoib_hdr_t);\r
2485                         if( p_dst->h_mcast)\r
2486                         {\r
2487                                 if( p_dst->dgid.multicast.raw_group_id[10] == 0xFF &&\r
2488                                         p_dst->dgid.multicast.raw_group_id[11] == 0xFF &&\r
2489                                         p_dst->dgid.multicast.raw_group_id[12] == 0xFF &&\r
2490                                         p_dst->dgid.multicast.raw_group_id[13] == 0xFF )\r
2491                                 {\r
2492                                         p_desc->type = PKT_TYPE_BCAST;\r
2493                                         ip_stat = IP_STAT_BCAST_BYTES;\r
2494                                 }\r
2495                                 else\r
2496                                 {\r
2497                                         p_desc->type = PKT_TYPE_MCAST;\r
2498                                         ip_stat = IP_STAT_MCAST_BYTES;\r
2499                                 }\r
2500                         }\r
2501                         else\r
2502                         {\r
2503                                 p_desc->type = PKT_TYPE_UCAST;\r
2504                                 ip_stat = IP_STAT_UCAST_BYTES;\r
2505                                 \r
2506                         }\r
2507                         cl_qlist_insert_tail( p_done_list, &p_desc->item.list_item );\r
2508                         ipoib_inc_recv_stat( p_port->p_adapter, ip_stat, len, 1 );  \r
2509                 }\r
2510         }\r
2511 \r
2512         IPOIB_EXIT( IPOIB_DBG_RECV );\r
2513         return recv_cnt;\r
2514 }\r
2515 \r
2516 \r
2517 static ib_api_status_t\r
2518 __recv_gen(\r
2519         IN              const   ipoib_pkt_t* const                      p_ipoib,\r
2520                 OUT                     eth_pkt_t* const                        p_eth,\r
2521         IN                              ipoib_endpt_t* const            p_src,\r
2522         IN                              ipoib_endpt_t* const            p_dst )\r
2523 {\r
2524         IPOIB_ENTER( IPOIB_DBG_RECV );\r
2525 \r
2526         if( !p_src || !p_dst )\r
2527         {\r
2528                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2529                         ("Received packet with no matching endpoints.\n") );\r
2530                 return IB_NOT_DONE;\r
2531         }\r
2532 \r
2533         /*\r
2534          * Fill in the ethernet header.  Note that doing so will overwrite\r
2535          * the IPoIB header, so start by moving the information from the IPoIB\r
2536          * header.\r
2537          */\r
2538         p_eth->hdr.type = p_ipoib->hdr.type;\r
2539         p_eth->hdr.src = p_src->mac;\r
2540         p_eth->hdr.dst = p_dst->mac;\r
2541 \r
2542         if ( p_eth->hdr.dst.addr[0] == 1 && \r
2543                  p_eth->hdr.type == ETH_PROT_TYPE_IP &&\r
2544                  p_eth->hdr.dst.addr[2] == 0x5E)  \r
2545         {\r
2546                 p_eth->hdr.dst.addr[1] = 0;\r
2547                 p_eth->hdr.dst.addr[3] = p_eth->hdr.dst.addr[3] & 0x7f;\r
2548         }\r
2549         if (p_dst->h_mcast)\r
2550                 p_dst->is_in_use = TRUE;\r
2551 \r
2552         IPOIB_EXIT( IPOIB_DBG_RECV );\r
2553         return IB_SUCCESS;\r
2554 }\r
2555 \r
2556 \r
2557 static ib_api_status_t\r
2558 __recv_dhcp(\r
2559         IN                              ipoib_port_t* const                     p_port,\r
2560         IN              const   ipoib_pkt_t* const                      p_ipoib,\r
2561                 OUT                     eth_pkt_t* const                        p_eth,\r
2562         IN                              ipoib_endpt_t* const            p_src,\r
2563         IN                              ipoib_endpt_t* const            p_dst )\r
2564 {\r
2565         ib_api_status_t         status;\r
2566         dhcp_pkt_t                      *p_dhcp;\r
2567         uint8_t                         *p_option;\r
2568         uint8_t                         *p_cid = NULL;\r
2569         ib_gid_t                        gid;\r
2570         uint8_t                         msg = 0;\r
2571 \r
2572         IPOIB_ENTER( IPOIB_DBG_RECV );\r
2573 \r
2574         UNUSED_PARAM( p_port );\r
2575 \r
2576         /* Create the ethernet header. */\r
2577         status = __recv_gen( p_ipoib, p_eth, p_src, p_dst );\r
2578         if( status != IB_SUCCESS )\r
2579         {\r
2580                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2581                         ("__recv_gen returned %s.\n", \r
2582                         p_port->p_adapter->p_ifc->get_err_str( status )) );\r
2583                 return status;\r
2584         }\r
2585 \r
2586         /* Fixup the payload. */\r
2587         p_dhcp = &p_eth->type.ip.prot.udp.dhcp;\r
2588         if( p_dhcp->op != DHCP_REQUEST && p_dhcp->op != DHCP_REPLY )\r
2589         {\r
2590                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2591                         ("Invalid DHCP op code.\n") );\r
2592                 return IB_INVALID_SETTING;\r
2593         }\r
2594 \r
2595         /*\r
2596          * Find the client identifier option, making sure to skip\r
2597          * the "magic cookie".\r
2598          */\r
2599         p_option = &p_dhcp->options[0];\r
2600         if ( *(uint32_t *)p_option != DHCP_COOKIE )\r
2601         {\r
2602                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2603                         ("DHCP cookie corrupted.\n") );\r
2604                 return IB_INVALID_PARAMETER;\r
2605         }\r
2606 \r
2607         p_option = &p_dhcp->options[4];\r
2608         while( *p_option != DHCP_OPT_END && p_option < &p_dhcp->options[312] )\r
2609         {\r
2610                 switch( *p_option )\r
2611                 {\r
2612                 case DHCP_OPT_PAD:\r
2613                         p_option++;\r
2614                         break;\r
2615 \r
2616                 case DHCP_OPT_MSG:\r
2617                         msg = p_option[2];\r
2618                         p_option += 3;\r
2619                         break;\r
2620 \r
2621                 case DHCP_OPT_CLIENT_ID:\r
2622                         p_cid = p_option;\r
2623                         /* Fall through. */\r
2624 \r
2625                 default:\r
2626                         /*\r
2627                          * All other options have a length byte following the option code.\r
2628                          * Offset by the length to get to the next option.\r
2629                          */\r
2630                         p_option += (p_option[1] + 2);\r
2631                 }\r
2632         }\r
2633 \r
2634         switch( msg )\r
2635         {\r
2636         /* message from client */\r
2637         case DHCPDISCOVER:\r
2638         case DHCPREQUEST:\r
2639         case DHCPDECLINE:\r
2640         case DHCPRELEASE:\r
2641         case DHCPINFORM:\r
2642                 if( !p_cid )\r
2643                 {\r
2644                         IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2645                                 ("Failed to find required Client-identifier option.\n") );\r
2646                         return IB_INVALID_SETTING;\r
2647                 }\r
2648                 if( p_dhcp->htype != DHCP_HW_TYPE_IB )\r
2649                 {\r
2650                         IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2651                                 ("Invalid hardware address type.\n") );\r
2652                         return IB_INVALID_SETTING;\r
2653                 }\r
2654                 break;\r
2655         /* message from DHCP server */\r
2656         case DHCPOFFER:\r
2657         case DHCPACK:\r
2658         case DHCPNAK:\r
2659                 break;\r
2660 \r
2661         default:\r
2662                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2663                         ("Invalide message type.\n") );\r
2664                 return IB_INVALID_PARAMETER;\r
2665         }\r
2666         p_eth->type.ip.prot.udp.hdr.chksum = 0;\r
2667         p_dhcp->htype = DHCP_HW_TYPE_ETH;\r
2668         p_dhcp->hlen = HW_ADDR_LEN;\r
2669 \r
2670         if( p_cid ) /* from client */\r
2671         {\r
2672                 /* Validate that the length and type of the option is as required. */\r
2673                 if( p_cid[1] != 21 )\r
2674                 {\r
2675                         IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2676                                 ("Client-identifier length not 21 as required.\n") );\r
2677                         return IB_INVALID_SETTING;\r
2678                 }\r
2679                 if( p_cid[2] != DHCP_HW_TYPE_IB )\r
2680                 {\r
2681                         IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2682                                 ("Client-identifier type is wrong.\n") );\r
2683                         return IB_INVALID_SETTING;\r
2684                 }\r
2685                 /*\r
2686                  * Copy the GID value from the option so that we can make aligned\r
2687                  * accesses to the contents.\r
2688                  * Recover CID to standard type.\r
2689                  */\r
2690                 cl_memcpy( &gid, &p_cid[7], sizeof(ib_gid_t) );\r
2691                 p_cid[1] =  HW_ADDR_LEN +1;// CID length \r
2692                 p_cid[2] =  DHCP_HW_TYPE_ETH;// CID type \r
2693                 status = ipoib_mac_from_guid( gid.unicast.interface_id, p_port->p_adapter->params.guid_mask, (mac_addr_t*)&p_cid[3] );\r
2694                 if (status == IB_INVALID_GUID_MASK)\r
2695                 {\r
2696                         IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_ERROR,\r
2697                                 ("Invalid GUID mask received, rejecting it") );\r
2698                         ipoib_create_log(p_port->p_adapter->h_adapter, GUID_MASK_LOG_INDEX, EVENT_IPOIB_WRONG_PARAMETER_WRN);\r
2699                         status = IB_SUCCESS;\r
2700                 }\r
2701                 p_cid[HW_ADDR_LEN + 3] = DHCP_OPT_END; //terminate tag\r
2702         }\r
2703         IPOIB_EXIT( IPOIB_DBG_RECV );\r
2704         return status;\r
2705 }\r
2706 \r
2707 \r
2708 static ib_api_status_t\r
2709 __recv_arp(\r
2710         IN                              ipoib_port_t* const                     p_port,\r
2711         IN                              ib_wc_t* const                          p_wc,\r
2712         IN              const   ipoib_pkt_t* const                      p_ipoib,\r
2713                 OUT                     eth_pkt_t* const                        p_eth,\r
2714         IN                              ipoib_endpt_t** const           pp_src,\r
2715         IN                              ipoib_endpt_t* const            p_dst )\r
2716 {\r
2717         ib_api_status_t                 status;\r
2718         arp_pkt_t                               *p_arp;\r
2719         const ipoib_arp_pkt_t   *p_ib_arp;\r
2720         ib_gid_t                                gid;\r
2721         mac_addr_t                              mac;\r
2722         ipoib_hw_addr_t                 null_hw = {0};\r
2723         uint8_t                                 cm_capable = 0;\r
2724 \r
2725         IPOIB_ENTER( IPOIB_DBG_RECV );\r
2726 \r
2727         if( !p_dst )\r
2728         {\r
2729                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2730                         ("Unknown destination endpoint\n") );\r
2731                 return IB_INVALID_SETTING;\r
2732         }\r
2733 \r
2734         p_ib_arp = &p_ipoib->type.arp;\r
2735         p_arp = &p_eth->type.arp;\r
2736 \r
2737         if( p_ib_arp->hw_type != ARP_HW_TYPE_IB )\r
2738         {\r
2739                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2740                         ("ARP hardware type is not IB\n") );\r
2741                 return IB_INVALID_SETTING;\r
2742         }\r
2743 \r
2744         if( p_ib_arp->hw_size != sizeof(ipoib_hw_addr_t) )\r
2745         {\r
2746                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2747                         ("ARP hardware address size is not sizeof(ipoib_hw_addr_t)\n") );\r
2748                 return IB_INVALID_SETTING;\r
2749         }\r
2750 \r
2751         if( p_ib_arp->prot_type != ETH_PROT_TYPE_IP )\r
2752         {\r
2753                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2754                         ("ARP protocal type not IP\n") );\r
2755                 return IB_INVALID_SETTING;\r
2756         }\r
2757 \r
2758         cm_capable = ipoib_addr_get_flags( &p_ib_arp->src_hw );\r
2759 \r
2760         /*\r
2761          * If we don't have a source, lookup the endpoint specified in the payload.\r
2762          */\r
2763         if( !*pp_src )\r
2764                 *pp_src = __endpt_mgr_get_by_gid( p_port, &p_ib_arp->src_hw.gid );\r
2765 \r
2766         /*\r
2767          * If the endpoint exists for the GID, make sure\r
2768          * the dlid and qpn match the arp.\r
2769          */\r
2770         if( *pp_src )\r
2771         {\r
2772                 if( cl_memcmp( &(*pp_src)->dgid, &p_ib_arp->src_hw.gid,\r
2773                         sizeof(ib_gid_t) ) )\r
2774                 {\r
2775                         /*\r
2776                          * GIDs for the endpoint are different.  The ARP must\r
2777                          * have been proxied.  Dereference it.\r
2778                          */\r
2779                         *pp_src = NULL;\r
2780                 }\r
2781                 else if( (*pp_src)->dlid &&\r
2782                         (*pp_src)->dlid != p_wc->recv.ud.remote_lid )\r
2783                 {\r
2784                         /* Out of date!  Destroy the endpoint and replace it. */\r
2785                         __endpt_mgr_remove( p_port, *pp_src );\r
2786                         *pp_src = NULL;\r
2787                 }\r
2788                 else if ( ! ((*pp_src)->dlid)) {\r
2789                         /* Out of date!  Destroy the endpoint and replace it. */\r
2790                         __endpt_mgr_remove( p_port, *pp_src );\r
2791                         *pp_src = NULL;\r
2792                 }\r
2793                 else if( ipoib_is_voltaire_router_gid( &(*pp_src)->dgid ) )\r
2794                 {\r
2795                         if( (*pp_src)->qpn != ipoib_addr_get_qpn( &p_ib_arp->src_hw ) &&\r
2796                                  p_wc->recv.ud.remote_qp !=     ipoib_addr_get_qpn( &p_ib_arp->src_hw ) )\r
2797                         {\r
2798                                 /* Out of date!  Destroy the endpoint and replace it. */\r
2799                                 __endpt_mgr_remove( p_port, *pp_src );\r
2800                                 *pp_src = NULL;\r
2801                         }\r
2802                 }\r
2803                 else if( (*pp_src)->qpn != p_wc->recv.ud.remote_qp )\r
2804                 {\r
2805                         /* Out of date!  Destroy the endpoint and replace it. */\r
2806                         __endpt_mgr_remove( p_port, *pp_src );\r
2807                         *pp_src = NULL;\r
2808                 }\r
2809         }\r
2810 \r
2811         /* Do we need to create an endpoint for this GID? */\r
2812         if( !*pp_src )\r
2813         {\r
2814                 /* Copy the src GID to allow aligned access */\r
2815                 cl_memcpy( &gid, &p_ib_arp->src_hw.gid, sizeof(ib_gid_t) );\r
2816                 status = ipoib_mac_from_guid( gid.unicast.interface_id, p_port->p_adapter->params.guid_mask, &mac );\r
2817                 if (status == IB_INVALID_GUID_MASK)\r
2818                 {\r
2819                         IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_ERROR,\r
2820                                 ("Invalid GUID mask received, rejecting it") );\r
2821                         ipoib_create_log(p_port->p_adapter->h_adapter, GUID_MASK_LOG_INDEX, EVENT_IPOIB_WRONG_PARAMETER_WRN);\r
2822                 }\r
2823                 else if( status != IB_SUCCESS )\r
2824                 {\r
2825                         IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2826                                 ("ipoib_mac_from_guid returned %s\n",\r
2827                                 p_port->p_adapter->p_ifc->get_err_str( status )) );\r
2828                         return status;\r
2829                 }\r
2830                 /*\r
2831                  * Create the endpoint.\r
2832                  */\r
2833                 *pp_src = ipoib_endpt_create( &p_ib_arp->src_hw.gid,\r
2834                         p_wc->recv.ud.remote_lid, ipoib_addr_get_qpn( &p_ib_arp->src_hw ) );\r
2835 \r
2836                 if( !*pp_src )\r
2837                 {\r
2838                         IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2839                                 ("ipoib_endpt_create failed\n") );\r
2840                         return status;\r
2841                 }\r
2842 \r
2843                 cl_obj_lock( &p_port->obj );\r
2844                 status = __endpt_mgr_insert( p_port, mac, *pp_src );\r
2845                 if( status != IB_SUCCESS )\r
2846                 {\r
2847                         cl_obj_unlock( &p_port->obj );\r
2848                         IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
2849                                 ("__endpt_mgr_insert return %s \n",\r
2850                                 p_port->p_adapter->p_ifc->get_err_str( status )) );\r
2851                         return status;\r
2852                 }\r
2853 \r
2854                 cl_obj_unlock( &p_port->obj );\r
2855         }\r
2856 \r
2857         (*pp_src)->cm_flag = cm_capable;\r
2858 \r
2859         CL_ASSERT( !cl_memcmp(\r
2860                 &(*pp_src)->dgid, &p_ib_arp->src_hw.gid, sizeof(ib_gid_t) ) );\r
2861         CL_ASSERT( ipoib_is_voltaire_router_gid( &(*pp_src)->dgid ) ||\r
2862                 (*pp_src)->qpn == ipoib_addr_get_qpn( &p_ib_arp->src_hw ) );\r
2863 #if 0\r
2864         if( p_port->p_adapter->params.cm_enabled &&\r
2865                 p_ib_arp->op == ARP_OP_REQ &&\r
2866                 cm_capable == IPOIB_CM_FLAG_RC )\r
2867         {\r
2868                 /* if we've got ARP request and RC flag is set, \r
2869                 save SID for connect REQ to be sent in ARP reply\r
2870                 when requestor's path get resolved */\r
2871                 if( endpt_cm_get_state( (*pp_src) ) == IPOIB_CM_DISCONNECTED )\r
2872                 {\r
2873                         (*pp_src)->cm_flag = cm_capable;\r
2874                         ipoib_addr_set_sid( \r
2875                                 &(*pp_src)->conn.service_id,\r
2876                                 ipoib_addr_get_qpn( &p_ib_arp->src_hw ) );\r
2877                 }\r
2878         }\r
2879 #endif\r
2880 #if 0 //DBG\r
2881         if( p_port->p_adapter->params.cm_enabled )\r
2882         {\r
2883                 IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
2884                         (" ARP %s from ENDPT[%p] state %d CM cap: %d QPN: %#x MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",\r
2885                         ((p_ib_arp->op == ARP_OP_REQ )? "REQUEST" : "REPLY"),\r
2886                         *pp_src, endpt_cm_get_state( *pp_src ), \r
2887                         ((cm_capable == IPOIB_CM_FLAG_RC)? 1: 0),\r
2888                         cl_ntoh32( ipoib_addr_get_qpn( &p_ib_arp->src_hw ) ),\r
2889                         (*pp_src)->mac.addr[0], (*pp_src)->mac.addr[1],\r
2890                         (*pp_src)->mac.addr[2], (*pp_src)->mac.addr[3],\r
2891                         (*pp_src)->mac.addr[4], (*pp_src)->mac.addr[5] ));\r
2892         }\r
2893 #endif\r
2894 \r
2895         /* Now swizzle the data. */\r
2896         p_arp->hw_type = ARP_HW_TYPE_ETH;\r
2897         p_arp->hw_size = sizeof(mac_addr_t);\r
2898         p_arp->src_hw = (*pp_src)->mac;\r
2899         p_arp->src_ip = p_ib_arp->src_ip;\r
2900 \r
2901         if( cl_memcmp( &p_ib_arp->dst_hw, &null_hw, sizeof(ipoib_hw_addr_t) ) )\r
2902         {\r
2903                 if( cl_memcmp( &p_dst->dgid, &p_ib_arp->dst_hw.gid, sizeof(ib_gid_t) ) )\r
2904                 {\r
2905                         /*\r
2906                          * We received bcast ARP packet that means\r
2907                          * remote port lets everyone know it was changed IP/MAC\r
2908                          * or just activated\r
2909                          */\r
2910 \r
2911                         /* Guy: TODO: Check why this check fails in case of Voltaire IPR */\r
2912 \r
2913                         if ( !ipoib_is_voltaire_router_gid( &(*pp_src)->dgid ) &&\r
2914                                  !ib_gid_is_multicast( (const ib_gid_t*)&p_dst->dgid ) )\r