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