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
36 #include "ipoib_port.h"
\r
37 #include "ipoib_adapter.h"
\r
38 #include "ipoib_debug.h"
\r
39 #if defined(EVENT_TRACING)
\r
43 #include "ipoib_port.tmh"
\r
45 #include <offload.h>
\r
48 /* Amount of physical memory to register. */
\r
49 #define MEM_REG_SIZE 0xFFFFFFFFFFFFFFFF
\r
51 /* Number of work completions to chain for send and receive polling. */
\r
52 #define MAX_SEND_WC 8
\r
53 #define MAX_RECV_WC 16
\r
56 ib_gid_t bcast_mgid_template = {
\r
57 0xff, /* multicast field */
\r
58 0x12, /* scope (to be filled in) */
\r
59 0x40, 0x1b, /* IPv4 signature */
\r
60 0xff, 0xff, /* 16 bits of P_Key (to be filled in) */
\r
61 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 48 bits of zeros */
\r
62 0xff, 0xff, 0xff, 0xff, /* 32 bit IPv4 broadcast address */
\r
67 /* Handy pointer for debug use. */
\r
68 ipoib_port_t *gp_ipoib_port;
\r
71 static void __port_mcast_garbage_dpc(KDPC *p_gc_dpc,void *context,void *s_arg1, void *s_arg2);
\r
72 static void __port_do_mcast_garbage(ipoib_port_t* const p_port );
\r
75 static void __recv_cb_dpc(KDPC *p_gc_dpc,void *context,void *s_arg1, void *s_arg2);
\r
78 /******************************************************************************
\r
82 ******************************************************************************/
\r
85 IN ipoib_port_t* const p_port );
\r
87 static ib_api_status_t
\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
95 IN cl_obj_t* const p_obj );
\r
99 IN cl_obj_t* const p_obj );
\r
103 IN cl_obj_t* const p_obj );
\r
106 /******************************************************************************
\r
108 * IB resource manager operations
\r
110 ******************************************************************************/
\r
112 __ib_mgr_construct(
\r
113 IN ipoib_port_t* const p_port );
\r
115 static ib_api_status_t
\r
117 IN ipoib_port_t* const p_port );
\r
121 IN ipoib_port_t* const p_port );
\r
125 IN ib_async_event_rec_t *p_event_rec );
\r
129 IN ib_async_event_rec_t *p_event_rec );
\r
131 static ib_api_status_t
\r
133 IN ipoib_port_t* const p_port );
\r
135 /******************************************************************************
\r
137 * Buffer manager operations.
\r
139 ******************************************************************************/
\r
141 __buf_mgr_construct(
\r
142 IN ipoib_port_t* const p_port );
\r
144 static ib_api_status_t
\r
146 IN ipoib_port_t* const p_port );
\r
150 IN ipoib_port_t* const p_port );
\r
154 IN void* const p_object,
\r
156 OUT cl_pool_item_t** const pp_pool_item );
\r
158 #if !IPOIB_INLINE_RECV
\r
161 IN const cl_pool_item_t* const p_pool_item,
\r
162 IN void *context );
\r
163 #endif /* IPOIB_INLINE_RECV */
\r
165 static inline ipoib_send_desc_t*
\r
166 __buf_mgr_get_send(
\r
167 IN ipoib_port_t* const p_port );
\r
170 __buf_mgr_put_send(
\r
171 IN ipoib_port_t* const p_port,
\r
172 IN ipoib_send_desc_t* const p_desc );
\r
174 static inline ipoib_recv_desc_t*
\r
175 __buf_mgr_get_recv(
\r
176 IN ipoib_port_t* const p_port );
\r
179 __buf_mgr_put_recv(
\r
180 IN ipoib_port_t* const p_port,
\r
181 IN ipoib_recv_desc_t* const p_desc,
\r
182 IN NDIS_PACKET* const p_packet OPTIONAL );
\r
185 __buf_mgr_put_recv_list(
\r
186 IN ipoib_port_t* const p_port,
\r
187 IN cl_qlist_t* const p_list );
\r
189 static inline NDIS_PACKET*
\r
190 __buf_mgr_get_ndis_pkt(
\r
191 IN ipoib_port_t* const p_port,
\r
192 IN ipoib_recv_desc_t* const p_desc );
\r
195 /******************************************************************************
\r
197 * Receive manager operations.
\r
199 ******************************************************************************/
\r
201 __recv_mgr_construct(
\r
202 IN ipoib_port_t* const p_port );
\r
204 static ib_api_status_t
\r
206 IN ipoib_port_t* const p_port );
\r
209 __recv_mgr_destroy(
\r
210 IN ipoib_port_t* const p_port );
\r
212 /* Posts receive buffers to the receive queue. */
\r
213 static ib_api_status_t
\r
215 IN ipoib_port_t* const p_port );
\r
219 IN const ib_cq_handle_t h_cq,
\r
220 IN void *cq_context );
\r
224 IN ipoib_port_t* const p_port,
\r
225 IN ipoib_recv_desc_t* const p_desc,
\r
226 IN ib_wc_t* const p_wc,
\r
227 OUT ipoib_endpt_t** const pp_src,
\r
228 OUT ipoib_endpt_t** const pp_dst );
\r
232 IN ipoib_port_t* const p_port,
\r
233 IN ib_wc_t* const p_done_wc_list,
\r
234 OUT cl_qlist_t* const p_done_list,
\r
235 OUT cl_qlist_t* const p_bad_list );
\r
237 static ib_api_status_t
\r
239 IN const ipoib_pkt_t* const p_ipoib,
\r
240 OUT eth_pkt_t* const p_eth,
\r
241 IN ipoib_endpt_t* const p_src,
\r
242 IN ipoib_endpt_t* const p_dst );
\r
244 static ib_api_status_t
\r
246 IN ipoib_port_t* const p_port,
\r
247 IN const ipoib_pkt_t* const p_ipoib,
\r
248 OUT eth_pkt_t* const p_eth,
\r
249 IN ipoib_endpt_t* const p_src,
\r
250 IN ipoib_endpt_t* const p_dst );
\r
252 static ib_api_status_t
\r
254 IN ipoib_port_t* const p_port,
\r
255 IN ib_wc_t* const p_wc,
\r
256 IN const ipoib_pkt_t* const p_ipoib,
\r
257 OUT eth_pkt_t* const p_eth,
\r
258 IN ipoib_endpt_t** const p_src,
\r
259 IN ipoib_endpt_t* const p_dst );
\r
261 static ib_api_status_t
\r
262 __recv_mgr_prepare_pkt(
\r
263 IN ipoib_port_t* const p_port,
\r
264 IN ipoib_recv_desc_t* const p_desc,
\r
265 OUT NDIS_PACKET** const pp_packet );
\r
268 __recv_mgr_build_pkt_array(
\r
269 IN ipoib_port_t* const p_port,
\r
270 IN int32_t shortage,
\r
271 OUT cl_qlist_t* const p_done_list,
\r
272 OUT int32_t* const p_discarded );
\r
274 /******************************************************************************
\r
276 * Send manager operations.
\r
278 ******************************************************************************/
\r
280 __send_mgr_construct(
\r
281 IN ipoib_port_t* const p_port );
\r
284 __send_mgr_destroy(
\r
285 IN ipoib_port_t* const p_port );
\r
289 IN ipoib_port_t* const p_port,
\r
290 IN ipoib_send_desc_t* const p_desc,
\r
291 IN INT lso_data_index);
\r
294 __send_mgr_filter_ip(
\r
295 IN ipoib_port_t* const p_port,
\r
296 IN const eth_hdr_t* const p_eth_hdr,
\r
297 IN NDIS_BUFFER* p_buf,
\r
299 IN OUT ipoib_send_desc_t* const p_desc );
\r
302 __send_mgr_filter_igmp_v2(
\r
303 IN ipoib_port_t* const p_port,
\r
304 IN const ip_hdr_t* const p_ip_hdr,
\r
305 IN size_t iph_options_size,
\r
306 IN NDIS_BUFFER* p_buf,
\r
307 IN size_t buf_len );
\r
310 __send_mgr_filter_udp(
\r
311 IN ipoib_port_t* const p_port,
\r
312 IN const ip_hdr_t* const p_ip_hdr,
\r
313 IN NDIS_BUFFER* p_buf,
\r
315 IN OUT ipoib_send_desc_t* const p_desc );
\r
318 __send_mgr_filter_dhcp(
\r
319 IN ipoib_port_t* const p_port,
\r
320 IN const udp_hdr_t* const p_udp_hdr,
\r
321 IN NDIS_BUFFER* p_buf,
\r
323 IN OUT ipoib_send_desc_t* const p_desc );
\r
326 __send_mgr_filter_arp(
\r
327 IN ipoib_port_t* const p_port,
\r
328 IN const eth_hdr_t* const p_eth_hdr,
\r
329 IN NDIS_BUFFER* p_buf,
\r
331 IN OUT ipoib_send_desc_t* const p_desc );
\r
334 __process_failed_send(
\r
335 IN ipoib_port_t* const p_port,
\r
336 IN ipoib_send_desc_t* const p_desc,
\r
337 IN const NDIS_STATUS status );
\r
341 IN const ib_cq_handle_t h_cq,
\r
342 IN void *cq_context );
\r
344 static NDIS_STATUS GetLsoHeaderSize(
\r
345 IN ipoib_port_t* const pPort,
\r
346 IN PNDIS_BUFFER CurrBuffer,
\r
347 IN LsoData *pLsoData,
\r
348 OUT uint16_t *pSize,
\r
349 OUT INT *IndexOfData,
\r
350 IN ipoib_hdr_t *ipoib_hdr
\r
353 /******************************************************************************
\r
355 * Endpoint manager operations
\r
357 ******************************************************************************/
\r
359 __endpt_mgr_construct(
\r
360 IN ipoib_port_t* const p_port );
\r
362 static ib_api_status_t
\r
364 IN ipoib_port_t* const p_port );
\r
367 __endpt_mgr_destroy(
\r
368 IN ipoib_port_t* const p_port );
\r
370 /****f* IPoIB/__endpt_mgr_remove_all
\r
372 * __endpt_mgr_remove_all
\r
375 * Removes all enpoints from the port, dereferencing them to initiate
\r
381 __endpt_mgr_remove_all(
\r
382 IN ipoib_port_t* const p_port );
\r
387 __endpt_mgr_remove(
\r
388 IN ipoib_port_t* const p_port,
\r
389 IN ipoib_endpt_t* const p_endpt );
\r
392 __endpt_mgr_reset_all(
\r
393 IN ipoib_port_t* const p_port );
\r
395 static inline NDIS_STATUS
\r
397 IN ipoib_port_t* const p_port,
\r
398 IN const mac_addr_t mac,
\r
399 OUT ipoib_endpt_t** const pp_endpt );
\r
401 static inline NDIS_STATUS
\r
402 __endpt_mgr_get_gid_qpn(
\r
403 IN ipoib_port_t* const p_port,
\r
404 IN const mac_addr_t mac,
\r
405 OUT ib_gid_t* const p_gid,
\r
406 OUT UNALIGNED net32_t* const p_qpn );
\r
408 static inline ipoib_endpt_t*
\r
409 __endpt_mgr_get_by_gid(
\r
410 IN ipoib_port_t* const p_port,
\r
411 IN const ib_gid_t* const p_gid );
\r
413 static inline ipoib_endpt_t*
\r
414 __endpt_mgr_get_by_lid(
\r
415 IN ipoib_port_t* const p_port,
\r
416 IN const net16_t lid );
\r
418 static inline ib_api_status_t
\r
419 __endpt_mgr_insert_locked(
\r
420 IN ipoib_port_t* const p_port,
\r
421 IN const mac_addr_t mac,
\r
422 IN ipoib_endpt_t* const p_endpt );
\r
424 static inline ib_api_status_t
\r
425 __endpt_mgr_insert(
\r
426 IN ipoib_port_t* const p_port,
\r
427 IN const mac_addr_t mac,
\r
428 IN ipoib_endpt_t* const p_endpt );
\r
430 static ib_api_status_t
\r
431 __endpt_mgr_add_local(
\r
432 IN ipoib_port_t* const p_port,
\r
433 IN ib_port_info_t* const p_port_info );
\r
435 static ib_api_status_t
\r
436 __endpt_mgr_add_bcast(
\r
437 IN ipoib_port_t* const p_port,
\r
438 IN ib_mcast_rec_t *p_mcast_rec );
\r
440 /******************************************************************************
\r
442 * MCast operations.
\r
444 ******************************************************************************/
\r
445 static ib_api_status_t
\r
447 IN ipoib_port_t* const p_port );
\r
449 static ib_api_status_t
\r
451 IN ipoib_port_t* const p_port,
\r
452 IN ib_member_rec_t* const p_member_rec );
\r
454 static ib_api_status_t
\r
455 __port_create_bcast(
\r
456 IN ipoib_port_t* const p_port );
\r
462 IN ib_query_rec_t *p_query_rec );
\r
467 IN ib_mcast_rec_t *p_mcast_rec );
\r
472 IN ib_mcast_rec_t *p_mcast_rec );
\r
475 __leave_error_mcast_cb(
\r
476 IN void *context );
\r
481 IN const void* const p_key1,
\r
482 IN const void* const p_key2 )
\r
484 return cl_memcmp( p_key1, p_key2, sizeof(ib_gid_t) );
\r
488 inline void ipoib_port_ref( ipoib_port_t * p_port, int type )
\r
490 cl_obj_ref( &p_port->obj );
\r
492 cl_atomic_inc( &p_port->ref[type % ref_mask] );
\r
493 IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ,
\r
494 ("ref type %d ref_cnt %d\n", type, p_port->obj.ref_cnt) );
\r
496 UNREFERENCED_PARAMETER(type);
\r
501 inline void ipoib_port_deref(ipoib_port_t * p_port, int type)
\r
504 cl_atomic_dec( &p_port->ref[type % ref_mask] );
\r
505 IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ,
\r
506 ("deref type %d ref_cnt %d\n", type, p_port->obj.ref_cnt) );
\r
508 UNREFERENCED_PARAMETER(type);
\r
510 cl_obj_deref( &p_port->obj );
\r
514 /* function returns pointer to payload that is going after IP header.
\r
515 * asssuming that payload and IP header are in the same buffer
\r
517 static void* GetIpPayloadPtr(const ip_hdr_t* const p_ip_hdr)
\r
519 return (void*)((uint8_t*)p_ip_hdr + 4*(p_ip_hdr->ver_hl & 0xf));
\r
522 /******************************************************************************
\r
526 ******************************************************************************/
\r
529 IN ipoib_adapter_t* const p_adapter,
\r
530 IN ib_pnp_port_rec_t* const p_pnp_rec,
\r
531 OUT ipoib_port_t** const pp_port )
\r
533 ib_api_status_t status;
\r
534 ipoib_port_t *p_port;
\r
536 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
538 CL_ASSERT( !p_adapter->p_port );
\r
540 p_port = cl_zalloc( sizeof(ipoib_port_t) +
\r
541 (sizeof(ipoib_hdr_t) * (p_adapter->params.sq_depth - 1)) );
\r
544 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
545 ("Failed to allocate ipoib_port_t (%d bytes)\n",
\r
546 sizeof(ipoib_port_t)) );
\r
547 return IB_INSUFFICIENT_MEMORY;
\r
551 gp_ipoib_port = p_port;
\r
554 __port_construct( p_port );
\r
556 status = __port_init( p_port, p_adapter, p_pnp_rec );
\r
557 if( status != IB_SUCCESS )
\r
559 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
560 ("ipoib_port_init returned %s.\n",
\r
561 p_adapter->p_ifc->get_err_str( status )) );
\r
562 __port_cleanup( &p_port->obj );
\r
563 __port_free( &p_port->obj );
\r
568 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
574 ipoib_port_destroy(
\r
575 IN ipoib_port_t* const p_port )
\r
577 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
579 CL_ASSERT( p_port );
\r
580 CL_ASSERT( p_port->p_adapter );
\r
581 CL_ASSERT( !p_port->p_adapter->p_port );
\r
583 cl_obj_destroy( &p_port->obj );
\r
585 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
591 IN ipoib_port_t* const p_port )
\r
593 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
595 p_port->state = IB_QPS_RESET;
\r
597 cl_obj_construct( &p_port->obj, IPOIB_OBJ_PORT );
\r
598 cl_spinlock_construct( &p_port->send_lock );
\r
599 cl_spinlock_construct( &p_port->recv_lock );
\r
600 __ib_mgr_construct( p_port );
\r
601 __buf_mgr_construct( p_port );
\r
603 __recv_mgr_construct( p_port );
\r
604 __send_mgr_construct( p_port );
\r
606 __endpt_mgr_construct( p_port );
\r
608 KeInitializeEvent( &p_port->sa_event, NotificationEvent, TRUE );
\r
609 KeInitializeEvent( &p_port->leave_mcast_event, NotificationEvent, TRUE );
\r
611 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
615 static ib_api_status_t
\r
617 IN ipoib_port_t* const p_port,
\r
618 IN ipoib_adapter_t* const p_adapter,
\r
619 IN ib_pnp_port_rec_t* const p_pnp_rec )
\r
621 cl_status_t cl_status;
\r
622 ib_api_status_t status;
\r
624 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
626 p_port->port_num = p_pnp_rec->p_port_attr->port_num;
\r
627 p_port->p_adapter = p_adapter;
\r
629 cl_status = cl_spinlock_init( &p_port->send_lock );
\r
630 if( cl_status != CL_SUCCESS )
\r
632 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
633 ("cl_spinlock_init returned %#x\n", cl_status) );
\r
637 cl_status = cl_spinlock_init( &p_port->recv_lock );
\r
638 if( cl_status != CL_SUCCESS )
\r
640 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
641 ("cl_spinlock_init returned %#x\n", cl_status) );
\r
645 /* Initialize the IB resource manager. */
\r
646 status = __ib_mgr_init( p_port );
\r
647 if( status != IB_SUCCESS )
\r
649 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
650 ("__ib_mgr_init returned %s\n",
\r
651 p_adapter->p_ifc->get_err_str( status )) );
\r
655 /* Initialize the buffer manager. */
\r
656 status = __buf_mgr_init( p_port );
\r
657 if( status != IB_SUCCESS )
\r
659 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
660 ("__buf_mgr_init returned %s\n",
\r
661 p_adapter->p_ifc->get_err_str( status )) );
\r
665 /* Initialize the receive manager. */
\r
666 status = __recv_mgr_init( p_port );
\r
667 if( status != IB_SUCCESS )
\r
669 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
670 ("__recv_mgr_init returned %s\n",
\r
671 p_adapter->p_ifc->get_err_str( status )) );
\r
675 /* Initialize the endpoint manager. */
\r
676 status = __endpt_mgr_init( p_port );
\r
677 if( status != IB_SUCCESS )
\r
679 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
680 ("__endpt_mgr_init returned %s\n",
\r
681 p_adapter->p_ifc->get_err_str( status )) );
\r
685 KeInitializeDpc(&p_port->recv_dpc,(PKDEFERRED_ROUTINE)__recv_cb_dpc,p_port);
\r
688 /* Initialize multicast garbage collector timer and DPC object */
\r
689 KeInitializeDpc(&p_port->gc_dpc,(PKDEFERRED_ROUTINE)__port_mcast_garbage_dpc,p_port);
\r
690 KeInitializeTimerEx(&p_port->gc_timer,SynchronizationTimer);
\r
692 /* We only ever destroy from the PnP callback thread. */
\r
693 cl_status = cl_obj_init( &p_port->obj, CL_DESTROY_SYNC,
\r
694 __port_destroying, __port_cleanup, __port_free );
\r
697 cl_atomic_inc( &p_port->ref[ref_init] );
\r
698 IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_OBJ,
\r
699 ("ref type %d ref_cnt %d\n", ref_init, p_port->obj.ref_cnt) );
\r
702 if( cl_status != CL_SUCCESS )
\r
704 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
705 ("cl_obj_init returned %#x\n", cl_status) );
\r
709 cl_status = cl_obj_insert_rel( &p_port->rel, &p_adapter->obj, &p_port->obj );
\r
710 if( cl_status != CL_SUCCESS )
\r
712 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
713 ("cl_obj_insert_rel returned %#x\n", cl_status) );
\r
714 cl_obj_destroy( &p_port->obj );
\r
719 cl_atomic_inc( &p_port->ref[ref_init] );
\r
720 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_OBJ,
\r
721 ("ref type %d ref_cnt %d\n", ref_init, p_port->obj.ref_cnt) );
\r
724 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
731 IN cl_obj_t* const p_obj )
\r
733 ipoib_port_t *p_port;
\r
735 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
737 CL_ASSERT( p_obj );
\r
739 p_port = PARENT_STRUCT( p_obj, ipoib_port_t, obj );
\r
741 ipoib_port_down( p_port );
\r
743 __endpt_mgr_remove_all( p_port );
\r
745 ipoib_port_resume( p_port );
\r
747 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
753 IN cl_obj_t* const p_obj )
\r
755 ipoib_port_t *p_port;
\r
757 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
759 CL_ASSERT( p_obj );
\r
761 p_port = PARENT_STRUCT( p_obj, ipoib_port_t, obj );
\r
763 /* Wait for all sends and receives to get flushed. */
\r
764 while( p_port->send_mgr.depth || p_port->recv_mgr.depth )
\r
765 cl_thread_suspend( 0 );
\r
767 /* Destroy the send and receive managers before closing the CA. */
\r
768 __ib_mgr_destroy( p_port );
\r
770 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
776 IN cl_obj_t* const p_obj )
\r
778 ipoib_port_t *p_port;
\r
780 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
782 CL_ASSERT( p_obj );
\r
784 p_port = PARENT_STRUCT( p_obj, ipoib_port_t, obj );
\r
786 KeCancelTimer(&p_port->gc_timer);
\r
787 KeFlushQueuedDpcs();
\r
788 __endpt_mgr_destroy( p_port );
\r
789 __recv_mgr_destroy( p_port );
\r
790 __send_mgr_destroy( p_port );
\r
791 __buf_mgr_destroy( p_port );
\r
793 cl_spinlock_destroy( &p_port->send_lock );
\r
794 cl_spinlock_destroy( &p_port->recv_lock );
\r
796 cl_obj_deinit( p_obj );
\r
800 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
805 /******************************************************************************
\r
807 * IB resource manager implementation.
\r
809 ******************************************************************************/
\r
811 __ib_mgr_construct(
\r
812 IN ipoib_port_t* const p_port )
\r
814 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
816 cl_memclr( &p_port->ib_mgr, sizeof(ipoib_ib_mgr_t) );
\r
818 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
822 static ib_api_status_t
\r
824 IN ipoib_port_t* const p_port )
\r
826 ib_api_status_t status;
\r
827 ib_cq_create_t cq_create;
\r
828 ib_qp_create_t qp_create;
\r
829 ib_phys_create_t phys_create;
\r
830 ib_phys_range_t phys_range;
\r
833 ib_qp_attr_t qp_attr;
\r
834 ib_ca_attr_t * p_ca_attr;
\r
835 uint32_t attr_size;
\r
837 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
840 status = p_port->p_adapter->p_ifc->open_ca(
\r
841 p_port->p_adapter->h_al, p_port->p_adapter->guids.ca_guid,
\r
842 NULL, p_port, &p_port->ib_mgr.h_ca );
\r
843 if( status != IB_SUCCESS )
\r
845 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
846 EVENT_IPOIB_OPEN_CA, 1, status );
\r
847 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
848 ("ib_open_ca returned %s\n",
\r
849 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
853 /* Allocate the PD. */
\r
854 status = p_port->p_adapter->p_ifc->alloc_pd(
\r
855 p_port->ib_mgr.h_ca, IB_PDT_UD, p_port, &p_port->ib_mgr.h_pd );
\r
856 if( status != IB_SUCCESS )
\r
858 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
859 EVENT_IPOIB_ALLOC_PD, 1, status );
\r
860 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
861 ("ib_alloc_pd returned %s\n",
\r
862 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
866 /* Allocate receive CQ. */
\r
867 cq_create.size = p_port->p_adapter->params.rq_depth;
\r
868 cq_create.pfn_comp_cb = __recv_cb;
\r
869 cq_create.h_wait_obj = NULL;
\r
871 status = p_port->p_adapter->p_ifc->create_cq(
\r
872 p_port->ib_mgr.h_ca, &cq_create, p_port,
\r
873 __cq_event, &p_port->ib_mgr.h_recv_cq );
\r
874 if( status != IB_SUCCESS )
\r
876 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
877 EVENT_IPOIB_CREATE_RECV_CQ, 1, status );
\r
878 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
879 ("ib_create_cq returned %s.\n",
\r
880 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
884 /* Allocate send CQ. */
\r
885 cq_create.size = p_port->p_adapter->params.sq_depth;
\r
886 cq_create.pfn_comp_cb = __send_cb;
\r
888 status = p_port->p_adapter->p_ifc->create_cq(
\r
889 p_port->ib_mgr.h_ca, &cq_create, p_port,
\r
890 __cq_event, &p_port->ib_mgr.h_send_cq );
\r
891 if( status != IB_SUCCESS )
\r
893 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
894 EVENT_IPOIB_CREATE_SEND_CQ, 1, status );
\r
895 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
896 ("ib_create_cq returned %s.\n",
\r
897 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
901 /* Allocate the QP. */
\r
902 cl_memclr( &qp_create, sizeof(qp_create) );
\r
903 qp_create.qp_type = IB_QPT_UNRELIABLE_DGRM;
\r
904 qp_create.rq_depth = p_port->p_adapter->params.rq_depth;
\r
905 qp_create.rq_sge = 2; /* To support buffers spanning pages. */
\r
906 qp_create.h_rq_cq = p_port->ib_mgr.h_recv_cq;
\r
907 qp_create.sq_depth = p_port->p_adapter->params.sq_depth;
\r
909 //Figure out the right number of SGE entries for sends.
\r
910 /* Get the size of the CA attribute structure. */
\r
911 status = p_port->p_adapter->p_ifc->query_ca( p_port->ib_mgr.h_ca, NULL, &attr_size );
\r
912 if( status != IB_INSUFFICIENT_MEMORY )
\r
914 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
915 ("ib_query_ca failed with status %s.\n", p_port->p_adapter->p_ifc->get_err_str(status)) );
\r
919 /* Allocate enough space to store the attribute structure. */
\r
920 p_ca_attr = cl_malloc( attr_size );
\r
923 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
924 ("cl_malloc failed to allocate p_ca_attr!\n") );
\r
925 return IB_INSUFFICIENT_RESOURCES;
\r
928 /* Query the CA attributes. */
\r
929 status = p_port->p_adapter->p_ifc->query_ca(p_port->ib_mgr.h_ca, p_ca_attr, &attr_size );
\r
930 if( status != IB_SUCCESS )
\r
932 cl_free( p_ca_attr );
\r
934 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
935 ("ib_query_ca failed with status %s.\n", p_port->p_adapter->p_ifc->get_err_str(status)) );
\r
938 #define UD_QP_USED_SGE 3
\r
939 qp_create.sq_sge = MAX_SEND_SGE < p_ca_attr->max_sges ? MAX_SEND_SGE : (p_ca_attr->max_sges - UD_QP_USED_SGE);
\r
940 if (!p_ca_attr->ipoib_csum) {
\r
941 //checksum is not supported by device
\r
942 //user must specify BYPASS to explicitly cancel checksum calculation
\r
943 if (p_port->p_adapter->params.send_chksum_offload == CSUM_ENABLED)
\r
944 p_port->p_adapter->params.send_chksum_offload = CSUM_DISABLED;
\r
945 if (p_port->p_adapter->params.recv_chksum_offload == CSUM_ENABLED)
\r
946 p_port->p_adapter->params.recv_chksum_offload = CSUM_DISABLED;
\r
948 cl_free( p_ca_attr );
\r
950 qp_create.h_sq_cq = p_port->ib_mgr.h_send_cq;
\r
951 qp_create.sq_signaled = TRUE;
\r
952 status = p_port->p_adapter->p_ifc->create_qp(
\r
953 p_port->ib_mgr.h_pd, &qp_create, p_port,
\r
954 __qp_event, &p_port->ib_mgr.h_qp );
\r
955 if( status != IB_SUCCESS )
\r
957 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
958 EVENT_IPOIB_CREATE_QP, 1, status );
\r
959 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
960 ("ib_create_qp returned %s\n",
\r
961 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
964 /* Query the QP so we can get our QPN. */
\r
965 status = p_port->p_adapter->p_ifc->query_qp(
\r
966 p_port->ib_mgr.h_qp, &qp_attr );
\r
967 if( status != IB_SUCCESS )
\r
969 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
970 EVENT_IPOIB_QUERY_QP, 1, status );
\r
971 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
972 ("ib_query_qp returned %s\n",
\r
973 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
976 p_port->ib_mgr.qpn = qp_attr.num;
\r
978 /* Register all of physical memory */
\r
979 phys_create.length = MEM_REG_SIZE;
\r
980 phys_create.num_ranges = 1;
\r
981 phys_create.range_array = &phys_range;
\r
982 phys_create.buf_offset = 0;
\r
983 phys_create.hca_page_size = PAGE_SIZE;
\r
984 phys_create.access_ctrl = IB_AC_LOCAL_WRITE;
\r
985 phys_range.base_addr = 0;
\r
986 phys_range.size = MEM_REG_SIZE;
\r
988 status = p_port->p_adapter->p_ifc->reg_phys(
\r
989 p_port->ib_mgr.h_pd, &phys_create, &vaddr,
\r
990 &p_port->ib_mgr.lkey, &rkey, &p_port->ib_mgr.h_mr );
\r
991 if( status != IB_SUCCESS )
\r
993 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
994 EVENT_IPOIB_REG_PHYS, 1, status );
\r
995 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
996 ("ib_reg_phys returned %s\n",
\r
997 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
1001 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
1002 return IB_SUCCESS;
\r
1008 IN ipoib_port_t* const p_port )
\r
1010 ib_api_status_t status;
\r
1012 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
1014 if( p_port->ib_mgr.h_ca )
\r
1017 p_port->p_adapter->p_ifc->close_ca( p_port->ib_mgr.h_ca, NULL );
\r
1018 CL_ASSERT( status == IB_SUCCESS );
\r
1019 p_port->ib_mgr.h_ca = NULL;
\r
1022 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
1027 /******************************************************************************
\r
1029 * Buffer manager implementation.
\r
1031 ******************************************************************************/
\r
1033 __buf_mgr_construct(
\r
1034 IN ipoib_port_t* const p_port )
\r
1036 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
1038 cl_qpool_construct( &p_port->buf_mgr.recv_pool );
\r
1040 p_port->buf_mgr.h_packet_pool = NULL;
\r
1041 p_port->buf_mgr.h_buffer_pool = NULL;
\r
1043 ExInitializeNPagedLookasideList( &p_port->buf_mgr.send_buf_list,
\r
1044 NULL, NULL, 0, MAX_XFER_BLOCK_SIZE, 'bipi', 0 );
\r
1046 p_port->buf_mgr.h_send_pkt_pool = NULL;
\r
1047 p_port->buf_mgr.h_send_buf_pool = NULL;
\r
1049 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
1053 static ib_api_status_t
\r
1055 IN ipoib_port_t* const p_port )
\r
1057 cl_status_t cl_status;
\r
1058 NDIS_STATUS ndis_status;
\r
1059 ipoib_params_t *p_params;
\r
1061 IPOIB_ENTER(IPOIB_DBG_INIT );
\r
1063 CL_ASSERT( p_port );
\r
1064 CL_ASSERT( p_port->p_adapter );
\r
1066 p_params = &p_port->p_adapter->params;
\r
1068 /* Allocate the receive descriptor pool */
\r
1069 cl_status = cl_qpool_init( &p_port->buf_mgr.recv_pool,
\r
1070 p_params->rq_depth * p_params->recv_pool_ratio,
\r
1071 #if IPOIB_INLINE_RECV
\r
1072 0, 0, sizeof(ipoib_recv_desc_t), __recv_ctor, NULL, p_port );
\r
1073 #else /* IPOIB_INLINE_RECV */
\r
1074 0, 0, sizeof(ipoib_recv_desc_t), __recv_ctor, __recv_dtor, p_port );
\r
1075 #endif /* IPOIB_INLINE_RECV */
\r
1076 if( cl_status != CL_SUCCESS )
\r
1078 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
1079 EVENT_IPOIB_RECV_POOL, 1, cl_status );
\r
1080 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1081 ("cl_qpool_init for recvs returned %#x\n",
\r
1083 return IB_INSUFFICIENT_MEMORY;
\r
1086 /* Allocate the NDIS buffer and packet pools for receive indication. */
\r
1087 NdisAllocatePacketPool( &ndis_status, &p_port->buf_mgr.h_packet_pool,
\r
1088 p_params->rq_depth, PROTOCOL_RESERVED_SIZE_IN_PACKET );
\r
1089 if( ndis_status != NDIS_STATUS_SUCCESS )
\r
1091 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
1092 EVENT_IPOIB_RECV_PKT_POOL, 1, ndis_status );
\r
1093 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1094 ("NdisAllocatePacketPool returned %08X\n", ndis_status) );
\r
1095 return IB_INSUFFICIENT_RESOURCES;
\r
1098 NdisAllocateBufferPool( &ndis_status, &p_port->buf_mgr.h_buffer_pool,
\r
1099 p_params->rq_depth );
\r
1100 if( ndis_status != NDIS_STATUS_SUCCESS )
\r
1102 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
1103 EVENT_IPOIB_RECV_BUF_POOL, 1, ndis_status );
\r
1104 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1105 ("NdisAllocateBufferPool returned %08X\n", ndis_status) );
\r
1106 return IB_INSUFFICIENT_RESOURCES;
\r
1109 /* Allocate the NDIS buffer and packet pools for send formatting. */
\r
1110 NdisAllocatePacketPool( &ndis_status, &p_port->buf_mgr.h_send_pkt_pool,
\r
1111 1, PROTOCOL_RESERVED_SIZE_IN_PACKET );
\r
1112 if( ndis_status != NDIS_STATUS_SUCCESS )
\r
1114 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
1115 EVENT_IPOIB_SEND_PKT_POOL, 1, ndis_status );
\r
1116 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1117 ("NdisAllocatePacketPool returned %08X\n", ndis_status) );
\r
1118 return IB_INSUFFICIENT_RESOURCES;
\r
1121 NdisAllocateBufferPool( &ndis_status,
\r
1122 &p_port->buf_mgr.h_send_buf_pool, 1 );
\r
1123 if( ndis_status != NDIS_STATUS_SUCCESS )
\r
1125 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
1126 EVENT_IPOIB_SEND_BUF_POOL, 1, ndis_status );
\r
1127 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1128 ("NdisAllocateBufferPool returned %08X\n", ndis_status) );
\r
1129 return IB_INSUFFICIENT_RESOURCES;
\r
1132 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
1133 return IB_SUCCESS;
\r
1138 __buf_mgr_destroy(
\r
1139 IN ipoib_port_t* const p_port )
\r
1141 IPOIB_ENTER(IPOIB_DBG_INIT );
\r
1143 CL_ASSERT( p_port );
\r
1145 /* Destroy the send packet and buffer pools. */
\r
1146 if( p_port->buf_mgr.h_send_buf_pool )
\r
1147 NdisFreeBufferPool( p_port->buf_mgr.h_send_buf_pool );
\r
1148 if( p_port->buf_mgr.h_send_pkt_pool )
\r
1149 NdisFreePacketPool( p_port->buf_mgr.h_send_pkt_pool );
\r
1151 /* Destroy the receive packet and buffer pools. */
\r
1152 if( p_port->buf_mgr.h_buffer_pool )
\r
1153 NdisFreeBufferPool( p_port->buf_mgr.h_buffer_pool );
\r
1154 if( p_port->buf_mgr.h_packet_pool )
\r
1155 NdisFreePacketPool( p_port->buf_mgr.h_packet_pool );
\r
1157 /* Free the receive and send descriptors. */
\r
1158 cl_qpool_destroy( &p_port->buf_mgr.recv_pool );
\r
1160 /* Free the lookaside list of scratch buffers. */
\r
1161 ExDeleteNPagedLookasideList( &p_port->buf_mgr.send_buf_list );
\r
1163 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
1167 static cl_status_t
\r
1169 IN void* const p_object,
\r
1171 OUT cl_pool_item_t** const pp_pool_item )
\r
1173 ipoib_recv_desc_t *p_desc;
\r
1174 ipoib_port_t *p_port;
\r
1177 IPOIB_ENTER( IPOIB_DBG_ALLOC );
\r
1179 CL_ASSERT( p_object );
\r
1180 CL_ASSERT( context );
\r
1182 p_desc = (ipoib_recv_desc_t*)p_object;
\r
1183 p_port = (ipoib_port_t*)context;
\r
1185 /* Setup the work request. */
\r
1186 p_desc->wr.ds_array = p_desc->local_ds;
\r
1187 p_desc->wr.wr_id = (uintn_t)p_desc;
\r
1189 #if IPOIB_INLINE_RECV
\r
1190 /* Sanity check on the receive buffer layout */
\r
1191 CL_ASSERT( (void*)&p_desc->buf.eth.pkt.type ==
\r
1192 (void*)&p_desc->buf.ib.pkt.type );
\r
1193 CL_ASSERT( sizeof(recv_buf_t) == sizeof(ipoib_pkt_t) + sizeof(ib_grh_t) );
\r
1195 /* Setup the local data segment. */
\r
1196 p_desc->local_ds[0].vaddr = cl_get_physaddr( &p_desc->buf );
\r
1197 p_desc->local_ds[0].lkey = p_port->ib_mgr.lkey;
\r
1199 PAGE_SIZE - ((uint32_t)p_desc->local_ds[0].vaddr & (PAGE_SIZE - 1));
\r
1200 if( ds0_len >= sizeof(recv_buf_t) )
\r
1202 /* The whole buffer is within a page. */
\r
1203 p_desc->local_ds[0].length = ds0_len;
\r
1204 p_desc->wr.num_ds = 1;
\r
1208 /* The buffer crosses page boundaries. */
\r
1209 p_desc->local_ds[0].length = ds0_len;
\r
1210 p_desc->local_ds[1].vaddr = cl_get_physaddr(
\r
1211 ((uint8_t*)&p_desc->buf) + ds0_len );
\r
1212 p_desc->local_ds[1].lkey = p_port->ib_mgr.lkey;
\r
1213 p_desc->local_ds[1].length = sizeof(recv_buf_t) - ds0_len;
\r
1214 p_desc->wr.num_ds = 2;
\r
1216 #else /* IPOIB_INLINE_RECV */
\r
1217 /* Allocate the receive buffer. */
\r
1218 p_desc->p_buf = (recv_buf_t*)cl_zalloc( sizeof(recv_buf_t) );
\r
1219 if( !p_desc->p_buf )
\r
1221 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1222 ("Failed to allocate receive buffer.\n") );
\r
1223 return CL_INSUFFICIENT_MEMORY;
\r
1226 /* Sanity check on the receive buffer layout */
\r
1227 CL_ASSERT( (void*)&p_desc->p_buf->eth.pkt.type ==
\r
1228 (void*)&p_desc->p_buf->ib.pkt.type );
\r
1230 /* Setup the local data segment. */
\r
1231 p_desc->local_ds[0].vaddr = cl_get_physaddr( p_desc->p_buf );
\r
1232 p_desc->local_ds[0].length = sizeof(ipoib_pkt_t) + sizeof(ib_grh_t);
\r
1233 p_desc->local_ds[0].lkey = p_port->ib_mgr.lkey;
\r
1234 #endif /* IPOIB_INLINE_RECV */
\r
1236 *pp_pool_item = &p_desc->item;
\r
1238 IPOIB_EXIT( IPOIB_DBG_ALLOC );
\r
1239 return CL_SUCCESS;
\r
1243 #if !IPOIB_INLINE_RECV
\r
1246 IN const cl_pool_item_t* const p_pool_item,
\r
1247 IN void *context )
\r
1249 ipoib_recv_desc_t *p_desc;
\r
1251 IPOIB_ENTER( IPOIB_DBG_ALLOC );
\r
1253 UNUSED_PARAM( context );
\r
1255 p_desc = PARENT_STRUCT( p_pool_item, ipoib_recv_desc_t, item );
\r
1257 if( p_desc->p_buf )
\r
1258 cl_free( p_desc->p_buf );
\r
1260 IPOIB_EXIT( IPOIB_DBG_ALLOC );
\r
1265 static inline ipoib_recv_desc_t*
\r
1266 __buf_mgr_get_recv(
\r
1267 IN ipoib_port_t* const p_port )
\r
1269 ipoib_recv_desc_t *p_desc;
\r
1270 IPOIB_ENTER( IPOIB_DBG_RECV );
\r
1271 p_desc = (ipoib_recv_desc_t*)cl_qpool_get( &p_port->buf_mgr.recv_pool );
\r
1272 /* Reference the port object for the send. */
\r
1275 ipoib_port_ref( p_port, ref_get_recv );
\r
1276 CL_ASSERT( p_desc->wr.wr_id == (uintn_t)p_desc );
\r
1277 #if IPOIB_INLINE_RECV
\r
1278 CL_ASSERT( p_desc->local_ds[0].vaddr ==
\r
1279 cl_get_physaddr( &p_desc->buf ) );
\r
1280 #else /* IPOIB_INLINE_RECV */
\r
1281 CL_ASSERT( p_desc->local_ds[0].vaddr ==
\r
1282 cl_get_physaddr( p_desc->p_buf ) );
\r
1283 CL_ASSERT( p_desc->local_ds[0].length ==
\r
1284 (sizeof(ipoib_pkt_t) + sizeof(ib_grh_t)) );
\r
1285 #endif /* IPOIB_INLINE_RECV */
\r
1286 CL_ASSERT( p_desc->local_ds[0].lkey == p_port->ib_mgr.lkey );
\r
1288 IPOIB_EXIT( IPOIB_DBG_RECV );
\r
1293 static inline void
\r
1294 __buf_mgr_put_recv(
\r
1295 IN ipoib_port_t* const p_port,
\r
1296 IN ipoib_recv_desc_t* const p_desc,
\r
1297 IN NDIS_PACKET* const p_packet OPTIONAL )
\r
1299 NDIS_BUFFER *p_buf;
\r
1301 IPOIB_ENTER(IPOIB_DBG_RECV );
\r
1305 /* Unchain the NDIS buffer. */
\r
1306 NdisUnchainBufferAtFront( p_packet, &p_buf );
\r
1307 CL_ASSERT( p_buf );
\r
1308 /* Return the NDIS packet and NDIS buffer to their pools. */
\r
1309 NdisDprFreePacketNonInterlocked( p_packet );
\r
1310 NdisFreeBuffer( p_buf );
\r
1313 /* Return the descriptor to its pools. */
\r
1314 cl_qpool_put( &p_port->buf_mgr.recv_pool, &p_desc->item );
\r
1317 * Dereference the port object since the receive is no longer outstanding.
\r
1319 ipoib_port_deref( p_port, ref_get_recv );
\r
1320 IPOIB_EXIT( IPOIB_DBG_RECV );
\r
1324 static inline void
\r
1325 __buf_mgr_put_recv_list(
\r
1326 IN ipoib_port_t* const p_port,
\r
1327 IN cl_qlist_t* const p_list )
\r
1329 //IPOIB_ENTER( IPOIB_DBG_RECV );
\r
1330 cl_qpool_put_list( &p_port->buf_mgr.recv_pool, p_list );
\r
1331 //IPOIB_EXIT( IPOIB_DBG_RECV );
\r
1335 static inline NDIS_PACKET*
\r
1336 __buf_mgr_get_ndis_pkt(
\r
1337 IN ipoib_port_t* const p_port,
\r
1338 IN ipoib_recv_desc_t* const p_desc )
\r
1340 NDIS_STATUS status;
\r
1341 NDIS_PACKET *p_packet;
\r
1342 NDIS_BUFFER *p_buffer;
\r
1344 IPOIB_ENTER( IPOIB_DBG_RECV );
\r
1346 NdisDprAllocatePacketNonInterlocked( &status, &p_packet,
\r
1347 p_port->buf_mgr.h_packet_pool );
\r
1348 if( status != NDIS_STATUS_SUCCESS )
\r
1350 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1351 ("Failed to allocate NDIS_PACKET: %08x\n", status) );
\r
1355 IPOIB_PORT_FROM_PACKET( p_packet ) = p_port;
\r
1356 IPOIB_RECV_FROM_PACKET( p_packet ) = p_desc;
\r
1358 NdisAllocateBuffer( &status, &p_buffer,
\r
1359 #if IPOIB_INLINE_RECV
\r
1360 p_port->buf_mgr.h_buffer_pool, &p_desc->buf.eth.pkt, p_desc->len );
\r
1361 #else /* IPOIB_INLINE_RECV */
\r
1362 p_port->buf_mgr.h_buffer_pool, &p_desc->p_buf->eth.pkt, p_desc->len );
\r
1363 #endif /* IPOIB_INLINE_RECV */
\r
1364 if( status != NDIS_STATUS_SUCCESS )
\r
1366 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1367 ("Failed to allocate NDIS_BUFFER: %08x\n", status) );
\r
1368 NdisDprFreePacketNonInterlocked( p_packet );
\r
1372 NdisChainBufferAtFront( p_packet, p_buffer );
\r
1373 NDIS_SET_PACKET_HEADER_SIZE( p_packet, sizeof(eth_hdr_t) );
\r
1375 IPOIB_EXIT( IPOIB_DBG_RECV );
\r
1379 /******************************************************************************
\r
1381 * Receive manager implementation.
\r
1383 ******************************************************************************/
\r
1385 __recv_mgr_construct(
\r
1386 IN ipoib_port_t* const p_port )
\r
1388 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
1390 cl_qlist_init( &p_port->recv_mgr.done_list );
\r
1392 p_port->recv_mgr.recv_pkt_array = NULL;
\r
1394 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
1398 static ib_api_status_t
\r
1400 IN ipoib_port_t* const p_port )
\r
1402 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
1404 /* Allocate the NDIS_PACKET pointer array for indicating receives. */
\r
1405 p_port->recv_mgr.recv_pkt_array = cl_malloc(
\r
1406 sizeof(NDIS_PACKET*) * p_port->p_adapter->params.rq_depth );
\r
1407 if( !p_port->recv_mgr.recv_pkt_array )
\r
1409 NdisWriteErrorLogEntry( p_port->p_adapter->h_adapter,
\r
1410 EVENT_IPOIB_RECV_PKT_ARRAY, 0 );
\r
1411 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1412 ("cl_malloc for PNDIS_PACKET array failed.\n") );
\r
1413 return IB_INSUFFICIENT_MEMORY;
\r
1416 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
1417 return IB_SUCCESS;
\r
1422 __recv_mgr_destroy(
\r
1423 IN ipoib_port_t* const p_port )
\r
1425 IPOIB_ENTER( IPOIB_DBG_INIT );
\r
1427 CL_ASSERT( cl_is_qlist_empty( &p_port->recv_mgr.done_list ) );
\r
1428 CL_ASSERT( !p_port->recv_mgr.depth );
\r
1430 if( p_port->recv_mgr.recv_pkt_array )
\r
1431 cl_free( p_port->recv_mgr.recv_pkt_array );
\r
1433 IPOIB_EXIT( IPOIB_DBG_INIT );
\r
1438 * Posts receive buffers to the receive queue and returns the number
\r
1439 * of receives needed to bring the RQ to its low water mark. Note
\r
1440 * that the value is signed, and can go negative. All tests must
\r
1444 __recv_mgr_repost(
\r
1445 IN ipoib_port_t* const p_port )
\r
1447 ipoib_recv_desc_t *p_head = NULL, *p_tail = NULL, *p_next;
\r
1448 ib_api_status_t status;
\r
1449 ib_recv_wr_t *p_failed;
\r
1450 PERF_DECLARE( GetRecv );
\r
1451 PERF_DECLARE( PostRecv );
\r
1453 IPOIB_ENTER( IPOIB_DBG_RECV );
\r
1455 CL_ASSERT( p_port );
\r
1456 cl_obj_lock( &p_port->obj );
\r
1457 if( p_port->state != IB_QPS_RTS )
\r
1459 cl_obj_unlock( &p_port->obj );
\r
1460 IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV,
\r
1461 ("Port in invalid state. Not reposting.\n") );
\r
1464 ipoib_port_ref( p_port, ref_repost );
\r
1465 cl_obj_unlock( &p_port->obj );
\r
1467 while( p_port->recv_mgr.depth < p_port->p_adapter->params.rq_depth )
\r
1469 /* Pull receives out of the pool and chain them up. */
\r
1470 cl_perf_start( GetRecv );
\r
1471 p_next = __buf_mgr_get_recv( p_port );
\r
1472 cl_perf_stop( &p_port->p_adapter->perf, GetRecv );
\r
1475 IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV,
\r
1476 ("Out of receive descriptors! recv queue depath 0x%x\n",p_port->recv_mgr.depth) );
\r
1483 p_next->wr.p_next = NULL;
\r
1487 p_next->wr.p_next = &p_head->wr;
\r
1492 p_port->recv_mgr.depth++;
\r
1497 cl_perf_start( PostRecv );
\r
1498 status = p_port->p_adapter->p_ifc->post_recv(
\r
1499 p_port->ib_mgr.h_qp, &p_head->wr, &p_failed );
\r
1500 cl_perf_stop( &p_port->p_adapter->perf, PostRecv );
\r
1502 if( status != IB_SUCCESS )
\r
1504 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1505 ("ip_post_recv returned %s\n",
\r
1506 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
1507 /* return the descriptors to the pool */
\r
1510 p_head = PARENT_STRUCT( p_failed, ipoib_recv_desc_t, wr );
\r
1511 p_failed = p_failed->p_next;
\r
1513 __buf_mgr_put_recv( p_port, p_head, NULL );
\r
1514 p_port->recv_mgr.depth--;
\r
1519 ipoib_port_deref( p_port, ref_repost );
\r
1520 IPOIB_EXIT( IPOIB_DBG_RECV );
\r
1521 return p_port->p_adapter->params.rq_low_watermark - p_port->recv_mgr.depth;
\r
1526 ipoib_return_packet(
\r
1527 IN NDIS_HANDLE adapter_context,
\r
1528 IN NDIS_PACKET *p_packet )
\r
1530 cl_list_item_t *p_item;
\r
1531 ipoib_port_t *p_port;
\r
1532 ipoib_recv_desc_t *p_desc;
\r
1533 ib_api_status_t status = IB_NOT_DONE;
\r
1535 PERF_DECLARE( ReturnPacket );
\r
1536 PERF_DECLARE( ReturnPutRecv );
\r
1537 PERF_DECLARE( ReturnRepostRecv );
\r
1538 PERF_DECLARE( ReturnPreparePkt );
\r
1539 PERF_DECLARE( ReturnNdisIndicate );
\r
1541 IPOIB_ENTER( IPOIB_DBG_RECV );
\r
1543 UNUSED_PARAM( adapter_context );
\r
1544 CL_ASSERT( p_packet );
\r
1546 cl_perf_start( ReturnPacket );
\r
1548 /* Get the port and descriptor from the packet. */
\r
1549 p_port = IPOIB_PORT_FROM_PACKET( p_packet );
\r
1550 p_desc = IPOIB_RECV_FROM_PACKET( p_packet );
\r
1552 cl_spinlock_acquire( &p_port->recv_lock );
\r
1554 cl_perf_start( ReturnPutRecv );
\r
1555 __buf_mgr_put_recv( p_port, p_desc, p_packet );
\r
1556 cl_perf_stop( &p_port->p_adapter->perf, ReturnPutRecv );
\r
1558 /* Repost buffers. */
\r
1559 cl_perf_start( ReturnRepostRecv );
\r
1560 shortage = __recv_mgr_repost( p_port );
\r
1561 cl_perf_stop( &p_port->p_adapter->perf, ReturnRepostRecv );
\r
1563 for( p_item = cl_qlist_remove_head( &p_port->recv_mgr.done_list );
\r
1564 p_item != cl_qlist_end( &p_port->recv_mgr.done_list );
\r
1565 p_item = cl_qlist_remove_head( &p_port->recv_mgr.done_list ) )
\r
1567 p_desc = (ipoib_recv_desc_t*)p_item;
\r
1569 cl_perf_start( ReturnPreparePkt );
\r
1570 status = __recv_mgr_prepare_pkt( p_port, p_desc, &p_packet );
\r
1571 cl_perf_stop( &p_port->p_adapter->perf, ReturnPreparePkt );
\r
1572 if( status == IB_SUCCESS )
\r
1574 if( shortage > 0 )
\r
1575 NDIS_SET_PACKET_STATUS( p_packet, NDIS_STATUS_RESOURCES );
\r
1577 NDIS_SET_PACKET_STATUS( p_packet, NDIS_STATUS_SUCCESS );
\r
1579 cl_spinlock_release( &p_port->recv_lock );
\r
1580 cl_perf_start( ReturnNdisIndicate );
\r
1581 NdisMIndicateReceivePacket( p_port->p_adapter->h_adapter,
\r
1583 cl_perf_stop( &p_port->p_adapter->perf, ReturnNdisIndicate );
\r
1584 cl_spinlock_acquire( &p_port->recv_lock );
\r
1586 if( shortage > 0 )
\r
1588 cl_perf_start( ReturnPutRecv );
\r
1589 __buf_mgr_put_recv( p_port, p_desc, p_packet );
\r
1590 cl_perf_stop( &p_port->p_adapter->perf, ReturnPutRecv );
\r
1592 /* Repost buffers. */
\r
1593 cl_perf_start( ReturnRepostRecv );
\r
1594 shortage = __recv_mgr_repost( p_port );
\r
1595 cl_perf_stop( &p_port->p_adapter->perf, ReturnRepostRecv );
\r
1598 else if( status != IB_NOT_DONE )
\r
1600 IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV,
\r
1601 ("__recv_mgr_prepare_pkt returned %s\n",
\r
1602 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
1603 /* Return the item to the head of the list. */
\r
1604 cl_qlist_insert_head( &p_port->recv_mgr.done_list, p_item );
\r
1608 cl_spinlock_release( &p_port->recv_lock );
\r
1609 cl_perf_stop( &p_port->p_adapter->perf, ReturnPacket );
\r
1611 IPOIB_EXIT( IPOIB_DBG_RECV );
\r
1614 static void __recv_cb_dpc(KDPC *p_gc_dpc,void *context,void * s_arg1 , void * s_arg2)
\r
1617 ipoib_port_t *p_port = context;
\r
1619 UNREFERENCED_PARAMETER(p_gc_dpc);
\r
1620 UNREFERENCED_PARAMETER(s_arg1);
\r
1621 UNREFERENCED_PARAMETER(s_arg2);
\r
1624 __recv_cb(NULL, p_port);
\r
1625 ipoib_port_deref( p_port, ref_recv_cb );
\r
1633 IN const ib_cq_handle_t h_cq,
\r
1634 IN void *cq_context )
\r
1636 ipoib_port_t *p_port;
\r
1637 ib_api_status_t status;
\r
1638 ib_wc_t wc[MAX_RECV_WC], *p_free, *p_wc;
\r
1639 int32_t pkt_cnt, recv_cnt = 0, shortage, discarded;
\r
1640 cl_qlist_t done_list, bad_list;
\r
1642 PERF_DECLARE( RecvCompBundle );
\r
1643 PERF_DECLARE( RecvCb );
\r
1644 PERF_DECLARE( PollRecv );
\r
1645 PERF_DECLARE( RepostRecv );
\r
1646 PERF_DECLARE( FilterRecv );
\r
1647 PERF_DECLARE( BuildPktArray );
\r
1648 PERF_DECLARE( RecvNdisIndicate );
\r
1649 PERF_DECLARE( RearmRecv );
\r
1650 PERF_DECLARE( PutRecvList );
\r
1652 IPOIB_ENTER( IPOIB_DBG_RECV );
\r
1654 cl_perf_clr( RecvCompBundle );
\r
1656 cl_perf_start( RecvCb );
\r
1658 UNUSED_PARAM( h_cq );
\r
1660 p_port = (ipoib_port_t*)cq_context;
\r
1662 cl_qlist_init( &done_list );
\r
1663 cl_qlist_init( &bad_list );
\r
1665 ipoib_port_ref( p_port, ref_recv_cb );
\r
1666 for( i = 0; i < MAX_RECV_WC; i++ )
\r
1667 wc[i].p_next = &wc[i + 1];
\r
1668 wc[MAX_RECV_WC - 1].p_next = NULL;
\r
1671 * We'll be accessing the endpoint map so take a reference
\r
1672 * on it to prevent modifications.
\r
1674 cl_obj_lock( &p_port->obj );
\r
1675 cl_atomic_inc( &p_port->endpt_rdr );
\r
1676 cl_obj_unlock( &p_port->obj );
\r
1680 /* If we get here, then the list of WCs is intact. */
\r
1683 cl_perf_start( PollRecv );
\r
1684 status = p_port->p_adapter->p_ifc->poll_cq(
\r
1685 p_port->ib_mgr.h_recv_cq, &p_free, &p_wc );
\r
1686 cl_perf_stop( &p_port->p_adapter->perf, PollRecv );
\r
1687 CL_ASSERT( status == IB_SUCCESS || status == IB_NOT_FOUND );
\r
1689 /* Look at the payload now and filter ARP and DHCP packets. */
\r
1690 cl_perf_start( FilterRecv );
\r
1691 recv_cnt += __recv_mgr_filter( p_port, p_wc, &done_list, &bad_list );
\r
1692 cl_perf_stop( &p_port->p_adapter->perf, FilterRecv );
\r
1694 } while( (!p_free) && (recv_cnt < 128));
\r
1696 /* We're done looking at the endpoint map, release the reference. */
\r
1697 cl_atomic_dec( &p_port->endpt_rdr );
\r
1699 cl_perf_log( &p_port->p_adapter->perf, RecvCompBundle, recv_cnt );
\r
1701 cl_spinlock_acquire( &p_port->recv_lock );
\r
1703 /* Update our posted depth. */
\r
1704 p_port->recv_mgr.depth -= recv_cnt;
\r
1706 /* Return any discarded receives to the pool */
\r
1707 cl_perf_start( PutRecvList );
\r
1708 __buf_mgr_put_recv_list( p_port, &bad_list );
\r
1709 cl_perf_stop( &p_port->p_adapter->perf, PutRecvList );
\r
1713 /* Repost ASAP so we don't starve the RQ. */
\r
1714 cl_perf_start( RepostRecv );
\r
1715 shortage = __recv_mgr_repost( p_port );
\r
1716 cl_perf_stop( &p_port->p_adapter->perf, RepostRecv );
\r
1718 cl_perf_start( BuildPktArray );
\r
1719 /* Notify NDIS of any and all possible receive buffers. */
\r
1720 pkt_cnt = __recv_mgr_build_pkt_array(
\r
1721 p_port, shortage, &done_list, &discarded );
\r
1722 cl_perf_stop( &p_port->p_adapter->perf, BuildPktArray );
\r
1724 /* Only indicate receives if we actually had any. */
\r
1725 if( discarded && shortage > 0 )
\r
1727 /* We may have thrown away packets, and have a shortage */
\r
1728 cl_perf_start( RepostRecv );
\r
1729 __recv_mgr_repost( p_port );
\r
1730 cl_perf_stop( &p_port->p_adapter->perf, RepostRecv );
\r
1736 cl_spinlock_release( &p_port->recv_lock );
\r
1738 cl_perf_start( RecvNdisIndicate );
\r
1739 NdisMIndicateReceivePacket( p_port->p_adapter->h_adapter,
\r
1740 p_port->recv_mgr.recv_pkt_array, pkt_cnt );
\r
1741 cl_perf_stop( &p_port->p_adapter->perf, RecvNdisIndicate );
\r
1744 * Cap the number of receives to put back to what we just indicated
\r
1745 * with NDIS_STATUS_RESOURCES.
\r
1747 if( shortage > 0 )
\r
1749 if( pkt_cnt < shortage )
\r
1750 shortage = pkt_cnt;
\r
1752 /* Return all but the last packet to the pool. */
\r
1753 cl_spinlock_acquire( &p_port->recv_lock );
\r
1754 while( shortage-- > 1 )
\r
1756 __buf_mgr_put_recv( p_port,
\r
1757 IPOIB_RECV_FROM_PACKET( p_port->recv_mgr.recv_pkt_array[shortage] ),
\r
1758 p_port->recv_mgr.recv_pkt_array[shortage] );
\r
1760 cl_spinlock_release( &p_port->recv_lock );
\r
1763 * Return the last packet as if NDIS returned it, so that we repost
\r
1764 * and report any other pending receives.
\r
1766 ipoib_return_packet( NULL, p_port->recv_mgr.recv_pkt_array[0] );
\r
1768 cl_spinlock_acquire( &p_port->recv_lock );
\r
1770 } while( pkt_cnt );
\r
1771 cl_spinlock_release( &p_port->recv_lock );
\r
1775 * Rearm after filtering to prevent contention on the enpoint maps
\r
1776 * and eliminate the possibility of having a call to
\r
1777 * __endpt_mgr_insert find a duplicate.
\r
1779 cl_perf_start( RearmRecv );
\r
1780 status = p_port->p_adapter->p_ifc->rearm_cq(
\r
1781 p_port->ib_mgr.h_recv_cq, FALSE );
\r
1782 cl_perf_stop( &p_port->p_adapter->perf, RearmRecv );
\r
1783 CL_ASSERT( status == IB_SUCCESS );
\r
1785 ipoib_port_deref( p_port, ref_recv_cb );
\r
1787 // Please note the reference is still up
\r
1788 KeInsertQueueDpc(&p_port->recv_dpc, NULL, NULL);
\r
1791 cl_perf_stop( &p_port->p_adapter->perf, RecvCb );
\r
1793 IPOIB_EXIT( IPOIB_DBG_RECV );
\r
1798 __recv_get_endpts(
\r
1799 IN ipoib_port_t* const p_port,
\r
1800 IN ipoib_recv_desc_t* const p_desc,
\r
1801 IN ib_wc_t* const p_wc,
\r
1802 OUT ipoib_endpt_t** const pp_src,
\r
1803 OUT ipoib_endpt_t** const pp_dst )
\r
1805 ib_api_status_t status;
\r
1807 PERF_DECLARE( GetEndptByGid );
\r
1808 PERF_DECLARE( GetEndptByLid );
\r
1809 PERF_DECLARE( EndptInsert );
\r
1811 IPOIB_ENTER( IPOIB_DBG_RECV );
\r
1813 /* Setup our shortcut pointers based on whether GRH is valid. */
\r
1814 if( p_wc->recv.ud.recv_opt & IB_RECV_OPT_GRH_VALID )
\r
1816 /* Lookup the source endpoints based on GID. */
\r
1817 cl_perf_start( GetEndptByGid );
\r
1819 #if IPOIB_INLINE_RECV
\r
1820 __endpt_mgr_get_by_gid( p_port, &p_desc->buf.ib.grh.src_gid );
\r
1821 #else /* IPOIB_INLINE_RECV */
\r
1822 __endpt_mgr_get_by_gid( p_port, &p_desc->p_buf->ib.grh.src_gid );
\r
1823 #endif /* IPOIB_INLINE_RECV */
\r
1824 cl_perf_stop( &p_port->p_adapter->perf, GetEndptByGid );
\r
1827 * Lookup the destination endpoint based on GID.
\r
1828 * This is used along with the packet filter to determine
\r
1829 * whether to report this to NDIS.
\r
1831 cl_perf_start( GetEndptByGid );
\r
1833 #if IPOIB_INLINE_RECV
\r
1834 __endpt_mgr_get_by_gid( p_port, &p_desc->buf.ib.grh.dest_gid );
\r
1835 #else /* IPOIB_INLINE_RECV */
\r
1836 __endpt_mgr_get_by_gid( p_port, &p_desc->p_buf->ib.grh.dest_gid );
\r
1837 #endif /* IPOIB_INLINE_RECV */
\r
1838 cl_perf_stop( &p_port->p_adapter->perf, GetEndptByGid );
\r
1841 * Create the source endpoint if it does not exist. Note that we
\r
1842 * can only do this for globally routed traffic since we need the
\r
1843 * information from the GRH to generate the MAC.
\r
1847 status = ipoib_mac_from_guid(
\r
1848 #if IPOIB_INLINE_RECV
\r
1849 p_desc->buf.ib.grh.src_gid.unicast.interface_id, p_port->p_adapter->params.guid_mask, &mac );
\r
1850 #else /* IPOIB_INLINE_RECV */
\r
1851 p_desc->p_buf->ib.grh.src_gid.unicast.interface_id, p_port->p_adapter->params.guid_mask, &mac );
\r
1852 #endif /* IPOIB_INLINE_RECV */
\r
1853 if( status != IB_SUCCESS )
\r
1855 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1856 ("ipoib_mac_from_guid returned %s\n",
\r
1857 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
1861 /* Create the endpoint. */
\r
1862 #if IPOIB_INLINE_RECV
\r
1863 *pp_src = ipoib_endpt_create( &p_desc->buf.ib.grh.src_gid,
\r
1864 #else /* IPOIB_INLINE_RECV */
\r
1865 *pp_src = ipoib_endpt_create( &p_desc->p_buf->ib.grh.src_gid,
\r
1866 #endif /* IPOIB_INLINE_RECV */
\r
1867 p_wc->recv.ud.remote_lid, p_wc->recv.ud.remote_qp );
\r
1870 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1871 ("ipoib_endpt_create failed\n") );
\r
1874 cl_perf_start( EndptInsert );
\r
1875 cl_obj_lock( &p_port->obj );
\r
1876 status = __endpt_mgr_insert( p_port, mac, *pp_src );
\r
1877 if( status != IB_SUCCESS )
\r
1879 cl_obj_unlock( &p_port->obj );
\r
1880 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1881 ("__endpt_mgr_insert returned %s\n",
\r
1882 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
1886 cl_obj_unlock( &p_port->obj );
\r
1887 cl_perf_stop( &p_port->p_adapter->perf, EndptInsert );
\r
1893 * Lookup the remote endpoint based on LID. Note that only
\r
1894 * unicast traffic can be LID routed.
\r
1896 cl_perf_start( GetEndptByLid );
\r
1897 *pp_src = __endpt_mgr_get_by_lid( p_port, p_wc->recv.ud.remote_lid );
\r
1898 cl_perf_stop( &p_port->p_adapter->perf, GetEndptByLid );
\r
1899 *pp_dst = p_port->p_local_endpt;
\r
1900 CL_ASSERT( *pp_dst );
\r
1903 if( *pp_src && !ipoib_is_voltaire_router_gid( &(*pp_src)->dgid ) &&
\r
1904 (*pp_src)->qpn != p_wc->recv.ud.remote_qp )
\r
1906 /* Update the QPN for the endpoint. */
\r
1907 IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV,
\r
1908 ("Updating QPN for MAC: %02X-%02X-%02X-%02X-%02X-%02X\n",
\r
1909 (*pp_src )->mac.addr[0], (*pp_src )->mac.addr[1],
\r
1910 (*pp_src )->mac.addr[2], (*pp_src )->mac.addr[3],
\r
1911 (*pp_src )->mac.addr[4], (*pp_src )->mac.addr[5]) );
\r
1912 (*pp_src)->qpn = p_wc->recv.ud.remote_qp;
\r
1915 if( *pp_src && *pp_dst )
\r
1917 IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV,
\r
1919 "\tsrc MAC: %02X-%02X-%02X-%02X-%02X-%02X\n"
\r
1920 "\tdst MAC: %02X-%02X-%02X-%02X-%02X-%02X\n",
\r
1921 (*pp_src )->mac.addr[0], (*pp_src )->mac.addr[1],
\r
1922 (*pp_src )->mac.addr[2], (*pp_src )->mac.addr[3],
\r
1923 (*pp_src )->mac.addr[4], (*pp_src )->mac.addr[5],
\r
1924 (*pp_dst )->mac.addr[0], (*pp_dst )->mac.addr[1],
\r
1925 (*pp_dst )->mac.addr[2], (*pp_dst )->mac.addr[3],
\r
1926 (*pp_dst )->mac.addr[4], (*pp_dst )->mac.addr[5]) );
\r
1929 IPOIB_EXIT( IPOIB_DBG_RECV );
\r
1934 __recv_mgr_filter(
\r
1935 IN ipoib_port_t* const p_port,
\r
1936 IN ib_wc_t* const p_done_wc_list,
\r
1937 OUT cl_qlist_t* const p_done_list,
\r
1938 OUT cl_qlist_t* const p_bad_list )
\r
1940 ipoib_recv_desc_t *p_desc;
\r
1942 ipoib_pkt_t *p_ipoib;
\r
1944 ipoib_endpt_t *p_src, *p_dst;
\r
1945 ib_api_status_t status;
\r
1947 int32_t recv_cnt = 0;
\r
1948 PERF_DECLARE( GetRecvEndpts );
\r
1949 PERF_DECLARE( RecvGen );
\r
1950 PERF_DECLARE( RecvTcp );
\r
1951 PERF_DECLARE( RecvUdp );
\r
1952 PERF_DECLARE( RecvDhcp );
\r
1953 PERF_DECLARE( RecvArp );
\r
1955 IPOIB_ENTER( IPOIB_DBG_RECV );
\r
1957 for( p_wc = p_done_wc_list; p_wc; p_wc = p_wc->p_next )
\r
1959 CL_ASSERT( p_wc->status != IB_WCS_SUCCESS || p_wc->wc_type == IB_WC_RECV );
\r
1960 p_desc = (ipoib_recv_desc_t*)(uintn_t)p_wc->wr_id;
\r
1963 if( p_wc->status != IB_WCS_SUCCESS )
\r
1965 if( p_wc->status != IB_WCS_WR_FLUSHED_ERR )
\r
1967 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1968 ("Failed completion %s (vendor specific %#x)\n",
\r
1969 p_port->p_adapter->p_ifc->get_wc_status_str( p_wc->status ),
\r
1970 (int)p_wc->vendor_specific) );
\r
1971 ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0 );
\r
1975 IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV,
\r
1976 ("Flushed completion %s\n",
\r
1977 p_port->p_adapter->p_ifc->get_wc_status_str( p_wc->status )) );
\r
1978 ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_DROPPED, 0 );
\r
1980 cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item );
\r
1981 /* Dereference the port object on behalf of the failed receive. */
\r
1982 ipoib_port_deref( p_port, ref_failed_recv_wc );
\r
1986 len = p_wc->length - sizeof(ib_grh_t);
\r
1988 if( len < sizeof(ipoib_hdr_t) )
\r
1990 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
1991 ("Received ETH packet < min size\n") );
\r
1992 ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0 );
\r
1993 cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item );
\r
1994 ipoib_port_deref( p_port, ref_recv_inv_len );
\r
1998 if((len - sizeof(ipoib_hdr_t)) > p_port->p_adapter->params.payload_mtu)
\r
2000 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2001 ("Received ETH packet > payload MTU (%d)\n",
\r
2002 p_port->p_adapter->params.payload_mtu) );
\r
2003 ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0 );
\r
2004 cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item );
\r
2005 ipoib_port_deref( p_port, ref_recv_inv_len );
\r
2009 /* Successful completion. Get the receive information. */
\r
2010 p_desc->ndis_csum.Value = ( (p_wc->recv.ud.recv_opt & IB_RECV_OPT_CSUM_MASK ) >> 8 );
\r
2011 cl_perf_start( GetRecvEndpts );
\r
2012 __recv_get_endpts( p_port, p_desc, p_wc, &p_src, &p_dst );
\r
2013 cl_perf_stop( &p_port->p_adapter->perf, GetRecvEndpts );
\r
2015 #if IPOIB_INLINE_RECV
\r
2016 p_ipoib = &p_desc->buf.ib.pkt;
\r
2017 p_eth = &p_desc->buf.eth.pkt;
\r
2018 #else /* IPOIB_INLINE_RECV */
\r
2019 p_ipoib = &p_desc->p_buf->ib.pkt;
\r
2020 p_eth = &p_desc->p_buf->eth.pkt;
\r
2021 #endif /*IPOIB_INLINE_RECV */
\r
2025 /* Don't report loopback traffic - we requested SW loopback. */
\r
2026 if( !cl_memcmp( &p_port->p_adapter->params.conf_mac,
\r
2027 &p_src->mac, sizeof(p_port->p_adapter->params.conf_mac) ) )
\r
2030 * "This is not the packet you're looking for" - don't update
\r
2031 * receive statistics, the packet never happened.
\r
2033 cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item );
\r
2034 /* Dereference the port object on behalf of the failed recv. */
\r
2035 ipoib_port_deref( p_port, ref_recv_loopback );
\r
2040 switch( p_ipoib->hdr.type )
\r
2042 case ETH_PROT_TYPE_IP:
\r
2043 if( len < (sizeof(ipoib_hdr_t) + sizeof(ip_hdr_t)) )
\r
2045 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2046 ("Received IP packet < min size\n") );
\r
2047 status = IB_INVALID_SETTING;
\r
2051 if( p_ipoib->type.ip.hdr.offset ||
\r
2052 p_ipoib->type.ip.hdr.prot != IP_PROT_UDP )
\r
2054 /* Unfiltered. Setup the ethernet header and report. */
\r
2055 cl_perf_start( RecvTcp );
\r
2056 status = __recv_gen( p_ipoib, p_eth, p_src, p_dst );
\r
2057 cl_perf_stop( &p_port->p_adapter->perf, RecvTcp );
\r
2061 /* First packet of a UDP transfer. */
\r
2063 (sizeof(ipoib_hdr_t) + sizeof(ip_hdr_t) + sizeof(udp_hdr_t)) )
\r
2065 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2066 ("Received UDP packet < min size\n") );
\r
2067 status = IB_INVALID_SETTING;
\r
2071 /* Check if DHCP conversion is required. */
\r
2072 if( (p_ipoib->type.ip.prot.udp.hdr.dst_port == DHCP_PORT_SERVER &&
\r
2073 p_ipoib->type.ip.prot.udp.hdr.src_port == DHCP_PORT_CLIENT) ||
\r
2074 (p_ipoib->type.ip.prot.udp.hdr.dst_port == DHCP_PORT_CLIENT &&
\r
2075 p_ipoib->type.ip.prot.udp.hdr.src_port == DHCP_PORT_SERVER) )
\r
2077 if( len < (sizeof(ipoib_hdr_t) + sizeof(ip_hdr_t) +
\r
2078 sizeof(udp_hdr_t) + DHCP_MIN_SIZE) )
\r
2080 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2081 ("Received DHCP < min size\n") );
\r
2082 status = IB_INVALID_SETTING;
\r
2085 if ((p_ipoib->type.ip.hdr.ver_hl & 0x0f) != 5 ) {
\r
2086 // If there are IP options in this message, we are in trouble in any case
\r
2087 status = IB_INVALID_SETTING;
\r
2090 /* UDP packet with BOOTP ports in src/dst port numbers. */
\r
2091 cl_perf_start( RecvDhcp );
\r
2092 status = __recv_dhcp( p_port, p_ipoib, p_eth, p_src, p_dst );
\r
2093 cl_perf_stop( &p_port->p_adapter->perf, RecvDhcp );
\r
2097 /* Unfiltered. Setup the ethernet header and report. */
\r
2098 cl_perf_start( RecvUdp );
\r
2099 status = __recv_gen( p_ipoib, p_eth, p_src, p_dst );
\r
2100 cl_perf_stop( &p_port->p_adapter->perf, RecvUdp );
\r
2104 case ETH_PROT_TYPE_ARP:
\r
2105 if( len < (sizeof(ipoib_hdr_t) + sizeof(ipoib_arp_pkt_t)) )
\r
2107 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2108 ("Received ARP < min size\n") );
\r
2109 status = IB_INVALID_SETTING;
\r
2112 cl_perf_start( RecvArp );
\r
2113 status = __recv_arp( p_port, p_wc, p_ipoib, p_eth, &p_src, p_dst );
\r
2114 cl_perf_stop( &p_port->p_adapter->perf, RecvArp );
\r
2115 len = sizeof(ipoib_hdr_t) + sizeof(arp_pkt_t);
\r
2119 /* Unfiltered. Setup the ethernet header and report. */
\r
2120 cl_perf_start( RecvGen );
\r
2121 status = __recv_gen( p_ipoib, p_eth, p_src, p_dst );
\r
2122 cl_perf_stop( &p_port->p_adapter->perf, RecvGen );
\r
2125 if( status != IB_SUCCESS )
\r
2127 /* Update stats. */
\r
2128 ipoib_inc_recv_stat( p_port->p_adapter, IP_STAT_ERROR, 0 );
\r
2129 cl_qlist_insert_tail( p_bad_list, &p_desc->item.list_item );
\r
2130 /* Dereference the port object on behalf of the failed receive. */
\r
2131 ipoib_port_deref( p_port, ref_recv_filter );
\r
2135 ip_stat_sel_t ip_stat;
\r
2137 len + sizeof(eth_hdr_t) - sizeof(ipoib_hdr_t);
\r
2138 if( p_dst->h_mcast)
\r
2140 if( p_dst->dgid.multicast.raw_group_id[10] == 0xFF &&
\r
2141 p_dst->dgid.multicast.raw_group_id[11] == 0xFF &&
\r
2142 p_dst->dgid.multicast.raw_group_id[12] == 0xFF &&
\r
2143 p_dst->dgid.multicast.raw_group_id[13] == 0xFF )
\r
2145 p_desc->type = PKT_TYPE_BCAST;
\r
2146 ip_stat = IP_STAT_BCAST_BYTES;
\r
2150 p_desc->type = PKT_TYPE_MCAST;
\r
2151 ip_stat = IP_STAT_MCAST_BYTES;
\r
2156 p_desc->type = PKT_TYPE_UCAST;
\r
2157 ip_stat = IP_STAT_UCAST_BYTES;
\r
2160 cl_qlist_insert_tail( p_done_list, &p_desc->item.list_item );
\r
2161 ipoib_inc_recv_stat( p_port->p_adapter,ip_stat , len );
\r
2165 IPOIB_EXIT( IPOIB_DBG_RECV );
\r
2170 static ib_api_status_t
\r
2172 IN const ipoib_pkt_t* const p_ipoib,
\r
2173 OUT eth_pkt_t* const p_eth,
\r
2174 IN ipoib_endpt_t* const p_src,
\r
2175 IN ipoib_endpt_t* const p_dst )
\r
2177 IPOIB_ENTER( IPOIB_DBG_RECV );
\r
2179 if( !p_src || !p_dst )
\r
2181 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2182 ("Received packet with no matching endpoints.\n") );
\r
2183 return IB_NOT_DONE;
\r
2187 * Fill in the ethernet header. Note that doing so will overwrite
\r
2188 * the IPoIB header, so start by moving the information from the IPoIB
\r
2191 p_eth->hdr.type = p_ipoib->hdr.type;
\r
2192 p_eth->hdr.src = p_src->mac;
\r
2193 p_eth->hdr.dst = p_dst->mac;
\r
2195 if ( p_eth->hdr.dst.addr[0] == 1 &&
\r
2196 p_eth->hdr.type == ETH_PROT_TYPE_IP &&
\r
2197 p_eth->hdr.dst.addr[2] == 0x5E)
\r
2199 p_eth->hdr.dst.addr[1] = 0;
\r
2200 p_eth->hdr.dst.addr[3] = p_eth->hdr.dst.addr[3] & 0x7f;
\r
2202 if (p_dst->h_mcast)
\r
2203 p_dst->is_in_use = TRUE;
\r
2205 IPOIB_EXIT( IPOIB_DBG_RECV );
\r
2206 return IB_SUCCESS;
\r
2210 static ib_api_status_t
\r
2212 IN ipoib_port_t* const p_port,
\r
2213 IN const ipoib_pkt_t* const p_ipoib,
\r
2214 OUT eth_pkt_t* const p_eth,
\r
2215 IN ipoib_endpt_t* const p_src,
\r
2216 IN ipoib_endpt_t* const p_dst )
\r
2218 ib_api_status_t status;
\r
2219 dhcp_pkt_t *p_dhcp;
\r
2220 uint8_t *p_option;
\r
2221 uint8_t *p_cid = NULL;
\r
2225 IPOIB_ENTER( IPOIB_DBG_RECV );
\r
2227 UNUSED_PARAM( p_port );
\r
2229 /* Create the ethernet header. */
\r
2230 status = __recv_gen( p_ipoib, p_eth, p_src, p_dst );
\r
2231 if( status != IB_SUCCESS )
\r
2233 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2234 ("__recv_gen returned %s.\n",
\r
2235 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
2239 /* Fixup the payload. */
\r
2240 p_dhcp = &p_eth->type.ip.prot.udp.dhcp;
\r
2241 if( p_dhcp->op != DHCP_REQUEST && p_dhcp->op != DHCP_REPLY )
\r
2243 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2244 ("Invalid DHCP op code.\n") );
\r
2245 return IB_INVALID_SETTING;
\r
2249 * Find the client identifier option, making sure to skip
\r
2250 * the "magic cookie".
\r
2252 p_option = &p_dhcp->options[0];
\r
2253 if ( *(uint32_t *)p_option != DHCP_COOKIE )
\r
2255 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2256 ("DHCP cookie corrupted.\n") );
\r
2257 return IB_INVALID_PARAMETER;
\r
2260 p_option = &p_dhcp->options[4];
\r
2261 while( *p_option != DHCP_OPT_END && p_option < &p_dhcp->options[312] )
\r
2263 switch( *p_option )
\r
2265 case DHCP_OPT_PAD:
\r
2269 case DHCP_OPT_MSG:
\r
2270 msg = p_option[2];
\r
2274 case DHCP_OPT_CLIENT_ID:
\r
2276 /* Fall through. */
\r
2280 * All other options have a length byte following the option code.
\r
2281 * Offset by the length to get to the next option.
\r
2283 p_option += (p_option[1] + 2);
\r
2289 /* message from client */
\r
2290 case DHCPDISCOVER:
\r
2297 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2298 ("Failed to find required Client-identifier option.\n") );
\r
2299 return IB_INVALID_SETTING;
\r
2301 if( p_dhcp->htype != DHCP_HW_TYPE_IB )
\r
2303 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2304 ("Invalid hardware address type.\n") );
\r
2305 return IB_INVALID_SETTING;
\r
2308 /* message from DHCP server */
\r
2315 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2316 ("Invalide message type.\n") );
\r
2317 return IB_INVALID_PARAMETER;
\r
2319 p_eth->type.ip.prot.udp.hdr.chksum = 0;
\r
2320 p_dhcp->htype = DHCP_HW_TYPE_ETH;
\r
2321 p_dhcp->hlen = HW_ADDR_LEN;
\r
2323 if( p_cid ) /* from client */
\r
2325 /* Validate that the length and type of the option is as required. */
\r
2326 if( p_cid[1] != 21 )
\r
2328 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2329 ("Client-identifier length not 21 as required.\n") );
\r
2330 return IB_INVALID_SETTING;
\r
2332 if( p_cid[2] != DHCP_HW_TYPE_IB )
\r
2334 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2335 ("Client-identifier type is wrong.\n") );
\r
2336 return IB_INVALID_SETTING;
\r
2339 * Copy the GID value from the option so that we can make aligned
\r
2340 * accesses to the contents.
\r
2341 * Recover CID to standard type.
\r
2343 cl_memcpy( &gid, &p_cid[7], sizeof(ib_gid_t) );
\r
2344 p_cid[1] = HW_ADDR_LEN +1;// CID length
\r
2345 p_cid[2] = DHCP_HW_TYPE_ETH;// CID type
\r
2346 status = ipoib_mac_from_guid( gid.unicast.interface_id, p_port->p_adapter->params.guid_mask, (mac_addr_t*)&p_cid[3] );
\r
2347 if (status == IB_INVALID_GUID_MASK)
\r
2349 IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_ERROR,
\r
2350 ("Invalid GUID mask received, rejecting it") );
\r
2351 ipoib_create_log(p_port->p_adapter->h_adapter, GUID_MASK_LOG_INDEX, EVENT_IPOIB_WRONG_PARAMETER_WRN);
\r
2352 status = IB_SUCCESS;
\r
2354 p_cid[HW_ADDR_LEN + 3] = DHCP_OPT_END; //terminate tag
\r
2356 IPOIB_EXIT( IPOIB_DBG_RECV );
\r
2361 static ib_api_status_t
\r
2363 IN ipoib_port_t* const p_port,
\r
2364 IN ib_wc_t* const p_wc,
\r
2365 IN const ipoib_pkt_t* const p_ipoib,
\r
2366 OUT eth_pkt_t* const p_eth,
\r
2367 IN ipoib_endpt_t** const pp_src,
\r
2368 IN ipoib_endpt_t* const p_dst )
\r
2370 ib_api_status_t status;
\r
2372 const ipoib_arp_pkt_t *p_ib_arp;
\r
2375 ipoib_hw_addr_t null_hw = {0};
\r
2377 IPOIB_ENTER( IPOIB_DBG_RECV );
\r
2381 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2382 ("Unknown destination endpoint\n") );
\r
2383 return IB_INVALID_SETTING;
\r
2386 p_ib_arp = &p_ipoib->type.arp;
\r
2387 p_arp = &p_eth->type.arp;
\r
2389 if( p_ib_arp->hw_type != ARP_HW_TYPE_IB )
\r
2391 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2392 ("ARP hardware type is not IB\n") );
\r
2393 return IB_INVALID_SETTING;
\r
2396 if( p_ib_arp->hw_size != sizeof(ipoib_hw_addr_t) )
\r
2398 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2399 ("ARP hardware address size is not sizeof(ipoib_hw_addr_t)\n") );
\r
2400 return IB_INVALID_SETTING;
\r
2403 if( p_ib_arp->prot_type != ETH_PROT_TYPE_IP )
\r
2405 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2406 ("ARP protocal type not IP\n") );
\r
2407 return IB_INVALID_SETTING;
\r
2411 * If we don't have a source, lookup the endpoint specified in the payload.
\r
2414 *pp_src = __endpt_mgr_get_by_gid( p_port, &p_ib_arp->src_hw.gid );
\r
2417 * If the endpoint exists for the GID, make sure
\r
2418 * the dlid and qpn match the arp.
\r
2422 if( cl_memcmp( &(*pp_src)->dgid, &p_ib_arp->src_hw.gid,
\r
2423 sizeof(ib_gid_t) ) )
\r
2426 * GIDs for the endpoint are different. The ARP must
\r
2427 * have been proxied. Dereference it.
\r
2431 else if( (*pp_src)->dlid &&
\r
2432 (*pp_src)->dlid != p_wc->recv.ud.remote_lid )
\r
2434 /* Out of date! Destroy the endpoint and replace it. */
\r
2435 __endpt_mgr_remove( p_port, *pp_src );
\r
2438 else if ( ! ((*pp_src)->dlid)) {
\r
2439 /* Out of date! Destroy the endpoint and replace it. */
\r
2440 __endpt_mgr_remove( p_port, *pp_src );
\r
2443 else if( ipoib_is_voltaire_router_gid( &(*pp_src)->dgid ) )
\r
2445 if( (*pp_src)->qpn !=
\r
2446 (p_ib_arp->src_hw.flags_qpn & CL_HTON32(0x00FFFFFF)) &&
\r
2447 p_wc->recv.ud.remote_qp !=
\r
2448 (p_ib_arp->src_hw.flags_qpn & CL_HTON32(0x00FFFFFF)) )
\r
2450 /* Out of date! Destroy the endpoint and replace it. */
\r
2451 __endpt_mgr_remove( p_port, *pp_src );
\r
2455 else if( (*pp_src)->qpn != p_wc->recv.ud.remote_qp )
\r
2457 /* Out of date! Destroy the endpoint and replace it. */
\r
2458 __endpt_mgr_remove( p_port, *pp_src );
\r
2463 /* Do we need to create an endpoint for this GID? */
\r
2466 /* Copy the src GID to allow aligned access */
\r
2467 cl_memcpy( &gid, &p_ib_arp->src_hw.gid, sizeof(ib_gid_t) );
\r
2468 status = ipoib_mac_from_guid( gid.unicast.interface_id, p_port->p_adapter->params.guid_mask, &mac );
\r
2469 if (status == IB_INVALID_GUID_MASK)
\r
2471 IPOIB_PRINT( TRACE_LEVEL_WARNING, IPOIB_DBG_ERROR,
\r
2472 ("Invalid GUID mask received, rejecting it") );
\r
2473 ipoib_create_log(p_port->p_adapter->h_adapter, GUID_MASK_LOG_INDEX, EVENT_IPOIB_WRONG_PARAMETER_WRN);
\r
2475 else if( status != IB_SUCCESS )
\r
2477 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2478 ("ipoib_mac_from_guid returned %s\n",
\r
2479 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
2483 * Create the endpoint.
\r
2485 *pp_src = ipoib_endpt_create( &p_ib_arp->src_hw.gid,
\r
2486 p_wc->recv.ud.remote_lid, (p_ib_arp->src_hw.flags_qpn & CL_HTON32(0x00FFFFFF)) );
\r
2490 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2491 ("ipoib_endpt_create failed\n") );
\r
2495 cl_obj_lock( &p_port->obj );
\r
2496 status = __endpt_mgr_insert( p_port, mac, *pp_src );
\r
2497 if( status != IB_SUCCESS )
\r
2499 cl_obj_unlock( &p_port->obj );
\r
2500 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2501 ("__endpt_mgr_insert return %s \n",
\r
2502 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
2506 cl_obj_unlock( &p_port->obj );
\r
2509 CL_ASSERT( !cl_memcmp(
\r
2510 &(*pp_src)->dgid, &p_ib_arp->src_hw.gid, sizeof(ib_gid_t) ) );
\r
2511 CL_ASSERT( ipoib_is_voltaire_router_gid( &(*pp_src)->dgid ) ||
\r
2513 (p_ib_arp->src_hw.flags_qpn & CL_HTON32(0x00FFFFFF)) );
\r
2514 /* Now swizzle the data. */
\r
2515 p_arp->hw_type = ARP_HW_TYPE_ETH;
\r
2516 p_arp->hw_size = sizeof(mac_addr_t);
\r
2517 p_arp->src_hw = (*pp_src)->mac;
\r
2518 p_arp->src_ip = p_ib_arp->src_ip;
\r
2520 if( cl_memcmp( &p_ib_arp->dst_hw, &null_hw, sizeof(ipoib_hw_addr_t) ) )
\r
2522 if( cl_memcmp( &p_dst->dgid, &p_ib_arp->dst_hw.gid, sizeof(ib_gid_t) ) )
\r
2525 * We received bcast ARP packet that means
\r
2526 * remote port lets everyone know it was changed IP/MAC
\r
2527 * or just activated
\r
2530 /* Guy: TODO: Check why this check fails in case of Voltaire IPR */
\r
2532 if ( !ipoib_is_voltaire_router_gid( &(*pp_src)->dgid ) &&
\r
2533 !ib_gid_is_multicast( (const ib_gid_t*)&p_dst->dgid ) )
\r
2535 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2536 ("ARP: is not ARP MCAST\n") );
\r
2537 return IB_INVALID_SETTING;
\r
2540 p_arp->dst_hw = p_port->p_local_endpt->mac;
\r
2541 p_dst->mac = p_port->p_local_endpt->mac;
\r
2543 * we don't care what receiver ip addr is,
\r
2544 * as long as OS' ARP table is global ???
\r
2546 p_arp->dst_ip = (net32_t)0;
\r
2548 else /* we've got reply to our ARP request */
\r
2550 p_arp->dst_hw = p_dst->mac;
\r
2551 p_arp->dst_ip = p_ib_arp->dst_ip;
\r
2552 CL_ASSERT( p_dst->qpn ==
\r
2553 (p_ib_arp->dst_hw.flags_qpn & CL_HTON32(0x00FFFFFF)) );
\r
2556 else /* we got ARP reqeust */
\r
2558 cl_memclr( &p_arp->dst_hw, sizeof(mac_addr_t) );
\r
2559 p_arp->dst_ip = p_ib_arp->dst_ip;
\r
2563 * Create the ethernet header. Note that this is done last so that
\r
2564 * we have a chance to create a new endpoint.
\r
2566 status = __recv_gen( p_ipoib, p_eth, *pp_src, p_dst );
\r
2567 if( status != IB_SUCCESS )
\r
2569 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2570 ("__recv_gen returned %s.\n",
\r
2571 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
2575 IPOIB_EXIT( IPOIB_DBG_RECV );
\r
2576 return IB_SUCCESS;
\r
2580 static ib_api_status_t
\r
2581 __recv_mgr_prepare_pkt(
\r
2582 IN ipoib_port_t* const p_port,
\r
2583 IN ipoib_recv_desc_t* const p_desc,
\r
2584 OUT NDIS_PACKET** const pp_packet )
\r
2586 NDIS_STATUS status;
\r
2587 uint32_t pkt_filter;
\r
2588 ip_stat_sel_t type;
\r
2589 NDIS_TCP_IP_CHECKSUM_PACKET_INFO chksum;
\r
2591 PERF_DECLARE( GetNdisPkt );
\r
2593 IPOIB_ENTER( IPOIB_DBG_RECV );
\r
2595 pkt_filter = p_port->p_adapter->packet_filter;
\r
2596 /* Check the packet filter. */
\r
2597 switch( p_desc->type )
\r
2600 case PKT_TYPE_UCAST:
\r
2601 if( pkt_filter & NDIS_PACKET_TYPE_PROMISCUOUS ||
\r
2602 pkt_filter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL ||
\r
2603 pkt_filter & NDIS_PACKET_TYPE_SOURCE_ROUTING ||
\r
2604 pkt_filter & NDIS_PACKET_TYPE_DIRECTED )
\r
2606 /* OK to report. */
\r
2607 type = IP_STAT_UCAST_BYTES;
\r
2608 status = NDIS_STATUS_SUCCESS;
\r
2612 type = IP_STAT_DROPPED;
\r
2613 status = NDIS_STATUS_FAILURE;
\r
2616 case PKT_TYPE_BCAST:
\r
2617 if( pkt_filter & NDIS_PACKET_TYPE_PROMISCUOUS ||
\r
2618 pkt_filter & NDIS_PACKET_TYPE_BROADCAST )
\r
2620 /* OK to report. */
\r
2621 type = IP_STAT_BCAST_BYTES;
\r
2622 status = NDIS_STATUS_SUCCESS;
\r
2626 type = IP_STAT_DROPPED;
\r
2627 status = NDIS_STATUS_FAILURE;
\r
2630 case PKT_TYPE_MCAST:
\r
2631 if( pkt_filter & NDIS_PACKET_TYPE_PROMISCUOUS ||
\r
2632 pkt_filter & NDIS_PACKET_TYPE_ALL_MULTICAST ||
\r
2633 pkt_filter & NDIS_PACKET_TYPE_MULTICAST )
\r
2635 /* OK to report. */
\r
2636 type = IP_STAT_MCAST_BYTES;
\r
2637 status = NDIS_STATUS_SUCCESS;
\r
2641 type = IP_STAT_DROPPED;
\r
2642 status = NDIS_STATUS_FAILURE;
\r
2647 if( status != NDIS_STATUS_SUCCESS )
\r
2649 ipoib_inc_recv_stat( p_port->p_adapter, type, 0 );
\r
2650 /* Return the receive descriptor to the pool. */
\r
2651 __buf_mgr_put_recv( p_port, p_desc, NULL );
\r
2652 IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV,
\r
2653 ("Packet filter doesn't match receive. Dropping.\n") );
\r
2655 * Return IB_NOT_DONE since the packet has been completed,
\r
2656 * but has not consumed an array entry.
\r
2658 return IB_NOT_DONE;
\r
2661 cl_perf_start( GetNdisPkt );
\r
2662 *pp_packet = __buf_mgr_get_ndis_pkt( p_port, p_desc );
\r
2663 cl_perf_stop( &p_port->p_adapter->perf, GetNdisPkt );
\r
2666 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2667 ("__buf_mgr_get_ndis_pkt failed\n") );
\r
2668 return IB_INSUFFICIENT_RESOURCES;
\r
2672 switch (p_port->p_adapter->params.recv_chksum_offload) {
\r
2673 case CSUM_DISABLED:
\r
2674 NDIS_PER_PACKET_INFO_FROM_PACKET( *pp_packet, TcpIpChecksumPacketInfo ) =
\r
2675 (void*)(uintn_t)chksum.Value;
\r
2677 case CSUM_ENABLED:
\r
2678 /* Get the checksums directly from packet information. */
\r
2679 /* In this case, no one of cheksum's cat get false value */
\r
2680 /* If hardware checksum failed or wasn't calculated, NDIS will recalculate it again */
\r
2681 NDIS_PER_PACKET_INFO_FROM_PACKET( *pp_packet, TcpIpChecksumPacketInfo ) =
\r
2682 (void*)(uintn_t)(p_desc->ndis_csum.Value);
\r
2685 /* Flag the checksums as having been calculated. */
\r
2686 chksum.Receive.NdisPacketTcpChecksumSucceeded = TRUE;
\r
2687 chksum.Receive.NdisPacketUdpChecksumSucceeded = TRUE;
\r
2688 chksum.Receive.NdisPacketIpChecksumSucceeded = TRUE;
\r
2689 NDIS_PER_PACKET_INFO_FROM_PACKET( *pp_packet, TcpIpChecksumPacketInfo ) =
\r
2690 (void*)(uintn_t)chksum.Value;
\r
2694 NDIS_PER_PACKET_INFO_FROM_PACKET( *pp_packet, TcpIpChecksumPacketInfo ) =
\r
2695 (void*)(uintn_t)chksum.Value;
\r
2697 ipoib_inc_recv_stat( p_port->p_adapter, type, p_desc->len );
\r
2699 IPOIB_EXIT( IPOIB_DBG_RECV );
\r
2700 return IB_SUCCESS;
\r
2705 __recv_mgr_build_pkt_array(
\r
2706 IN ipoib_port_t* const p_port,
\r
2707 IN int32_t shortage,
\r
2708 OUT cl_qlist_t* const p_done_list,
\r
2709 OUT int32_t* const p_discarded )
\r
2711 cl_list_item_t *p_item;
\r
2712 ipoib_recv_desc_t *p_desc;
\r
2714 ib_api_status_t status;
\r
2715 PERF_DECLARE( PreparePkt );
\r
2717 IPOIB_ENTER( IPOIB_DBG_RECV );
\r
2721 /* Move any existing receives to the head to preserve ordering. */
\r
2722 cl_qlist_insert_list_head( p_done_list, &p_port->recv_mgr.done_list );
\r
2723 p_item = cl_qlist_remove_head( p_done_list );
\r
2724 while( p_item != cl_qlist_end( p_done_list ) )
\r
2726 p_desc = (ipoib_recv_desc_t*)p_item;
\r
2728 cl_perf_start( PreparePkt );
\r
2729 status = __recv_mgr_prepare_pkt( p_port, p_desc,
\r
2730 &p_port->recv_mgr.recv_pkt_array[i] );
\r
2731 cl_perf_stop( &p_port->p_adapter->perf, PreparePkt );
\r
2732 if( status == IB_SUCCESS )
\r
2734 CL_ASSERT( p_port->recv_mgr.recv_pkt_array[i] );
\r
2735 if( shortage-- > 0 )
\r
2737 NDIS_SET_PACKET_STATUS(
\r
2738 p_port->recv_mgr.recv_pkt_array[i], NDIS_STATUS_RESOURCES );
\r
2742 NDIS_SET_PACKET_STATUS(
\r
2743 p_port->recv_mgr.recv_pkt_array[i], NDIS_STATUS_SUCCESS );
\r
2747 else if( status == IB_NOT_DONE )
\r
2753 IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV,
\r
2754 ("__recv_mgr_prepare_pkt returned %s\n",
\r
2755 p_port->p_adapter->p_ifc->get_err_str( status )) );
\r
2756 /* Put all completed receives on the port's done list. */
\r
2757 cl_qlist_insert_tail( &p_port->recv_mgr.done_list, p_item );
\r
2758 cl_qlist_insert_list_tail( &p_port->recv_mgr.done_list, p_done_list );
\r
2762 p_item = cl_qlist_remove_head( p_done_list );
\r
2765 IPOIB_EXIT( IPOIB_DBG_RECV );
\r
2772 /******************************************************************************
\r
2774 * Send manager implementation.
\r
2776 ******************************************************************************/
\r
2778 __send_mgr_construct(
\r
2779 IN ipoib_port_t* const p_port )
\r
2781 IPOIB_ENTER( IPOIB_DBG_SEND );
\r
2782 p_port->send_mgr.depth = 0;
\r
2783 cl_qlist_init( &p_port->send_mgr.pending_list );
\r
2784 IPOIB_EXIT( IPOIB_DBG_SEND );
\r
2789 __pending_list_destroy(
\r
2790 IN ipoib_port_t* const p_port )
\r
2792 cl_list_item_t *p_item;
\r
2793 NDIS_PACKET *p_packet;
\r
2795 cl_spinlock_acquire( &p_port->send_lock );
\r
2796 /* Complete any pending packets. */
\r
2797 for( p_item = cl_qlist_remove_head( &p_port->send_mgr.pending_list );
\r
2798 p_item != cl_qlist_end( &p_port->send_mgr.pending_list );
\r
2799 p_item = cl_qlist_remove_head( &p_port->send_mgr.pending_list ) )
\r
2801 p_packet = IPOIB_PACKET_FROM_LIST_ITEM( p_item );
\r
2802 NdisMSendCompleteX( p_port->p_adapter->h_adapter, p_packet,
\r
2803 NDIS_STATUS_RESET_IN_PROGRESS );
\r
2805 cl_spinlock_release( &p_port->send_lock );
\r
2809 __send_mgr_destroy(
\r
2810 IN ipoib_port_t* const p_port )
\r
2812 IPOIB_ENTER( IPOIB_DBG_SEND );
\r
2813 __pending_list_destroy(p_port);
\r
2815 IPOIB_EXIT( IPOIB_DBG_SEND );
\r
2819 static NDIS_STATUS
\r
2820 __send_mgr_filter(
\r
2821 IN ipoib_port_t* const p_port,
\r
2822 IN const eth_hdr_t* const p_eth_hdr,
\r
2823 IN NDIS_BUFFER* const p_buf,
\r
2824 IN size_t buf_len,
\r
2825 IN OUT ipoib_send_desc_t* const p_desc )
\r
2827 NDIS_STATUS status;
\r
2829 PERF_DECLARE( FilterIp );
\r
2830 PERF_DECLARE( FilterArp );
\r
2831 PERF_DECLARE( SendGen );
\r
2833 IPOIB_ENTER( IPOIB_DBG_SEND );
\r
2836 * We already checked the ethernet header length, so we know it's safe
\r
2837 * to decrement the buf_len without underflowing.
\r
2839 buf_len -= sizeof(eth_hdr_t);
\r
2841 switch( p_eth_hdr->type )
\r
2843 case ETH_PROT_TYPE_IP:
\r
2844 cl_perf_start( FilterIp );
\r
2845 status = __send_mgr_filter_ip(
\r
2846 p_port, p_eth_hdr, p_buf, buf_len, p_desc );
\r
2847 cl_perf_stop( &p_port->p_adapter->perf, FilterIp );
\r
2850 case ETH_PROT_TYPE_ARP:
\r
2851 cl_perf_start( FilterArp );
\r
2852 status = __send_mgr_filter_arp(
\r
2853 p_port, p_eth_hdr, p_buf, buf_len, p_desc );
\r
2854 cl_perf_stop( &p_port->p_adapter->perf, FilterArp );
\r
2859 * The IPoIB spec doesn't define how to send non IP or ARP packets.
\r
2860 * Just send the payload and hope for the best.
\r
2862 cl_perf_start( SendGen );
\r
2863 status = __send_gen( p_port, p_desc, 0 );
\r
2864 cl_perf_stop( &p_port->p_adapter->perf, SendGen );
\r
2868 IPOIB_EXIT( IPOIB_DBG_SEND );
\r
2873 static NDIS_STATUS
\r
2875 IN ipoib_port_t* const p_port,
\r
2876 IN ipoib_send_desc_t* const p_desc )
\r
2878 NDIS_PACKET *p_packet;
\r
2879 NDIS_BUFFER *p_buf;
\r
2880 NDIS_STATUS status;
\r
2881 UINT tot_len, bytes_copied = 0;
\r
2883 IPOIB_ENTER( IPOIB_DBG_SEND );
\r
2886 ExAllocateFromNPagedLookasideList( &p_port->buf_mgr.send_buf_list );
\r
2887 if( !p_desc->p_buf )
\r
2889 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2890 ("Failed to allocate buffer for packet copy.\n") );
\r
2891 return NDIS_STATUS_RESOURCES;
\r
2894 NdisAllocatePacket( &status, &p_packet, p_port->buf_mgr.h_send_pkt_pool );
\r
2895 if( status != NDIS_STATUS_SUCCESS )
\r
2897 IPOIB_PRINT_EXIT( TRACE_LEVEL_WARNING, IPOIB_DBG_SEND,
\r
2898 ("Failed to allocate NDIS_PACKET for copy.\n") );
\r
2902 NdisAllocateBuffer( &status, &p_buf, p_port->buf_mgr.h_send_buf_pool,
\r
2903 p_desc->p_buf, p_port->p_adapter->params.xfer_block_size );
\r
2904 if( status != NDIS_STATUS_SUCCESS )
\r
2906 NdisFreePacket( p_packet );
\r
2907 IPOIB_PRINT_EXIT( TRACE_LEVEL_WARNING, IPOIB_DBG_SEND,
\r
2908 ("Failed to allocate NDIS_BUFFER for copy.\n") );
\r
2912 NdisChainBufferAtFront( p_packet, p_buf );
\r
2914 NdisQueryPacketLength( p_desc->p_pkt, &tot_len );
\r
2916 /* Setup the work request. */
\r
2917 p_desc->local_ds[1].vaddr = cl_get_physaddr(
\r
2918 ((uint8_t*)p_desc->p_buf) + sizeof(eth_hdr_t) );
\r
2919 p_desc->local_ds[1].length = tot_len - sizeof(eth_hdr_t);
\r
2920 p_desc->local_ds[1].lkey = p_port->ib_mgr.lkey;
\r
2921 p_desc->wr.num_ds = 2;
\r
2923 /* Copy the packet. */
\r
2924 NdisCopyFromPacketToPacketSafe( p_packet, bytes_copied, tot_len,
\r
2925 p_desc->p_pkt, bytes_copied, &bytes_copied,
\r
2926 NormalPagePriority );
\r
2928 /* Free our temp packet now that the data is copied. */
\r
2929 NdisUnchainBufferAtFront( p_packet, &p_buf );
\r
2930 NdisFreeBuffer( p_buf );
\r
2931 NdisFreePacket( p_packet );
\r
2933 if( bytes_copied != tot_len )
\r
2935 /* Something went wrong. Drop the packet. */
\r
2936 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2937 ("Failed to copy full packet: %d of %d bytes copied.\n",
\r
2938 bytes_copied, tot_len) );
\r
2939 return NDIS_STATUS_RESOURCES;
\r
2942 IPOIB_EXIT( IPOIB_DBG_SEND );
\r
2943 return NDIS_STATUS_SUCCESS;
\r
2947 #if !IPOIB_USE_DMA
\r
2948 /* Send using the MDL's page information rather than the SGL. */
\r
2949 static ib_api_status_t
\r
2951 IN ipoib_port_t* const p_port,
\r
2952 IN ipoib_send_desc_t* const p_desc )
\r
2954 uint32_t i, j = 1;
\r
2957 UINT num_pages, tot_len;
\r
2959 PPFN_NUMBER page_array;
\r
2960 boolean_t hdr_done = FALSE;
\r
2961 ib_api_status_t status;
\r
2963 IPOIB_ENTER( IPOIB_DBG_SEND );
\r
2965 NdisQueryPacket( p_desc->p_pkt, &num_pages, NULL, &p_mdl,
\r
2970 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,
\r
2971 ("No buffers associated with packet.\n") );
\r
2975 /* Remember that one of the DS entries is reserved for the IPoIB header. */
\r
2976 if( num_pages >= MAX_SEND_SGE )
\r
2978 IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_SEND,
\r
2979 ("Too many buffers to fit in WR ds_array. Copying data.\n") );
\r
2980 status = __send_copy( p_port, p_desc );
\r
2981 IPOIB_EXIT( IPOIB_DBG_SEND );
\r
2985 CL_ASSERT( tot_len > sizeof(eth_hdr_t) );
\r
2986 CL_ASSERT( tot_len <= p_port->p_adapter->params.xfer_block_size );
\r
2988 * Assume that the ethernet header is always fully contained
\r
2989 * in the first page of the first MDL. This makes for much
\r
2992 offset = MmGetMdlByteOffset( p_mdl ) + sizeof(eth_hdr_t);
\r
2993 CL_ASSERT( offset <= PAGE_SIZE );
\r
2997 buf_len = MmGetMdlByteCount( p_mdl );
\r
2998 page_array = MmGetMdlPfnArray( p_mdl );
\r
2999 CL_ASSERT( page_array );
\r
3003 CL_ASSERT( buf_len >= sizeof(eth_hdr_t) );
\r
3004 /* Skip the ethernet header. */
\r
3005 buf_len -= sizeof(eth_hdr_t);
\r
3006 CL_ASSERT( buf_len <= p_port->p_adapter->params.payload_mtu );
\r
3009 /* The ethernet header is a subset of this MDL. */
\r
3010 CL_ASSERT( i == 0 );
\r
3011 if( offset < PAGE_SIZE )
\r
3013 p_desc->local_ds[j].lkey = p_port->ib_mgr.lkey;
\r
3014 p_desc->local_ds[j].vaddr = (page_array[i] << PAGE_SHIFT);
\r