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