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