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