[IPoIB] Handle SM reregister/LID change without a reset
[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_PORT_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                 cl_obj_lock( &p_adapter->obj );\r
569                 p_adapter->state = IB_PNP_PORT_INIT;\r
570                 cl_obj_unlock( &p_adapter->obj );\r
571                 ipoib_port_up( p_adapter->p_port, (ib_pnp_port_rec_t*)p_pnp_rec );\r
572 \r
573                 status = IB_SUCCESS;\r
574                 break;\r
575 \r
576         case IB_PNP_PORT_ARMED:\r
577                 status = IB_SUCCESS;\r
578                 break;\r
579 \r
580         case IB_PNP_PORT_INIT:\r
581                 /*\r
582                  * Init could happen if the SM brings the port down\r
583                  * without changing the physical link.\r
584                  */\r
585         case IB_PNP_PORT_DOWN:\r
586                 CL_ASSERT( p_pnp_rec->context );\r
587 \r
588                 cl_obj_lock( &p_adapter->obj );\r
589                 old_state = p_adapter->state;\r
590                 p_adapter->state = IB_PNP_PORT_DOWN;\r
591                 cl_obj_unlock( &p_adapter->obj );\r
592                 status = IB_SUCCESS;\r
593 \r
594                 if( !p_adapter->registering && old_state != IB_PNP_PORT_DOWN )\r
595                 {\r
596                         NdisMIndicateStatus( p_adapter->h_adapter,\r
597                                 NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0 );\r
598                         NdisMIndicateStatusComplete( p_adapter->h_adapter );\r
599 \r
600                         IPOIB_TRACE( IPOIB_DBG_INFO, ("Link DOWN!\n") );\r
601 \r
602                         ipoib_port_down( p_adapter->p_port );\r
603                 }\r
604                 break;\r
605 \r
606         case IB_PNP_REG_COMPLETE:\r
607                 if( p_adapter->registering )\r
608                 {\r
609                         p_adapter->registering = FALSE;\r
610                         cl_obj_lock( &p_adapter->obj );\r
611                         old_state = p_adapter->state;\r
612                         cl_obj_unlock( &p_adapter->obj );\r
613 \r
614                         if( old_state == IB_PNP_PORT_DOWN )\r
615                         {\r
616                                 /* If we were initializing, we might have pended some OIDs. */\r
617                                 ipoib_resume_oids( p_adapter );\r
618                                 NdisMIndicateStatus( p_adapter->h_adapter,\r
619                                         NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0 );\r
620                                 NdisMIndicateStatusComplete( p_adapter->h_adapter );\r
621                         }\r
622                 }\r
623 \r
624                 if( p_adapter->reset && p_adapter->state != IB_PNP_PORT_INIT )\r
625                 {\r
626                         p_adapter->reset = FALSE;\r
627                         NdisMResetComplete(\r
628                                 p_adapter->h_adapter, NDIS_STATUS_SUCCESS, TRUE );\r
629                 }\r
630                 status = IB_SUCCESS;\r
631                 break;\r
632 \r
633         default:\r
634                 IPOIB_TRACE( IPOIB_DBG_INFO,\r
635                         ("IPOIB: Received unhandled PnP event 0x%x\n",\r
636                         p_pnp_rec->pnp_event) );\r
637                 /* Fall through. */\r
638         case IB_PNP_PKEY_CHANGE:\r
639         case IB_PNP_SM_CHANGE:\r
640         case IB_PNP_GID_CHANGE:\r
641         case IB_PNP_LID_CHANGE:\r
642                 cl_obj_lock( &p_adapter->obj );\r
643                 old_state = p_adapter->state;\r
644                 switch( old_state )\r
645                 {\r
646                 case IB_PNP_PORT_DOWN:\r
647                         p_adapter->state = IB_PNP_PORT_INIT;\r
648                         break;\r
649 \r
650                 default:\r
651                         p_adapter->state = IB_PNP_PORT_DOWN;\r
652                 }\r
653                 cl_obj_unlock( &p_adapter->obj );\r
654                 \r
655                 status = IB_SUCCESS;\r
656                 if( p_adapter->registering )\r
657                         break;\r
658 \r
659                 switch( old_state )\r
660                 {\r
661                 case IB_PNP_PORT_ACTIVE:\r
662                         NdisMIndicateStatus( p_adapter->h_adapter,\r
663                                 NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0 );\r
664                         NdisMIndicateStatusComplete( p_adapter->h_adapter );\r
665 \r
666                         IPOIB_TRACE( IPOIB_DBG_INFO, ("Link DOWN!\n") );\r
667 \r
668                         ipoib_port_down( p_adapter->p_port );\r
669                         /* Fall through. */\r
670 \r
671                 case IB_PNP_PORT_DOWN:\r
672                         ipoib_port_up( p_adapter->p_port, (ib_pnp_port_rec_t*)p_pnp_rec );\r
673                 }\r
674                 break;\r
675         }\r
676 \r
677         KeReleaseMutex( &p_adapter->mutex, FALSE );\r
678 \r
679         IPOIB_EXIT( IPOIB_DBG_PNP );\r
680         return status;\r
681 }\r
682 \r
683 \r
684 /* Joins/leaves mcast groups based on currently programmed mcast MACs. */\r
685 void\r
686 ipoib_refresh_mcast(\r
687         IN                              ipoib_adapter_t* const          p_adapter,\r
688         IN                              mac_addr_t* const                       p_mac_array,\r
689         IN              const   uint8_t                                         num_macs )\r
690 {\r
691         uint8_t                         i, j;\r
692         ipoib_port_t            *p_port = NULL;\r
693 \r
694         IPOIB_ENTER( IPOIB_DBG_MCAST );\r
695         cl_obj_lock( &p_adapter->obj );\r
696         if( p_adapter->state == IB_PNP_PORT_ACTIVE )\r
697         {\r
698                 p_port = p_adapter->p_port;\r
699                 cl_obj_ref( &p_port->obj );\r
700         }\r
701         cl_obj_unlock( &p_adapter->obj );\r
702 \r
703         if( p_port )\r
704         {\r
705                 /* Purge old entries. */\r
706                 for( i = 0; i < p_adapter->mcast_array_size; i++ )\r
707                 {\r
708                         for( j = 0; j < num_macs; j++ )\r
709                         {\r
710                                 if( !cl_memcmp( &p_adapter->mcast_array[i], &p_mac_array[j],\r
711                                         sizeof(mac_addr_t) ) )\r
712                                 {\r
713                                         break;\r
714                                 }\r
715                         }\r
716                         if( j != num_macs )\r
717                                 continue;\r
718 \r
719                         ipoib_port_remove_endpt( p_port, p_adapter->mcast_array[i] );\r
720                 }\r
721 \r
722                 /* Add new entries */\r
723                 for( i = 0; i < num_macs; i++ )\r
724                 {\r
725                         for( j = 0; j < p_adapter->mcast_array_size; j++ )\r
726                         {\r
727                                 if( !cl_memcmp( &p_adapter->mcast_array[j], &p_mac_array[i],\r
728                                         sizeof(mac_addr_t) ) )\r
729                                 {\r
730                                         break;\r
731                                 }\r
732                         }\r
733 \r
734                         if( j != p_adapter->mcast_array_size )\r
735                                 continue;\r
736 \r
737                         ipoib_port_join_mcast( p_port, p_mac_array[i] );\r
738                 }\r
739         }\r
740 \r
741         /* Copy the MAC array. */\r
742         NdisMoveMemory( p_adapter->mcast_array, p_mac_array,\r
743                 num_macs * sizeof(mac_addr_t) );\r
744         p_adapter->mcast_array_size = num_macs;\r
745 \r
746         if( p_port )\r
747                 cl_obj_deref( &p_port->obj );\r
748 \r
749         IPOIB_EXIT( IPOIB_DBG_MCAST );\r
750 }\r
751 \r
752 \r
753 ib_api_status_t\r
754 ipoib_reset_adapter(\r
755         IN                              ipoib_adapter_t* const          p_adapter )\r
756 {\r
757         ib_api_status_t         status;\r
758         ib_pnp_handle_t         h_pnp;\r
759 \r
760         IPOIB_ENTER( IPOIB_DBG_INIT );\r
761 \r
762         if( p_adapter->reset )\r
763                 return IB_INVALID_STATE;\r
764 \r
765         p_adapter->hung = FALSE;\r
766         p_adapter->reset = TRUE;\r
767 \r
768         if( p_adapter->h_pnp )\r
769         {\r
770                 h_pnp = p_adapter->h_pnp;\r
771                 p_adapter->h_pnp  = NULL;\r
772                 status = p_adapter->p_ifc->dereg_pnp( h_pnp, __ipoib_pnp_dereg );\r
773                 if( status == IB_SUCCESS )\r
774                         status = IB_NOT_DONE;\r
775         }\r
776         else\r
777         {\r
778                 status = __ipoib_pnp_reg( p_adapter, IB_PNP_FLAG_REG_COMPLETE );\r
779                 if( status == IB_SUCCESS )\r
780                         p_adapter->hung = FALSE;\r
781         }\r
782 \r
783         IPOIB_EXIT( IPOIB_DBG_INIT );\r
784         return status;\r
785 }\r
786 \r
787 \r
788 static void\r
789 __ipoib_pnp_dereg(\r
790         IN                              void*                                           context )\r
791 {\r
792         ipoib_adapter_t*        p_adapter;\r
793         ipoib_port_t*           p_port;\r
794         ib_api_status_t         status;\r
795         ib_pnp_event_t          state;\r
796 \r
797         IPOIB_ENTER( IPOIB_DBG_INIT );\r
798 \r
799         p_adapter = PARENT_STRUCT( context, ipoib_adapter_t, obj );\r
800 \r
801         /* Synchronize with destruction */\r
802         KeWaitForMutexObject(\r
803                 &p_adapter->mutex, Executive, KernelMode, FALSE, NULL );\r
804 \r
805         cl_obj_lock( &p_adapter->obj );\r
806 \r
807         CL_ASSERT( !p_adapter->h_pnp );\r
808 \r
809         if( p_adapter->state != IB_PNP_PORT_REMOVE )\r
810                 p_adapter->state = IB_PNP_PORT_ADD;\r
811 \r
812         state = p_adapter->state;\r
813 \r
814         /* Destroy the current port instance if it still exists. */\r
815         p_port = p_adapter->p_port;\r
816         p_adapter->p_port = NULL;\r
817         cl_obj_unlock( &p_adapter->obj );\r
818 \r
819         if( p_port )\r
820                 ipoib_port_destroy( p_port );\r
821 \r
822         if( state != IB_PNP_PORT_REMOVE )\r
823         {\r
824                 status = __ipoib_pnp_reg( p_adapter, IB_PNP_FLAG_REG_COMPLETE );\r
825                 if( status != IB_SUCCESS )\r
826                 {\r
827                         p_adapter->reset = FALSE;\r
828                         IPOIB_TRACE( IPOIB_DBG_ERROR,\r
829                                 ("__ipoib_pnp_reg returned %s\n",\r
830                                 p_adapter->p_ifc->get_err_str( status )) );\r
831                         NdisMResetComplete( \r
832                                 p_adapter->h_adapter, NDIS_STATUS_HARD_ERRORS, TRUE );\r
833                 }\r
834         }\r
835         else\r
836         {\r
837                 p_adapter->reset = FALSE;\r
838                 NdisMResetComplete(\r
839                         p_adapter->h_adapter, NDIS_STATUS_SUCCESS, TRUE );\r
840                 status = IB_SUCCESS;\r
841         }\r
842 \r
843         /* Dereference the adapter since the previous registration is now gone. */\r
844         cl_obj_deref( &p_adapter->obj );\r
845 \r
846         KeReleaseMutex( &p_adapter->mutex, FALSE );\r
847 \r
848         IPOIB_EXIT( IPOIB_DBG_INIT );\r
849 }\r
850 \r
851 \r
852 void\r
853 ipoib_set_rate(\r
854         IN                              ipoib_adapter_t* const          p_adapter,\r
855         IN              const   uint8_t                                         link_width, \r
856         IN              const   uint8_t                                         link_speed )\r
857 {\r
858         IPOIB_ENTER( IPOIB_DBG_INIT );\r
859 \r
860         cl_obj_lock( &p_adapter->obj );\r
861         /* Set the link speed based on the IB link speed (1x vs 4x, etc). */\r
862         switch( link_speed )\r
863         {\r
864         case IB_LINK_SPEED_ACTIVE_2_5:\r
865                 IPOIB_TRACE( IPOIB_DBG_INIT | IPOIB_DBG_INFO,\r
866                         ("Link speed is 2.5Gs\n") );\r
867                 p_adapter->rate = IB_LINK_SPEED_ACTIVE_2_5;\r
868                 break;\r
869 \r
870         case IB_LINK_SPEED_ACTIVE_5:\r
871                 IPOIB_TRACE( IPOIB_DBG_INIT | IPOIB_DBG_INFO,\r
872                         ("Link speed is 5G\n") );\r
873                 p_adapter->rate = IB_LINK_SPEED_ACTIVE_5;\r
874                 break;\r
875 \r
876         case IB_LINK_SPEED_ACTIVE_10:\r
877                 IPOIB_TRACE( IPOIB_DBG_INIT | IPOIB_DBG_INFO,\r
878                         ("Link speed is 10G\n") );\r
879                 p_adapter->rate = IB_LINK_SPEED_ACTIVE_10;\r
880                 break;\r
881 \r
882         default:\r
883                 IPOIB_TRACE( IPOIB_DBG_ERROR,\r
884                         ("Invalid link speed %d.\n", link_speed) );\r
885                 p_adapter->rate = 0;\r
886         }\r
887 \r
888         switch( link_width )\r
889         {\r
890         case IB_LINK_WIDTH_ACTIVE_1X:\r
891                 IPOIB_TRACE( IPOIB_DBG_INIT | IPOIB_DBG_INFO,\r
892                         ("Link width is 1X\n") );\r
893                 p_adapter->rate *= ONE_X_IN_100BPS;\r
894                 break;\r
895 \r
896         case IB_LINK_WIDTH_ACTIVE_4X:\r
897                 IPOIB_TRACE( IPOIB_DBG_INIT | IPOIB_DBG_INFO,\r
898                         ("Link width is 4X\n") );\r
899                 p_adapter->rate *= FOUR_X_IN_100BPS;\r
900                 break;\r
901 \r
902         case IB_LINK_WIDTH_ACTIVE_12X:\r
903                 IPOIB_TRACE( IPOIB_DBG_INIT | IPOIB_DBG_INFO,\r
904                         ("Link width is 12X\n") );\r
905                 p_adapter->rate *= TWELVE_X_IN_100BPS;\r
906                 break;\r
907 \r
908         default:\r
909                 IPOIB_TRACE( IPOIB_DBG_ERROR,\r
910                         ("Invalid link rate (%d).\n", link_width) );\r
911                 p_adapter->rate = 0;\r
912         }\r
913         cl_obj_unlock( &p_adapter->obj );\r
914         IPOIB_EXIT( IPOIB_DBG_INIT );\r
915 }\r
916 \r
917 \r
918 void\r
919 ipoib_set_active(\r
920         IN                              ipoib_adapter_t* const          p_adapter )\r
921 {\r
922         ib_pnp_event_t  old_state;\r
923         uint8_t                 i;\r
924 \r
925         IPOIB_ENTER( IPOIB_DBG_INIT );\r
926 \r
927         cl_obj_lock( &p_adapter->obj );\r
928         old_state = p_adapter->state;\r
929 \r
930         /* Change the state to indicate that we are now connected and live. */\r
931         if( old_state != IB_PNP_PORT_REMOVE )\r
932                 p_adapter->state = IB_PNP_PORT_ACTIVE;\r
933 \r
934         cl_obj_unlock( &p_adapter->obj );\r
935 \r
936         /*\r
937          * If we had a pending OID request for OID_GEN_LINK_SPEED,\r
938          * complete it now.\r
939          */\r
940         switch( old_state )\r
941         {\r
942         case IB_PNP_PORT_ADD:\r
943                 ipoib_reg_addrs( p_adapter );\r
944                 /* Fall through. */\r
945 \r
946         case IB_PNP_PORT_REMOVE:\r
947                 ipoib_resume_oids( p_adapter );\r
948                 break;\r
949 \r
950         default:\r
951                 /* Join all programmed multicast groups. */\r
952                 for( i = 0; i < p_adapter->mcast_array_size; i++ )\r
953                 {\r
954                         ipoib_port_join_mcast(\r
955                                 p_adapter->p_port, p_adapter->mcast_array[i] );\r
956                 }\r
957 \r
958                 /* Register all existing addresses. */\r
959                 ipoib_reg_addrs( p_adapter );\r
960 \r
961                 ipoib_resume_oids( p_adapter );\r
962 \r
963                 /*\r
964                  * Now that we're in the broadcast group, notify that\r
965                  * we have a link.\r
966                  */\r
967                 IPOIB_TRACE( IPOIB_DBG_INFO, ("Link UP!\n") );\r
968                 NdisWriteErrorLogEntry( p_adapter->h_adapter,\r
969                         EVENT_IPOIB_PORT_UP + (p_adapter->rate/ONE_X_IN_100BPS),\r
970                         1, p_adapter->rate );\r
971 \r
972                 if( !p_adapter->reset )\r
973                 {\r
974                         NdisMIndicateStatus( p_adapter->h_adapter, NDIS_STATUS_MEDIA_CONNECT,\r
975                                 NULL, 0 );\r
976                         NdisMIndicateStatusComplete( p_adapter->h_adapter );\r
977                 }\r
978         }\r
979 \r
980         if( p_adapter->reset )\r
981         {\r
982                 p_adapter->reset = FALSE;\r
983                 NdisMResetComplete(\r
984                         p_adapter->h_adapter, NDIS_STATUS_SUCCESS, TRUE );\r
985         }\r
986 \r
987         IPOIB_EXIT( IPOIB_DBG_INIT );\r
988 }\r
989 \r
990 \r
991 NDIS_STATUS\r
992 ipoib_get_recv_stat(\r
993         IN                              ipoib_adapter_t* const          p_adapter,\r
994         IN              const   ip_stat_sel_t                           stat_sel,\r
995         IN                              pending_oid_t* const            p_oid_info )\r
996 {\r
997         uint64_t        stat;\r
998 \r
999         IPOIB_ENTER( IPOIB_DBG_STAT );\r
1000 \r
1001         CL_ASSERT( p_adapter );\r
1002 \r
1003         cl_spinlock_acquire( &p_adapter->recv_stat_lock );\r
1004         switch( stat_sel )\r
1005         {\r
1006         case IP_STAT_SUCCESS:\r
1007                 stat = p_adapter->recv_stats.comp.success;\r
1008                 break;\r
1009 \r
1010         case IP_STAT_ERROR:\r
1011                 stat = p_adapter->recv_stats.comp.error;\r
1012                 break;\r
1013 \r
1014         case IP_STAT_DROPPED:\r
1015                 stat = p_adapter->recv_stats.comp.dropped;\r
1016                 break;\r
1017 \r
1018         case IP_STAT_UCAST_BYTES:\r
1019                 stat = p_adapter->recv_stats.ucast.bytes;\r
1020                 break;\r
1021 \r
1022         case IP_STAT_UCAST_FRAMES:\r
1023                 stat = p_adapter->recv_stats.ucast.frames;\r
1024                 break;\r
1025 \r
1026         case IP_STAT_BCAST_BYTES:\r
1027                 stat = p_adapter->recv_stats.bcast.bytes;\r
1028                 break;\r
1029 \r
1030         case IP_STAT_BCAST_FRAMES:\r
1031                 stat = p_adapter->recv_stats.bcast.frames;\r
1032                 break;\r
1033 \r
1034         case IP_STAT_MCAST_BYTES:\r
1035                 stat = p_adapter->recv_stats.mcast.bytes;\r
1036                 break;\r
1037 \r
1038         case IP_STAT_MCAST_FRAMES:\r
1039                 stat = p_adapter->recv_stats.mcast.frames;\r
1040                 break;\r
1041 \r
1042         default:\r
1043                 stat = 0;\r
1044         }\r
1045         cl_spinlock_release( &p_adapter->recv_stat_lock );\r
1046 \r
1047         *p_oid_info->p_bytes_needed = sizeof(uint64_t);\r
1048 \r
1049         if( p_oid_info->buf_len >= sizeof(uint64_t) )\r
1050         {\r
1051                 *((uint64_t*)p_oid_info->p_buf) = stat;\r
1052                 *p_oid_info->p_bytes_used = sizeof(uint64_t);\r
1053         }\r
1054         else if( p_oid_info->buf_len >= sizeof(uint32_t) )\r
1055         {\r
1056                 *((uint32_t*)p_oid_info->p_buf) = (uint32_t)stat;\r
1057                 *p_oid_info->p_bytes_used = sizeof(uint32_t);\r
1058         }\r
1059         else\r
1060         {\r
1061                 *p_oid_info->p_bytes_used = 0;\r
1062                 IPOIB_EXIT( IPOIB_DBG_STAT );\r
1063                 return NDIS_STATUS_INVALID_LENGTH;\r
1064         }\r
1065 \r
1066         IPOIB_EXIT( IPOIB_DBG_STAT );\r
1067         return NDIS_STATUS_SUCCESS;\r
1068 }\r
1069 \r
1070 \r
1071 void\r
1072 ipoib_inc_recv_stat(\r
1073         IN                              ipoib_adapter_t* const          p_adapter,\r
1074         IN              const   ip_stat_sel_t                           stat_sel,\r
1075         IN              const   size_t                                          bytes OPTIONAL )\r
1076 {\r
1077         IPOIB_ENTER( IPOIB_DBG_STAT );\r
1078 \r
1079         cl_spinlock_acquire( &p_adapter->recv_stat_lock );\r
1080         switch( stat_sel )\r
1081         {\r
1082         case IP_STAT_ERROR:\r
1083                 p_adapter->recv_stats.comp.error++;\r
1084                 break;\r
1085 \r
1086         case IP_STAT_DROPPED:\r
1087                 p_adapter->recv_stats.comp.dropped++;\r
1088                 break;\r
1089 \r
1090         case IP_STAT_UCAST_BYTES:\r
1091         case IP_STAT_UCAST_FRAMES:\r
1092                 p_adapter->recv_stats.comp.success++;\r
1093                 p_adapter->recv_stats.ucast.frames++;\r
1094                 p_adapter->recv_stats.ucast.bytes += bytes;\r
1095                 break;\r
1096 \r
1097         case IP_STAT_BCAST_BYTES:\r
1098         case IP_STAT_BCAST_FRAMES:\r
1099                 p_adapter->recv_stats.comp.success++;\r
1100                 p_adapter->recv_stats.bcast.frames++;\r
1101                 p_adapter->recv_stats.bcast.bytes += bytes;\r
1102                 break;\r
1103 \r
1104         case IP_STAT_MCAST_BYTES:\r
1105         case IP_STAT_MCAST_FRAMES:\r
1106                 p_adapter->recv_stats.comp.success++;\r
1107                 p_adapter->recv_stats.mcast.frames++;\r
1108                 p_adapter->recv_stats.mcast.bytes += bytes;\r
1109                 break;\r
1110 \r
1111         default:\r
1112                 break;\r
1113         }\r
1114         cl_spinlock_release( &p_adapter->recv_stat_lock );\r
1115 \r
1116         IPOIB_EXIT( IPOIB_DBG_STAT );\r
1117 }\r
1118 \r
1119 NDIS_STATUS\r
1120 ipoib_get_send_stat(\r
1121         IN                              ipoib_adapter_t* const          p_adapter,\r
1122         IN              const   ip_stat_sel_t                           stat_sel,\r
1123         IN                              pending_oid_t* const            p_oid_info )\r
1124 {\r
1125         uint64_t        stat;\r
1126 \r
1127         IPOIB_ENTER( IPOIB_DBG_STAT );\r
1128 \r
1129         CL_ASSERT( p_adapter );\r
1130 \r
1131         cl_spinlock_acquire( &p_adapter->send_stat_lock );\r
1132         switch( stat_sel )\r
1133         {\r
1134         case IP_STAT_SUCCESS:\r
1135                 stat = p_adapter->send_stats.comp.success;\r
1136                 break;\r
1137 \r
1138         case IP_STAT_ERROR:\r
1139                 stat = p_adapter->send_stats.comp.error;\r
1140                 break;\r
1141 \r
1142         case IP_STAT_DROPPED:\r
1143                 stat = p_adapter->send_stats.comp.dropped;\r
1144                 break;\r
1145 \r
1146         case IP_STAT_UCAST_BYTES:\r
1147                 stat = p_adapter->send_stats.ucast.bytes;\r
1148                 break;\r
1149 \r
1150         case IP_STAT_UCAST_FRAMES:\r
1151                 stat = p_adapter->send_stats.ucast.frames;\r
1152                 break;\r
1153 \r
1154         case IP_STAT_BCAST_BYTES:\r
1155                 stat = p_adapter->send_stats.bcast.bytes;\r
1156                 break;\r
1157 \r
1158         case IP_STAT_BCAST_FRAMES:\r
1159                 stat = p_adapter->send_stats.bcast.frames;\r
1160                 break;\r
1161 \r
1162         case IP_STAT_MCAST_BYTES:\r
1163                 stat = p_adapter->send_stats.mcast.bytes;\r
1164                 break;\r
1165 \r
1166         case IP_STAT_MCAST_FRAMES:\r
1167                 stat = p_adapter->send_stats.mcast.frames;\r
1168                 break;\r
1169 \r
1170         default:\r
1171                 stat = 0;\r
1172         }\r
1173         cl_spinlock_release( &p_adapter->send_stat_lock );\r
1174 \r
1175         *p_oid_info->p_bytes_needed = sizeof(uint64_t);\r
1176 \r
1177         if( p_oid_info->buf_len >= sizeof(uint64_t) )\r
1178         {\r
1179                 *((uint64_t*)p_oid_info->p_buf) = stat;\r
1180                 *p_oid_info->p_bytes_used = sizeof(uint64_t);\r
1181         }\r
1182         else if( p_oid_info->buf_len >= sizeof(uint32_t) )\r
1183         {\r
1184                 *((uint32_t*)p_oid_info->p_buf) = (uint32_t)stat;\r
1185                 *p_oid_info->p_bytes_used = sizeof(uint32_t);\r
1186         }\r
1187         else\r
1188         {\r
1189                 *p_oid_info->p_bytes_used = 0;\r
1190                 IPOIB_EXIT( IPOIB_DBG_STAT );\r
1191                 return NDIS_STATUS_INVALID_LENGTH;\r
1192         }\r
1193 \r
1194         IPOIB_EXIT( IPOIB_DBG_STAT );\r
1195         return NDIS_STATUS_SUCCESS;\r
1196 }\r
1197 \r
1198 \r
1199 void\r
1200 ipoib_inc_send_stat(\r
1201         IN                              ipoib_adapter_t* const          p_adapter,\r
1202         IN              const   ip_stat_sel_t                           stat_sel,\r
1203         IN              const   size_t                                          bytes OPTIONAL )\r
1204 {\r
1205         IPOIB_ENTER( IPOIB_DBG_STAT );\r
1206 \r
1207         cl_spinlock_acquire( &p_adapter->send_stat_lock );\r
1208         switch( stat_sel )\r
1209         {\r
1210         case IP_STAT_ERROR:\r
1211                 p_adapter->send_stats.comp.error++;\r
1212                 break;\r
1213 \r
1214         case IP_STAT_DROPPED:\r
1215                 p_adapter->send_stats.comp.dropped++;\r
1216                 break;\r
1217 \r
1218         case IP_STAT_UCAST_BYTES:\r
1219         case IP_STAT_UCAST_FRAMES:\r
1220                 p_adapter->send_stats.comp.success++;\r
1221                 p_adapter->send_stats.ucast.frames++;\r
1222                 p_adapter->send_stats.ucast.bytes += bytes;\r
1223                 break;\r
1224 \r
1225         case IP_STAT_BCAST_BYTES:\r
1226         case IP_STAT_BCAST_FRAMES:\r
1227                 p_adapter->send_stats.comp.success++;\r
1228                 p_adapter->send_stats.bcast.frames++;\r
1229                 p_adapter->send_stats.bcast.bytes += bytes;\r
1230                 break;\r
1231 \r
1232         case IP_STAT_MCAST_BYTES:\r
1233         case IP_STAT_MCAST_FRAMES:\r
1234                 p_adapter->send_stats.comp.success++;\r
1235                 p_adapter->send_stats.mcast.frames++;\r
1236                 p_adapter->send_stats.mcast.bytes += bytes;\r
1237                 break;\r
1238 \r
1239         default:\r
1240                 break;\r
1241         }\r
1242         cl_spinlock_release( &p_adapter->send_stat_lock );\r
1243 \r
1244         IPOIB_EXIT( IPOIB_DBG_STAT );\r
1245 }\r