[IPoIB] Add support for address translation
[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         cl_qlist_insert_tail( &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 \r
247         /*\r
248          * Clear the pointer to the port object since the object destruction\r
249          * will cascade to child objects.  This prevents potential duplicate\r
250          * destruction (or worse, stale pointer usage).\r
251          */\r
252         p_adapter->p_port = NULL;\r
253 \r
254         cl_obj_unlock( &p_adapter->obj );\r
255 \r
256         cl_mutex_release( &p_adapter->mutex );\r
257 \r
258         cl_obj_destroy( &p_adapter->obj );\r
259 \r
260         IPOIB_EXIT( IPOIB_DBG_INIT );\r
261 }\r
262 \r
263 \r
264 static void\r
265 adapter_construct(\r
266         IN                              ipoib_adapter_t* const          p_adapter )\r
267 {\r
268         cl_obj_construct( &p_adapter->obj, IPOIB_OBJ_INSTANCE );\r
269         cl_spinlock_construct( &p_adapter->send_stat_lock );\r
270         cl_spinlock_construct( &p_adapter->recv_stat_lock );\r
271         cl_qpool_construct( &p_adapter->item_pool );\r
272         cl_mutex_construct( &p_adapter->mutex );\r
273         cl_vector_construct( &p_adapter->ip_vector );\r
274 \r
275         cl_perf_construct( &p_adapter->perf );\r
276 \r
277         p_adapter->state = IB_PNP_PORT_ADD;\r
278         p_adapter->rate = FOUR_X_IN_100BPS;\r
279 }\r
280 \r
281 \r
282 static ib_api_status_t\r
283 adapter_init(\r
284         IN                              ipoib_adapter_t* const          p_adapter )\r
285 {\r
286         cl_status_t                     cl_status;\r
287         ib_api_status_t         status;\r
288 \r
289         IPOIB_ENTER( IPOIB_DBG_INIT );\r
290 \r
291         cl_status = cl_perf_init( &p_adapter->perf, MaxPerf );\r
292         if( cl_status != CL_SUCCESS )\r
293         {\r
294                 IPOIB_TRACE_EXIT( IPOIB_DBG_ERROR,\r
295                         ("cl_perf_init returned %s\n", cl_status_text[cl_status]) );\r
296                 return IB_ERROR;\r
297         }\r
298 \r
299         cl_status = cl_spinlock_init( &p_adapter->send_stat_lock );\r
300         if( cl_status != CL_SUCCESS )\r
301         {\r
302                 IPOIB_TRACE_EXIT( IPOIB_DBG_ERROR,\r
303                         ("cl_spinlock_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->recv_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_qpool_init( &p_adapter->item_pool, ITEM_POOL_START, 0,\r
316                 ITEM_POOL_GROW, sizeof(cl_pool_obj_t), NULL, NULL, NULL );\r
317         if( cl_status != CL_SUCCESS )\r
318         {\r
319                 IPOIB_TRACE_EXIT( IPOIB_DBG_ERROR,\r
320                         ("cl_qpool_init returned %s\n", cl_status_text[cl_status]) );\r
321                 return IB_ERROR;\r
322         }\r
323 \r
324         cl_status = cl_mutex_init( &p_adapter->mutex );\r
325         if( cl_status != CL_SUCCESS )\r
326         {\r
327                 IPOIB_TRACE_EXIT( IPOIB_DBG_ERROR,\r
328                         ("cl_mutex_init returned %s\n", cl_status_text[cl_status]) );\r
329                 return IB_ERROR;\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_TRACE_EXIT( IPOIB_DBG_ERROR,\r
338                         ("cl_vector_init for ip_vector returned %s\n",\r
339                         CL_STATUS_MSG(cl_status)) );\r
340                 return IB_ERROR;\r
341         }\r
342 \r
343         /* Validate the port GUID and generate the MAC address. */\r
344         status =\r
345                 ipoib_mac_from_guid( p_adapter->guids.port_guid, &p_adapter->mac );\r
346         if( status != IB_SUCCESS )\r
347         {\r
348                 IPOIB_TRACE_EXIT( IPOIB_DBG_ERROR,\r
349                         ("ipoib_mac_from_guid returned %s\n", \r
350                         p_adapter->p_ifc->get_err_str( status )) );\r
351                 return status;\r
352         }\r
353 \r
354         /* Open AL. */\r
355         status = p_adapter->p_ifc->open_al( &p_adapter->h_al );\r
356         if( status != IB_SUCCESS )\r
357         {\r
358                 IPOIB_TRACE_EXIT( IPOIB_DBG_ERROR,\r
359                         ("ib_open_al returned %s\n", \r
360                         p_adapter->p_ifc->get_err_str( status )) );\r
361                 return status;\r
362         }\r
363 \r
364         IPOIB_EXIT( IPOIB_DBG_INIT );\r
365         return status;\r
366 }\r
367 \r
368 \r
369 static ib_api_status_t\r
370 __ipoib_pnp_reg(\r
371         IN                              ipoib_adapter_t* const          p_adapter,\r
372         IN                              ib_pnp_class_t                          flags )\r
373 {\r
374         ib_api_status_t         status;\r
375         ib_pnp_req_t            pnp_req;\r
376         \r
377         IPOIB_ENTER( IPOIB_DBG_INIT );\r
378 \r
379         CL_ASSERT( !p_adapter->h_pnp );\r
380 \r
381         /* Register for PNP events. */\r
382         cl_memclr( &pnp_req, sizeof(pnp_req) );\r
383         pnp_req.pnp_class = IB_PNP_PORT | flags;\r
384         /*\r
385          * Context is the cl_obj of the adapter to allow passing cl_obj_deref\r
386          * to ib_dereg_pnp.\r
387          */\r
388         pnp_req.pnp_context = &p_adapter->obj;\r
389         pnp_req.pfn_pnp_cb = __ipoib_pnp_cb;\r
390         status = p_adapter->p_ifc->reg_pnp( p_adapter->h_al, &pnp_req, &p_adapter->h_pnp );\r
391         if( status != IB_SUCCESS )\r
392         {\r
393                 IPOIB_TRACE_EXIT( IPOIB_DBG_ERROR,\r
394                         ("ib_reg_pnp returned %s\n", \r
395                         p_adapter->p_ifc->get_err_str( status )) );\r
396                 return status;\r
397         }\r
398         /*\r
399          * Reference the adapter on behalf of the PNP registration.\r
400          * This allows the destruction to block until the PNP deregistration\r
401          * completes.\r
402          */\r
403         cl_obj_ref( &p_adapter->obj );\r
404 \r
405         IPOIB_EXIT( IPOIB_DBG_INIT );\r
406         return status;\r
407 }\r
408 \r
409 \r
410 static void\r
411 __adapter_destroying(\r
412         IN                              cl_obj_t* const                         p_obj )\r
413 {\r
414         ipoib_adapter_t         *p_adapter;\r
415         KLOCK_QUEUE_HANDLE      hdl;\r
416 \r
417         IPOIB_ENTER( IPOIB_DBG_INIT );\r
418 \r
419         p_adapter = PARENT_STRUCT( p_obj, ipoib_adapter_t, obj );\r
420 \r
421         /*\r
422          * The adapter's object will be dereferenced when the deregistration\r
423          * completes.  No need to lock here since all PnP related API calls\r
424          * are driven by NDIS (via the Init/Reset/Destroy paths).\r
425          */\r
426         if( p_adapter->h_pnp )\r
427         {\r
428                 p_adapter->p_ifc->dereg_pnp( p_adapter->h_pnp, cl_obj_deref );\r
429                 p_adapter->h_pnp = NULL;\r
430         }\r
431 \r
432         KeAcquireInStackQueuedSpinLock( &g_ipoib.lock, &hdl );\r
433         ASSERT( cl_qlist_count( &g_ipoib.adapter_list ) );\r
434         cl_qlist_remove_item( &g_ipoib.adapter_list, &p_adapter->entry );\r
435         KeReleaseInStackQueuedSpinLock( &hdl );\r
436 \r
437         IPOIB_EXIT( IPOIB_DBG_INIT );\r
438 }\r
439 \r
440 \r
441 static void\r
442 __adapter_free(\r
443         IN                              cl_obj_t* const                         p_obj )\r
444 {\r
445         ipoib_adapter_t *p_adapter;\r
446 \r
447         IPOIB_ENTER( IPOIB_DBG_INIT );\r
448 \r
449         p_adapter = PARENT_STRUCT( p_obj, ipoib_adapter_t, obj );\r
450 \r
451         if( p_adapter->p_ifc )\r
452         {\r
453                 if( p_adapter->h_al )\r
454                         p_adapter->p_ifc->close_al( p_adapter->h_al );\r
455 \r
456                 cl_free( p_adapter->p_ifc );\r
457         }\r
458 \r
459         cl_vector_destroy( &p_adapter->ip_vector );\r
460         cl_qpool_destroy( &p_adapter->item_pool );\r
461         cl_spinlock_destroy( &p_adapter->recv_stat_lock );\r
462         cl_spinlock_destroy( &p_adapter->send_stat_lock );\r
463         cl_mutex_destroy( &p_adapter->mutex );\r
464         cl_obj_deinit( p_obj );\r
465 \r
466         cl_perf_destroy( &p_adapter->perf, TRUE );\r
467 \r
468         cl_free( p_adapter );\r
469 \r
470         IPOIB_EXIT( IPOIB_DBG_INIT );\r
471 }\r
472 \r
473 \r
474 static ib_api_status_t\r
475 __ipoib_pnp_cb(\r
476         IN                              ib_pnp_rec_t                            *p_pnp_rec )\r
477 {\r
478         ib_api_status_t         status;\r
479         ipoib_adapter_t         *p_adapter;\r
480         ipoib_port_t            *p_port;\r
481         ib_pnp_event_t          old_state;\r
482 \r
483         IPOIB_ENTER( IPOIB_DBG_PNP );\r
484 \r
485         CL_ASSERT( p_pnp_rec );\r
486 \r
487         p_adapter =\r
488                 PARENT_STRUCT( p_pnp_rec->pnp_context, ipoib_adapter_t, obj );\r
489 \r
490         CL_ASSERT( p_adapter );\r
491 \r
492         /* Synchronize with destruction */\r
493         cl_mutex_acquire( &p_adapter->mutex );\r
494         cl_obj_lock( &p_adapter->obj );\r
495         old_state = p_adapter->state;\r
496         cl_obj_unlock( &p_adapter->obj );\r
497         if( old_state == IB_PNP_PORT_REMOVE )\r
498         {\r
499                 cl_mutex_release( &p_adapter->mutex );\r
500                 IPOIB_TRACE_EXIT( IPOIB_DBG_PNP,\r
501                         ("Aborting - Adapter destroying.\n") );\r
502                 return IB_NOT_DONE;\r
503         }\r
504 \r
505         IPOIB_TRACE( IPOIB_DBG_INFO,\r
506                 ("p_pnp_rec->pnp_event = 0x%x\n",p_pnp_rec->pnp_event));\r
507 \r
508         switch( p_pnp_rec->pnp_event )\r
509         {\r
510         case IB_PNP_PORT_ADD:\r
511                 CL_ASSERT( !p_pnp_rec->context );\r
512                 /* Only process our port GUID. */\r
513                 if( p_pnp_rec->guid != p_adapter->guids.port_guid )\r
514                 {\r
515                         status = IB_NOT_DONE;\r
516                         break;\r
517                 }\r
518 \r
519                 /* Don't process if we're destroying. */\r
520                 if( p_adapter->obj.state == CL_DESTROYING )\r
521                 {\r
522                         status = IB_NOT_DONE;\r
523                         break;\r
524                 }\r
525 \r
526                 CL_ASSERT( !p_adapter->p_port );\r
527                 /* Allocate all IB resources. */\r
528                 cl_obj_lock( &p_adapter->obj );\r
529                 p_adapter->state = IB_PNP_PORT_ADD;\r
530                 cl_obj_unlock( &p_adapter->obj );\r
531                 status = ipoib_create_port( p_adapter,\r
532                         (ib_pnp_port_rec_t*)p_pnp_rec, &p_port );\r
533                 cl_obj_lock( &p_adapter->obj );\r
534                 if( status != IB_SUCCESS )\r
535                 {\r
536                         p_adapter->state = old_state;\r
537                         cl_obj_unlock( &p_adapter->obj );\r
538                         p_adapter->hung = TRUE;\r
539                         break;\r
540                 }\r
541 \r
542                 p_pnp_rec->context = p_port;\r
543 \r
544                 p_adapter->p_port = p_port;\r
545                 cl_obj_unlock( &p_adapter->obj );\r
546                 break;\r
547 \r
548         case IB_PNP_PORT_REMOVE:\r
549                 /* Release all IB resources. */\r
550                 CL_ASSERT( p_pnp_rec->context );\r
551 \r
552                 cl_obj_lock( &p_adapter->obj );\r
553                 p_adapter->state = IB_PNP_PORT_REMOVE;\r
554                 p_port = p_adapter->p_port;\r
555                 p_adapter->p_port = NULL;\r
556                 cl_obj_unlock( &p_adapter->obj );\r
557                 ipoib_port_destroy( p_port );\r
558                 p_pnp_rec->context = NULL;\r
559                 status = IB_SUCCESS;\r
560                 break;\r
561 \r
562         case IB_PNP_PORT_ACTIVE:\r
563                 /* Join multicast groups and put QP in RTS. */\r
564                 CL_ASSERT( p_pnp_rec->context );\r
565 \r
566                 ipoib_port_up( p_adapter->p_port, (ib_pnp_port_rec_t*)p_pnp_rec );\r
567 \r
568                 status = IB_SUCCESS;\r
569                 break;\r
570 \r
571         case IB_PNP_PORT_INIT:\r
572         case IB_PNP_PORT_ARMED:\r
573         case IB_PNP_PORT_DOWN:\r
574                 /* Leave multicast groups. */\r
575                 CL_ASSERT( p_pnp_rec->context );\r
576 \r
577                 cl_obj_lock( &p_adapter->obj );\r
578                 old_state = p_adapter->state;\r
579                 p_adapter->state = IB_PNP_PORT_DOWN;\r
580                 cl_obj_unlock( &p_adapter->obj );\r
581                 status = IB_SUCCESS;\r
582 \r
583                 switch( old_state )\r
584                 {\r
585                 case IB_PNP_PORT_ACTIVE:\r
586                         NdisMIndicateStatus( p_adapter->h_adapter,\r
587                                 NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0 );\r
588                         NdisMIndicateStatusComplete( p_adapter->h_adapter );\r
589 \r
590                         IPOIB_TRACE( IPOIB_DBG_INFO, ("Link DOWN!\n") );\r
591 \r
592                         ipoib_port_down( p_adapter->p_port );\r
593                         break;\r
594 \r
595                 case IB_PNP_PORT_ADD:\r
596                         /* If we were initializing, we might have pended some OIDs. */\r
597                         ipoib_resume_oids( p_adapter );\r
598                         NdisMIndicateStatus( p_adapter->h_adapter,\r
599                                 NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0 );\r
600                         NdisMIndicateStatusComplete( p_adapter->h_adapter );\r
601                         break;\r
602 \r
603                 default:\r
604                         break;\r
605                 }\r
606                 break;\r
607 \r
608         case IB_PNP_REG_COMPLETE:\r
609                 if( p_adapter->hung )\r
610                 {\r
611                         p_adapter->hung = FALSE;\r
612                         NdisMResetComplete(\r
613                                 p_adapter->h_adapter, NDIS_STATUS_SUCCESS, TRUE );\r
614                 }\r
615                 status = IB_SUCCESS;\r
616                 break;\r
617 \r
618         default:\r
619                 IPOIB_TRACE( IPOIB_DBG_INFO,\r
620                         ("IPOIB: Received unhandled PnP event 0x%x\n",\r
621                         p_pnp_rec->pnp_event) );\r
622                 /* Fall through. */\r
623         case IB_PNP_PKEY_CHANGE:\r
624         case IB_PNP_SM_CHANGE:\r
625         case IB_PNP_GID_CHANGE:\r
626         case IB_PNP_LID_CHANGE:\r
627                 p_adapter->hung = TRUE;\r
628                 status = IB_SUCCESS;\r
629                 break;\r
630         }\r
631 \r
632         cl_mutex_release( &p_adapter->mutex );\r
633 \r
634         IPOIB_EXIT( IPOIB_DBG_PNP );\r
635         return status;\r
636 }\r
637 \r
638 \r
639 /* Joins/leaves mcast groups based on currently programmed mcast MACs. */\r
640 void\r
641 ipoib_refresh_mcast(\r
642         IN                              ipoib_adapter_t* const          p_adapter,\r
643         IN                              mac_addr_t* const                       p_mac_array,\r
644         IN              const   uint8_t                                         num_macs )\r
645 {\r
646         uint8_t                         i, j;\r
647         ipoib_port_t            *p_port = NULL;\r
648 \r
649         IPOIB_ENTER( IPOIB_DBG_MCAST );\r
650         cl_obj_lock( &p_adapter->obj );\r
651         if( p_adapter->state == IB_PNP_PORT_ACTIVE )\r
652         {\r
653                 p_port = p_adapter->p_port;\r
654                 cl_obj_ref( &p_port->obj );\r
655         }\r
656         cl_obj_unlock( &p_adapter->obj );\r
657 \r
658         if( p_port )\r
659         {\r
660                 /* Purge old entries. */\r
661                 for( i = 0; i < p_adapter->mcast_array_size; i++ )\r
662                 {\r
663                         for( j = 0; j < num_macs; j++ )\r
664                         {\r
665                                 if( !cl_memcmp( &p_adapter->mcast_array[i], &p_mac_array[j],\r
666                                         sizeof(mac_addr_t) ) )\r
667                                 {\r
668                                         break;\r
669                                 }\r
670                         }\r
671                         if( j != num_macs )\r
672                                 continue;\r
673 \r
674                         ipoib_port_remove_endpt( p_port, p_adapter->mcast_array[i] );\r
675                 }\r
676 \r
677                 /* Add new entries */\r
678                 for( i = 0; i < num_macs; i++ )\r
679                 {\r
680                         for( j = 0; j < p_adapter->mcast_array_size; j++ )\r
681                         {\r
682                                 if( !cl_memcmp( &p_adapter->mcast_array[j], &p_mac_array[i],\r
683                                         sizeof(mac_addr_t) ) )\r
684                                 {\r
685                                         break;\r
686                                 }\r
687                         }\r
688 \r
689                         if( j != p_adapter->mcast_array_size )\r
690                                 continue;\r
691 \r
692                         ipoib_port_join_mcast( p_port, p_mac_array[i] );\r
693                 }\r
694         }\r
695 \r
696         /* Copy the MAC array. */\r
697         NdisMoveMemory( p_adapter->mcast_array, p_mac_array,\r
698                 num_macs * sizeof(mac_addr_t) );\r
699         p_adapter->mcast_array_size = num_macs;\r
700 \r
701         if( p_port )\r
702                 cl_obj_deref( &p_port->obj );\r
703 \r
704         IPOIB_EXIT( IPOIB_DBG_MCAST );\r
705 }\r
706 \r
707 \r
708 ib_api_status_t\r
709 ipoib_reset_adapter(\r
710         IN                              ipoib_adapter_t* const          p_adapter )\r
711 {\r
712         ib_api_status_t         status;\r
713 \r
714         IPOIB_ENTER( IPOIB_DBG_INIT );\r
715 \r
716         if( p_adapter->h_pnp )\r
717         {\r
718                 status = p_adapter->p_ifc->dereg_pnp(\r
719                         p_adapter->h_pnp, __ipoib_pnp_dereg );\r
720                 p_adapter->h_pnp = NULL;\r
721                 if( status == IB_SUCCESS )\r
722                         status = IB_NOT_DONE;\r
723         }\r
724         else\r
725         {\r
726                 status = __ipoib_pnp_reg( p_adapter, IB_PNP_FLAG_REG_COMPLETE );\r
727                 if( status == IB_SUCCESS )\r
728                         p_adapter->hung = FALSE;\r
729         }\r
730 \r
731         IPOIB_EXIT( IPOIB_DBG_INIT );\r
732         return status;\r
733 }\r
734 \r
735 \r
736 static void\r
737 __ipoib_pnp_dereg(\r
738         IN                              void*                                           context )\r
739 {\r
740         ipoib_adapter_t*        p_adapter;\r
741         ipoib_port_t*           p_port;\r
742         ib_api_status_t         status;\r
743         ib_pnp_event_t          state;\r
744 \r
745         IPOIB_ENTER( IPOIB_DBG_INIT );\r
746 \r
747         p_adapter = PARENT_STRUCT( context, ipoib_adapter_t, obj );\r
748 \r
749         /* Synchronize with destruction */\r
750         cl_mutex_acquire( &p_adapter->mutex );\r
751 \r
752         cl_obj_lock( &p_adapter->obj );\r
753 \r
754         CL_ASSERT( !p_adapter->h_pnp );\r
755 \r
756         if( p_adapter->state != IB_PNP_PORT_REMOVE )\r
757                 p_adapter->state = IB_PNP_PORT_ADD;\r
758 \r
759         state = p_adapter->state;\r
760 \r
761         /* Destroy the current port instance if it still exists. */\r
762         p_port = p_adapter->p_port;\r
763         p_adapter->p_port = NULL;\r
764         cl_obj_unlock( &p_adapter->obj );\r
765 \r
766         if( p_port )\r
767                 ipoib_port_destroy( p_port );\r
768 \r
769         /* Complete any pending OIDs. */\r
770         ipoib_resume_oids( p_adapter );\r
771 \r
772         if( state != IB_PNP_PORT_REMOVE )\r
773         {\r
774                 status = __ipoib_pnp_reg( p_adapter, IB_PNP_FLAG_REG_COMPLETE );\r
775                 if( status != IB_SUCCESS )\r
776                 {\r
777                         p_adapter->hung = FALSE;\r
778                         IPOIB_TRACE( IPOIB_DBG_ERROR,\r
779                                 ("__ipoib_pnp_reg returned %s\n",\r
780                                 p_adapter->p_ifc->get_err_str( status )) );\r
781                         NdisMResetComplete( \r
782                                 p_adapter->h_adapter, NDIS_STATUS_HARD_ERRORS, TRUE );\r
783                 }\r
784         }\r
785         else\r
786         {\r
787                 p_adapter->hung = FALSE;\r
788                 NdisMResetComplete(\r
789                         p_adapter->h_adapter, NDIS_STATUS_SUCCESS, TRUE );\r
790                 status = IB_SUCCESS;\r
791         }\r
792 \r
793         /* Dereference the adapter since the previous registration is now gone. */\r
794         cl_obj_deref( &p_adapter->obj );\r
795 \r
796         cl_mutex_release( &p_adapter->mutex );\r
797 \r
798         IPOIB_EXIT( IPOIB_DBG_INIT );\r
799 }\r
800 \r
801 \r
802 void\r
803 ipoib_set_rate(\r
804         IN                              ipoib_adapter_t* const          p_adapter,\r
805         IN              const   uint8_t                                         link_width )\r
806 {\r
807         IPOIB_ENTER( IPOIB_DBG_INIT );\r
808 \r
809         cl_obj_lock( &p_adapter->obj );\r
810         /* Set the link speed based on the IB link speed (1x vs 4x, etc). */\r
811         switch( link_width )\r
812         {\r
813         case IB_LINK_WIDTH_ACTIVE_1X:\r
814                 IPOIB_TRACE( IPOIB_DBG_INFO, ("Link speed is 2.5Gbps\n") );\r
815                 p_adapter->rate = ONE_X_IN_100BPS;\r
816                 break;\r
817 \r
818         case IB_LINK_WIDTH_ACTIVE_4X:\r
819                 IPOIB_TRACE( IPOIB_DBG_INFO, ("Link speed is 10Gbps\n") );\r
820                 p_adapter->rate = FOUR_X_IN_100BPS;\r
821                 break;\r
822 \r
823         case IB_LINK_WIDTH_ACTIVE_12X:\r
824                 IPOIB_TRACE( IPOIB_DBG_INFO, ("Link speed is 30Gbps\n") );\r
825                 p_adapter->rate = TWELVE_X_IN_100BPS;\r
826                 break;\r
827 \r
828         default:\r
829                 IPOIB_TRACE( IPOIB_DBG_INFO, ("Invalid rate.\n") );\r
830                 p_adapter->rate = 0;\r
831         }\r
832         cl_obj_unlock( &p_adapter->obj );\r
833 \r
834         IPOIB_EXIT( IPOIB_DBG_INIT );\r
835 }\r
836 \r
837 \r
838 void\r
839 ipoib_set_active(\r
840         IN                              ipoib_adapter_t* const          p_adapter )\r
841 {\r
842         ib_pnp_event_t  old_state;\r
843         uint8_t                 i;\r
844 \r
845         IPOIB_ENTER( IPOIB_DBG_INIT );\r
846 \r
847         cl_obj_lock( &p_adapter->obj );\r
848         old_state = p_adapter->state;\r
849 \r
850         /* Change the state to indicate that we are now connected and live. */\r
851         if( old_state != IB_PNP_PORT_REMOVE )\r
852                 p_adapter->state = IB_PNP_PORT_ACTIVE;\r
853 \r
854         cl_obj_unlock( &p_adapter->obj );\r
855 \r
856         /*\r
857          * If we had a pending OID request for OID_GEN_LINK_SPEED,\r
858          * complete it now.\r
859          */\r
860         switch( old_state )\r
861         {\r
862         case IB_PNP_PORT_ADD:\r
863                 ipoib_reg_addrs( p_adapter );\r
864                 /* Fall through. */\r
865 \r
866         case IB_PNP_PORT_REMOVE:\r
867                 ipoib_resume_oids( p_adapter );\r
868                 break;\r
869 \r
870         default:\r
871                 /* Join all programmed multicast groups. */\r
872                 for( i = 0; i < p_adapter->mcast_array_size; i++ )\r
873                 {\r
874                         ipoib_port_join_mcast( p_adapter->p_port, p_adapter->mcast_array[i] );\r
875                 }\r
876 \r
877                 /* Register all existing addresses. */\r
878                 ipoib_reg_addrs( p_adapter );\r
879 \r
880                 /* Now that we're in the broadcast group, notify that we have a link. */\r
881                 IPOIB_TRACE( IPOIB_DBG_INFO, ("Link UP!\n") );\r
882                 NdisMIndicateStatus( p_adapter->h_adapter, NDIS_STATUS_MEDIA_CONNECT,\r
883                         NULL, 0 );\r
884                 NdisMIndicateStatusComplete( p_adapter->h_adapter );\r
885         }\r
886 \r
887         IPOIB_EXIT( IPOIB_DBG_INIT );\r
888 }\r
889 \r
890 \r
891 NDIS_STATUS\r
892 ipoib_get_recv_stat(\r
893         IN                              ipoib_adapter_t* const          p_adapter,\r
894         IN              const   ip_stat_sel_t                           stat_sel,\r
895         IN                              pending_oid_t* const            p_oid_info )\r
896 {\r
897         uint64_t        stat;\r
898 \r
899         IPOIB_ENTER( IPOIB_DBG_INFO );\r
900 \r
901         CL_ASSERT( p_adapter );\r
902 \r
903         cl_spinlock_acquire( &p_adapter->recv_stat_lock );\r
904         switch( stat_sel )\r
905         {\r
906         case IP_STAT_SUCCESS:\r
907                 stat = p_adapter->recv_stats.comp.success;\r
908                 break;\r
909 \r
910         case IP_STAT_ERROR:\r
911                 stat = p_adapter->recv_stats.comp.error;\r
912                 break;\r
913 \r
914         case IP_STAT_DROPPED:\r
915                 stat = p_adapter->recv_stats.comp.dropped;\r
916                 break;\r
917 \r
918         case IP_STAT_UCAST_BYTES:\r
919                 stat = p_adapter->recv_stats.ucast.bytes;\r
920                 break;\r
921 \r
922         case IP_STAT_UCAST_FRAMES:\r
923                 stat = p_adapter->recv_stats.ucast.frames;\r
924                 break;\r
925 \r
926         case IP_STAT_BCAST_BYTES:\r
927                 stat = p_adapter->recv_stats.bcast.bytes;\r
928                 break;\r
929 \r
930         case IP_STAT_BCAST_FRAMES:\r
931                 stat = p_adapter->recv_stats.bcast.frames;\r
932                 break;\r
933 \r
934         case IP_STAT_MCAST_BYTES:\r
935                 stat = p_adapter->recv_stats.mcast.bytes;\r
936                 break;\r
937 \r
938         case IP_STAT_MCAST_FRAMES:\r
939                 stat = p_adapter->recv_stats.mcast.frames;\r
940                 break;\r
941 \r
942         default:\r
943                 stat = 0;\r
944         }\r
945         cl_spinlock_release( &p_adapter->recv_stat_lock );\r
946 \r
947         *p_oid_info->p_bytes_needed = sizeof(uint64_t);\r
948 \r
949         if( p_oid_info->buf_len >= sizeof(uint64_t) )\r
950         {\r
951                 *((uint64_t*)p_oid_info->p_buf) = stat;\r
952                 *p_oid_info->p_bytes_used = sizeof(uint64_t);\r
953         }\r
954         else if( p_oid_info->buf_len >= sizeof(uint32_t) )\r
955         {\r
956                 *((uint32_t*)p_oid_info->p_buf) = (uint32_t)stat;\r
957                 *p_oid_info->p_bytes_used = sizeof(uint32_t);\r
958         }\r
959         else\r
960         {\r
961                 *p_oid_info->p_bytes_used = 0;\r
962                 IPOIB_EXIT( IPOIB_DBG_INFO );\r
963                 return NDIS_STATUS_INVALID_LENGTH;\r
964         }\r
965 \r
966         IPOIB_EXIT( IPOIB_DBG_INFO );\r
967         return NDIS_STATUS_SUCCESS;\r
968 }\r
969 \r
970 \r
971 void\r
972 ipoib_inc_recv_stat(\r
973         IN                              ipoib_adapter_t* const          p_adapter,\r
974         IN              const   ip_stat_sel_t                           stat_sel,\r
975         IN              const   size_t                                          bytes OPTIONAL )\r
976 {\r
977         IPOIB_ENTER( IPOIB_DBG_INFO );\r
978 \r
979         cl_spinlock_acquire( &p_adapter->recv_stat_lock );\r
980         switch( stat_sel )\r
981         {\r
982         case IP_STAT_ERROR:\r
983                 p_adapter->recv_stats.comp.error++;\r
984                 break;\r
985 \r
986         case IP_STAT_DROPPED:\r
987                 p_adapter->recv_stats.comp.dropped++;\r
988                 break;\r
989 \r
990         case IP_STAT_UCAST_BYTES:\r
991         case IP_STAT_UCAST_FRAMES:\r
992                 p_adapter->recv_stats.comp.success++;\r
993                 p_adapter->recv_stats.ucast.frames++;\r
994                 p_adapter->recv_stats.ucast.bytes += bytes;\r
995                 break;\r
996 \r
997         case IP_STAT_BCAST_BYTES:\r
998         case IP_STAT_BCAST_FRAMES:\r
999                 p_adapter->recv_stats.comp.success++;\r
1000                 p_adapter->recv_stats.bcast.frames++;\r
1001                 p_adapter->recv_stats.bcast.bytes += bytes;\r
1002                 break;\r
1003 \r
1004         case IP_STAT_MCAST_BYTES:\r
1005         case IP_STAT_MCAST_FRAMES:\r
1006                 p_adapter->recv_stats.comp.success++;\r
1007                 p_adapter->recv_stats.mcast.frames++;\r
1008                 p_adapter->recv_stats.mcast.bytes += bytes;\r
1009                 break;\r
1010 \r
1011         default:\r
1012                 break;\r
1013         }\r
1014         cl_spinlock_release( &p_adapter->recv_stat_lock );\r
1015 \r
1016         IPOIB_EXIT( IPOIB_DBG_INFO );\r
1017 }\r
1018 \r
1019 NDIS_STATUS\r
1020 ipoib_get_send_stat(\r
1021         IN                              ipoib_adapter_t* const          p_adapter,\r
1022         IN              const   ip_stat_sel_t                           stat_sel,\r
1023         IN                              pending_oid_t* const            p_oid_info )\r
1024 {\r
1025         uint64_t        stat;\r
1026 \r
1027         IPOIB_ENTER( IPOIB_DBG_INFO );\r
1028 \r
1029         CL_ASSERT( p_adapter );\r
1030 \r
1031         cl_spinlock_acquire( &p_adapter->send_stat_lock );\r
1032         switch( stat_sel )\r
1033         {\r
1034         case IP_STAT_SUCCESS:\r
1035                 stat = p_adapter->send_stats.comp.success;\r
1036                 break;\r
1037 \r
1038         case IP_STAT_ERROR:\r
1039                 stat = p_adapter->send_stats.comp.error;\r
1040                 break;\r
1041 \r
1042         case IP_STAT_DROPPED:\r
1043                 stat = p_adapter->send_stats.comp.dropped;\r
1044                 break;\r
1045 \r
1046         case IP_STAT_UCAST_BYTES:\r
1047                 stat = p_adapter->send_stats.ucast.bytes;\r
1048                 break;\r
1049 \r
1050         case IP_STAT_UCAST_FRAMES:\r
1051                 stat = p_adapter->send_stats.ucast.frames;\r
1052                 break;\r
1053 \r
1054         case IP_STAT_BCAST_BYTES:\r
1055                 stat = p_adapter->send_stats.bcast.bytes;\r
1056                 break;\r
1057 \r
1058         case IP_STAT_BCAST_FRAMES:\r
1059                 stat = p_adapter->send_stats.bcast.frames;\r
1060                 break;\r
1061 \r
1062         case IP_STAT_MCAST_BYTES:\r
1063                 stat = p_adapter->send_stats.mcast.bytes;\r
1064                 break;\r
1065 \r
1066         case IP_STAT_MCAST_FRAMES:\r
1067                 stat = p_adapter->send_stats.mcast.frames;\r
1068                 break;\r
1069 \r
1070         default:\r
1071                 stat = 0;\r
1072         }\r
1073         cl_spinlock_release( &p_adapter->send_stat_lock );\r
1074 \r
1075         *p_oid_info->p_bytes_needed = sizeof(uint64_t);\r
1076 \r
1077         if( p_oid_info->buf_len >= sizeof(uint64_t) )\r
1078         {\r
1079                 *((uint64_t*)p_oid_info->p_buf) = stat;\r
1080                 *p_oid_info->p_bytes_used = sizeof(uint64_t);\r
1081         }\r
1082         else if( p_oid_info->buf_len >= sizeof(uint32_t) )\r
1083         {\r
1084                 *((uint32_t*)p_oid_info->p_buf) = (uint32_t)stat;\r
1085                 *p_oid_info->p_bytes_used = sizeof(uint32_t);\r
1086         }\r
1087         else\r
1088         {\r
1089                 *p_oid_info->p_bytes_used = 0;\r
1090                 IPOIB_EXIT( IPOIB_DBG_INFO );\r
1091                 return NDIS_STATUS_INVALID_LENGTH;\r
1092         }\r
1093 \r
1094         IPOIB_EXIT( IPOIB_DBG_INFO );\r
1095         return NDIS_STATUS_SUCCESS;\r
1096 }\r
1097 \r
1098 \r
1099 void\r
1100 ipoib_inc_send_stat(\r
1101         IN                              ipoib_adapter_t* const          p_adapter,\r
1102         IN              const   ip_stat_sel_t                           stat_sel,\r
1103         IN              const   size_t                                          bytes OPTIONAL )\r
1104 {\r
1105         IPOIB_ENTER( IPOIB_DBG_INFO );\r
1106 \r
1107         cl_spinlock_acquire( &p_adapter->send_stat_lock );\r
1108         switch( stat_sel )\r
1109         {\r
1110         case IP_STAT_ERROR:\r
1111                 p_adapter->send_stats.comp.error++;\r
1112                 break;\r
1113 \r
1114         case IP_STAT_DROPPED:\r
1115                 p_adapter->send_stats.comp.dropped++;\r
1116                 break;\r
1117 \r
1118         case IP_STAT_UCAST_BYTES:\r
1119         case IP_STAT_UCAST_FRAMES:\r
1120                 p_adapter->send_stats.comp.success++;\r
1121                 p_adapter->send_stats.ucast.frames++;\r
1122                 p_adapter->send_stats.ucast.bytes += bytes;\r
1123                 break;\r
1124 \r
1125         case IP_STAT_BCAST_BYTES:\r
1126         case IP_STAT_BCAST_FRAMES:\r
1127                 p_adapter->send_stats.comp.success++;\r
1128                 p_adapter->send_stats.bcast.frames++;\r
1129                 p_adapter->send_stats.bcast.bytes += bytes;\r
1130                 break;\r
1131 \r
1132         case IP_STAT_MCAST_BYTES:\r
1133         case IP_STAT_MCAST_FRAMES:\r
1134                 p_adapter->send_stats.comp.success++;\r
1135                 p_adapter->send_stats.mcast.frames++;\r
1136                 p_adapter->send_stats.mcast.bytes += bytes;\r
1137                 break;\r
1138 \r
1139         default:\r
1140                 break;\r
1141         }\r
1142         cl_spinlock_release( &p_adapter->send_stat_lock );\r
1143 \r
1144         IPOIB_EXIT( IPOIB_DBG_INFO );\r
1145 }\r