2 * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.
\r
3 * Copyright (c) 2006 Mellanox Technologies. All rights reserved.
\r
4 * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved.
\r
6 * This software is available to you under the OpenIB.org BSD license
\r
9 * Redistribution and use in source and binary forms, with or
\r
10 * without modification, are permitted provided that the following
\r
11 * conditions are met:
\r
13 * - Redistributions of source code must retain the above
\r
14 * copyright notice, this list of conditions and the following
\r
17 * - Redistributions in binary form must reproduce the above
\r
18 * copyright notice, this list of conditions and the following
\r
19 * disclaimer in the documentation and/or other materials
\r
20 * provided with the distribution.
\r
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
\r
23 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
\r
24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
\r
25 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
\r
26 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
\r
27 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
28 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
\r
31 * $Id: ipoib_port.c 4506 2009-06-23 14:40:54Z xalex $
\r
34 #include "precompile.h"
\r
36 #if defined(EVENT_TRACING)
\r
40 #include "ipoib_port.tmh"
\r
42 #include <offload.h>
\r
47 extern ULONG g_ipoib_send;
\r
48 extern ULONG g_ipoib_send_ack;
\r
49 extern ULONG g_ipoib_send_SW;
\r
50 extern ULONG g_ipoib_send_SG;
\r
51 extern ULONG g_ipoib_send_SW_in_loop;
\r
52 extern ULONG g_ipoib_send_SG_pending;
\r
53 extern ULONG g_ipoib_send_SG_real;
\r
54 extern ULONG g_ipoib_send_SG_failed;
\r
55 extern ULONG g_ipoib_send_reset;
\r
61 ib_gid_t bcast_mgid_template = {
\r
62 0xff, /* multicast field */
\r
63 0x12, /* scope (to be filled in) */
\r
64 0x40, 0x1b, /* IPv4 signature */
\r
65 0xff, 0xff, /* 16 bits of P_Key (to be filled in) */
\r
66 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 48 bits of zeros */
\r
67 0xff, 0xff, 0xff, 0xff, /* 32 bit IPv4 broadcast address */
\r
72 /* Handy pointer for debug use. */
\r
73 ipoib_port_t *gp_ipoib_port;
\r
76 static void __port_mcast_garbage_dpc(KDPC *p_gc_dpc,void *context,void *s_arg1, void *s_arg2);
\r
77 static void __port_do_mcast_garbage(ipoib_port_t* const p_port );
\r
80 static void __recv_cb_dpc(KDPC *p_gc_dpc,void *context,void *s_arg1, void *s_arg2);
\r
83 #ifndef _IPOIB_DEBUG_NDIS6
\r
84 #define _IPOIB_DEBUG_NDIS6
\r
85 CL_INLINE void CL_API
\r
86 cl_qlist_check_validity(
\r
87 IN cl_qlist_t* const p_list )
\r
89 cl_list_item_t *p_item;
\r
92 /* CL_ASSERT that a non-null pointer is provided. */
\r
93 CL_ASSERT( p_list );
\r
94 /* CL_ASSERT that the list was initialized. */
\r
95 CL_ASSERT( p_list->state == CL_INITIALIZED );
\r
96 p_item = cl_qlist_head(p_list);
\r
97 while(p_item != cl_qlist_end(p_list)) {
\r
99 CL_ASSERT(p_item->p_list == p_list);
\r
100 p_item = p_item->p_next;
\r
101 CL_ASSERT (cnt <= p_list->count);
\r
103 CL_ASSERT (cnt == p_list->count);
\r
108 /******************************************************************************
\r
112 ******************************************************************************/
\r
115 IN ipoib_port_t* const p_port );
\r
117 static ib_api_status_t
\r
119 IN ipoib_port_t* const p_port,
\r
120 IN ipoib_adapter_t* const p_adapter,
\r
121 IN ib_pnp_port_rec_t* const p_pnp_rec );
\r
125 IN cl_obj_t* const p_obj );
\r
129 IN cl_obj_t* const p_obj );
\r
133 IN cl_obj_t* const p_obj );
\r
135 static ib_api_status_t
\r
136 __port_query_ca_attrs(
\r
137 IN ipoib_port_t* const p_port,
\r
138 IN ib_ca_attr_t** pp_ca_attrs );
\r
141 __srq_async_event_cb(
\r
142 IN ib_async_event_rec_t *p_event_rec );
\r
144 /******************************************************************************
\r
146 * IB resource manager operations
\r
148 ******************************************************************************/
\r
150 __ib_mgr_construct(
\r
151 IN ipoib_port_t* const p_port );
\r
153 static ib_api_status_t
\r
155 IN ipoib_port_t* const p_port );
\r
159 IN ipoib_port_t* const p_port );
\r
163 IN ib_async_event_rec_t *p_event_rec );
\r
167 IN ib_async_event_rec_t *p_event_rec );
\r
169 static ib_api_status_t
\r
171 IN ipoib_port_t* const p_port );
\r
173 /******************************************************************************
\r
175 * Buffer manager operations.
\r
177 ******************************************************************************/
\r
179 __buf_mgr_construct(
\r
180 IN ipoib_port_t* const p_port );
\r
182 static ib_api_status_t
\r
184 IN ipoib_port_t* const p_port );
\r
188 IN ipoib_port_t* const p_port );
\r
192 IN void* const p_object,
\r
194 OUT cl_pool_item_t** const pp_pool_item );
\r
196 #if !IPOIB_INLINE_RECV
\r
199 IN const cl_pool_item_t* const p_pool_item,
\r
200 IN void *context );
\r
201 #endif /* IPOIB_INLINE_RECV */
\r
203 static inline ipoib_send_desc_t*
\r
204 __buf_mgr_get_send(
\r
205 IN ipoib_port_t* const p_port );
\r
208 __buf_mgr_put_send(
\r
209 IN ipoib_port_t* const p_port,
\r
210 IN ipoib_send_desc_t* const p_desc );
\r
212 static inline ipoib_recv_desc_t*
\r
213 __buf_mgr_get_recv(
\r
214 IN ipoib_port_t* const p_port );
\r
217 __buf_mgr_put_recv(
\r
218 IN ipoib_port_t* const p_port,
\r
219 IN ipoib_recv_desc_t* const p_desc,
\r
220 IN NET_BUFFER_LIST* const p_net_buffer_list OPTIONAL );
\r
223 __buf_mgr_put_recv_list(
\r
224 IN ipoib_port_t* const p_port,
\r
225 IN cl_qlist_t* const p_list );
\r
228 static inline NET_BUFFER_LIST*
\r
230 IN ipoib_port_t* const p_port,
\r
231 IN ipoib_recv_desc_t* const p_desc );
\r
234 /******************************************************************************
\r
236 * Receive manager operations.
\r
238 ******************************************************************************/
\r
240 __recv_mgr_construct(
\r
241 IN ipoib_port_t* const p_port );
\r
243 static ib_api_status_t
\r
245 IN ipoib_port_t* const p_port );
\r
248 __recv_mgr_destroy(
\r
249 IN ipoib_port_t* const p_port );
\r
251 /* Posts receive buffers to the receive queue. */
\r
254 IN ipoib_port_t* const p_port );
\r
258 IN const ib_cq_handle_t h_cq,
\r
259 IN void *cq_context );
\r
263 IN ipoib_port_t* const p_port,
\r
264 IN ipoib_recv_desc_t* const p_desc,
\r
265 IN ib_wc_t* const p_wc,
\r
266 OUT ipoib_endpt_t** const pp_src,
\r
267 OUT ipoib_endpt_t** const pp_dst );
\r
271 IN ipoib_port_t* const p_port,
\r
272 IN ib_wc_t* const p_done_wc_list,
\r
273 OUT cl_qlist_t* const p_done_list,
\r
274 OUT cl_qlist_t* const p_bad_list );
\r
276 static ib_api_status_t
\r
278 IN const ipoib_pkt_t* const p_ipoib,
\r
279 OUT eth_pkt_t* const p_eth,
\r
280 IN ipoib_endpt_t* const p_src,
\r
281 IN ipoib_endpt_t* const p_dst );
\r
283 static ib_api_status_t
\r
285 IN ipoib_port_t* const p_port,
\r
286 IN const ipoib_pkt_t* const p_ipoib,
\r
287 OUT eth_pkt_t* const p_eth,
\r
288 IN ipoib_endpt_t* const p_src,
\r
289 IN ipoib_endpt_t* const p_dst );
\r
291 static ib_api_status_t
\r
293 IN ipoib_port_t* const p_port,
\r
294 IN ib_wc_t* const p_wc,
\r
295 IN const ipoib_pkt_t* const p_ipoib,
\r
296 OUT eth_pkt_t* const p_eth,
\r
297 IN ipoib_endpt_t** const p_src,
\r
298 IN ipoib_endpt_t* const p_dst );
\r
300 static ib_api_status_t
\r
301 __recv_mgr_prepare_NBL(
\r
302 IN ipoib_port_t* const p_port,
\r
303 IN ipoib_recv_desc_t* const p_desc,
\r
304 OUT NET_BUFFER_LIST** const pp_net_buffer_list );
\r
307 __recv_mgr_build_NBL_array(
\r
308 IN ipoib_port_t* const p_port,
\r
309 OUT cl_qlist_t* p_done_list,
\r
310 OUT int32_t* const p_discarded );
\r
312 /******************************************************************************
\r
314 * Send manager operations.
\r
316 ******************************************************************************/
\r
318 __send_mgr_construct(
\r
319 IN ipoib_port_t* const p_port );
\r
321 static ib_api_status_t
\r
323 IN ipoib_port_t* const p_port );
\r
327 __send_mgr_destroy(
\r
328 IN ipoib_port_t* const p_port );
\r
332 IN ipoib_send_NB_SG * s_buf,
\r
333 IN INT lso_data_index,
\r
334 IN UINT lso_header_size OPTIONAL);
\r
337 __send_mgr_filter_ip(
\r
338 IN const eth_hdr_t* const p_eth_hdr,
\r
341 IN OUT ipoib_send_NB_SG* const s_buf);
\r
344 __send_mgr_filter_igmp_v2(
\r
345 IN ipoib_port_t* const p_port,
\r
346 IN const ip_hdr_t* const p_ip_hdr,
\r
347 IN size_t iph_options_size,
\r
349 IN size_t buf_len );
\r
352 __send_mgr_filter_udp(
\r
353 IN const ip_hdr_t* const p_ip_hdr,
\r
356 IN OUT ipoib_send_NB_SG* const s_buf);
\r
359 __send_mgr_filter_dhcp(
\r
360 IN const udp_hdr_t* const p_udp_hdr,
\r
363 IN OUT ipoib_send_NB_SG* const s_buf );
\r
366 __send_mgr_filter_arp(
\r
367 IN const eth_hdr_t* const p_eth_hdr,
\r
370 IN OUT ipoib_send_NB_SG* const s_buf );
\r
372 static inline void
\r
373 __send_complete_net_buffer(
\r
374 IN ipoib_send_NB_SG *s_buf,
\r
375 IN NDIS_STATUS status,
\r
376 IN ULONG compl_flags,
\r
377 IN boolean_t bLock );
\r
380 static inline NDIS_STATUS
\r
382 IN ipoib_port_t* const p_port,
\r
383 IN eth_hdr_t* const p_eth_hdr,
\r
384 OUT ipoib_endpt_t** const pp_endpt );
\r
388 IN eth_hdr_t* const p_eth_hdr,
\r
389 IN MDL* const p_mdl,
\r
390 IN const size_t mdl_len,
\r
391 IN ipoib_send_NB_SG *s_buf);
\r
396 IN const ib_cq_handle_t h_cq,
\r
397 IN void *cq_context );
\r
399 static NDIS_STATUS
\r
401 IN PNET_BUFFER pNetBuffer,
\r
402 IN LsoData *pLsoData,
\r
403 OUT UINT *IndexOfData,
\r
404 IN ipoib_hdr_t *ipoib_hdr );
\r
409 IN ipoib_port_t* const p_port,
\r
411 IN int32_t hdr_idx,
\r
412 IN PNDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO p_lso_info,
\r
413 IN NET_BUFFER *p_netbuf);
\r
420 IN ipoib_port_t* const p_port,
\r
421 IN ipoib_send_desc_t* const p_desc,
\r
422 IN eth_hdr_t* const p_eth_hdr,
\r
423 IN ip_hdr_t* const p_ip_hdr,
\r
424 IN uint32_t buf_len,
\r
425 IN NDIS_BUFFER* p_ndis_buf );
\r
429 __update_fragment_ip_hdr(
\r
430 IN ip_hdr_t* const p_ip_hdr,
\r
431 IN uint16_t fragment_size,
\r
432 IN uint16_t fragment_offset,
\r
433 IN BOOLEAN more_fragments );
\r
438 IN uint8_t* p_options,
\r
439 IN uint32_t options_len,
\r
440 IN BOOLEAN copy_all );
\r
442 /******************************************************************************
\r
444 * Endpoint manager operations
\r
446 ******************************************************************************/
\r
448 __endpt_mgr_construct(
\r
449 IN ipoib_port_t* const p_port );
\r
451 static ib_api_status_t
\r
453 IN ipoib_port_t* const p_port );
\r
456 __endpt_mgr_destroy(
\r
457 IN ipoib_port_t* const p_port );
\r
459 /****f* IPoIB/__endpt_mgr_remove_all
\r
461 * __endpt_mgr_remove_all
\r
464 * Removes all enpoints from the port, dereferencing them to initiate
\r
470 __endpt_mgr_remove_all(
\r
471 IN ipoib_port_t* const p_port );
\r
476 __endpt_mgr_remove(
\r
477 IN ipoib_port_t* const p_port,
\r
478 IN ipoib_endpt_t* const p_endpt );
\r
481 __endpt_mgr_reset_all(
\r
482 IN ipoib_port_t* const p_port );
\r
484 static inline NDIS_STATUS
\r
486 IN ipoib_port_t* const p_port,
\r
487 IN const mac_addr_t mac,
\r
488 OUT ipoib_endpt_t** const pp_endpt );
\r
490 static inline NDIS_STATUS
\r
491 __endpt_mgr_get_gid_qpn(
\r
492 IN ipoib_port_t* const p_port,
\r
493 IN const mac_addr_t mac,
\r
494 OUT ib_gid_t* const p_gid,
\r
495 OUT UNALIGNED net32_t* const p_qpn );
\r
497 static inline ipoib_endpt_t*
\r
498 __endpt_mgr_get_by_gid(
\r
499 IN ipoib_port_t* const p_port,
\r
500 IN const ib_gid_t* const p_gid );
\r
502 static inline ipoib_endpt_t*
\r
503 __endpt_mgr_get_by_lid(
\r
504 IN ipoib_port_t* const p_port,
\r
505 IN const net16_t lid );
\r
507 static inline ib_api_status_t
\r
508 __endpt_mgr_insert_locked(
\r
509 IN ipoib_port_t* const p_port,
\r
510 IN const mac_addr_t mac,
\r
511 IN ipoib_endpt_t* const p_endpt );
\r
513 static inline ib_api_status_t
\r
514 __endpt_mgr_insert(
\r
515 IN ipoib_port_t* const p_port,
\r
516 IN const mac_addr_t mac,
\r
517 IN ipoib_endpt_t* const p_endpt );
\r
519 static ib_api_status_t
\r
520 __endpt_mgr_add_local(
\r
521 IN ipoib_port_t* const p_port,
\r
522 IN ib_port_info_t* const p_port_info );
\r
524 static ib_api_status_t
\r
525 __endpt_mgr_add_bcast(
\r
526 IN ipoib_port_t* const p_port,
\r
527 IN ib_mcast_rec_t *p_mcast_rec );
\r
529 /******************************************************************************
\r
531 * MCast operations.
\r
533 ******************************************************************************/
\r
534 static ib_api_status_t
\r
536 IN ipoib_port_t* const p_port );
\r
538 static ib_api_status_t
\r
540 IN ipoib_port_t* const p_port,
\r
541 IN ib_member_rec_t* const p_member_rec );
\r
543 static ib_api_status_t
\r
544 __port_create_bcast(
\r
545 IN ipoib_port_t* const p_port );
\r
551 IN ib_query_rec_t *p_query_rec );
\r
556 IN ib_mcast_rec_t *p_mcast_rec );
\r
561 IN ib_mcast_rec_t *p_mcast_rec );
\r
564 __leave_error_mcast_cb(
\r
565 IN void *context );
\r
570 IN const void* const p_key1,
\r
571 IN const void* const p_key2 )
\r
573 return cl_memcmp( p_key1, p_key2, sizeof(ib_gid_t) );
\r
577 inline void ipoib_port_ref( ipoib_port_t * p_port, int type )
\r
579 cl_obj_ref( &p_port->obj );
\r
581 cl_atomic_inc( &p_port->ref[type % ref_mask] );
\r
582 IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ,
\r
583 ("Port[%d] refcount raised to %d\n", p_port->port_num, p_port->obj.ref_cnt));
\r
585 if ((p_port->obj.ref_cnt % 20)==0)
\r
586 IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ,
\r
587 ("ref type %d ref_cnt %d\n", type, p_port->obj.ref_cnt) );
\r
589 UNREFERENCED_PARAMETER(type);
\r
594 inline void ipoib_port_deref(ipoib_port_t * p_port, int type)
\r
596 cl_obj_deref( &p_port->obj );
\r
598 cl_atomic_dec( &p_port->ref[type % ref_mask] );
\r
599 IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ,
\r
600 ("Port[%d] refcount decremented to %d\n", p_port->port_num, p_port->obj.ref_cnt));
\r
601 if ((p_port->obj.ref_cnt % 20) == 0)
\r
602 IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ,
\r
603 ("deref type %d ref_cnt %d\n", type, p_port->obj.ref_cnt) );
\r
605 UNREFERENCED_PARAMETER(type);
\r
609 /* function returns pointer to payload that is going after IP header.
\r
610 * asssuming that payload and IP header are in the same buffer
\r
612 static void* GetIpPayloadPtr(const ip_hdr_t* const p_ip_hdr)
\r
614 return (void*)((uint8_t*)p_ip_hdr + IP_HEADER_LENGTH(p_ip_hdr));
\r
617 /******************************************************************************
\r
621 ******************************************************************************/
\r
624 IN ipoib_adapter_t* const p_adapter,
\r
625 IN ib_pnp_port_rec_t* const p_pnp_rec,
\r
626 OUT ipoib_port_t** const pp_port )
\r
628 ib_api_status_t status;
\r
629 ipoib_port_t *p_port;
\r
631 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
633 CL_ASSERT( !p_adapter->p_port );
\r
635 p_port = (ipoib_port_t *) cl_zalloc( sizeof(ipoib_port_t) +
\r
636 (sizeof(ipoib_hdr_t) * (p_adapter->params.sq_depth - 1)) );
\r
639 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
640 ("Failed to allocate ipoib_port_t (%d bytes)\n",
\r
641 sizeof(ipoib_port_t)) );
\r
642 return IB_INSUFFICIENT_MEMORY;
\r
646 gp_ipoib_port = p_port;
\r
649 __port_construct( p_port );
\r
651 status = __port_init( p_port, p_adapter, p_pnp_rec );
\r
652 if( status != IB_SUCCESS )
\r
654 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
655 ("ipoib_port_init returned %s.\n",
\r
656 p_adapter->p_ifc->get_err_str( status )) );
\r
657 __port_cleanup( &p_port->obj );
\r
658 __port_free( &p_port->obj );
\r
663 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
669 ipoib_port_destroy(
\r
670 IN ipoib_port_t* const p_port )
\r
672 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
674 CL_ASSERT( p_port );
\r
675 CL_ASSERT( p_port->p_adapter );
\r
676 CL_ASSERT( !p_port->p_adapter->p_port );
\r
678 cl_obj_destroy( &p_port->obj );
\r
680 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
686 IN ipoib_port_t* const p_port )
\r
688 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
690 p_port->state = IB_QPS_RESET;
\r
692 cl_obj_construct( &p_port->obj, IPOIB_OBJ_PORT );
\r
693 cl_spinlock_construct( &p_port->send_lock );
\r
694 cl_spinlock_construct( &p_port->recv_lock );
\r
695 __ib_mgr_construct( p_port );
\r
696 __buf_mgr_construct( p_port );
\r
698 __recv_mgr_construct( p_port );
\r
699 __send_mgr_construct( p_port );
\r
701 __endpt_mgr_construct( p_port );
\r
703 KeInitializeEvent( &p_port->sa_event, NotificationEvent, TRUE );
\r
704 KeInitializeEvent( &p_port->leave_mcast_event, NotificationEvent, TRUE );
\r
706 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
710 static ib_api_status_t
\r
712 IN ipoib_port_t* const p_port,
\r
713 IN ipoib_adapter_t* const p_adapter,
\r
714 IN ib_pnp_port_rec_t* const p_pnp_rec )
\r
716 cl_status_t cl_status;
\r
717 ib_api_status_t status;
\r
719 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
721 p_port->port_num = p_pnp_rec->p_port_attr->port_num;
\r
722 p_port->p_adapter = p_adapter;
\r
724 cl_status = cl_spinlock_init( &p_port->send_lock );
\r
725 if( cl_status != CL_SUCCESS )
\r
727 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
728 ("cl_spinlock_init returned %#x\n", cl_status) );
\r
732 cl_status = cl_spinlock_init( &p_port->recv_lock );
\r
733 if( cl_status != CL_SUCCESS )
\r
735 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
736 ("cl_spinlock_init returned %#x\n", cl_status) );
\r
740 /* Initialize the IB resource manager. */
\r
741 status = __ib_mgr_init( p_port );
\r
742 if( status != IB_SUCCESS )
\r
744 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
745 ("__ib_mgr_init returned %s\n",
\r
746 p_adapter->p_ifc->get_err_str( status )) );
\r
750 /* Initialize the buffer manager. */
\r
751 status = __buf_mgr_init( p_port );
\r
752 if( status != IB_SUCCESS )
\r
754 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
755 ("__buf_mgr_init returned %s\n",
\r
756 p_adapter->p_ifc->get_err_str( status )) );
\r
760 /* Initialize the receive manager. */
\r
761 status = __recv_mgr_init( p_port );
\r
762 if( status != IB_SUCCESS )
\r
764 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
765 ("__recv_mgr_init returned %s\n",
\r
766 p_adapter->p_ifc->get_err_str( status )) );
\r
770 status =__send_mgr_init( p_port );
\r
771 if( status != IB_SUCCESS )
\r
773 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
774 ("__send_mgr_init returned %s\n",
\r
775 p_adapter->p_ifc->get_err_str( status )) );
\r
779 /* Initialize the endpoint manager. */
\r
780 status = __endpt_mgr_init( p_port );
\r
781 if( status != IB_SUCCESS )
\r
783 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
784 ("__endpt_mgr_init returned %s\n",
\r
785 p_adapter->p_ifc->get_err_str( status )) );
\r
789 KeInitializeDpc(&p_port->recv_dpc,(PKDEFERRED_ROUTINE)__recv_cb_dpc,p_port);
\r
792 /* Initialize multicast garbage collector timer and DPC object */
\r
793 KeInitializeDpc(&p_port->gc_dpc,(PKDEFERRED_ROUTINE)__port_mcast_garbage_dpc,p_port);
\r
794 KeInitializeTimerEx(&p_port->gc_timer,SynchronizationTimer);
\r
796 /* We only ever destroy from the PnP callback thread. */
\r
797 cl_status = cl_obj_init( &p_port->obj, CL_DESTROY_SYNC,
\r
798 __port_destroying, __port_cleanup, __port_free );
\r
801 cl_atomic_inc( &p_port->ref[ref_init] );
\r
802 IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ,
\r
803 ("ref type %d ref_cnt %d\n", ref_init, p_port->obj.ref_cnt) );
\r
806 if( cl_status != CL_SUCCESS )
\r
808 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
809 ("cl_obj_init returned %#x\n", cl_status) );
\r
813 cl_status = cl_obj_insert_rel( &p_port->rel, &p_adapter->obj, &p_port->obj );
\r
814 if( cl_status != CL_SUCCESS )
\r
816 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
817 ("cl_obj_insert_rel returned %#x\n", cl_status) );
\r
818 cl_obj_destroy( &p_port->obj );
\r
823 cl_atomic_inc( &p_port->ref[ref_init] );
\r
824 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_OBJ,
\r
825 ("ref type %d ref_cnt %d\n", ref_init, p_port->obj.ref_cnt) );
\r
828 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
835 IN cl_obj_t* const p_obj )
\r
837 ipoib_port_t *p_port;
\r
839 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
841 CL_ASSERT( p_obj );
\r
843 p_port = PARENT_STRUCT( p_obj, ipoib_port_t, obj );
\r
845 ipoib_port_down( p_port );
\r
847 __endpt_mgr_remove_all( p_port );
\r
850 if( p_port->p_adapter->params.cm_enabled )
\r
852 endpt_cm_buf_mgr_destroy( p_port );
\r
853 ipoib_port_srq_destroy( p_port );
\r
854 p_port->endpt_mgr.thread_is_done = 1;
\r
855 cl_event_signal( &p_port->endpt_mgr.event );
\r
858 cl_spinlock_acquire(&p_port->send_lock);
\r
859 ipoib_port_resume( p_port, FALSE );
\r
860 cl_spinlock_release(&p_port->send_lock);
\r
862 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
868 IN cl_obj_t* const p_obj )
\r
870 ipoib_port_t *p_port;
\r
872 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
874 CL_ASSERT( p_obj );
\r
876 p_port = PARENT_STRUCT( p_obj, ipoib_port_t, obj );
\r
878 /* Wait for all sends and receives to get flushed. */
\r
879 while( p_port->send_mgr.depth || p_port->recv_mgr.depth )
\r
880 cl_thread_suspend( 0 );
\r
882 /* Destroy the send and receive managers before closing the CA. */
\r
883 __ib_mgr_destroy( p_port );
\r
885 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
891 IN cl_obj_t* const p_obj )
\r
893 ipoib_port_t *p_port;
\r
895 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
897 CL_ASSERT( p_obj );
\r
899 p_port = PARENT_STRUCT( p_obj, ipoib_port_t, obj );
\r
901 KeCancelTimer(&p_port->gc_timer);
\r
902 KeFlushQueuedDpcs();
\r
903 __endpt_mgr_destroy( p_port );
\r
904 __recv_mgr_destroy( p_port );
\r
905 __send_mgr_destroy( p_port );
\r
906 __buf_mgr_destroy( p_port );
\r
908 cl_spinlock_destroy( &p_port->send_lock );
\r
909 cl_spinlock_destroy( &p_port->recv_lock );
\r
911 cl_obj_deinit( p_obj );
\r
912 if( p_port->p_ca_attrs )
\r
914 cl_free ( p_port->p_ca_attrs );
\r
918 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
923 /******************************************************************************
\r
925 * IB resource manager implementation.
\r
927 ******************************************************************************/
\r
929 __ib_mgr_construct(
\r
930 IN ipoib_port_t* const p_port )
\r
932 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
934 cl_memclr( &p_port->ib_mgr, sizeof(ipoib_ib_mgr_t) );
\r
936 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
940 static ib_api_status_t
\r
942 IN ipoib_port_t* const p_port )
\r
944 ib_api_status_t status;
\r
945 ib_cq_create_t cq_create;
\r
946 ib_qp_create_t qp_create;
\r
947 ib_phys_create_t phys_create;
\r
948 ib_phys_range_t phys_range;
\r
951 ib_qp_attr_t qp_attr;
\r
953 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
956 status = p_port->p_adapter->p_ifc->open_ca(
\r
957 p_port->p_adapter->h_al, p_port->p_adapter->guids.ca_guid,
\r
958 NULL, p_port, &p_port->ib_mgr.h_ca );
\r
959 if( status != IB_SUCCESS )
\r
961 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
962 EVENT_IPOIB_OPEN_CA, 1, status );
\r
963 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
964 ("ib_open_ca returned %s\n",
\r
965 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
969 status = __port_query_ca_attrs( p_port, &p_port->p_ca_attrs );
\r
970 if( status != IB_SUCCESS )
\r
972 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
973 ("Query CA attributes failed\n" ) );
\r
977 if( p_port->p_adapter->params.cm_enabled )
\r
979 uint32_t payload_mtu = __port_attr_to_mtu_size(
\r
980 p_port->p_ca_attrs->p_port_attr[p_port->port_num - 1].mtu )
\r
981 - sizeof(ipoib_hdr_t);
\r
982 /* adjust ipoib UD payload MTU to actual port MTU size. */
\r
983 p_port->p_adapter->params.payload_mtu =
\r
984 max( DEFAULT_PAYLOAD_MTU, payload_mtu );
\r
985 p_port->p_adapter->params.xfer_block_size =
\r
986 (sizeof(eth_hdr_t) + p_port->p_adapter->params.payload_mtu);
\r
990 /* init DMA only once while running MiniportInitialize */
\r
991 if ( !p_port->p_adapter->reset )
\r
993 ULONG max_phys_mapping;
\r
994 if( p_port->p_adapter->params.cm_enabled )
\r
996 max_phys_mapping = p_port->p_adapter->params.cm_xfer_block_size;
\r
998 else if( p_port->p_adapter->params.lso )
\r
1000 max_phys_mapping = LARGE_SEND_OFFLOAD_SIZE;
\r
1004 max_phys_mapping = p_port->p_adapter->params.xfer_block_size;
\r
1006 /*if( NdisMInitializeScatterGatherDma( p_port->p_adapter->h_adapter,
\r
1007 TRUE, max_phys_mapping )!= NDIS_STATUS_SUCCESS )
\r
1009 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1010 ("NdisMInitializeScatterGatherDma failed\n" ) );
\r
1011 return IB_INSUFFICIENT_RESOURCES;
\r
1016 /* Allocate the PD. */
\r
1017 status = p_port->p_adapter->p_ifc->alloc_pd(
\r
1018 p_port->ib_mgr.h_ca, IB_PDT_UD, p_port, &p_port->ib_mgr.h_pd );
\r
1019 if( status != IB_SUCCESS )
\r
1021 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
1022 EVENT_IPOIB_ALLOC_PD, 1, status );
\r
1023 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1024 ("ib_alloc_pd returned %s\n",
\r
1025 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
1029 /* Allocate receive CQ. */
\r
1030 cq_create.size = p_port->p_adapter->params.rq_depth;
\r
1031 cq_create.pfn_comp_cb = __recv_cb;
\r
1032 cq_create.h_wait_obj = NULL;
\r
1034 status = p_port->p_adapter->p_ifc->create_cq(
\r
1035 p_port->ib_mgr.h_ca, &cq_create, p_port,
\r
1036 __cq_event, &p_port->ib_mgr.h_recv_cq );
\r
1037 if( status != IB_SUCCESS )
\r
1039 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
1040 EVENT_IPOIB_CREATE_RECV_CQ, 1, status );
\r
1041 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1042 ("ib_create_cq returned %s.\n",
\r
1043 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
1047 /* Allocate send CQ. */
\r
1048 cq_create.size = p_port->p_adapter->params.sq_depth;
\r
1049 cq_create.pfn_comp_cb = __send_cb;
\r
1051 status = p_port->p_adapter->p_ifc->create_cq(
\r
1052 p_port->ib_mgr.h_ca, &cq_create, p_port,
\r
1053 __cq_event, &p_port->ib_mgr.h_send_cq );
\r
1054 if( status != IB_SUCCESS )
\r
1056 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
1057 EVENT_IPOIB_CREATE_SEND_CQ, 1, status );
\r
1058 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1059 ("ib_create_cq returned %s.\n",
\r
1060 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
1064 /* Allocate the QP. */
\r
1065 cl_memclr( &qp_create, sizeof(qp_create) );
\r
1066 qp_create.qp_type = IB_QPT_UNRELIABLE_DGRM;
\r
1067 qp_create.rq_depth = p_port->p_adapter->params.rq_depth;
\r
1068 qp_create.rq_sge = 2; /* To support buffers spanning pages. */
\r
1069 qp_create.h_rq_cq = p_port->ib_mgr.h_recv_cq;
\r
1070 qp_create.sq_depth = p_port->p_adapter->params.sq_depth;
\r
1072 #define UD_QP_USED_SGE 3
\r
1073 qp_create.sq_sge = MAX_SEND_SGE < p_port->p_ca_attrs->max_sges ?
\r
1074 MAX_SEND_SGE : ( p_port->p_ca_attrs->max_sges - UD_QP_USED_SGE );
\r
1075 if ( !p_port->p_ca_attrs->ipoib_csum )
\r
1077 /* checksum is not supported by device
\r
1078 user must specify BYPASS to explicitly cancel checksum calculation */
\r
1079 if (p_port->p_adapter->params.send_chksum_offload == CSUM_ENABLED)
\r
1080 p_port->p_adapter->params.send_chksum_offload = CSUM_DISABLED;
\r
1081 if (p_port->p_adapter->params.recv_chksum_offload == CSUM_ENABLED)
\r
1082 p_port->p_adapter->params.recv_chksum_offload = CSUM_DISABLED;
\r
1086 // Now, params struct contains the intersection between the user definition
\r
1087 // and actual HW capabilites
\r
1088 // Remember these values for NDIS OID requests
\r
1089 p_port->p_adapter->offload_cap.lso = !!(p_port->p_adapter->params.lso);
\r
1090 p_port->p_adapter->offload_cap.send_chksum_offload =
\r
1091 !! (p_port->p_adapter->params.send_chksum_offload);
\r
1092 p_port->p_adapter->offload_cap.recv_chksum_offload =
\r
1093 !! (p_port->p_adapter->params.recv_chksum_offload);
\r
1098 qp_create.h_sq_cq = p_port->ib_mgr.h_send_cq;
\r
1099 qp_create.sq_signaled = FALSE;
\r
1100 status = p_port->p_adapter->p_ifc->create_qp(
\r
1101 p_port->ib_mgr.h_pd, &qp_create, p_port,
\r
1102 __qp_event, &p_port->ib_mgr.h_qp );
\r
1103 if( status != IB_SUCCESS )
\r
1105 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
1106 EVENT_IPOIB_CREATE_QP, 1, status );
\r
1107 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1108 ("ib_create_qp returned %s\n",
\r
1109 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
1112 /* Query the QP so we can get our QPN. */
\r
1113 status = p_port->p_adapter->p_ifc->query_qp(
\r
1114 p_port->ib_mgr.h_qp, &qp_attr );
\r
1115 if( status != IB_SUCCESS )
\r
1117 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
1118 EVENT_IPOIB_QUERY_QP, 1, status );
\r
1119 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1120 ("ib_query_qp returned %s\n",
\r
1121 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
1124 p_port->ib_mgr.qpn = qp_attr.num;
\r
1126 /* Register all of physical memory */
\r
1127 phys_create.length = MEM_REG_SIZE;
\r
1128 phys_create.num_ranges = 1;
\r
1129 phys_create.range_array = &phys_range;
\r
1130 phys_create.buf_offset = 0;
\r
1131 phys_create.hca_page_size = PAGE_SIZE;
\r
1132 phys_create.access_ctrl = IB_AC_LOCAL_WRITE;
\r
1133 phys_range.base_addr = 0;
\r
1134 phys_range.size = MEM_REG_SIZE;
\r
1136 status = p_port->p_adapter->p_ifc->reg_phys(
\r
1137 p_port->ib_mgr.h_pd, &phys_create, &vaddr,
\r
1138 &p_port->ib_mgr.lkey, &rkey, &p_port->ib_mgr.h_mr );
\r
1139 if( status != IB_SUCCESS )
\r
1141 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
1142 EVENT_IPOIB_REG_PHYS, 1, status );
\r
1143 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1144 ("ib_reg_phys returned %s\n",
\r
1145 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
1149 status = ipoib_port_srq_init( p_port );
\r
1150 if( status != IB_SUCCESS )
\r
1152 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1153 ("ipoib_port_srq_init failed %s\n",
\r
1154 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
1155 /* disable further CM initialization */
\r
1156 p_port->p_adapter->params.cm_enabled = FALSE;
\r
1158 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
1159 EVENT_IPOIB_CONNECTED_MODE_ERR, 1, 0xbadc0de1 );
\r
1164 if( p_port->p_adapter->params.cm_enabled )
\r
1166 status = endpt_cm_buf_mgr_init( p_port );
\r
1167 if( status != IB_SUCCESS )
\r
1169 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1170 ("CM Init buf mgr failed status %#x\n", status ) );
\r
1171 ipoib_port_srq_destroy( p_port );
\r
1172 p_port->p_adapter->params.cm_enabled = FALSE;
\r
1174 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
1175 EVENT_IPOIB_CONNECTED_MODE_ERR, 1, 0xbadc0de2 );
\r
1179 if ( p_port->p_adapter->params.send_chksum_offload )
\r
1180 p_port->p_adapter->params.send_chksum_offload = CSUM_DISABLED;
\r
1184 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
1185 return IB_SUCCESS;
\r
1189 __srq_async_event_cb(
\r
1190 IN ib_async_event_rec_t *p_event_rec )
\r
1192 ipoib_port_t* p_port =
\r
1193 (ipoib_port_t *)p_event_rec->context;
\r
1195 switch( p_event_rec->code )
\r
1197 case IB_AE_SRQ_LIMIT_REACHED:
\r
1198 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1199 ("SRQ ASYNC EVENT CODE %d: %s\n",
\r
1200 p_event_rec->code, "IB_AE_SRQ_LIMIT_REACHED" ) );
\r
1202 case IB_AE_SRQ_CATAS_ERROR:
\r
1203 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1204 ("SRQ ASYNC EVENT CODE %d: %s\n",
\r
1205 p_event_rec->code, "IB_AE_SRQ_CATAS_ERROR" ) );
\r
1206 /*SRQ is in err state, must reinitialize */
\r
1207 p_port->p_adapter->hung = TRUE;
\r
1209 case IB_AE_SRQ_QP_LAST_WQE_REACHED:
\r
1210 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1211 ("SRQ ASYNC EVENT CODE %d: %s\n",
\r
1212 p_event_rec->code, "IB_AE_SRQ_QP_LAST_WQE_REACHED" ) );
\r
1213 /*SRQ is in err state, must reinitialize */
\r
1214 p_port->p_adapter->hung = TRUE;
\r
1217 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1218 ("ASYNC EVENT CODE ARRIVED %d(%#x)\n",
\r
1219 p_event_rec->code, p_event_rec->code ) );
\r
1224 ipoib_port_srq_init(
\r
1225 IN ipoib_port_t* const p_port )
\r
1227 ib_api_status_t ib_status;
\r
1228 ib_srq_handle_t h_srq;
\r
1229 ib_srq_attr_t srq_attr;
\r
1231 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
1233 if( !p_port->p_adapter->params.cm_enabled )
\r
1234 return IB_SUCCESS;
\r
1236 srq_attr.max_sge = min( 2, p_port->p_ca_attrs->max_srq_sges );
\r
1237 srq_attr.srq_limit = 10;
\r
1238 srq_attr.max_wr =
\r
1239 min( (uint32_t)p_port->p_adapter->params.rq_depth * 8,
\r
1240 p_port->p_ca_attrs->max_srq_wrs/2 );
\r
1242 ib_status = p_port->p_adapter->p_ifc->create_srq(
\r
1243 p_port->ib_mgr.h_pd,
\r
1246 __srq_async_event_cb,
\r
1248 if( ib_status != IB_SUCCESS )
\r
1250 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
1251 EVENT_IPOIB_CREATE_QP, 1, ib_status );
\r
1252 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1253 ("ib_create_srq failed status %s\n",
\r
1254 p_port->p_adapter->p_ifc->get_err_str( ib_status )) );
\r
1257 p_port->ib_mgr.h_srq = h_srq;
\r
1259 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
1264 /* __port_query_ca_attrs()
\r
1265 * returns a pointer to allocated memory.
\r
1266 * must be released by caller.
\r
1268 static ib_api_status_t
\r
1269 __port_query_ca_attrs(
\r
1270 IN ipoib_port_t* const p_port,
\r
1271 IN ib_ca_attr_t** pp_ca_attrs )
\r
1273 ib_api_status_t ib_status;
\r
1274 uint32_t attr_size;
\r
1275 ib_ca_attr_t* p_ca_attrs;
\r
1277 *pp_ca_attrs = NULL;
\r
1280 p_port->p_adapter->p_ifc->query_ca( p_port->ib_mgr.h_ca, NULL , &attr_size );
\r
1281 if( ib_status != IB_INSUFFICIENT_MEMORY )
\r
1283 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1284 ("ib_query_ca failed status %s\n",
\r
1285 p_port->p_adapter->p_ifc->get_err_str( ib_status )) );
\r
1288 CL_ASSERT( attr_size );
\r
1290 p_ca_attrs = (ib_ca_attr_t *) cl_zalloc( attr_size );
\r
1291 if ( p_ca_attrs == NULL )
\r
1293 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1294 ("Allocate %d bytes failed for CA Attributes\n", attr_size ));
\r
1295 ib_status = IB_INSUFFICIENT_MEMORY;
\r
1300 p_port->p_adapter->p_ifc->query_ca( p_port->ib_mgr.h_ca, p_ca_attrs , &attr_size );
\r
1301 if ( ib_status != IB_SUCCESS )
\r
1303 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1304 ("CA attributes query failed\n") );
\r
1305 cl_free ( p_ca_attrs );
\r
1309 *pp_ca_attrs = p_ca_attrs;
\r
1315 ipoib_port_srq_destroy(
\r
1316 IN ipoib_port_t* const p_port )
\r
1318 ib_api_status_t status;
\r
1320 if( p_port->ib_mgr.h_srq )
\r
1323 p_port->p_adapter->p_ifc->destroy_srq( p_port->ib_mgr.h_srq, NULL );
\r
1324 CL_ASSERT( status == IB_SUCCESS );
\r
1325 p_port->ib_mgr.h_srq = NULL;
\r
1331 IN ipoib_port_t* const p_port )
\r
1333 ib_api_status_t status;
\r
1335 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
1337 if( p_port->ib_mgr.h_ca )
\r
1340 p_port->p_adapter->p_ifc->close_ca( p_port->ib_mgr.h_ca, NULL );
\r
1341 CL_ASSERT( status == IB_SUCCESS );
\r
1342 p_port->ib_mgr.h_ca = NULL;
\r
1345 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
1350 /******************************************************************************
\r
1352 * Buffer manager implementation.
\r
1354 ******************************************************************************/
\r
1356 __buf_mgr_construct(
\r
1357 IN ipoib_port_t* const p_port )
\r
1359 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
1361 cl_qpool_construct( &p_port->buf_mgr.recv_pool );
\r
1363 p_port->buf_mgr.h_packet_pool = NULL;
\r
1364 p_port->buf_mgr.h_buffer_pool = NULL;
\r
1366 NdisInitializeNPagedLookasideList( &p_port->buf_mgr.send_buf_list,
\r
1367 NULL, NULL, 0, MAX_LSO_PAYLOAD_MTU, 'bipi', 0 );
\r
1369 p_port->buf_mgr.h_send_pkt_pool = NULL;
\r
1371 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
1375 static ib_api_status_t
\r
1377 IN ipoib_port_t* const p_port )
\r
1379 cl_status_t cl_status;
\r
1380 ipoib_params_t *p_params;
\r
1381 NET_BUFFER_LIST_POOL_PARAMETERS pool_parameters;
\r
1382 IPOIB_ENTER(IPOIB_DBG_INIT );
\r
1384 CL_ASSERT( p_port );
\r
1385 CL_ASSERT( p_port->p_adapter );
\r
1387 p_params = &p_port->p_adapter->params;
\r
1389 /* Allocate the receive descriptor pool */
\r
1390 cl_status = cl_qpool_init( &p_port->buf_mgr.recv_pool,
\r
1391 p_params->rq_depth * p_params->recv_pool_ratio,
\r
1392 #if IPOIB_INLINE_RECV
\r
1393 0, 0, sizeof(ipoib_recv_desc_t), __recv_ctor, NULL, p_port );
\r
1394 #else /* IPOIB_INLINE_RECV */
\r
1395 0, 0, sizeof(ipoib_recv_desc_t), __recv_ctor, __recv_dtor, p_port );
\r
1396 #endif /* IPOIB_INLINE_RECV */
\r
1397 if( cl_status != CL_SUCCESS )
\r
1399 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
1400 EVENT_IPOIB_RECV_POOL, 1, cl_status );
\r
1401 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1402 ("cl_qpool_init for recvs returned %#x\n",
\r
1404 return IB_INSUFFICIENT_MEMORY;
\r
1407 /* Allocate the NET BUFFER list pools for receive indication. */
\r
1408 NdisZeroMemory(&pool_parameters, sizeof(NET_BUFFER_LIST_POOL_PARAMETERS));
\r
1409 pool_parameters.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
\r
1410 pool_parameters.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
\r
1411 pool_parameters.Header.Size = sizeof(pool_parameters);
\r
1412 pool_parameters.ProtocolId = 0;
\r
1413 pool_parameters.ContextSize = 0;
\r
1414 pool_parameters.fAllocateNetBuffer = TRUE;
\r
1415 pool_parameters.PoolTag = 'CRPI';
\r
1416 pool_parameters.DataSize = 0;
\r
1418 p_port->buf_mgr.h_packet_pool = NdisAllocateNetBufferListPool(
\r
1419 p_port->p_adapter->h_adapter,
\r
1420 &pool_parameters);
\r
1422 if( !p_port->buf_mgr.h_packet_pool )
\r
1424 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
1425 EVENT_IPOIB_RECV_PKT_POOL, 1, NDIS_STATUS_RESOURCES );
\r
1426 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1427 ("NdisAllocatePacketPool returned %08X\n", (UINT)NDIS_STATUS_RESOURCES) );
\r
1428 return IB_INSUFFICIENT_RESOURCES;
\r
1431 /* Allocate the NET buffer list pool for send formatting. */
\r
1432 pool_parameters.PoolTag = 'XTPI';
\r
1434 p_port->buf_mgr.h_send_pkt_pool = NdisAllocateNetBufferListPool(
\r
1435 p_port->p_adapter->h_adapter,
\r
1436 &pool_parameters);
\r
1437 if( !p_port->buf_mgr.h_send_pkt_pool)
\r
1439 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
1440 EVENT_IPOIB_SEND_PKT_POOL, 1, NDIS_STATUS_RESOURCES );
\r
1441 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1442 ("NdisAllocatePacketPool returned %08X\n", (UINT)NDIS_STATUS_RESOURCES) );
\r
1443 return IB_INSUFFICIENT_RESOURCES;
\r
1446 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
1447 return IB_SUCCESS;
\r
1452 __buf_mgr_destroy(
\r
1453 IN ipoib_port_t* const p_port )
\r
1455 IPOIB_ENTER(IPOIB_DBG_INIT );
\r
1457 CL_ASSERT( p_port );
\r
1459 /* Destroy the send packet and buffer pools.
\r
1460 if( p_port->buf_mgr.h_send_buf_pool )
\r
1461 NdisFreeBufferPool( p_port->buf_mgr.h_send_buf_pool );*/
\r
1462 if( p_port->buf_mgr.h_send_pkt_pool )
\r
1463 NdisFreeNetBufferListPool ( p_port->buf_mgr.h_send_pkt_pool );
\r
1465 /* Destroy the receive packet and buffer pools.
\r
1466 if( p_port->buf_mgr.h_buffer_pool )
\r
1467 NdisFreeBufferPool( p_port->buf_mgr.h_buffer_pool );*/
\r
1468 if( p_port->buf_mgr.h_packet_pool )
\r
1469 NdisFreeNetBufferListPool ( p_port->buf_mgr.h_packet_pool );
\r
1471 /* Free the receive and send descriptors. */
\r
1472 cl_qpool_destroy( &p_port->buf_mgr.recv_pool );
\r
1474 /* Free the lookaside list of scratch buffers. */
\r
1475 NdisDeleteNPagedLookasideList( &p_port->buf_mgr.send_buf_list );
\r
1477 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
1481 static cl_status_t
\r
1483 IN void* const p_object,
\r
1485 OUT cl_pool_item_t** const pp_pool_item )
\r
1487 ipoib_recv_desc_t *p_desc;
\r
1488 ipoib_port_t *p_port;
\r
1490 #if IPOIB_INLINE_RECV
\r
1494 IPOIB_ENTER( IPOIB_DBG_ALLOC );
\r
1496 CL_ASSERT( p_object );
\r
1497 CL_ASSERT( context );
\r
1499 p_desc = (ipoib_recv_desc_t*)p_object;
\r
1500 p_port = (ipoib_port_t*)context;
\r
1502 /* Setup the work request. */
\r
1503 p_desc->wr.ds_array = p_desc->local_ds;
\r
1504 p_desc->wr.wr_id = (uintn_t)p_desc;
\r
1506 #if IPOIB_INLINE_RECV
\r
1507 /* Sanity check on the receive buffer layout */
\r
1508 CL_ASSERT( (void*)&p_desc->buf.eth.pkt.type ==
\r
1509 (void*)&p_desc->buf.ib.pkt.type );
\r
1510 CL_ASSERT( sizeof(recv_buf_t) == sizeof(ipoib_pkt_t) + sizeof(ib_grh_t) );
\r
1512 /* Setup the local data segment. */
\r
1513 p_desc->local_ds[0].vaddr = cl_get_physaddr( &p_desc->buf );
\r
1514 p_desc->local_ds[0].lkey = p_port->ib_mgr.lkey;
\r
1516 PAGE_SIZE - ((uint32_t)p_desc->local_ds[0].vaddr & (PAGE_SIZE - 1));
\r
1517 if( ds0_len >= sizeof(recv_buf_t) )
\r
1519 /* The whole buffer is within a page. */
\r
1520 p_desc->local_ds[0].length = ds0_len;
\r
1521 p_desc->wr.num_ds = 1;
\r
1525 /* The buffer crosses page boundaries. */
\r
1526 p_desc->local_ds[0].length = ds0_len;
\r
1527 p_desc->local_ds[1].vaddr = cl_get_physaddr(
\r
1528 ((uint8_t*)&p_desc->buf) + ds0_len );
\r
1529 p_desc->local_ds[1].lkey = p_port->ib_mgr.lkey;
\r
1530 p_desc->local_ds[1].length = sizeof(recv_buf_t) - ds0_len;
\r
1531 p_desc->wr.num_ds = 2;
\r
1533 #else /* IPOIB_INLINE_RECV */
\r
1534 /* Allocate the receive buffer. */
\r
1535 p_desc->p_buf = (recv_buf_t*)cl_zalloc( sizeof(recv_buf_t) );
\r
1536 if( !p_desc->p_buf )
\r
1538 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1539 ("Failed to allocate receive buffer.\n") );
\r
1540 return CL_INSUFFICIENT_MEMORY;
\r
1543 /* Sanity check on the receive buffer layout */
\r
1544 CL_ASSERT( (void*)&p_desc->p_buf->eth.pkt.type ==
\r
1545 (void*)&p_desc->p_buf->ib.pkt.type );
\r
1547 /* Setup the local data segment. */
\r
1548 p_desc->local_ds[0].vaddr = cl_get_physaddr( p_desc->p_buf );
\r
1549 p_desc->local_ds[0].length = sizeof(ipoib_pkt_t) + sizeof(ib_grh_t);
\r
1550 p_desc->local_ds[0].lkey = p_port->ib_mgr.lkey;
\r
1551 p_desc->wr.num_ds = 1;
\r
1552 #endif /* IPOIB_INLINE_RECV */
\r
1554 *pp_pool_item = &p_desc->item;
\r
1556 IPOIB_EXIT( IPOIB_DBG_ALLOC );
\r
1557 return CL_SUCCESS;
\r
1561 #if !IPOIB_INLINE_RECV
\r
1564 IN const cl_pool_item_t* const p_pool_item,
\r
1565 IN void *context )
\r
1567 ipoib_recv_desc_t *p_desc;
\r
1569 IPOIB_ENTER( IPOIB_DBG_ALLOC );
\r
1571 UNUSED_PARAM( context );
\r
1573 p_desc = PARENT_STRUCT( p_pool_item, ipoib_recv_desc_t, item );
\r
1575 if( p_desc->p_buf )
\r
1576 cl_free( p_desc->p_buf );
\r
1578 IPOIB_EXIT( IPOIB_DBG_ALLOC );
\r
1583 static inline ipoib_recv_desc_t*
\r
1584 __buf_mgr_get_recv(
\r
1585 IN ipoib_port_t* const p_port )
\r
1587 ipoib_recv_desc_t *p_desc;
\r
1588 IPOIB_ENTER( IPOIB_DBG_RECV );
\r
1589 p_desc = (ipoib_recv_desc_t*)cl_qpool_get( &p_port->buf_mgr.recv_pool );
\r
1590 /* Reference the port object for the send. */
\r
1593 ipoib_port_ref( p_port, ref_get_recv );
\r
1594 CL_ASSERT( p_desc->wr.wr_id == (uintn_t)p_desc );
\r
1595 #if IPOIB_INLINE_RECV
\r
1596 CL_ASSERT( p_desc->local_ds[0].vaddr ==
\r
1597 cl_get_physaddr( &p_desc->buf ) );
\r
1598 #else /* IPOIB_INLINE_RECV */
\r
1599 CL_ASSERT( p_desc->local_ds[0].vaddr ==
\r
1600 cl_get_physaddr( p_desc->p_buf ) );
\r
1601 CL_ASSERT( p_desc->local_ds[0].length ==
\r
1602 (sizeof(ipoib_pkt_t) + sizeof(ib_grh_t)) );
\r
1603 #endif /* IPOIB_INLINE_RECV */
\r
1604 CL_ASSERT( p_desc->local_ds[0].lkey == p_port->ib_mgr.lkey );
\r
1606 IPOIB_EXIT( IPOIB_DBG_RECV );
\r
1612 static inline void
\r
1613 __buf_mgr_put_recv(
\r
1614 IN ipoib_port_t* const p_port,
\r
1615 IN ipoib_recv_desc_t* const p_desc,
\r
1616 IN NET_BUFFER_LIST* const p_net_buffer_list OPTIONAL )
\r
1618 NET_BUFFER *p_buf = NULL;
\r
1619 MDL *p_mdl = NULL;
\r
1620 IPOIB_ENTER(IPOIB_DBG_RECV );
\r
1622 if( p_net_buffer_list )
\r
1624 NET_BUFFER_LIST_NEXT_NBL(p_net_buffer_list) = NULL;
\r
1625 p_buf = NET_BUFFER_LIST_FIRST_NB(p_net_buffer_list);
\r
1626 CL_ASSERT( p_buf );
\r
1627 p_mdl = NET_BUFFER_FIRST_MDL(p_buf);
\r
1628 CL_ASSERT( p_mdl );
\r
1629 NdisFreeMdl(p_mdl);
\r
1630 NdisFreeNetBufferList(p_net_buffer_list);
\r
1633 /* Return the descriptor to its pools. */
\r
1634 cl_qpool_put( &p_port->buf_mgr.recv_pool, &p_desc->item );
\r
1637 * Dereference the port object since the receive is no longer outstanding.
\r
1639 ipoib_port_deref( p_port, ref_get_recv );
\r
1640 IPOIB_EXIT( IPOIB_DBG_RECV );
\r
1644 static inline void
\r
1645 __buf_mgr_put_recv_list(
\r
1646 IN ipoib_port_t* const p_port,
\r
1647 IN cl_qlist_t* const p_list )
\r
1649 //IPOIB_ENTER( IPOIB_DBG_RECV );
\r
1650 cl_qpool_put_list( &p_port->buf_mgr.recv_pool, p_list );
\r
1651 //IPOIB_EXIT( IPOIB_DBG_RECV );
\r
1655 static inline NET_BUFFER_LIST*
\r
1656 __buf_mgr_get_NBL(
\r
1657 IN ipoib_port_t* const p_port,
\r
1658 IN ipoib_recv_desc_t* const p_desc )
\r
1660 NET_BUFFER_LIST *p_net_buffer_list;
\r
1663 IPOIB_ENTER( IPOIB_DBG_RECV );
\r
1665 p_mdl = NdisAllocateMdl(p_port->p_adapter->h_adapter,
\r
1666 &p_desc->buf.eth.pkt,
\r
1670 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1671 ("Failed to allocate MDL\n") );
\r
1675 p_net_buffer_list = NdisAllocateNetBufferAndNetBufferList(
\r
1676 p_port->buf_mgr.h_packet_pool,
\r
1683 if( !p_net_buffer_list )
\r
1685 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1686 ("Failed to allocate NET_BUFFER_LIST\n") );
\r
1687 NdisFreeMdl(p_mdl);
\r
1691 NET_BUFFER_LIST_NEXT_NBL(p_net_buffer_list) = NULL;
\r
1692 IPOIB_PORT_FROM_NBL( p_net_buffer_list ) = p_port;
\r
1693 IPOIB_RECV_FROM_NBL( p_net_buffer_list ) = p_desc;
\r
1694 p_net_buffer_list->SourceHandle = p_port->p_adapter->h_adapter;
\r
1696 IPOIB_EXIT( IPOIB_DBG_RECV );
\r
1697 return p_net_buffer_list;
\r
1701 /******************************************************************************
\r
1703 * Receive manager implementation.
\r
1705 ******************************************************************************/
\r
1707 __recv_mgr_construct(
\r
1708 IN ipoib_port_t* const p_port )
\r
1710 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
1712 cl_qlist_init( &p_port->recv_mgr.done_list );
\r
1714 p_port->recv_mgr.recv_NBL_array = NULL;
\r
1716 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
1720 static ib_api_status_t
\r
1722 IN ipoib_port_t* const p_port )
\r
1724 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
1726 /* Allocate the NDIS_PACKET pointer array for indicating receives. */
\r
1727 p_port->recv_mgr.recv_NBL_array = (NET_BUFFER_LIST **)cl_malloc(
\r
1728 sizeof(NET_BUFFER_LIST*) * p_port->p_adapter->params.rq_depth );
\r
1729 if( !p_port->recv_mgr.recv_NBL_array )
\r
1731 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
1732 EVENT_IPOIB_RECV_PKT_ARRAY, 0 );
\r
1733 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1734 ("cl_malloc for PNDIS_PACKET array failed.\n") );
\r
1735 return IB_INSUFFICIENT_MEMORY;
\r
1738 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
1739 return IB_SUCCESS;
\r
1744 __recv_mgr_destroy(
\r
1745 IN ipoib_port_t* const p_port )
\r
1747 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
1749 CL_ASSERT( cl_is_qlist_empty( &p_port->recv_mgr.done_list ) );
\r
1750 CL_ASSERT( !p_port->recv_mgr.depth );
\r
1752 if( p_port->recv_mgr.recv_NBL_array )
\r
1753 cl_free( p_port->recv_mgr.recv_NBL_array );
\r
1755 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
1760 * Posts receive buffers to the receive queue and returns the number
\r
1761 * of receives needed to bring the RQ to its low water mark. Note
\r
1762 * that the value is signed, and can go negative. All tests must
\r
1766 __recv_mgr_repost(
\r
1767 IN ipoib_port_t* const p_port )
\r
1769 ipoib_recv_desc_t *p_head = NULL, *p_tail = NULL, *p_next;
\r
1770 ib_api_status_t status;
\r
1771 ib_recv_wr_t *p_failed;
\r
1772 PERF_DECLARE( GetRecv );
\r
1773 PERF_DECLARE( PostRecv );
\r
1775 IPOIB_ENTER( IPOIB_DBG_RECV );
\r
1777 CL_ASSERT( p_port );
\r
1778 cl_obj_lock( &p_port->obj );
\r
1779 if( p_port->state != IB_QPS_RTS )
\r
1781 cl_obj_unlock( &p_port->obj );
\r
1782 IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV,
\r
1783 ("Port in invalid state. Not reposting.\n") );
\r
1786 ipoib_port_ref( p_port, ref_repost );
\r
1787 cl_obj_unlock( &p_port->obj );
\r
1789 while( p_port->recv_mgr.depth < p_port->p_adapter->params.rq_depth )
\r
1791 /* Pull receives out of the pool and chain them up. */
\r
1792 cl_perf_start( GetRecv );
\r
1793 p_next = __buf_mgr_get_recv( p_port );
\r
1794 cl_perf_stop( &p_port->p_adapter->perf, GetRecv );
\r
1797 IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_RECV,
\r
1798 ("Out of receive descriptors! recv queue depth 0x%x\n",p_port->recv_mgr.depth) );
\r
1805 p_next->wr.p_next = NULL;
\r
1809 p_next->wr.p_next = &p_head->wr;
\r
1814 p_port->recv_mgr.depth++;
\r
1819 cl_perf_start( PostRecv );
\r
1820 status = p_port->p_adapter->p_ifc->post_recv(
\r
1821 p_port->ib_mgr.h_qp, &p_head->wr, &p_failed );
\r
1822 cl_perf_stop( &p_port->p_adapter->perf, PostRecv );
\r
1824 if( status != IB_SUCCESS )
\r
1826 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1827 ("ip_post_recv returned %s\n",
\r
1828 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
1829 /* return the descriptors to the pool */
\r
1832 p_head = PARENT_STRUCT( p_failed, ipoib_recv_desc_t, wr );
\r
1833 p_failed = p_failed->p_next;
\r
1835 __buf_mgr_put_recv( p_port, p_head, NULL );
\r
1836 p_port->recv_mgr.depth--;
\r
1841 ipoib_port_deref( p_port, ref_repost );
\r
1842 IPOIB_EXIT( IPOIB_DBG_RECV );
\r
1843 return p_port->p_adapter->params.rq_low_watermark - p_port->recv_mgr.depth;
\r
1847 ipoib_return_net_buffer_list(
\r
1848 IN NDIS_HANDLE adapter_context,
\r
1849 IN NET_BUFFER_LIST *p_net_buffer_lists,
\r
1850 IN ULONG return_flags)
\r
1852 ipoib_port_t *p_port;
\r
1853 ipoib_recv_desc_t *p_desc;
\r
1854 NET_BUFFER_LIST *cur_net_buffer_list,*next_net_buffer_list;
\r
1857 PERF_DECLARE( ReturnPacket );
\r
1858 PERF_DECLARE( ReturnPutRecv );
\r
1859 PERF_DECLARE( ReturnRepostRecv );
\r
1860 PERF_DECLARE( ReturnPreparePkt );
\r
1861 PERF_DECLARE( ReturnNdisIndicate );
\r
1863 IPOIB_ENTER( IPOIB_DBG_RECV );
\r
1865 UNUSED_PARAM( return_flags );
\r
1867 p_port = ((ipoib_adapter_t*)adapter_context)->p_port;
\r
1868 CL_ASSERT( p_net_buffer_lists );
\r
1870 cl_perf_start( ReturnPacket );
\r
1871 cl_spinlock_acquire( &p_port->recv_lock );
\r
1872 for (cur_net_buffer_list = p_net_buffer_lists;
\r
1873 cur_net_buffer_list != NULL;
\r
1874 cur_net_buffer_list = next_net_buffer_list)
\r
1876 next_net_buffer_list = NET_BUFFER_LIST_NEXT_NBL(cur_net_buffer_list);
\r
1878 /* Get the port and descriptor from the NET_BUFFER_LIST. */
\r
1879 CL_ASSERT(p_port == IPOIB_PORT_FROM_NBL( cur_net_buffer_list ));
\r
1880 p_desc = IPOIB_RECV_FROM_NBL( cur_net_buffer_list );
\r
1883 //TODO: NDIS60, rewrite this block
\r
1885 #if 0 //TODO CM flow
\r
1886 if( p_desc->type == PKT_TYPE_CM_UCAST )
\r
1888 int32_t discarded;
\r
1889 uint32_t NBL_cnt = 0;
\r
1891 ib_api_status_t status = IB_NOT_DONE;
\r
1894 NDIS_BUFFER *p_buf;
\r
1896 /* Unchain the NDIS buffer. */
\r
1897 NdisUnchainBufferAtFront( p_packet, &p_buf );
\r
1898 CL_ASSERT( p_buf );
\r
1899 /* Return the NDIS packet and NDIS buffer to their pools. */
\r
1900 NdisDprFreePacketNonInterlocked( p_packet );
\r
1901 NdisFreeBuffer( p_buf );
\r
1903 endpt_cm_buf_mgr_put_recv( &p_port->cm_buf_mgr, (ipoib_cm_desc_t *)p_desc );
\r
1904 status = endpt_cm_post_recv( p_port );
\r
1905 if( status != IB_SUCCESS )
\r
1907 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1908 ("Post Recv QP failed\n" ) );
\r
1910 cl_spinlock_release( &p_port->recv_lock );
\r
1915 cl_perf_start( ReturnPutRecv );
\r
1916 __buf_mgr_put_recv( p_port, p_desc, cur_net_buffer_list );
\r
1917 cl_perf_stop( &p_port->p_adapter->perf, ReturnPutRecv );
\r
1922 /* Repost buffers to HW */
\r
1923 cl_perf_start( ReturnRepostRecv );
\r
1924 shortage = __recv_mgr_repost( p_port );
\r
1925 cl_perf_stop( &p_port->p_adapter->perf, ReturnRepostRecv );
\r
1926 cl_spinlock_release( &p_port->recv_lock );
\r
1927 cl_perf_stop( &p_port->p_adapter->perf, ReturnPacket );
\r
1929 IPOIB_EXIT( IPOIB_DBG_RECV );
\r
1932 static void __recv_cb_dpc(KDPC *p_gc_dpc,void *context,void * s_arg1 , void * s_arg2)
\r
1935 ipoib_port_t *p_port = (ipoib_port_t *) context;
\r
1937 UNREFERENCED_PARAMETER(p_gc_dpc);
\r
1938 UNREFERENCED_PARAMETER(s_arg1);
\r
1939 UNREFERENCED_PARAMETER(s_arg2);
\r
1942 __recv_cb(NULL, p_port);
\r
1943 ipoib_port_deref( p_port, ref_recv_cb );
\r
1951 IN const ib_cq_handle_t h_cq,
\r
1952 IN void *cq_context )
\r
1954 ipoib_port_t *p_port;
\r
1955 ib_api_status_t status;
\r
1956 ib_wc_t wc[MAX_RECV_WC], *p_free, *p_wc;
\r
1957 int32_t NBL_cnt, recv_cnt = 0, shortage, discarded;
\r
1958 cl_qlist_t done_list, bad_list;
\r
1960 ULONG recv_complete_flags = 0;
\r
1962 PERF_DECLARE( RecvCompBundle );
\r
1963 PERF_DECLARE( RecvCb );
\r
1964 PERF_DECLARE( PollRecv );
\r
1965 PERF_DECLARE( RepostRecv );
\r
1966 PERF_DECLARE( FilterRecv );
\r
1967 PERF_DECLARE( BuildNBLArray );
\r
1968 PERF_DECLARE( RecvNdisIndicate );
\r
1969 PERF_DECLARE( RearmRecv );
\r
1970 PERF_DECLARE( PutRecvList );
\r
1972 IPOIB_ENTER( IPOIB_DBG_RECV );
\r
1974 cl_perf_clr( RecvCompBundle );
\r
1976 cl_perf_start( RecvCb );
\r
1978 UNUSED_PARAM( h_cq );
\r
1980 NDIS_SET_SEND_COMPLETE_FLAG(recv_complete_flags, NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL );
\r
1982 p_port = (ipoib_port_t*)cq_context;
\r
1984 cl_qlist_init( &done_list );
\r
1985 cl_qlist_init( &bad_list );
\r
1987 ipoib_port_ref( p_port, ref_recv_cb );
\r
1988 for( i = 0; i < MAX_RECV_WC; i++ )
\r
1989 wc[i].p_next = &wc[i + 1];
\r
1990 wc[MAX_RECV_WC - 1].p_next = NULL;
\r
1993 * We'll be accessing the endpoint map so take a reference
\r
1994 * on it to prevent modifications.
\r
1996 cl_obj_lock( &p_port->obj );
\r
1997 cl_atomic_inc( &p_port->endpt_rdr );
\r
1998 cl_obj_unlock( &p_port->obj );
\r
2002 /* If we get here, then the list of WCs is intact. */
\r
2005 cl_perf_start( PollRecv );
\r
2006 status = p_port->p_adapter->p_ifc->poll_cq(
\r
2007 p_port->ib_mgr.h_recv_cq, &p_free, &p_wc );
\r
2008 cl_perf_stop( &p_port->p_adapter->perf, PollRecv );
\r
2009 CL_ASSERT( status == IB_SUCCESS || status == IB_NOT_FOUND );
\r
2011 /* Look at the payload now and filter ARP and DHCP packets. */
\r
2012 cl_perf_start( FilterRecv );
\r
2013 recv_cnt += __recv_mgr_filter( p_port, p_wc, &done_list, &bad_list );
\r
2014 cl_perf_stop( &p_port->p_adapter->perf, FilterRecv );
\r
2016 } while( ( !p_free ) && ( recv_cnt < 16 )); //TODO restore back to 128
\r
2018 /* We're done looking at the endpoint map, release the reference. */
\r
2019 cl_atomic_dec( &p_port->endpt_rdr );
\r
2021 cl_perf_log( &p_port->p_adapter->perf, RecvCompBundle, recv_cnt );
\r
2023 cl_spinlock_acquire( &p_port->recv_lock );
\r
2025 /* Update our posted depth. */
\r
2026 p_port->recv_mgr.depth -= recv_cnt;
\r
2028 /* Return any discarded receives to the pool */
\r
2029 cl_perf_start( PutRecvList );
\r
2030 __buf_mgr_put_recv_list( p_port, &bad_list );
\r
2031 cl_perf_stop( &p_port->p_adapter->perf, PutRecvList );
\r
2036 /* Repost ASAP so we don't starve the RQ. */
\r
2037 cl_perf_start( RepostRecv );
\r
2038 shortage = __recv_mgr_repost( p_port );
\r
2040 if( shortage > 0 )
\r
2042 recv_complete_flags |= NDIS_RECEIVE_FLAGS_RESOURCES;
\r
2043 cl_dbg_out("Got SHORTAGE=%d\n",shortage);
\r
2046 cl_perf_stop( &p_port->p_adapter->perf, RepostRecv );
\r
2048 cl_perf_start( BuildNBLArray );
\r
2049 /* Notify NDIS of any and all possible receive buffers. */
\r
2050 NBL_cnt = __recv_mgr_build_NBL_array(
\r
2051 p_port, &done_list, &discarded);
\r
2052 cl_perf_stop( &p_port->p_adapter->perf, BuildNBLArray );
\r
2054 /* Only indicate receives if we actually had any. */
\r
2055 if( discarded && shortage > 0 )
\r
2057 /* We may have thrown away packets, and have a shortage */
\r
2058 cl_perf_start( RepostRecv );
\r
2059 __recv_mgr_repost( p_port );
\r
2060 cl_perf_stop( &p_port->p_adapter->perf, RepostRecv );
\r
2064 //cl_dbg_out("NBL cnt == 0 :-(\n");
\r
2068 cl_spinlock_release( &p_port->recv_lock );
\r
2070 cl_perf_start( RecvNdisIndicate );
\r
2072 NdisMIndicateReceiveNetBufferLists(
\r
2073 p_port->p_adapter->h_adapter,
\r
2074 p_port->recv_mgr.recv_NBL_array[0],
\r
2075 NDIS_DEFAULT_PORT_NUMBER,
\r
2077 recv_complete_flags);
\r
2079 cl_perf_stop( &p_port->p_adapter->perf, RecvNdisIndicate );
\r
2082 * Cap the number of receives to put back to what we just indicated
\r
2083 * with NDIS_STATUS_RESOURCES.
\r
2085 if( shortage > 0 )
\r
2088 cl_dbg_out("GOT SHORTAGE <===============\n");
\r
2089 /* Return all but the last packet to the pool. */
\r
2090 cl_spinlock_acquire( &p_port->recv_lock );
\r
2091 //while( shortage-- > 1 )
\r
2092 while ( NBL_cnt-- > 0)
\r
2094 __buf_mgr_put_recv( p_port,
\r
2095 (ipoib_recv_desc_t *)IPOIB_RECV_FROM_NBL( p_port->recv_mgr.recv_NBL_array[NBL_cnt] ),
\r
2096 p_port->recv_mgr.recv_NBL_array[NBL_cnt] );
\r
2098 __recv_mgr_repost( p_port );
\r
2099 cl_spinlock_release( &p_port->recv_lock );
\r
2102 * Return the last packet as if NDIS returned it, so that we repost
\r
2103 * and report any other pending receives.
\r
2105 //ipoib_return_net_buffer_list( p_port, p_port->recv_mgr.recv_NBL_array[0],recv_complete_flags );
\r
2107 cl_spinlock_acquire( &p_port->recv_lock );
\r
2109 } while( NBL_cnt );
\r
2110 cl_spinlock_release( &p_port->recv_lock );
\r
2114 * Rearm after filtering to prevent contention on the enpoint maps
\r
2115 * and eliminate the possibility of having a call to
\r
2116 * __endpt_mgr_insert find a duplicate.
\r
2118 cl_perf_start( RearmRecv );
\r
2119 status = p_port->p_adapter->p_ifc->rearm_cq(
\r
2120 p_port->ib_mgr.h_recv_cq, FALSE );
\r
2121 cl_perf_stop( &p_port->p_adapter->perf, RearmRecv );
\r
2122 CL_ASSERT( status == IB_SUCCESS );
\r
2124 ipoib_port_deref( p_port, ref_recv_cb );
\r
2126 // Please note the reference is still up
\r
2127 KeInsertQueueDpc(&p_port->recv_dpc, NULL, NULL);
\r
2130 cl_perf_stop( &p_port->p_adapter->perf, RecvCb );
\r
2132 IPOIB_EXIT( IPOIB_DBG_RECV );
\r
2137 __recv_get_endpts(
\r
2138 IN ipoib_port_t* const p_port,
\r
2139 IN ipoib_recv_desc_t* const p_desc,
\r
2140 IN ib_wc_t* const p_wc,
\r
2141 OUT ipoib_endpt_t** const pp_src,
\r
2142 OUT ipoib_endpt_t** const pp_dst )
\r
2144 ib_api_status_t status;
\r
2146 PERF_DECLARE( GetEndptByGid );
\r
2147 PERF_DECLARE( GetEndptByLid );
\r
2148 PERF_DECLARE( EndptInsert );
\r
2150 IPOIB_ENTER( IPOIB_DBG_RECV );
\r
2152 /* Setup our shortcut pointers based on whether GRH is valid. */
\r
2153 if( p_wc->recv.ud.recv_opt & IB_RECV_OPT_GRH_VALID )
\r
2155 /* Lookup the source endpoints based on GID. */
\r
2156 cl_perf_start( GetEndptByGid );
\r
2158 #if IPOIB_INLINE_RECV
\r
2159 __endpt_mgr_get_by_gid( p_port, &p_desc->buf.ib.grh.src_gid );
\r
2160 #else /* IPOIB_INLINE_RECV */
\r
2161 __endpt_mgr_get_by_gid( p_port, &p_desc->p_buf->ib.grh.src_gid );
\r
2162 #endif /* IPOIB_INLINE_RECV */
\r
2163 cl_perf_stop( &p_port->p_adapter->perf, GetEndptByGid );
\r
2166 * Lookup the destination endpoint based on GID.
\r
2167 * This is used along with the packet filter to determine
\r
2168 * whether to report this to NDIS.
\r
2170 cl_perf_start( GetEndptByGid );
\r
2172 #if IPOIB_INLINE_RECV
\r
2173 __endpt_mgr_get_by_gid( p_port, &p_desc->buf.ib.grh.dest_gid );
\r
2174 #else /* IPOIB_INLINE_RECV */
\r
2175 __endpt_mgr_get_by_gid( p_port, &p_desc->p_buf->ib.grh.dest_gid );
\r
2176 #endif /* IPOIB_INLINE_RECV */
\r
2177 cl_perf_stop( &p_port->p_adapter->perf, GetEndptByGid );
\r
2180 * Create the source endpoint if it does not exist. Note that we
\r
2181 * can only do this for globally routed traffic since we need the
\r
2182 * information from the GRH to generate the MAC.
\r
2186 status = ipoib_mac_from_guid(
\r
2187 #if IPOIB_INLINE_RECV
\r
2188 p_desc->buf.ib.grh.src_gid.unicast.interface_id, p_port->p_adapter->params.guid_mask, &mac );
\r
2189 #else /* IPOIB_INLINE_RECV */
\r
2190 p_desc->p_buf->ib.grh.src_gid.unicast.interface_id, p_port->p_adapter->params.guid_mask, &mac );
\r
2191 #endif /* IPOIB_INLINE_RECV */
\r
2192 if( status != IB_SUCCESS )
\r
2194 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2195 ("ipoib_mac_from_guid returned %s\n",
\r
2196 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
2200 /* Create the endpoint. */
\r
2201 #if IPOIB_INLINE_RECV
\r
2202 *pp_src = ipoib_endpt_create( &p_desc->buf.ib.grh.src_gid,
\r
2203 #else /* IPOIB_INLINE_RECV */
\r
2204 *pp_src = ipoib_endpt_create( &p_desc->p_buf->ib.grh.src_gid,
\r
2205 #endif /* IPOIB_INLINE_RECV */
\r
2206 p_wc->recv.ud.remote_lid, p_wc->recv.ud.remote_qp );
\r
2209 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2210 ("ipoib_endpt_create failed\n") );
\r
2213 cl_perf_start( EndptInsert );
\r
2214 cl_obj_lock( &p_port->obj );
\r
2215 status = __endpt_mgr_insert( p_port, mac, *pp_src );
\r
2216 if( status != IB_SUCCESS )
\r
2218 cl_obj_unlock( &p_port->obj );
\r
2219 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2220 ("__endpt_mgr_insert returned %s\n",
\r
2221 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
2225 cl_obj_unlock( &p_port->obj );
\r
2226 cl_perf_stop( &p_port->p_adapter->perf, EndptInsert );
\r
2232 * Lookup the remote endpoint based on LID. Note that only
\r
2233 * unicast traffic can be LID routed.
\r
2235 cl_perf_start( GetEndptByLid );
\r
2236 *pp_src = __endpt_mgr_get_by_lid( p_port, p_wc->recv.ud.remote_lid );
\r
2237 cl_perf_stop( &p_port->p_adapter->perf, GetEndptByLid );
\r
2238 *pp_dst = p_port->p_local_endpt;
\r
2239 CL_ASSERT( *pp_dst );
\r
2242 if( *pp_src && !ipoib_is_voltaire_router_gid( &(*pp_src)->dgid ) &&
\r
2243 (*pp_src)->qpn != p_wc->recv.ud.remote_qp )
\r
2245 /* Update the QPN for the endpoint. */
\r
2246 IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV,
\r
2247 ("Updating QPN for MAC: %02X-%02X-%02X-%02X-%02X-%02X\n",
\r
2248 (*pp_src )->mac.addr[0], (*pp_src )->mac.addr[1],
\r
2249 (*pp_src )->mac.addr[2], (*pp_src )->mac.addr[3],
\r
2250 (*pp_src )->mac.addr[4], (*pp_src )->mac.addr[5]) );
\r
2251 // (*pp_src)->qpn = p_wc->recv.ud.remote_qp;
\r
2254 if( *pp_src && *pp_dst )
\r
2256 IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_RECV,
\r
2258 "\tsrc MAC: %02X-%02X-%02X-%02X-%02X-%02X\n"
\r
2259 "\tdst MAC: %02X-%02X-%02X-%02X-%02X-%02X\n",
\r
2260 (*pp_src )->mac.addr[0], (*pp_src )->mac.addr[1],
\r
2261 (*pp_src )->mac.addr[2], (*pp_src )->mac.addr[3],
\r
2262 (*pp_src )->mac.addr[4], (*pp_src )->mac.addr[5],
\r
2263 (*pp_dst )->mac.addr[0], (*pp_dst )->mac.addr[1],
\r
2264 (*pp_dst )->mac.addr[2], (*pp_dst )->mac.addr[3],
\r
2265 (*pp_dst )->mac.addr[4], (*pp_dst )->mac.addr[5]) );
\r
2268 IPOIB_EXIT( IPOIB_DBG_RECV );
\r
2273 __recv_mgr_filter(
\r
2274 IN ipoib_port_t* const p_port,
\r
2275 IN ib_wc_t* const p_done_wc_list,
\r
2276 OUT cl_qlist_t* const p_done_list,
\r
2277 OUT cl_qlist_t* const p_bad_list )
\r
2279 ipoib_recv_desc_t *p_desc;
\r
2281 ipoib_pkt_t *p_ipoib;
\r
2283 ipoib_endpt_t *p_src, *p_dst;
\r
2284 ib_api_status_t status;
\r
2286 int32_t recv_cnt = 0;
\r
2287 PERF_DECLARE( GetRecvEndpts );
\r
2288 PERF_DECLARE( RecvGen );
\r
2289 PERF_DECLARE( RecvTcp );
\r
2290 PERF_DECLARE( RecvUdp );
\r
2291 PERF_DECLARE( RecvDhcp );
\r
2292 PERF_DECLARE( RecvArp );
\r
2294 IPOIB_ENTER( IPOIB_DBG_RECV );
\r
2296 for( p_wc = p_done_wc_list; p_wc; p_wc = p_wc->p_next )
\r
2298 CL_ASSERT( p_wc->status != IB_WCS_SUCCESS || p_wc->wc_type == IB_WC_RECV );
\r
2299 p_desc = (ipoib_recv_desc_t*)(uintn_t)p_wc->wr_id;
\r
2302 if( p_wc->status != IB_WCS_SUCCESS )
\r
2304 if( p_wc->status != IB_WCS_WR_FLUSHED_ERR )
\r
2306 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2307 ("Failed completion %s (vendor specific %#x)\n",
\r
2308 p_port->p_adapter->p_ifc->get_wc_status_str( p_wc->status ),
\r
2309 (int)p_wc->vendor_specific) );
\r
2310 ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0, 0 );
\r
2314 IPOIB_PRINT(TRACE_LEVEL_VERBOSE, IPOIB_DBG_RECV,
\r
2315 ("Flushed completion %s\n",
\r
2316 p_port->p_adapter->p_ifc->get_wc_status_str( p_wc->status )) );
\r
2317 ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_DROPPED, 0, 0 );
\r
2319 cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item );
\r
2320 /* Dereference the port object on behalf of the failed receive. */
\r
2321 ipoib_port_deref( p_port, ref_failed_recv_wc );
\r
2325 len = p_wc->length - sizeof(ib_grh_t);
\r
2327 if( len < sizeof(ipoib_hdr_t) )
\r
2329 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2330 ("Received ETH packet < min size\n") );
\r
2331 ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0, 0 );
\r
2332 cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item );
\r
2333 ipoib_port_deref( p_port, ref_recv_inv_len );
\r
2337 if((len - sizeof(ipoib_hdr_t)) > p_port->p_adapter->params.payload_mtu)
\r
2339 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2340 ("Received ETH packet len %d > payload MTU (%d)\n",
\r
2341 (len - sizeof(ipoib_hdr_t)),
\r
2342 p_port->p_adapter->params.payload_mtu) );
\r
2343 ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0, 0 );
\r
2344 cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item );
\r
2345 ipoib_port_deref( p_port, ref_recv_inv_len );
\r
2349 /* Successful completion. Get the receive information. */
\r
2350 p_desc->ndis_csum.Value = ( ( p_wc->recv.ud.recv_opt & IB_RECV_OPT_CSUM_MASK ) >> 8 );
\r
2351 p_desc->len = len + 14 - 4 ;
\r
2352 cl_perf_start( GetRecvEndpts );
\r
2353 __recv_get_endpts( p_port, p_desc, p_wc, &p_src, &p_dst );
\r
2354 cl_perf_stop( &p_port->p_adapter->perf, GetRecvEndpts );
\r
2356 #if IPOIB_INLINE_RECV
\r
2357 p_ipoib = &p_desc->buf.ib.pkt;
\r
2358 p_eth = &p_desc->buf.eth.pkt;
\r
2359 #else /* IPOIB_INLINE_RECV */
\r
2360 p_ipoib = &p_desc->p_buf->ib.pkt;
\r
2361 p_eth = &p_desc->p_buf->eth.pkt;
\r
2362 #endif /*IPOIB_INLINE_RECV */
\r
2366 /* Don't report loopback traffic - we requested SW loopback. */
\r
2367 if( !cl_memcmp( &p_port->p_adapter->params.conf_mac,
\r
2368 &p_src->mac, sizeof(p_port->p_adapter->params.conf_mac) ) )
\r
2371 * "This is not the packet you're looking for" - don't update
\r
2372 * receive statistics, the packet never happened.
\r
2374 cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item );
\r
2375 /* Dereference the port object on behalf of the failed recv. */
\r
2376 ipoib_port_deref( p_port, ref_recv_loopback );
\r
2381 switch( p_ipoib->hdr.type )
\r
2383 case ETH_PROT_TYPE_IP:
\r
2384 if( len < (sizeof(ipoib_hdr_t) + sizeof(ip_hdr_t)) )
\r
2386 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2387 ("Received IP packet < min size\n") );
\r
2388 status = IB_INVALID_SETTING;
\r
2392 if( p_ipoib->type.ip.hdr.offset ||
\r
2393 p_ipoib->type.ip.hdr.prot != IP_PROT_UDP )
\r
2395 /* Unfiltered. Setup the ethernet header and report. */
\r
2396 cl_perf_start( RecvTcp );
\r
2397 status = __recv_gen( p_ipoib, p_eth, p_src, p_dst );
\r
2398 cl_perf_stop( &p_port->p_adapter->perf, RecvTcp );
\r
2402 /* First packet of a UDP transfer. */
\r
2404 (sizeof(ipoib_hdr_t) + sizeof(ip_hdr_t) + sizeof(udp_hdr_t)) )
\r
2406 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2407 ("Received UDP packet < min size\n") );
\r
2408 status = IB_INVALID_SETTING;
\r
2412 /* Check if DHCP conversion is required. */
\r
2413 if( (p_ipoib->type.ip.prot.udp.hdr.dst_port == DHCP_PORT_SERVER &&
\r
2414 p_ipoib->type.ip.prot.udp.hdr.src_port == DHCP_PORT_CLIENT) ||
\r
2415 (p_ipoib->type.ip.prot.udp.hdr.dst_port == DHCP_PORT_CLIENT &&
\r
2416 p_ipoib->type.ip.prot.udp.hdr.src_port == DHCP_PORT_SERVER)||
\r
2417 (p_ipoib->type.ip.prot.udp.hdr.dst_port == DHCP_PORT_PROXY_SERVER &&
\r
2418 p_ipoib->type.ip.prot.udp.hdr.src_port == DHCP_PORT_CLIENT) ||
\r
2419 (p_ipoib->type.ip.prot.udp.hdr.dst_port == DHCP_PORT_CLIENT &&
\r
2420 p_ipoib->type.ip.prot.udp.hdr.src_port == DHCP_PORT_PROXY_SERVER))
\r
2422 if( len < (sizeof(ipoib_hdr_t) + sizeof(ip_hdr_t) +
\r
2423 sizeof(udp_hdr_t) + DHCP_MIN_SIZE) )
\r
2425 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2426 ("Received DHCP < min size\n") );
\r
2427 status = IB_INVALID_SETTING;
\r
2430 if ((p_ipoib->type.ip.hdr.ver_hl & 0x0f) != 5 ) {
\r
2431 // If there are IP options in this message, we are in trouble in any case
\r
2432 status = IB_INVALID_SETTING;
\r
2435 /* UDP packet with BOOTP ports in src/dst port numbers. */
\r
2436 cl_perf_start( RecvDhcp );
\r
2437 status = __recv_dhcp( p_port, p_ipoib, p_eth, p_src, p_dst );
\r
2438 cl_perf_stop( &p_port->p_adapter->perf, RecvDhcp );
\r
2442 /* Unfiltered. Setup the ethernet header and report. */
\r
2443 cl_perf_start( RecvUdp );
\r
2444 status = __recv_gen( p_ipoib, p_eth, p_src, p_dst );
\r
2445 cl_perf_stop( &p_port->p_adapter->perf, RecvUdp );
\r
2449 case ETH_PROT_TYPE_ARP:
\r
2450 if( len < (sizeof(ipoib_hdr_t) + sizeof(ipoib_arp_pkt_t)) )
\r
2452 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2453 ("Received ARP < min size\n") );
\r
2454 status = IB_INVALID_SETTING;
\r
2457 cl_perf_start( RecvArp );
\r
2458 status = __recv_arp( p_port, p_wc, p_ipoib, p_eth, &p_src, p_dst );
\r
2459 cl_perf_stop( &p_port->p_adapter->perf, RecvArp );
\r
2460 len = sizeof(ipoib_hdr_t) + sizeof(arp_pkt_t);
\r
2464 /* Unfiltered. Setup the ethernet header and report. */
\r
2465 cl_perf_start( RecvGen );
\r
2466 status = __recv_gen( p_ipoib, p_eth, p_src, p_dst );
\r
2467 cl_perf_stop( &p_port->p_adapter->perf, RecvGen );
\r
2470 if( status != IB_SUCCESS )
\r
2472 /* Update stats. */
\r
2473 ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0, 0 );
\r
2474 cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item );
\r
2475 /* Dereference the port object on behalf of the failed receive. */
\r
2476 ipoib_port_deref( p_port, ref_recv_filter );
\r
2480 ip_stat_sel_t ip_stat;
\r
2482 len + sizeof(eth_hdr_t) - sizeof(ipoib_hdr_t);
\r
2483 if( p_dst->h_mcast)
\r
2485 if( p_dst->dgid.multicast.raw_group_id[10] == 0xFF &&
\r
2486 p_dst->dgid.multicast.raw_group_id[11] == 0xFF &&
\r
2487 p_dst->dgid.multicast.raw_group_id[12] == 0xFF &&
\r
2488 p_dst->dgid.multicast.raw_group_id[13] == 0xFF )
\r
2490 p_desc->type = PKT_TYPE_BCAST;
\r
2491 ip_stat = IP_STAT_BCAST_BYTES;
\r
2495 p_desc->type = PKT_TYPE_MCAST;
\r
2496 ip_stat = IP_STAT_MCAST_BYTES;
\r
2501 p_desc->type = PKT_TYPE_UCAST;
\r
2502 ip_stat = IP_STAT_UCAST_BYTES;
\r
2505 cl_qlist_insert_tail( p_done_list, &p_desc->item.list_item );
\r
2506 ipoib_inc_recv_stat( p_port->p_adapter, ip_stat, len, 1 );
\r
2510 IPOIB_EXIT( IPOIB_DBG_RECV );
\r
2515 static ib_api_status_t
\r
2517 IN const ipoib_pkt_t* const p_ipoib,
\r
2518 OUT eth_pkt_t* const p_eth,
\r
2519 IN ipoib_endpt_t* const p_src,
\r
2520 IN ipoib_endpt_t* const p_dst )
\r
2522 IPOIB_ENTER( IPOIB_DBG_RECV );
\r
2524 if( !p_src || !p_dst )
\r
2526 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2527 ("Received packet with no matching endpoints.\n") );
\r
2528 return IB_NOT_DONE;
\r
2532 * Fill in the ethernet header. Note that doing so will overwrite
\r
2533 * the IPoIB header, so start by moving the information from the IPoIB
\r
2536 p_eth->hdr.type = p_ipoib->hdr.type;
\r
2537 p_eth->hdr.src = p_src->mac;
\r
2538 p_eth->hdr.dst = p_dst->mac;
\r
2540 if ( p_eth->hdr.dst.addr[0] == 1 &&
\r
2541 p_eth->hdr.type == ETH_PROT_TYPE_IP &&
\r
2542 p_eth->hdr.dst.addr[2] == 0x5E)
\r
2544 p_eth->hdr.dst.addr[1] = 0;
\r
2545 p_eth->hdr.dst.addr[3] = p_eth->hdr.dst.addr[3] & 0x7f;
\r
2547 if (p_dst->h_mcast)
\r
2548 p_dst->is_in_use = TRUE;
\r
2550 IPOIB_EXIT( IPOIB_DBG_RECV );
\r
2551 return IB_SUCCESS;
\r
2555 static ib_api_status_t
\r
2557 IN ipoib_port_t* const p_port,
\r
2558 IN const ipoib_pkt_t* const p_ipoib,
\r
2559 OUT eth_pkt_t* const p_eth,
\r
2560 IN ipoib_endpt_t* const p_src,
\r
2561 IN ipoib_endpt_t* const p_dst )
\r
2563 ib_api_status_t status;
\r
2564 dhcp_pkt_t *p_dhcp;
\r
2565 uint8_t *p_option;
\r
2566 uint8_t *p_cid = NULL;
\r
2569 IPOIB_ENTER( IPOIB_DBG_RECV );
\r
2571 UNUSED_PARAM( p_port );
\r
2573 /* Create the ethernet header. */
\r
2574 status = __recv_gen( p_ipoib, p_eth, p_src, p_dst );
\r
2575 if( status != IB_SUCCESS )
\r
2577 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2578 ("__recv_gen returned %s.\n",
\r
2579 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
2583 /* Fixup the payload. */
\r
2584 p_dhcp = &p_eth->type.ip.prot.udp.dhcp;
\r
2585 if( p_dhcp->op != DHCP_REQUEST && p_dhcp->op != DHCP_REPLY )
\r
2587 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2588 ("Invalid DHCP op code.\n") );
\r
2589 return IB_INVALID_SETTING;
\r
2593 * Find the client identifier option, making sure to skip
\r
2594 * the "magic cookie".
\r
2596 p_option = &p_dhcp->options[0];
\r
2597 if ( *(uint32_t *)p_option != DHCP_COOKIE )
\r
2599 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2600 ("DHCP cookie corrupted.\n") );
\r
2601 return IB_INVALID_PARAMETER;
\r
2604 p_option = &p_dhcp->options[DHCP_COOKIE_SIZE];
\r
2605 while( *p_option != DHCP_OPT_END && p_option < &p_dhcp->options[312] )
\r
2607 switch( *p_option )
\r
2609 case DHCP_OPT_PAD:
\r
2613 case DHCP_OPT_MSG:
\r
2614 msg = p_option[2];
\r
2618 case DHCP_OPT_CLIENT_ID:
\r
2620 /* Fall through. */
\r
2624 * All other options have a length byte following the option code.
\r
2625 * Offset by the length to get to the next option.
\r
2627 p_option += (p_option[1] + 2);
\r
2633 /* message from client */
\r
2634 case DHCPDISCOVER:
\r
2641 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2642 ("Failed to find required Client-identifier option.\n") );
\r
2643 return IB_INVALID_SETTING;
\r
2645 if( p_dhcp->htype != DHCP_HW_TYPE_IB )
\r
2647 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2648 ("Invalid hardware address type.\n") );
\r
2649 return IB_INVALID_SETTING;
\r
2652 /* message from DHCP server */
\r
2659 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2660 ("Invalide message type.\n") );
\r
2661 return IB_INVALID_PARAMETER;
\r
2663 p_eth->type.ip.prot.udp.hdr.chksum = 0;
\r
2664 p_dhcp->htype = DHCP_HW_TYPE_ETH;
\r
2665 p_dhcp->hlen = HW_ADDR_LEN;
\r
2667 if( p_cid ) /* from client */
\r
2669 /* Validate that the length and type of the option is as required. */
\r
2670 if( p_cid[1] != 21 )
\r
2672 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2673 ("Client-identifier length not 21 as required.\n") );
\r
2674 return IB_INVALID_SETTING;
\r
2676 if( p_cid[2] != DHCP_HW_TYPE_IB )
\r
2678 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2679 ("Client-identifier type is wrong.\n") );
\r
2680 return IB_INVALID_SETTING;
\r
2683 * Copy the GID value from the option so that we can make aligned
\r
2684 * accesses to the contents.
\r
2685 * Recover CID to standard type.
\r
2687 p_cid[1] = sizeof (ib_net64_t) + 1;// CID length
\r
2688 p_cid[2] = DHCP_HW_TYPE_ETH;// CID type
\r
2689 RtlMoveMemory( &p_cid[3], &p_cid[15], sizeof (ib_net64_t) );
\r
2690 RtlFillMemory(&p_cid[11], 12, 0);
\r
2692 RtlCopyMemory( p_dhcp->chaddr, &p_src->mac, sizeof(p_src->mac) );
\r
2693 RtlFillMemory( &p_dhcp->chaddr[sizeof(p_src->mac)],
\r
2694 ( sizeof(p_dhcp->chaddr) - sizeof(p_src->mac) ), 0 );
\r
2696 IPOIB_EXIT( IPOIB_DBG_RECV );
\r
2701 static ib_api_status_t
\r
2703 IN ipoib_port_t* const p_port,
\r
2704 IN ib_wc_t* const p_wc,
\r
2705 IN const ipoib_pkt_t* const p_ipoib,
\r
2706 OUT eth_pkt_t* const p_eth,
\r
2707 IN ipoib_endpt_t** const pp_src,
\r
2708 IN ipoib_endpt_t* const p_dst )
\r
2710 ib_api_status_t status;
\r
2712 const ipoib_arp_pkt_t *p_ib_arp;
\r
2715 ipoib_hw_addr_t null_hw = {0};
\r
2716 uint8_t cm_capable = 0;
\r
2718 IPOIB_ENTER( IPOIB_DBG_RECV );
\r
2722 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2723 ("Unknown destination endpoint\n") );
\r
2724 return IB_INVALID_SETTING;
\r
2727 p_ib_arp = &p_ipoib->type.arp;
\r
2728 p_arp = &p_eth->type.arp;
\r
2730 if( p_ib_arp->hw_type != ARP_HW_TYPE_IB )
\r
2732 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2733 ("ARP hardware type is not IB\n") );
\r
2734 return IB_INVALID_SETTING;
\r
2737 if( p_ib_arp->hw_size != sizeof(ipoib_hw_addr_t) )
\r
2739 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2740 ("ARP hardware address size is not sizeof(ipoib_hw_addr_t)\n") );
\r
2741 return IB_INVALID_SETTING;
\r
2744 if( p_ib_arp->prot_type != ETH_PROT_TYPE_IP )
\r
2746 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2747 ("ARP protocal type not IP\n") );
\r
2748 return IB_INVALID_SETTING;
\r
2751 cm_capable = ipoib_addr_get_flags( &p_ib_arp->src_hw );
\r
2754 * If we don't have a source, lookup the endpoint specified in the payload.
\r
2757 *pp_src = __endpt_mgr_get_by_gid( p_port, &p_ib_arp->src_hw.gid );
\r
2760 * If the endpoint exists for the GID, make sure
\r
2761 * the dlid and qpn match the arp.
\r
2765 if( cl_memcmp( &(*pp_src)->dgid, &p_ib_arp->src_hw.gid,
\r
2766 sizeof(ib_gid_t) ) )
\r
2769 * GIDs for the endpoint are different. The ARP must
\r
2770 * have been proxied. Dereference it.
\r
2774 else if( (*pp_src)->dlid &&
\r
2775 (*pp_src)->dlid != p_wc->recv.ud.remote_lid )
\r
2777 /* Out of date! Destroy the endpoint and replace it. */
\r
2778 __endpt_mgr_remove( p_port, *pp_src );
\r
2781 else if ( ! ((*pp_src)->dlid)) {
\r
2782 /* Out of date! Destroy the endpoint and replace it. */
\r
2783 __endpt_mgr_remove( p_port, *pp_src );
\r
2786 else if( ipoib_is_voltaire_router_gid( &(*pp_src)->dgid ) )
\r
2788 if( (*pp_src)->qpn != ipoib_addr_get_qpn( &p_ib_arp->src_hw ) &&
\r
2789 p_wc->recv.ud.remote_qp != ipoib_addr_get_qpn( &p_ib_arp->src_hw ) )
\r
2791 /* Out of date! Destroy the endpoint and replace it. */
\r
2792 __endpt_mgr_remove( p_port, *pp_src );
\r
2796 else if( (*pp_src)->qpn != p_wc->recv.ud.remote_qp )
\r
2798 /* Out of date! Destroy the endpoint and replace it. */
\r
2799 __endpt_mgr_remove( p_port, *pp_src );
\r
2804 /* Do we need to create an endpoint for this GID? */
\r
2807 /* Copy the src GID to allow aligned access */
\r
2808 cl_memcpy( &gid, &p_ib_arp->src_hw.gid, sizeof(ib_gid_t) );
\r
2809 status = ipoib_mac_from_guid( gid.unicast.interface_id, p_port->p_adapter->params.guid_mask, &mac );
\r
2810 if (status == IB_INVALID_GUID_MASK)
\r
2812 IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_ERROR,
\r
2813 ("Invalid GUID mask received, rejecting it") );
\r
2814 ipoib_create_log(p_port->p_adapter->h_adapter, GUID_MASK_LOG_INDEX, EVENT_IPOIB_WRONG_PARAMETER_WRN);
\r
2816 else if( status != IB_SUCCESS )
\r
2818 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2819 ("ipoib_mac_from_guid returned %s\n",
\r
2820 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
2824 * Create the endpoint.
\r
2826 *pp_src = ipoib_endpt_create( &p_ib_arp->src_hw.gid,
\r
2827 p_wc->recv.ud.remote_lid, ipoib_addr_get_qpn( &p_ib_arp->src_hw ) );
\r
2831 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2832 ("ipoib_endpt_create failed\n") );
\r
2836 cl_obj_lock( &p_port->obj );
\r
2837 status = __endpt_mgr_insert( p_port, mac, *pp_src );
\r
2838 if( status != IB_SUCCESS )
\r
2840 cl_obj_unlock( &p_port->obj );
\r
2841 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2842 ("__endpt_mgr_insert return %s \n",
\r
2843 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
2847 cl_obj_unlock( &p_port->obj );
\r
2850 (*pp_src)->cm_flag = cm_capable;
\r
2852 CL_ASSERT( !cl_memcmp(
\r
2853 &(*pp_src)->dgid, &p_ib_arp->src_hw.gid, sizeof(ib_gid_t) ) );
\r
2854 CL_ASSERT( ipoib_is_voltaire_router_gid( &(*pp_src)->dgid ) ||
\r
2855 (*pp_src)->qpn == ipoib_addr_get_qpn( &p_ib_arp->src_hw ) );
\r
2857 if( p_port->p_adapter->params.cm_enabled &&
\r
2858 p_ib_arp->op == ARP_OP_REQ &&
\r
2859 cm_capable == IPOIB_CM_FLAG_RC )
\r
2861 /* if we've got ARP request and RC flag is set,
\r
2862 save SID for connect REQ to be sent in ARP reply
\r
2863 when requestor's path get resolved */
\r
2864 if( endpt_cm_get_state( (*pp_src) ) == IPOIB_CM_DISCONNECTED )
\r
2866 (*pp_src)->cm_flag = cm_capable;
\r
2867 ipoib_addr_set_sid(
\r
2868 &(*pp_src)->conn.service_id,
\r
2869 ipoib_addr_get_qpn( &p_ib_arp->src_hw ) );
\r
2874 if( p_port->p_adapter->params.cm_enabled )
\r
2876 IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,
\r
2877 (" ARP %s from ENDPT[%p] state %d CM cap: %d QPN: %#x MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
\r
2878 ((p_ib_arp->op == ARP_OP_REQ )? "REQUEST" : "REPLY"),
\r
2879 *pp_src, endpt_cm_get_state( *pp_src ),
\r
2880 ((cm_capable == IPOIB_CM_FLAG_RC)? 1: 0),
\r
2881 cl_ntoh32( ipoib_addr_get_qpn( &p_ib_arp->src_hw ) ),
\r
2882 (*pp_src)->mac.addr[0], (*pp_src)->mac.addr[1],
\r
2883 (*pp_src)->mac.addr[2], (*pp_src)->mac.addr[3],
\r
2884 (*pp_src)->mac.addr[4], (*pp_src)->mac.addr[5] ));
\r
2888 /* Now swizzle the data. */
\r
2889 p_arp->hw_type = ARP_HW_TYPE_ETH;
\r
2890 p_arp->hw_size = sizeof(mac_addr_t);
\r
2891 p_arp->src_hw = (*pp_src)->mac;
\r
2892 p_arp->src_ip = p_ib_arp->src_ip;
\r
2894 if( cl_memcmp( &p_ib_arp->dst_hw, &null_hw, sizeof(ipoib_hw_addr_t) ) )
\r
2896 if( cl_memcmp( &p_dst->dgid, &p_ib_arp->dst_hw.gid, sizeof(ib_gid_t) ) )
\r
2899 * We received bcast ARP packet that means
\r
2900 * remote port lets everyone know it was changed IP/MAC
\r
2901 * or just activated
\r
2904 /* Guy: TODO: Check why this check fails in case of Voltaire IPR */
\r
2906 if ( !ipoib_is_voltaire_router_gid( &(*pp_src)->dgid ) &&
\r
2907 !ib_gid_is_multicast( (const ib_gid_t*)&p_dst->dgid ) )
\r
2909 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2910 ("ARP: is not ARP MCAST\n") );
\r
2911 return IB_INVALID_SETTING;
\r
2914 p_arp->dst_hw = p_port->p_local_endpt->mac;
\r
2915 p_dst->mac = p_port->p_local_endpt->mac;
\r
2917 * we don't care what receiver ip addr is,
\r