[ipoib] mcast garbage collector and igmp V2 support.
[mirror/winof/.git] / ulp / ipoib / kernel / ipoib_adapter.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  * Copyright (c) 2006 Mellanox Technologies.  All rights reserved.\r
4  * Portions Copyright (c) 2008 Microsoft Corporation.  All rights reserved.\r
5  *\r
6  * This software is available to you under the OpenIB.org BSD license\r
7  * below:\r
8  *\r
9  *     Redistribution and use in source and binary forms, with or\r
10  *     without modification, are permitted provided that the following\r
11  *     conditions are met:\r
12  *\r
13  *      - Redistributions of source code must retain the above\r
14  *        copyright notice, this list of conditions and the following\r
15  *        disclaimer.\r
16  *\r
17  *      - Redistributions in binary form must reproduce the above\r
18  *        copyright notice, this list of conditions and the following\r
19  *        disclaimer in the documentation and/or other materials\r
20  *        provided with the distribution.\r
21  *\r
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
23  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
25  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
26  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
27  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
28  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
29  * SOFTWARE.\r
30  *\r
31  * $Id$\r
32  */\r
33 \r
34 \r
35 \r
36 #include "ipoib_adapter.h"\r
37 #include "ipoib_port.h"\r
38 #include "ipoib_driver.h"\r
39 #include "ipoib_debug.h"\r
40 \r
41 #if defined(EVENT_TRACING)\r
42 #ifdef offsetof\r
43 #undef offsetof\r
44 #endif\r
45 #include "ipoib_adapter.tmh"\r
46 #endif\r
47 \r
48 \r
49 #define ITEM_POOL_START         16\r
50 #define ITEM_POOL_GROW          16\r
51 \r
52 \r
53 /* IB Link speeds in 100bps */\r
54 #define ONE_X_IN_100BPS         25000000\r
55 #define FOUR_X_IN_100BPS        100000000\r
56 #define TWELVE_X_IN_100BPS      300000000\r
57 \r
58 \r
59 /* Declarations */\r
60 static void\r
61 adapter_construct(\r
62         IN                              ipoib_adapter_t* const          p_adapter );\r
63 \r
64 \r
65 static ib_api_status_t\r
66 adapter_init(\r
67         IN                              ipoib_adapter_t* const          p_adapter );\r
68 \r
69 \r
70 static void\r
71 __adapter_destroying(\r
72         IN                              cl_obj_t* const                         p_obj );\r
73 \r
74 \r
75 static void\r
76 __adapter_cleanup(\r
77         IN                              cl_obj_t* const                         p_obj );\r
78 \r
79 \r
80 static void\r
81 __adapter_free(\r
82         IN                              cl_obj_t* const                         p_obj );\r
83 \r
84 \r
85 static ib_api_status_t\r
86 __ipoib_pnp_reg(\r
87         IN                              ipoib_adapter_t* const          p_adapter,\r
88         IN                              ib_pnp_class_t                          flags );\r
89 \r
90 \r
91 static void\r
92 __ipoib_pnp_dereg(\r
93         IN                              void*                                           context );\r
94 \r
95 \r
96 static void\r
97 __ipoib_adapter_reset(\r
98         IN                              void*   context);\r
99 \r
100 \r
101 static ib_api_status_t\r
102 __ipoib_pnp_cb(\r
103         IN                              ib_pnp_rec_t                            *p_pnp_rec );\r
104 \r
105 \r
106 void\r
107 ipoib_join_mcast(\r
108         IN                              ipoib_adapter_t* const          p_adapter );\r
109 \r
110 \r
111 /* Leaves all mcast groups when port goes down. */\r
112 static void\r
113 ipoib_clear_mcast(\r
114         IN                              ipoib_port_t* const                     p_port );\r
115 \r
116 NDIS_STATUS\r
117 ipoib_get_adapter_guids(\r
118         IN                              NDIS_HANDLE* const                      h_adapter,\r
119         IN      OUT                     ipoib_adapter_t                         *p_adapter );\r
120 \r
121 NDIS_STATUS\r
122 ipoib_get_adapter_params(\r
123         IN                              NDIS_HANDLE* const                      wrapper_config_context,\r
124         IN      OUT                     ipoib_adapter_t                         *p_adapter );\r
125 \r
126 \r
127 /* Implementation */\r
128 ib_api_status_t\r
129 ipoib_create_adapter(\r
130         IN                              NDIS_HANDLE                                     wrapper_config_context,\r
131         IN                              void* const                                     h_adapter,\r
132                 OUT                     ipoib_adapter_t** const         pp_adapter )\r
133 {\r
134         ipoib_adapter_t         *p_adapter;\r
135         ib_api_status_t         status;\r
136         cl_status_t                     cl_status;\r
137 \r
138         IPOIB_ENTER( IPOIB_DBG_INIT );\r
139 \r
140         p_adapter = cl_zalloc( sizeof(ipoib_adapter_t) );\r
141         if( !p_adapter )\r
142         {\r
143                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
144                         ("Failed to allocate ipoib_adapter_t (%d bytes)",\r
145                         sizeof(ipoib_adapter_t)) );\r
146                 return IB_INSUFFICIENT_MEMORY;\r
147         }\r
148 \r
149         adapter_construct( p_adapter );\r
150 \r
151         p_adapter->h_adapter = h_adapter;\r
152 \r
153         p_adapter->p_ifc = cl_zalloc( sizeof(ib_al_ifc_t) );\r
154         if( !p_adapter->p_ifc )\r
155         {\r
156                 __adapter_free( &p_adapter->obj );\r
157                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
158                         ("ipoib_create_adapter failed to alloc ipoib_ifc_t %d bytes\n",\r
159                         sizeof(ib_al_ifc_t)) );\r
160                 return IB_INSUFFICIENT_MEMORY;\r
161         }\r
162 \r
163         /* Get the CA and port GUID from the bus driver. */\r
164         status = ipoib_get_adapter_guids( h_adapter,  p_adapter );\r
165         if( status != NDIS_STATUS_SUCCESS )\r
166         {\r
167                 __adapter_free( &p_adapter->obj );\r
168                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
169                         ("ipoib_get_adapter_guids returned 0x%.8X.\n", status) );\r
170                 return status;\r
171         }\r
172 \r
173         IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
174                         ("Port %016I64x (CA %016I64x port %d) initializing\n",\r
175                         p_adapter->guids.port_guid.guid, p_adapter->guids.ca_guid,\r
176                         p_adapter->guids.port_num) );\r
177 \r
178         cl_status = cl_obj_init( &p_adapter->obj, CL_DESTROY_SYNC,\r
179                 __adapter_destroying, NULL, __adapter_free );\r
180         if( cl_status != CL_SUCCESS )\r
181         {\r
182                 __adapter_free( &p_adapter->obj );\r
183                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
184                         ("cl_obj_init returned %#x\n", cl_status) );\r
185                 return IB_ERROR;\r
186         }\r
187 \r
188         status = adapter_init( p_adapter );\r
189         if( status != IB_SUCCESS )\r
190         {\r
191                 cl_obj_destroy( &p_adapter->obj );\r
192                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
193                         ("adapter_init returned %s.\n", \r
194                         p_adapter->p_ifc->get_err_str( status )) );\r
195                 return status;\r
196         }\r
197 \r
198         /* Read configuration parameters. */\r
199         status = ipoib_get_adapter_params( wrapper_config_context,\r
200                 p_adapter );\r
201         if( status != NDIS_STATUS_SUCCESS )\r
202         {\r
203                 cl_obj_destroy( &p_adapter->obj );\r
204                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
205                         ("ipoib_get_adapter_params returned 0x%.8x.\n", status) );\r
206                 return status;\r
207         }\r
208 \r
209         *pp_adapter = p_adapter;\r
210 \r
211         IPOIB_EXIT( IPOIB_DBG_INIT );\r
212         return status;\r
213 }\r
214 \r
215 \r
216 ib_api_status_t\r
217 ipoib_start_adapter(\r
218         IN                              ipoib_adapter_t* const          p_adapter )\r
219 {\r
220         ib_api_status_t status;\r
221 \r
222         IPOIB_ENTER( IPOIB_DBG_INIT );\r
223 \r
224         status = __ipoib_pnp_reg( p_adapter,\r
225                 IB_PNP_FLAG_REG_SYNC | IB_PNP_FLAG_REG_COMPLETE );\r
226 \r
227         IPOIB_EXIT( IPOIB_DBG_INIT );\r
228         return status;\r
229 }\r
230 \r
231 \r
232 void\r
233 ipoib_destroy_adapter(\r
234         IN                              ipoib_adapter_t* const          p_adapter )\r
235 {\r
236         IPOIB_ENTER( IPOIB_DBG_INIT );\r
237 \r
238         CL_ASSERT( p_adapter );\r
239 \r
240         /*\r
241          * Flag the adapter as being removed.  We use the IB_PNP_PORT_REMOVE state\r
242          * for this purpose.  Note that we protect this state change with both the\r
243          * mutex and the lock.  The mutex provides synchronization as a whole\r
244          * between destruction and AL callbacks (PnP, Query, Destruction).\r
245          * The lock provides protection\r
246          */\r
247         KeWaitForMutexObject(\r
248                 &p_adapter->mutex, Executive, KernelMode, FALSE, NULL );\r
249         cl_obj_lock( &p_adapter->obj );\r
250         p_adapter->state = IB_PNP_PORT_REMOVE;\r
251 \r
252         /*\r
253          * Clear the pointer to the port object since the object destruction\r
254          * will cascade to child objects.  This prevents potential duplicate\r
255          * destruction (or worse, stale pointer usage).\r
256          */\r
257         p_adapter->p_port = NULL;\r
258 \r
259         cl_obj_unlock( &p_adapter->obj );\r
260 \r
261         KeReleaseMutex( &p_adapter->mutex, FALSE );\r
262 \r
263         cl_obj_destroy( &p_adapter->obj );\r
264 \r
265         IPOIB_EXIT( IPOIB_DBG_INIT );\r
266 }\r
267 \r
268 \r
269 static void\r
270 adapter_construct(\r
271         IN                              ipoib_adapter_t* const          p_adapter )\r
272 {\r
273         cl_obj_construct( &p_adapter->obj, IPOIB_OBJ_INSTANCE );\r
274         cl_spinlock_construct( &p_adapter->send_stat_lock );\r
275         cl_spinlock_construct( &p_adapter->recv_stat_lock );\r
276         cl_qpool_construct( &p_adapter->item_pool );\r
277         KeInitializeMutex( &p_adapter->mutex, 0 );\r
278 \r
279         cl_thread_construct(&p_adapter->destroy_thread);\r
280         \r
281         cl_vector_construct( &p_adapter->ip_vector );\r
282 \r
283         cl_perf_construct( &p_adapter->perf );\r
284 \r
285         p_adapter->state = IB_PNP_PORT_ADD;\r
286         p_adapter->rate = FOUR_X_IN_100BPS;\r
287 }\r
288 \r
289 \r
290 static ib_api_status_t\r
291 adapter_init(\r
292         IN                              ipoib_adapter_t* const          p_adapter )\r
293 {\r
294         cl_status_t                     cl_status;\r
295         ib_api_status_t         status;\r
296 \r
297         IPOIB_ENTER( IPOIB_DBG_INIT );\r
298 \r
299         cl_status = cl_perf_init( &p_adapter->perf, MaxPerf );\r
300         if( cl_status != CL_SUCCESS )\r
301         {\r
302                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
303                         ("cl_perf_init returned %#x\n", cl_status) );\r
304                 return IB_ERROR;\r
305         }\r
306 \r
307         cl_status = cl_spinlock_init( &p_adapter->send_stat_lock );\r
308         if( cl_status != CL_SUCCESS )\r
309         {\r
310                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
311                         ("cl_spinlock_init returned %#x\n", cl_status) );\r
312                 return IB_ERROR;\r
313         }\r
314 \r
315         cl_status = cl_spinlock_init( &p_adapter->recv_stat_lock );\r
316         if( cl_status != CL_SUCCESS )\r
317         {\r
318                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
319                         ("cl_spinlock_init returned %#x\n", cl_status) );\r
320                 return IB_ERROR;\r
321         }\r
322 \r
323         cl_status = cl_qpool_init( &p_adapter->item_pool, ITEM_POOL_START, 0,\r
324                 ITEM_POOL_GROW, sizeof(cl_pool_obj_t), NULL, NULL, NULL );\r
325         if( cl_status != CL_SUCCESS )\r
326         {\r
327                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
328                         ("cl_qpool_init returned %#x\n", cl_status) );\r
329                 return IB_ERROR;\r
330         }\r
331 \r
332 \r
333         /* We manually manage the size and capacity of the vector. */\r
334         cl_status = cl_vector_init( &p_adapter->ip_vector, 0,\r
335                 0, sizeof(net_address_item_t), NULL, NULL, p_adapter );\r
336         if( cl_status != CL_SUCCESS )\r
337         {\r
338                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
339                         ("cl_vector_init for ip_vector returned %#x\n",\r
340                         cl_status) );\r
341                 return IB_ERROR;\r
342         }\r
343 \r
344 \r
345         /* Validate the port GUID and generate the MAC address. */\r
346         status =\r
347                 ipoib_mac_from_guid( p_adapter->guids.port_guid.guid, &p_adapter->mac );\r
348         if( status != IB_SUCCESS )\r
349         {\r
350                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
351                         ("ipoib_mac_from_guid returned %s\n", \r
352                         p_adapter->p_ifc->get_err_str( status )) );\r
353                 return status;\r
354         }\r
355 \r
356         \r
357         \r
358         /* Open AL. */\r
359         status = p_adapter->p_ifc->open_al( &p_adapter->h_al );\r
360         if( status != IB_SUCCESS )\r
361         {\r
362                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
363                         ("ib_open_al returned %s\n", \r
364                         p_adapter->p_ifc->get_err_str( status )) );\r
365                 return status;\r
366         }\r
367 \r
368         IPOIB_EXIT( IPOIB_DBG_INIT );\r
369         return status;\r
370 }\r
371 \r
372 \r
373 static ib_api_status_t\r
374 __ipoib_pnp_reg(\r
375         IN                              ipoib_adapter_t* const          p_adapter,\r
376         IN                              ib_pnp_class_t                          flags )\r
377 {\r
378         ib_api_status_t         status;\r
379         ib_pnp_req_t            pnp_req;\r
380         \r
381         IPOIB_ENTER( IPOIB_DBG_INIT );\r
382 \r
383         CL_ASSERT( !p_adapter->h_pnp );\r
384         CL_ASSERT( !p_adapter->registering );\r
385 \r
386         p_adapter->registering = TRUE;\r
387         \r
388         /* Register for PNP events. */\r
389         cl_memclr( &pnp_req, sizeof(pnp_req) );\r
390         pnp_req.pnp_class = IB_PNP_PORT | flags;\r
391         /*\r
392          * Context is the cl_obj of the adapter to allow passing cl_obj_deref\r
393          * to ib_dereg_pnp.\r
394          */\r
395         pnp_req.pnp_context = &p_adapter->obj;\r
396         pnp_req.pfn_pnp_cb = __ipoib_pnp_cb;\r
397         status = p_adapter->p_ifc->reg_pnp( p_adapter->h_al, &pnp_req, &p_adapter->h_pnp );\r
398         if( status != IB_SUCCESS )\r
399         {\r
400                 p_adapter->registering = FALSE;\r
401                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
402                         ("ib_reg_pnp returned %s\n", \r
403                         p_adapter->p_ifc->get_err_str( status )) );\r
404                 return status;\r
405         }\r
406         /*\r
407          * Reference the adapter on behalf of the PNP registration.\r
408          * This allows the destruction to block until the PNP deregistration\r
409          * completes.\r
410          */\r
411         cl_obj_ref( &p_adapter->obj );\r
412 \r
413         IPOIB_EXIT( IPOIB_DBG_INIT );\r
414         return status;\r
415 }\r
416 \r
417 \r
418 static void\r
419 __adapter_destroying(\r
420         IN                              cl_obj_t* const                         p_obj )\r
421 {\r
422         ipoib_adapter_t         *p_adapter;\r
423         KLOCK_QUEUE_HANDLE      hdl;\r
424 \r
425         IPOIB_ENTER( IPOIB_DBG_INIT );\r
426 \r
427         p_adapter = PARENT_STRUCT( p_obj, ipoib_adapter_t, obj );\r
428 \r
429         /*\r
430          * The adapter's object will be dereferenced when the deregistration\r
431          * completes.  No need to lock here since all PnP related API calls\r
432          * are driven by NDIS (via the Init/Reset/Destroy paths).\r
433          */\r
434         if( p_adapter->h_pnp )\r
435         {\r
436                 p_adapter->p_ifc->dereg_pnp( p_adapter->h_pnp, cl_obj_deref );\r
437                 p_adapter->h_pnp = NULL;\r
438         }\r
439 \r
440         if( p_adapter->packet_filter )\r
441         {\r
442                 KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl );\r
443                 cl_obj_lock( &p_adapter->obj );\r
444 \r
445                 ASSERT( cl_qlist_count( &g_ipoib.adapter_list ) );\r
446                 cl_qlist_remove_item( &g_ipoib.adapter_list, &p_adapter->entry );\r
447 \r
448                 p_adapter->packet_filter = 0;\r
449 \r
450                 cl_obj_unlock( &p_adapter->obj );\r
451                 KeReleaseInStackQueuedSpinLock( &hdl );\r
452         }\r
453 \r
454         IPOIB_EXIT( IPOIB_DBG_INIT );\r
455 }\r
456 \r
457 \r
458 static void\r
459 __adapter_free(\r
460         IN                              cl_obj_t* const                         p_obj )\r
461 {\r
462         ipoib_adapter_t *p_adapter;\r
463 \r
464         IPOIB_ENTER( IPOIB_DBG_INIT );\r
465 \r
466         p_adapter = PARENT_STRUCT( p_obj, ipoib_adapter_t, obj );\r
467 \r
468         if( p_adapter->p_ifc )\r
469         {\r
470                 if( p_adapter->h_al )\r
471                         p_adapter->p_ifc->close_al( p_adapter->h_al );\r
472 \r
473                 cl_free( p_adapter->p_ifc );\r
474         }\r
475 \r
476         cl_vector_destroy( &p_adapter->ip_vector );\r
477         cl_qpool_destroy( &p_adapter->item_pool );\r
478         cl_spinlock_destroy( &p_adapter->recv_stat_lock );\r
479         cl_spinlock_destroy( &p_adapter->send_stat_lock );\r
480         cl_obj_deinit( p_obj );\r
481 \r
482         cl_perf_destroy( &p_adapter->perf, TRUE );\r
483 \r
484         cl_free( p_adapter );\r
485 \r
486         IPOIB_EXIT( IPOIB_DBG_INIT );\r
487 }\r
488 \r
489 \r
490 static ib_api_status_t\r
491 __ipoib_pnp_cb(\r
492         IN                              ib_pnp_rec_t                            *p_pnp_rec )\r
493 {\r
494         ib_api_status_t         status;\r
495         ipoib_adapter_t         *p_adapter;\r
496         ipoib_port_t            *p_port;\r
497         ib_pnp_event_t          old_state;\r
498         ib_pnp_port_rec_t       *p_port_rec;\r
499 \r
500         IPOIB_ENTER( IPOIB_DBG_PNP );\r
501 \r
502         CL_ASSERT( p_pnp_rec );\r
503 \r
504         p_adapter =\r
505                 PARENT_STRUCT( p_pnp_rec->pnp_context, ipoib_adapter_t, obj );\r
506 \r
507         CL_ASSERT( p_adapter );\r
508 \r
509         /* Synchronize with destruction */\r
510         KeWaitForMutexObject(\r
511                 &p_adapter->mutex, Executive, KernelMode, FALSE, NULL );\r
512         cl_obj_lock( &p_adapter->obj );\r
513         old_state = p_adapter->state;\r
514         cl_obj_unlock( &p_adapter->obj );\r
515         if( old_state == IB_PNP_PORT_REMOVE )\r
516         {\r
517                 KeReleaseMutex( &p_adapter->mutex, FALSE );\r
518                 IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_PNP,\r
519                         ("Aborting - Adapter destroying.\n") );\r
520                 return IB_NOT_DONE;\r
521         }\r
522 \r
523         IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_PNP,\r
524                 ("p_pnp_rec->pnp_event = 0x%x (%s)\n",\r
525                 p_pnp_rec->pnp_event, ib_get_pnp_event_str( p_pnp_rec->pnp_event )) );\r
526 \r
527         p_port_rec = (ib_pnp_port_rec_t*)p_pnp_rec;\r
528 \r
529         switch( p_pnp_rec->pnp_event )\r
530         {\r
531         case IB_PNP_PORT_ADD:\r
532                 CL_ASSERT( !p_pnp_rec->context );\r
533                 /* Only process our port GUID. */\r
534                 if( p_pnp_rec->guid != p_adapter->guids.port_guid.guid )\r
535                 {\r
536                         status = IB_NOT_DONE;\r
537                         break;\r
538                 }\r
539 \r
540                 /* Don't process if we're destroying. */\r
541                 if( p_adapter->obj.state == CL_DESTROYING )\r
542                 {\r
543                         status = IB_NOT_DONE;\r
544                         break;\r
545                 }\r
546 \r
547                 CL_ASSERT( !p_adapter->p_port );\r
548                 /* Allocate all IB resources. */\r
549                 cl_obj_lock( &p_adapter->obj );\r
550                 p_adapter->state = IB_PNP_PORT_ADD;\r
551                 cl_obj_unlock( &p_adapter->obj );\r
552                 status = ipoib_create_port( p_adapter, p_port_rec, &p_port );\r
553                 cl_obj_lock( &p_adapter->obj );\r
554                 if( status != IB_SUCCESS )\r
555                 {\r
556                         p_adapter->state = old_state;\r
557                         cl_obj_unlock( &p_adapter->obj );\r
558                         p_adapter->hung = TRUE;\r
559                         break;\r
560                 }\r
561 \r
562                 p_pnp_rec->context = p_port;\r
563 \r
564                 p_adapter->p_port = p_port;\r
565                 cl_obj_unlock( &p_adapter->obj );\r
566                 break;\r
567 \r
568         case IB_PNP_PORT_REMOVE:\r
569                 /* Release all IB resources. */\r
570                 CL_ASSERT( p_pnp_rec->context );\r
571 \r
572                 cl_obj_lock( &p_adapter->obj );\r
573                 p_adapter->state = IB_PNP_PORT_REMOVE;\r
574                 p_port = p_adapter->p_port;\r
575                 p_adapter->p_port = NULL;\r
576                 cl_obj_unlock( &p_adapter->obj );\r
577                 ipoib_port_destroy( p_port );\r
578                 p_pnp_rec->context = NULL;\r
579                 status = IB_SUCCESS;\r
580                 break;\r
581 \r
582         case IB_PNP_PORT_ACTIVE:\r
583                 /* Join multicast groups and put QP in RTS. */\r
584                 CL_ASSERT( p_pnp_rec->context );\r
585 \r
586                 cl_obj_lock( &p_adapter->obj );\r
587                 p_adapter->state = IB_PNP_PORT_INIT;\r
588                 cl_obj_unlock( &p_adapter->obj );\r
589                 ipoib_port_up( p_adapter->p_port, p_port_rec );\r
590 \r
591                 status = IB_SUCCESS;\r
592                 break;\r
593 \r
594         case IB_PNP_PORT_ARMED:\r
595                 status = IB_SUCCESS;\r
596                 break;\r
597 \r
598         case IB_PNP_PORT_INIT:\r
599                 /*\r
600                  * Init could happen if the SM brings the port down\r
601                  * without changing the physical link.\r
602                  */\r
603         case IB_PNP_PORT_DOWN:\r
604                 CL_ASSERT( p_pnp_rec->context );\r
605 \r
606                 cl_obj_lock( &p_adapter->obj );\r
607                 old_state = p_adapter->state;\r
608                 p_adapter->state = IB_PNP_PORT_DOWN;\r
609                 cl_obj_unlock( &p_adapter->obj );\r
610                 status = IB_SUCCESS;\r
611 \r
612                 if( !p_adapter->registering && old_state != IB_PNP_PORT_DOWN )\r
613                 {\r
614                         NdisMIndicateStatus( p_adapter->h_adapter,\r
615                                 NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0 );\r
616                         NdisMIndicateStatusComplete( p_adapter->h_adapter );\r
617 \r
618                         IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
619                                 ("Link DOWN!\n") );\r
620 \r
621                         ipoib_port_down( p_adapter->p_port );\r
622                 }\r
623                 break;\r
624 \r
625         case IB_PNP_REG_COMPLETE:\r
626                 if( p_adapter->registering )\r
627                 {\r
628                         p_adapter->registering = FALSE;\r
629                         cl_obj_lock( &p_adapter->obj );\r
630                         old_state = p_adapter->state;\r
631                         cl_obj_unlock( &p_adapter->obj );\r
632 \r
633                         if( old_state == IB_PNP_PORT_DOWN )\r
634                         {\r
635                                 /* If we were initializing, we might have pended some OIDs. */\r
636                                 ipoib_resume_oids( p_adapter );\r
637                                 NdisMIndicateStatus( p_adapter->h_adapter,\r
638                                         NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0 );\r
639                                 NdisMIndicateStatusComplete( p_adapter->h_adapter );\r
640                         }\r
641                 }\r
642 \r
643                 if( p_adapter->reset && p_adapter->state != IB_PNP_PORT_INIT )\r
644                 {\r
645                         p_adapter->reset = FALSE;\r
646                         NdisMResetComplete(\r
647                                 p_adapter->h_adapter, NDIS_STATUS_SUCCESS, TRUE );\r
648                 }\r
649                 status = IB_SUCCESS;\r
650                 break;\r
651 \r
652         default:\r
653                 IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
654                         ("IPOIB: Received unhandled PnP event 0x%x (%s)\n",\r
655                         p_pnp_rec->pnp_event, ib_get_pnp_event_str( p_pnp_rec->pnp_event )) );\r
656                 /* Fall through. */\r
657         case IB_PNP_PKEY_CHANGE:\r
658         case IB_PNP_SM_CHANGE:\r
659         case IB_PNP_GID_CHANGE:\r
660         case IB_PNP_LID_CHANGE:\r
661                 status = IB_SUCCESS;\r
662 \r
663                 /* We ignore this event if the link is not active. */\r
664                 if( p_port_rec->p_port_attr->link_state != IB_LINK_ACTIVE )\r
665                         break;\r
666 \r
667                 cl_obj_lock( &p_adapter->obj );\r
668                 old_state = p_adapter->state;\r
669                 switch( old_state )\r
670                 {\r
671                 case IB_PNP_PORT_DOWN:\r
672                         p_adapter->state = IB_PNP_PORT_INIT;\r
673                         break;\r
674 \r
675                 default:\r
676                         p_adapter->state = IB_PNP_PORT_DOWN;\r
677                 }\r
678                 cl_obj_unlock( &p_adapter->obj );\r
679                 \r
680                 if( p_adapter->registering )\r
681                         break;\r
682 \r
683                 switch( old_state )\r
684                 {\r
685                 case IB_PNP_PORT_ACTIVE:\r
686                 case IB_PNP_PORT_INIT:\r
687                         NdisMIndicateStatus( p_adapter->h_adapter,\r
688                                 NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0 );\r
689                         NdisMIndicateStatusComplete( p_adapter->h_adapter );\r
690 \r
691                         IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
692                                 ("Link DOWN!\n") );\r
693 \r
694                         ipoib_port_down( p_adapter->p_port );\r
695                         /* Fall through. */\r
696 \r
697                 case IB_PNP_PORT_DOWN:\r
698                         cl_obj_lock( &p_adapter->obj );\r
699                         p_adapter->state = IB_PNP_PORT_INIT;\r
700                         cl_obj_unlock( &p_adapter->obj );\r
701                         ipoib_port_up( p_adapter->p_port, (ib_pnp_port_rec_t*)p_pnp_rec );\r
702                 }\r
703                 break;\r
704         }\r
705 \r
706         KeReleaseMutex( &p_adapter->mutex, FALSE );\r
707 \r
708         IPOIB_EXIT( IPOIB_DBG_PNP );\r
709         return status;\r
710 }\r
711 \r
712 \r
713 /* Joins/leaves mcast groups based on currently programmed mcast MACs. */\r
714 void\r
715 ipoib_refresh_mcast(\r
716         IN                              ipoib_adapter_t* const          p_adapter,\r
717         IN                              mac_addr_t* const                       p_mac_array,\r
718         IN              const   uint8_t                                         num_macs )\r
719 {\r
720         uint8_t                         i, j;\r
721         ipoib_port_t            *p_port = NULL;\r
722 \r
723         IPOIB_ENTER( IPOIB_DBG_MCAST );\r
724         cl_obj_lock( &p_adapter->obj );\r
725         if( p_adapter->state == IB_PNP_PORT_ACTIVE )\r
726         {\r
727                 p_port = p_adapter->p_port;\r
728                 ipoib_port_ref( p_port, ref_refresh_mcast );\r
729         }\r
730         cl_obj_unlock( &p_adapter->obj );\r
731 \r
732         if( p_port )\r
733         {\r
734                 /* Purge old entries. */\r
735                 for( i = 0; i < p_adapter->mcast_array_size; i++ )\r
736                 {\r
737                         for( j = 0; j < num_macs; j++ )\r
738                         {\r
739                                 if( !cl_memcmp( &p_adapter->mcast_array[i], &p_mac_array[j],\r
740                                         sizeof(mac_addr_t) ) )\r
741                                 {\r
742                                         break;\r
743                                 }\r
744                         }\r
745                         if( j != num_macs )\r
746                                 continue;\r
747 \r
748                         ipoib_port_remove_endpt( p_port, p_adapter->mcast_array[i] );\r
749                 }\r
750 \r
751                 /* Add new entries */\r
752                 for( i = 0; i < num_macs; i++ )\r
753                 {\r
754                         for( j = 0; j < p_adapter->mcast_array_size; j++ )\r
755                         {\r
756                                 if( !cl_memcmp( &p_adapter->mcast_array[j], &p_mac_array[i],\r
757                                         sizeof(mac_addr_t) ) )\r
758                                 {\r
759                                         break;\r
760                                 }\r
761                         }\r
762 \r
763                         if( j != p_adapter->mcast_array_size )\r
764                                 continue;\r
765                         if ( ( p_mac_array[i].addr[0] == 1 && p_mac_array[i].addr[1] == 0 && p_mac_array[i].addr[2] == 0x5e &&\r
766                                    p_mac_array[i].addr[3] == 0 && p_mac_array[i].addr[4] == 0 && p_mac_array[i].addr[5] == 1 ) ||\r
767                                   !( p_mac_array[i].addr[0] == 1 && p_mac_array[i].addr[1] == 0 && p_mac_array[i].addr[2] == 0x5e )\r
768                                 )\r
769                         {\r
770                                 ipoib_port_join_mcast( p_port, p_mac_array[i], IB_MC_REC_STATE_FULL_MEMBER );\r
771                         }\r
772                 }\r
773         }\r
774 \r
775         /* Copy the MAC array. */\r
776         NdisMoveMemory( p_adapter->mcast_array, p_mac_array,\r
777                 num_macs * sizeof(mac_addr_t) );\r
778         p_adapter->mcast_array_size = num_macs;\r
779 \r
780         if( p_port )\r
781                 ipoib_port_deref( p_port, ref_refresh_mcast );\r
782 \r
783         IPOIB_EXIT( IPOIB_DBG_MCAST );\r
784 }\r
785 \r
786 \r
787 ib_api_status_t\r
788 ipoib_reset_adapter(\r
789         IN                              ipoib_adapter_t* const          p_adapter )\r
790 {\r
791         ib_api_status_t         status;\r
792         ib_pnp_handle_t         h_pnp;\r
793 \r
794         IPOIB_ENTER( IPOIB_DBG_INIT );\r
795 \r
796         if( p_adapter->reset )\r
797                 return IB_INVALID_STATE;\r
798 \r
799         p_adapter->hung = FALSE;\r
800         p_adapter->reset = TRUE;\r
801 \r
802         if( p_adapter->h_pnp )\r
803         {\r
804                 h_pnp = p_adapter->h_pnp;\r
805                 p_adapter->h_pnp  = NULL;\r
806                 status = p_adapter->p_ifc->dereg_pnp( h_pnp, __ipoib_pnp_dereg );\r
807                 if( status == IB_SUCCESS )\r
808                         status = IB_NOT_DONE;\r
809         }\r
810         else\r
811         {\r
812                 status = __ipoib_pnp_reg( p_adapter, IB_PNP_FLAG_REG_COMPLETE );\r
813                 if( status == IB_SUCCESS )\r
814                         p_adapter->hung = FALSE;\r
815         }\r
816         if (status == IB_NOT_DONE) {\r
817                 p_adapter->reset = TRUE;\r
818         }\r
819         else {\r
820                 p_adapter->reset = FALSE;\r
821         }\r
822         IPOIB_EXIT( IPOIB_DBG_INIT );\r
823         return status;\r
824 }\r
825 \r
826 \r
827 static void\r
828 __ipoib_pnp_dereg(\r
829         IN                              void*                                           context )\r
830 {\r
831         ipoib_adapter_t*        p_adapter;\r
832 \r
833         IPOIB_ENTER( IPOIB_DBG_INIT );\r
834 \r
835         p_adapter = PARENT_STRUCT( context, ipoib_adapter_t, obj );\r
836 \r
837         cl_thread_init(&p_adapter->destroy_thread, __ipoib_adapter_reset, (void*)p_adapter, "destroy_thread");\r
838         \r
839         IPOIB_ENTER( IPOIB_DBG_INIT );\r
840 \r
841 }\r
842 \r
843 static void\r
844 __ipoib_adapter_reset(\r
845         IN                              void*   context)\r
846 {\r
847 \r
848         ipoib_adapter_t *p_adapter;\r
849         ipoib_port_t            *p_port;\r
850         ib_api_status_t         status;\r
851         ib_pnp_event_t          state;\r
852         \r
853         IPOIB_ENTER( IPOIB_DBG_INIT );\r
854 \r
855         p_adapter = (ipoib_adapter_t*)context;\r
856         \r
857         /* Synchronize with destruction */\r
858         KeWaitForMutexObject(\r
859                 &p_adapter->mutex, Executive, KernelMode, FALSE, NULL );\r
860 \r
861         cl_obj_lock( &p_adapter->obj );\r
862 \r
863         CL_ASSERT( !p_adapter->h_pnp );\r
864 \r
865         if( p_adapter->state != IB_PNP_PORT_REMOVE )\r
866                 p_adapter->state = IB_PNP_PORT_ADD;\r
867 \r
868         state = p_adapter->state;\r
869 \r
870         /* Destroy the current port instance if it still exists. */\r
871         p_port = p_adapter->p_port;\r
872         p_adapter->p_port = NULL;\r
873         cl_obj_unlock( &p_adapter->obj );\r
874 \r
875         if( p_port )\r
876                 ipoib_port_destroy( p_port );\r
877         ASSERT(p_adapter->reset == TRUE);\r
878         if( state != IB_PNP_PORT_REMOVE )\r
879         {\r
880                 status = __ipoib_pnp_reg( p_adapter, IB_PNP_FLAG_REG_COMPLETE );\r
881                 if( status != IB_SUCCESS )\r
882                 {\r
883                         p_adapter->reset = FALSE;\r
884                         IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
885                                 ("__ipoib_pnp_reg returned %s\n",\r
886                                 p_adapter->p_ifc->get_err_str( status )) );\r
887                         NdisMResetComplete( \r
888                                 p_adapter->h_adapter, NDIS_STATUS_HARD_ERRORS, TRUE );\r
889                 }\r
890         }\r
891         else\r
892         {\r
893                 p_adapter->reset = FALSE;\r
894                 NdisMResetComplete(\r
895                         p_adapter->h_adapter, NDIS_STATUS_SUCCESS, TRUE );\r
896                 status = IB_SUCCESS;\r
897         }\r
898 \r
899         /* Dereference the adapter since the previous registration is now gone. */\r
900         cl_obj_deref( &p_adapter->obj );\r
901 \r
902         KeReleaseMutex( &p_adapter->mutex, FALSE );\r
903 \r
904         IPOIB_EXIT( IPOIB_DBG_INIT );\r
905 }\r
906 \r
907 \r
908 void\r
909 ipoib_set_rate(\r
910         IN                              ipoib_adapter_t* const          p_adapter,\r
911         IN              const   uint8_t                                         link_width, \r
912         IN              const   uint8_t                                         link_speed )\r
913 {\r
914         uint32_t        rate;\r
915 \r
916         IPOIB_ENTER( IPOIB_DBG_INIT );\r
917 \r
918         /* Set the link speed based on the IB link speed (1x vs 4x, etc). */\r
919         switch( link_speed )\r
920         {\r
921         case IB_LINK_SPEED_ACTIVE_2_5:\r
922                 IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
923                         ("Link speed is 2.5Gs\n") );\r
924                 rate = IB_LINK_SPEED_ACTIVE_2_5;\r
925                 break;\r
926 \r
927         case IB_LINK_SPEED_ACTIVE_5:\r
928                 IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
929                         ("Link speed is 5G\n") );\r
930                 rate = IB_LINK_SPEED_ACTIVE_5;\r
931                 break;\r
932 \r
933         case IB_LINK_SPEED_ACTIVE_10:\r
934                 IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
935                         ("Link speed is 10G\n") );\r
936                 rate = IB_LINK_SPEED_ACTIVE_10;\r
937                 break;\r
938 \r
939         default:\r
940                 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
941                         ("Invalid link speed %d.\n", link_speed) );\r
942                 rate = 0;\r
943         }\r
944 \r
945         switch( link_width )\r
946         {\r
947         case IB_LINK_WIDTH_ACTIVE_1X:\r
948                 IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
949                         ("Link width is 1X\n") );\r
950                 rate *= ONE_X_IN_100BPS;\r
951                 break;\r
952 \r
953         case IB_LINK_WIDTH_ACTIVE_4X:\r
954                 IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
955                         ("Link width is 4X\n") );\r
956                 rate *= FOUR_X_IN_100BPS;\r
957                 break;\r
958 \r
959         case IB_LINK_WIDTH_ACTIVE_12X:\r
960                 IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT,\r
961                         ("Link width is 12X\n") );\r
962                 rate *= TWELVE_X_IN_100BPS;\r
963                 break;\r
964 \r
965         default:\r
966                 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
967                         ("Invalid link rate (%d).\n", link_width) );\r
968                 rate = 0;\r
969         }\r
970 \r
971         p_adapter->rate = rate;\r
972         IPOIB_EXIT( IPOIB_DBG_INIT );\r
973 }\r
974 \r
975 \r
976 void\r
977 ipoib_set_active(\r
978         IN                              ipoib_adapter_t* const          p_adapter )\r
979 {\r
980         ib_pnp_event_t  old_state;\r
981         uint8_t                 i;\r
982 \r
983         IPOIB_ENTER( IPOIB_DBG_INIT );\r
984 \r
985         cl_obj_lock( &p_adapter->obj );\r
986         old_state = p_adapter->state;\r
987 \r
988         /* Change the state to indicate that we are now connected and live. */\r
989         if( old_state == IB_PNP_PORT_INIT )\r
990                 p_adapter->state = IB_PNP_PORT_ACTIVE;\r
991 \r
992         cl_obj_unlock( &p_adapter->obj );\r
993 \r
994         /*\r
995          * If we had a pending OID request for OID_GEN_LINK_SPEED,\r
996          * complete it now.\r
997          */\r
998         switch( old_state )\r
999         {\r
1000         case IB_PNP_PORT_ADD:\r
1001                 ipoib_reg_addrs( p_adapter );\r
1002                 /* Fall through. */\r
1003 \r
1004         case IB_PNP_PORT_REMOVE:\r
1005                 ipoib_resume_oids( p_adapter );\r
1006                 break;\r
1007 \r
1008         default:\r
1009                 /* Join all programmed multicast groups. */\r
1010                 for( i = 0; i < p_adapter->mcast_array_size; i++ )\r
1011                 {\r
1012                         ipoib_port_join_mcast(\r
1013                                 p_adapter->p_port, p_adapter->mcast_array[i] ,IB_MC_REC_STATE_FULL_MEMBER);\r
1014                 }\r
1015 \r
1016                 /* Register all existing addresses. */\r
1017                 ipoib_reg_addrs( p_adapter );\r
1018 \r
1019                 ipoib_resume_oids( p_adapter );\r
1020 \r
1021                 /*\r
1022                  * Now that we're in the broadcast group, notify that\r
1023                  * we have a link.\r
1024                  */\r
1025                 IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_INIT, ("Link UP!\n") );\r
1026                 NdisWriteErrorLogEntry( p_adapter->h_adapter,\r
1027                         EVENT_IPOIB_PORT_UP + (p_adapter->rate/ONE_X_IN_100BPS),\r
1028                         1, p_adapter->rate );\r
1029 \r
1030                 if( !p_adapter->reset )\r
1031                 {\r
1032                         NdisMIndicateStatus( p_adapter->h_adapter, NDIS_STATUS_MEDIA_CONNECT,\r
1033                                 NULL, 0 );\r
1034                         NdisMIndicateStatusComplete( p_adapter->h_adapter );\r
1035                 }\r
1036         }\r
1037 \r
1038         if( p_adapter->reset )\r
1039         {\r
1040                 p_adapter->reset = FALSE;\r
1041                 NdisMResetComplete(\r
1042                         p_adapter->h_adapter, NDIS_STATUS_SUCCESS, TRUE );\r
1043         }\r
1044 \r
1045         IPOIB_EXIT( IPOIB_DBG_INIT );\r
1046 }\r
1047 \r
1048 \r
1049 /*\r
1050  * If something goes wrong after the port goes active, e.g.\r
1051  *      - PortInfo query failure\r
1052  *      - MC Join timeout\r
1053  *      - etc\r
1054  * Mark the port state as down, resume any pended OIDS, etc.\r
1055  */\r
1056 void\r
1057 ipoib_set_inactive(\r
1058         IN                              ipoib_adapter_t* const          p_adapter )\r
1059 {\r
1060         ib_pnp_event_t  old_state;\r
1061 \r
1062         IPOIB_ENTER( IPOIB_DBG_INIT );\r
1063 \r
1064         cl_obj_lock( &p_adapter->obj );\r
1065         old_state = p_adapter->state;\r
1066         if( old_state != IB_PNP_PORT_REMOVE )\r
1067                 p_adapter->state = IB_PNP_PORT_DOWN;\r
1068         cl_obj_unlock( &p_adapter->obj );\r
1069 \r
1070         /*\r
1071          * If we had a pending OID request for OID_GEN_LINK_SPEED,\r
1072          * complete it now.\r
1073          */\r
1074         if( old_state == IB_PNP_PORT_INIT )\r
1075         {\r
1076                 NdisMIndicateStatus( p_adapter->h_adapter,\r
1077                         NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0 );\r
1078                 NdisMIndicateStatusComplete( p_adapter->h_adapter );\r
1079 \r
1080                 ipoib_resume_oids( p_adapter );\r
1081         }\r
1082 \r
1083         if( p_adapter->reset )\r
1084         {\r
1085                 p_adapter->reset = FALSE;\r
1086                 NdisMResetComplete(\r
1087                         p_adapter->h_adapter, NDIS_STATUS_SUCCESS, TRUE );\r
1088         }\r
1089 \r
1090         IPOIB_EXIT( IPOIB_DBG_INIT );\r
1091 }\r
1092 \r
1093 \r
1094 NDIS_STATUS\r
1095 ipoib_get_recv_stat(\r
1096         IN                              ipoib_adapter_t* const          p_adapter,\r
1097         IN              const   ip_stat_sel_t                           stat_sel,\r
1098         IN                              pending_oid_t* const            p_oid_info )\r
1099 {\r
1100         uint64_t        stat;\r
1101 \r
1102         IPOIB_ENTER( IPOIB_DBG_STAT );\r
1103 \r
1104         CL_ASSERT( p_adapter );\r
1105 \r
1106         cl_spinlock_acquire( &p_adapter->recv_stat_lock );\r
1107         switch( stat_sel )\r
1108         {\r
1109         case IP_STAT_SUCCESS:\r
1110                 stat = p_adapter->recv_stats.comp.success;\r
1111                 break;\r
1112 \r
1113         case IP_STAT_ERROR:\r
1114                 stat = p_adapter->recv_stats.comp.error;\r
1115                 break;\r
1116 \r
1117         case IP_STAT_DROPPED:\r
1118                 stat = p_adapter->recv_stats.comp.dropped;\r
1119                 break;\r
1120 \r
1121         case IP_STAT_UCAST_BYTES:\r
1122                 stat = p_adapter->recv_stats.ucast.bytes;\r
1123                 break;\r
1124 \r
1125         case IP_STAT_UCAST_FRAMES:\r
1126                 stat = p_adapter->recv_stats.ucast.frames;\r
1127                 break;\r
1128 \r
1129         case IP_STAT_BCAST_BYTES:\r
1130                 stat = p_adapter->recv_stats.bcast.bytes;\r
1131                 break;\r
1132 \r
1133         case IP_STAT_BCAST_FRAMES:\r
1134                 stat = p_adapter->recv_stats.bcast.frames;\r
1135                 break;\r
1136 \r
1137         case IP_STAT_MCAST_BYTES:\r
1138                 stat = p_adapter->recv_stats.mcast.bytes;\r
1139                 break;\r
1140 \r
1141         case IP_STAT_MCAST_FRAMES:\r
1142                 stat = p_adapter->recv_stats.mcast.frames;\r
1143                 break;\r
1144 \r
1145         default:\r
1146                 stat = 0;\r
1147         }\r
1148         cl_spinlock_release( &p_adapter->recv_stat_lock );\r
1149 \r
1150         *p_oid_info->p_bytes_needed = sizeof(uint64_t);\r
1151 \r
1152         if( p_oid_info->buf_len >= sizeof(uint64_t) )\r
1153         {\r
1154                 *((uint64_t*)p_oid_info->p_buf) = stat;\r
1155                 *p_oid_info->p_bytes_used = sizeof(uint64_t);\r
1156         }\r
1157         else if( p_oid_info->buf_len >= sizeof(uint32_t) )\r
1158         {\r
1159                 *((uint32_t*)p_oid_info->p_buf) = (uint32_t)stat;\r
1160                 *p_oid_info->p_bytes_used = sizeof(uint32_t);\r
1161         }\r
1162         else\r
1163         {\r
1164                 *p_oid_info->p_bytes_used = 0;\r
1165                 IPOIB_EXIT( IPOIB_DBG_STAT );\r
1166                 return NDIS_STATUS_INVALID_LENGTH;\r
1167         }\r
1168 \r
1169         IPOIB_EXIT( IPOIB_DBG_STAT );\r
1170         return NDIS_STATUS_SUCCESS;\r
1171 }\r
1172 \r
1173 \r
1174 void\r
1175 ipoib_inc_recv_stat(\r
1176         IN                              ipoib_adapter_t* const          p_adapter,\r
1177         IN              const   ip_stat_sel_t                           stat_sel,\r
1178         IN              const   size_t                                          bytes OPTIONAL )\r
1179 {\r
1180         IPOIB_ENTER( IPOIB_DBG_STAT );\r
1181 \r
1182         cl_spinlock_acquire( &p_adapter->recv_stat_lock );\r
1183         switch( stat_sel )\r
1184         {\r
1185         case IP_STAT_ERROR:\r
1186                 p_adapter->recv_stats.comp.error++;\r
1187                 break;\r
1188 \r
1189         case IP_STAT_DROPPED:\r
1190                 p_adapter->recv_stats.comp.dropped++;\r
1191                 break;\r
1192 \r
1193         case IP_STAT_UCAST_BYTES:\r
1194         case IP_STAT_UCAST_FRAMES:\r
1195                 p_adapter->recv_stats.comp.success++;\r
1196                 p_adapter->recv_stats.ucast.frames++;\r
1197                 p_adapter->recv_stats.ucast.bytes += bytes;\r
1198                 break;\r
1199 \r
1200         case IP_STAT_BCAST_BYTES:\r
1201         case IP_STAT_BCAST_FRAMES:\r
1202                 p_adapter->recv_stats.comp.success++;\r
1203                 p_adapter->recv_stats.bcast.frames++;\r
1204                 p_adapter->recv_stats.bcast.bytes += bytes;\r
1205                 break;\r
1206 \r
1207         case IP_STAT_MCAST_BYTES:\r
1208         case IP_STAT_MCAST_FRAMES:\r
1209                 p_adapter->recv_stats.comp.success++;\r
1210                 p_adapter->recv_stats.mcast.frames++;\r
1211                 p_adapter->recv_stats.mcast.bytes += bytes;\r
1212                 break;\r
1213 \r
1214         default:\r
1215                 break;\r
1216         }\r
1217         cl_spinlock_release( &p_adapter->recv_stat_lock );\r
1218 \r
1219         IPOIB_EXIT( IPOIB_DBG_STAT );\r
1220 }\r
1221 \r
1222 NDIS_STATUS\r
1223 ipoib_get_send_stat(\r
1224         IN                              ipoib_adapter_t* const          p_adapter,\r
1225         IN              const   ip_stat_sel_t                           stat_sel,\r
1226         IN                              pending_oid_t* const            p_oid_info )\r
1227 {\r
1228         uint64_t        stat;\r
1229 \r
1230         IPOIB_ENTER( IPOIB_DBG_STAT );\r
1231 \r
1232         CL_ASSERT( p_adapter );\r
1233 \r
1234         cl_spinlock_acquire( &p_adapter->send_stat_lock );\r
1235         switch( stat_sel )\r
1236         {\r
1237         case IP_STAT_SUCCESS:\r
1238                 stat = p_adapter->send_stats.comp.success;\r
1239                 break;\r
1240 \r
1241         case IP_STAT_ERROR:\r
1242                 stat = p_adapter->send_stats.comp.error;\r
1243                 break;\r
1244 \r
1245         case IP_STAT_DROPPED:\r
1246                 stat = p_adapter->send_stats.comp.dropped;\r
1247                 break;\r
1248 \r
1249         case IP_STAT_UCAST_BYTES:\r
1250                 stat = p_adapter->send_stats.ucast.bytes;\r
1251                 break;\r
1252 \r
1253         case IP_STAT_UCAST_FRAMES:\r
1254                 stat = p_adapter->send_stats.ucast.frames;\r
1255                 break;\r
1256 \r
1257         case IP_STAT_BCAST_BYTES:\r
1258                 stat = p_adapter->send_stats.bcast.bytes;\r
1259                 break;\r
1260 \r
1261         case IP_STAT_BCAST_FRAMES:\r
1262                 stat = p_adapter->send_stats.bcast.frames;\r
1263                 break;\r
1264 \r
1265         case IP_STAT_MCAST_BYTES:\r
1266                 stat = p_adapter->send_stats.mcast.bytes;\r
1267                 break;\r
1268 \r
1269         case IP_STAT_MCAST_FRAMES:\r
1270                 stat = p_adapter->send_stats.mcast.frames;\r
1271                 break;\r
1272 \r
1273         default:\r
1274                 stat = 0;\r
1275         }\r
1276         cl_spinlock_release( &p_adapter->send_stat_lock );\r
1277 \r
1278         *p_oid_info->p_bytes_needed = sizeof(uint64_t);\r
1279 \r
1280         if( p_oid_info->buf_len >= sizeof(uint64_t) )\r
1281         {\r
1282                 *((uint64_t*)p_oid_info->p_buf) = stat;\r
1283                 *p_oid_info->p_bytes_used = sizeof(uint64_t);\r
1284         }\r
1285         else if( p_oid_info->buf_len >= sizeof(uint32_t) )\r
1286         {\r
1287                 *((uint32_t*)p_oid_info->p_buf) = (uint32_t)stat;\r
1288                 *p_oid_info->p_bytes_used = sizeof(uint32_t);\r
1289         }\r
1290         else\r
1291         {\r
1292                 *p_oid_info->p_bytes_used = 0;\r
1293                 IPOIB_EXIT( IPOIB_DBG_STAT );\r
1294                 return NDIS_STATUS_INVALID_LENGTH;\r
1295         }\r
1296 \r
1297         IPOIB_EXIT( IPOIB_DBG_STAT );\r
1298         return NDIS_STATUS_SUCCESS;\r
1299 }\r
1300 \r
1301 \r
1302 void\r
1303 ipoib_inc_send_stat(\r
1304         IN                              ipoib_adapter_t* const          p_adapter,\r
1305         IN              const   ip_stat_sel_t                           stat_sel,\r
1306         IN              const   size_t                                          bytes OPTIONAL )\r
1307 {\r
1308         IPOIB_ENTER( IPOIB_DBG_STAT );\r
1309 \r
1310         cl_spinlock_acquire( &p_adapter->send_stat_lock );\r
1311         switch( stat_sel )\r
1312         {\r
1313         case IP_STAT_ERROR:\r
1314                 p_adapter->send_stats.comp.error++;\r
1315                 break;\r
1316 \r
1317         case IP_STAT_DROPPED:\r
1318                 p_adapter->send_stats.comp.dropped++;\r
1319                 break;\r
1320 \r
1321         case IP_STAT_UCAST_BYTES:\r
1322         case IP_STAT_UCAST_FRAMES:\r
1323                 p_adapter->send_stats.comp.success++;\r
1324                 p_adapter->send_stats.ucast.frames++;\r
1325                 p_adapter->send_stats.ucast.bytes += bytes;\r
1326                 break;\r
1327 \r
1328         case IP_STAT_BCAST_BYTES:\r
1329         case IP_STAT_BCAST_FRAMES:\r
1330                 p_adapter->send_stats.comp.success++;\r
1331                 p_adapter->send_stats.bcast.frames++;\r
1332                 p_adapter->send_stats.bcast.bytes += bytes;\r
1333                 break;\r
1334 \r
1335         case IP_STAT_MCAST_BYTES:\r
1336         case IP_STAT_MCAST_FRAMES:\r
1337                 p_adapter->send_stats.comp.success++;\r
1338                 p_adapter->send_stats.mcast.frames++;\r
1339                 p_adapter->send_stats.mcast.bytes += bytes;\r
1340                 break;\r
1341 \r
1342         default:\r
1343                 break;\r
1344         }\r
1345         cl_spinlock_release( &p_adapter->send_stat_lock );\r
1346 \r
1347         IPOIB_EXIT( IPOIB_DBG_STAT );\r
1348 }\r