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