[IPoIB] Use regular mutex so PnP callback runs at PASSIVE to support MTHCA driver.
[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 \r
725         IPOIB_ENTER( IPOIB_DBG_INIT );\r
726 \r
727         p_adapter->hung = FALSE;\r
728         p_adapter->reset = TRUE;\r
729 \r
730         if( p_adapter->h_pnp )\r
731         {\r
732                 status = p_adapter->p_ifc->dereg_pnp(\r
733                         p_adapter->h_pnp, __ipoib_pnp_dereg );\r
734                 p_adapter->h_pnp = NULL;\r
735                 if( status == IB_SUCCESS )\r
736                         status = IB_NOT_DONE;\r
737         }\r
738         else\r
739         {\r
740                 status = __ipoib_pnp_reg( p_adapter, IB_PNP_FLAG_REG_COMPLETE );\r
741                 if( status == IB_SUCCESS )\r
742                         p_adapter->hung = FALSE;\r
743         }\r
744 \r
745         IPOIB_EXIT( IPOIB_DBG_INIT );\r
746         return status;\r
747 }\r
748 \r
749 \r
750 static void\r
751 __ipoib_pnp_dereg(\r
752         IN                              void*                                           context )\r
753 {\r
754         ipoib_adapter_t*        p_adapter;\r
755         ipoib_port_t*           p_port;\r
756         ib_api_status_t         status;\r
757         ib_pnp_event_t          state;\r
758 \r
759         IPOIB_ENTER( IPOIB_DBG_INIT );\r
760 \r
761         p_adapter = PARENT_STRUCT( context, ipoib_adapter_t, obj );\r
762 \r
763         /* Synchronize with destruction */\r
764         KeWaitForMutexObject(\r
765                 &p_adapter->mutex, Executive, KernelMode, FALSE, NULL );\r
766 \r
767         cl_obj_lock( &p_adapter->obj );\r
768 \r
769         CL_ASSERT( !p_adapter->h_pnp );\r
770 \r
771         if( p_adapter->state != IB_PNP_PORT_REMOVE )\r
772                 p_adapter->state = IB_PNP_PORT_ADD;\r
773 \r
774         state = p_adapter->state;\r
775 \r
776         /* Destroy the current port instance if it still exists. */\r
777         p_port = p_adapter->p_port;\r
778         p_adapter->p_port = NULL;\r
779         cl_obj_unlock( &p_adapter->obj );\r
780 \r
781         if( p_port )\r
782                 ipoib_port_destroy( p_port );\r
783 \r
784         if( state != IB_PNP_PORT_REMOVE )\r
785         {\r
786                 status = __ipoib_pnp_reg( p_adapter, IB_PNP_FLAG_REG_COMPLETE );\r
787                 if( status != IB_SUCCESS )\r
788                 {\r
789                         p_adapter->reset = FALSE;\r
790                         IPOIB_TRACE( IPOIB_DBG_ERROR,\r
791                                 ("__ipoib_pnp_reg returned %s\n",\r
792                                 p_adapter->p_ifc->get_err_str( status )) );\r
793                         NdisMResetComplete( \r
794                                 p_adapter->h_adapter, NDIS_STATUS_HARD_ERRORS, TRUE );\r
795                 }\r
796         }\r
797         else\r
798         {\r
799                 p_adapter->reset = FALSE;\r
800                 NdisMResetComplete(\r
801                         p_adapter->h_adapter, NDIS_STATUS_SUCCESS, TRUE );\r
802                 status = IB_SUCCESS;\r
803         }\r
804 \r
805         /* Dereference the adapter since the previous registration is now gone. */\r
806         cl_obj_deref( &p_adapter->obj );\r
807 \r
808         KeReleaseMutex( &p_adapter->mutex, FALSE );\r
809 \r
810         IPOIB_EXIT( IPOIB_DBG_INIT );\r
811 }\r
812 \r
813 \r
814 void\r
815 ipoib_set_rate(\r
816         IN                              ipoib_adapter_t* const          p_adapter,\r
817         IN              const   uint8_t                                         link_width, \r
818         IN              const   uint8_t                                         link_speed )\r
819 {\r
820         IPOIB_ENTER( IPOIB_DBG_INIT );\r
821 \r
822         cl_obj_lock( &p_adapter->obj );\r
823         /* Set the link speed based on the IB link speed (1x vs 4x, etc). */\r
824         switch( link_speed )\r
825         {\r
826         case IB_LINK_SPEED_ACTIVE_2_5:\r
827                 IPOIB_TRACE( IPOIB_DBG_INIT | IPOIB_DBG_INFO,\r
828                         ("Link speed is 2.5Gs\n") );\r
829                 p_adapter->rate = IB_LINK_SPEED_ACTIVE_2_5;\r
830                 break;\r
831 \r
832         case IB_LINK_SPEED_ACTIVE_5:\r
833                 IPOIB_TRACE( IPOIB_DBG_INIT | IPOIB_DBG_INFO,\r
834                         ("Link speed is 5G\n") );\r
835                 p_adapter->rate = IB_LINK_SPEED_ACTIVE_5;\r
836                 break;\r
837 \r
838         case IB_LINK_SPEED_ACTIVE_10:\r
839                 IPOIB_TRACE( IPOIB_DBG_INIT | IPOIB_DBG_INFO,\r
840                         ("Link speed is 10G\n") );\r
841                 p_adapter->rate = IB_LINK_SPEED_ACTIVE_10;\r
842                 break;\r
843 \r
844         default:\r
845                 IPOIB_TRACE( IPOIB_DBG_ERROR,\r
846                         ("Invalid link speed %d.\n", link_speed) );\r
847                 p_adapter->rate = 0;\r
848         }\r
849 \r
850         switch( link_width )\r
851         {\r
852         case IB_LINK_WIDTH_ACTIVE_1X:\r
853                 IPOIB_TRACE( IPOIB_DBG_INIT | IPOIB_DBG_INFO,\r
854                         ("Link width is 1X\n") );\r
855                 p_adapter->rate *= ONE_X_IN_100BPS;\r
856                 break;\r
857 \r
858         case IB_LINK_WIDTH_ACTIVE_4X:\r
859                 IPOIB_TRACE( IPOIB_DBG_INIT | IPOIB_DBG_INFO,\r
860                         ("Link width is 4X\n") );\r
861                 p_adapter->rate *= FOUR_X_IN_100BPS;\r
862                 break;\r
863 \r
864         case IB_LINK_WIDTH_ACTIVE_12X:\r
865                 IPOIB_TRACE( IPOIB_DBG_INIT | IPOIB_DBG_INFO,\r
866                         ("Link width is 12X\n") );\r
867                 p_adapter->rate *= TWELVE_X_IN_100BPS;\r
868                 break;\r
869 \r
870         default:\r
871                 IPOIB_TRACE( IPOIB_DBG_ERROR,\r
872                         ("Invalid link rate (%d).\n", link_width) );\r
873                 p_adapter->rate = 0;\r
874         }\r
875         cl_obj_unlock( &p_adapter->obj );\r
876         IPOIB_EXIT( IPOIB_DBG_INIT );\r
877 }\r
878 \r
879 \r
880 void\r
881 ipoib_set_active(\r
882         IN                              ipoib_adapter_t* const          p_adapter )\r
883 {\r
884         ib_pnp_event_t  old_state;\r
885         uint8_t                 i;\r
886 \r
887         IPOIB_ENTER( IPOIB_DBG_INIT );\r
888 \r
889         cl_obj_lock( &p_adapter->obj );\r
890         old_state = p_adapter->state;\r
891 \r
892         /* Change the state to indicate that we are now connected and live. */\r
893         if( old_state != IB_PNP_PORT_REMOVE )\r
894                 p_adapter->state = IB_PNP_PORT_ACTIVE;\r
895 \r
896         cl_obj_unlock( &p_adapter->obj );\r
897 \r
898         /*\r
899          * If we had a pending OID request for OID_GEN_LINK_SPEED,\r
900          * complete it now.\r
901          */\r
902         switch( old_state )\r
903         {\r
904         case IB_PNP_PORT_ADD:\r
905                 ipoib_reg_addrs( p_adapter );\r
906                 /* Fall through. */\r
907 \r
908         case IB_PNP_PORT_REMOVE:\r
909                 ipoib_resume_oids( p_adapter );\r
910                 break;\r
911 \r
912         default:\r
913                 /* Join all programmed multicast groups. */\r
914                 for( i = 0; i < p_adapter->mcast_array_size; i++ )\r
915                 {\r
916                         ipoib_port_join_mcast(\r
917                                 p_adapter->p_port, p_adapter->mcast_array[i] );\r
918                 }\r
919 \r
920                 /* Register all existing addresses. */\r
921                 ipoib_reg_addrs( p_adapter );\r
922 \r
923                 /*\r
924                  * Now that we're in the broadcast group, notify that\r
925                  * we have a link.\r
926                  */\r
927                 IPOIB_TRACE( IPOIB_DBG_INFO, ("Link UP!\n") );\r
928                 NdisWriteErrorLogEntry( p_adapter->h_adapter,\r
929                         EVENT_IPOIB_PORT_UP + (p_adapter->rate/ONE_X_IN_100BPS),\r
930                         1, p_adapter->rate );\r
931 \r
932                 NdisMIndicateStatus( p_adapter->h_adapter, NDIS_STATUS_MEDIA_CONNECT,\r
933                         NULL, 0 );\r
934                 NdisMIndicateStatusComplete( p_adapter->h_adapter );\r
935         }\r
936 \r
937         if( p_adapter->reset )\r
938         {\r
939                 p_adapter->reset = FALSE;\r
940                 NdisMResetComplete(\r
941                         p_adapter->h_adapter, NDIS_STATUS_SUCCESS, TRUE );\r
942         }\r
943 \r
944         IPOIB_EXIT( IPOIB_DBG_INIT );\r
945 }\r
946 \r
947 \r
948 NDIS_STATUS\r
949 ipoib_get_recv_stat(\r
950         IN                              ipoib_adapter_t* const          p_adapter,\r
951         IN              const   ip_stat_sel_t                           stat_sel,\r
952         IN                              pending_oid_t* const            p_oid_info )\r
953 {\r
954         uint64_t        stat;\r
955 \r
956         IPOIB_ENTER( IPOIB_DBG_INFO );\r
957 \r
958         CL_ASSERT( p_adapter );\r
959 \r
960         cl_spinlock_acquire( &p_adapter->recv_stat_lock );\r
961         switch( stat_sel )\r
962         {\r
963         case IP_STAT_SUCCESS:\r
964                 stat = p_adapter->recv_stats.comp.success;\r
965                 break;\r
966 \r
967         case IP_STAT_ERROR:\r
968                 stat = p_adapter->recv_stats.comp.error;\r
969                 break;\r
970 \r
971         case IP_STAT_DROPPED:\r
972                 stat = p_adapter->recv_stats.comp.dropped;\r
973                 break;\r
974 \r
975         case IP_STAT_UCAST_BYTES:\r
976                 stat = p_adapter->recv_stats.ucast.bytes;\r
977                 break;\r
978 \r
979         case IP_STAT_UCAST_FRAMES:\r
980                 stat = p_adapter->recv_stats.ucast.frames;\r
981                 break;\r
982 \r
983         case IP_STAT_BCAST_BYTES:\r
984                 stat = p_adapter->recv_stats.bcast.bytes;\r
985                 break;\r
986 \r
987         case IP_STAT_BCAST_FRAMES:\r
988                 stat = p_adapter->recv_stats.bcast.frames;\r
989                 break;\r
990 \r
991         case IP_STAT_MCAST_BYTES:\r
992                 stat = p_adapter->recv_stats.mcast.bytes;\r
993                 break;\r
994 \r
995         case IP_STAT_MCAST_FRAMES:\r
996                 stat = p_adapter->recv_stats.mcast.frames;\r
997                 break;\r
998 \r
999         default:\r
1000                 stat = 0;\r
1001         }\r
1002         cl_spinlock_release( &p_adapter->recv_stat_lock );\r
1003 \r
1004         *p_oid_info->p_bytes_needed = sizeof(uint64_t);\r
1005 \r
1006         if( p_oid_info->buf_len >= sizeof(uint64_t) )\r
1007         {\r
1008                 *((uint64_t*)p_oid_info->p_buf) = stat;\r
1009                 *p_oid_info->p_bytes_used = sizeof(uint64_t);\r
1010         }\r
1011         else if( p_oid_info->buf_len >= sizeof(uint32_t) )\r
1012         {\r
1013                 *((uint32_t*)p_oid_info->p_buf) = (uint32_t)stat;\r
1014                 *p_oid_info->p_bytes_used = sizeof(uint32_t);\r
1015         }\r
1016         else\r
1017         {\r
1018                 *p_oid_info->p_bytes_used = 0;\r
1019                 IPOIB_EXIT( IPOIB_DBG_INFO );\r
1020                 return NDIS_STATUS_INVALID_LENGTH;\r
1021         }\r
1022 \r
1023         IPOIB_EXIT( IPOIB_DBG_INFO );\r
1024         return NDIS_STATUS_SUCCESS;\r
1025 }\r
1026 \r
1027 \r
1028 void\r
1029 ipoib_inc_recv_stat(\r
1030         IN                              ipoib_adapter_t* const          p_adapter,\r
1031         IN              const   ip_stat_sel_t                           stat_sel,\r
1032         IN              const   size_t                                          bytes OPTIONAL )\r
1033 {\r
1034         IPOIB_ENTER( IPOIB_DBG_INFO );\r
1035 \r
1036         cl_spinlock_acquire( &p_adapter->recv_stat_lock );\r
1037         switch( stat_sel )\r
1038         {\r
1039         case IP_STAT_ERROR:\r
1040                 p_adapter->recv_stats.comp.error++;\r
1041                 break;\r
1042 \r
1043         case IP_STAT_DROPPED:\r
1044                 p_adapter->recv_stats.comp.dropped++;\r
1045                 break;\r
1046 \r
1047         case IP_STAT_UCAST_BYTES:\r
1048         case IP_STAT_UCAST_FRAMES:\r
1049                 p_adapter->recv_stats.comp.success++;\r
1050                 p_adapter->recv_stats.ucast.frames++;\r
1051                 p_adapter->recv_stats.ucast.bytes += bytes;\r
1052                 break;\r
1053 \r
1054         case IP_STAT_BCAST_BYTES:\r
1055         case IP_STAT_BCAST_FRAMES:\r
1056                 p_adapter->recv_stats.comp.success++;\r
1057                 p_adapter->recv_stats.bcast.frames++;\r
1058                 p_adapter->recv_stats.bcast.bytes += bytes;\r
1059                 break;\r
1060 \r
1061         case IP_STAT_MCAST_BYTES:\r
1062         case IP_STAT_MCAST_FRAMES:\r
1063                 p_adapter->recv_stats.comp.success++;\r
1064                 p_adapter->recv_stats.mcast.frames++;\r
1065                 p_adapter->recv_stats.mcast.bytes += bytes;\r
1066                 break;\r
1067 \r
1068         default:\r
1069                 break;\r
1070         }\r
1071         cl_spinlock_release( &p_adapter->recv_stat_lock );\r
1072 \r
1073         IPOIB_EXIT( IPOIB_DBG_INFO );\r
1074 }\r
1075 \r
1076 NDIS_STATUS\r
1077 ipoib_get_send_stat(\r
1078         IN                              ipoib_adapter_t* const          p_adapter,\r
1079         IN              const   ip_stat_sel_t                           stat_sel,\r
1080         IN                              pending_oid_t* const            p_oid_info )\r
1081 {\r
1082         uint64_t        stat;\r
1083 \r
1084         IPOIB_ENTER( IPOIB_DBG_INFO );\r
1085 \r
1086         CL_ASSERT( p_adapter );\r
1087 \r
1088         cl_spinlock_acquire( &p_adapter->send_stat_lock );\r
1089         switch( stat_sel )\r
1090         {\r
1091         case IP_STAT_SUCCESS:\r
1092                 stat = p_adapter->send_stats.comp.success;\r
1093                 break;\r
1094 \r
1095         case IP_STAT_ERROR:\r
1096                 stat = p_adapter->send_stats.comp.error;\r
1097                 break;\r
1098 \r
1099         case IP_STAT_DROPPED:\r
1100                 stat = p_adapter->send_stats.comp.dropped;\r
1101                 break;\r
1102 \r
1103         case IP_STAT_UCAST_BYTES:\r
1104                 stat = p_adapter->send_stats.ucast.bytes;\r
1105                 break;\r
1106 \r
1107         case IP_STAT_UCAST_FRAMES:\r
1108                 stat = p_adapter->send_stats.ucast.frames;\r
1109                 break;\r
1110 \r
1111         case IP_STAT_BCAST_BYTES:\r
1112                 stat = p_adapter->send_stats.bcast.bytes;\r
1113                 break;\r
1114 \r
1115         case IP_STAT_BCAST_FRAMES:\r
1116                 stat = p_adapter->send_stats.bcast.frames;\r
1117                 break;\r
1118 \r
1119         case IP_STAT_MCAST_BYTES:\r
1120                 stat = p_adapter->send_stats.mcast.bytes;\r
1121                 break;\r
1122 \r
1123         case IP_STAT_MCAST_FRAMES:\r
1124                 stat = p_adapter->send_stats.mcast.frames;\r
1125                 break;\r
1126 \r
1127         default:\r
1128                 stat = 0;\r
1129         }\r
1130         cl_spinlock_release( &p_adapter->send_stat_lock );\r
1131 \r
1132         *p_oid_info->p_bytes_needed = sizeof(uint64_t);\r
1133 \r
1134         if( p_oid_info->buf_len >= sizeof(uint64_t) )\r
1135         {\r
1136                 *((uint64_t*)p_oid_info->p_buf) = stat;\r
1137                 *p_oid_info->p_bytes_used = sizeof(uint64_t);\r
1138         }\r
1139         else if( p_oid_info->buf_len >= sizeof(uint32_t) )\r
1140         {\r
1141                 *((uint32_t*)p_oid_info->p_buf) = (uint32_t)stat;\r
1142                 *p_oid_info->p_bytes_used = sizeof(uint32_t);\r
1143         }\r
1144         else\r
1145         {\r
1146                 *p_oid_info->p_bytes_used = 0;\r
1147                 IPOIB_EXIT( IPOIB_DBG_INFO );\r
1148                 return NDIS_STATUS_INVALID_LENGTH;\r
1149         }\r
1150 \r
1151         IPOIB_EXIT( IPOIB_DBG_INFO );\r
1152         return NDIS_STATUS_SUCCESS;\r
1153 }\r
1154 \r
1155 \r
1156 void\r
1157 ipoib_inc_send_stat(\r
1158         IN                              ipoib_adapter_t* const          p_adapter,\r
1159         IN              const   ip_stat_sel_t                           stat_sel,\r
1160         IN              const   size_t                                          bytes OPTIONAL )\r
1161 {\r
1162         IPOIB_ENTER( IPOIB_DBG_INFO );\r
1163 \r
1164         cl_spinlock_acquire( &p_adapter->send_stat_lock );\r
1165         switch( stat_sel )\r
1166         {\r
1167         case IP_STAT_ERROR:\r
1168                 p_adapter->send_stats.comp.error++;\r
1169                 break;\r
1170 \r
1171         case IP_STAT_DROPPED:\r
1172                 p_adapter->send_stats.comp.dropped++;\r
1173                 break;\r
1174 \r
1175         case IP_STAT_UCAST_BYTES:\r
1176         case IP_STAT_UCAST_FRAMES:\r
1177                 p_adapter->send_stats.comp.success++;\r
1178                 p_adapter->send_stats.ucast.frames++;\r
1179                 p_adapter->send_stats.ucast.bytes += bytes;\r
1180                 break;\r
1181 \r
1182         case IP_STAT_BCAST_BYTES:\r
1183         case IP_STAT_BCAST_FRAMES:\r
1184                 p_adapter->send_stats.comp.success++;\r
1185                 p_adapter->send_stats.bcast.frames++;\r
1186                 p_adapter->send_stats.bcast.bytes += bytes;\r
1187                 break;\r
1188 \r
1189         case IP_STAT_MCAST_BYTES:\r
1190         case IP_STAT_MCAST_FRAMES:\r
1191                 p_adapter->send_stats.comp.success++;\r
1192                 p_adapter->send_stats.mcast.frames++;\r
1193                 p_adapter->send_stats.mcast.bytes += bytes;\r
1194                 break;\r
1195 \r
1196         default:\r
1197                 break;\r
1198         }\r
1199         cl_spinlock_release( &p_adapter->send_stat_lock );\r
1200 \r
1201         IPOIB_EXIT( IPOIB_DBG_INFO );\r
1202 }\r