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