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