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