reschedule hearbeat messages if other control Queue send is not completed, typo in...
[mirror/winof/.git] / ulp / inic / kernel / vnic_viport.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 #include "iba/ib_al.h"\r
33 #include "vnic_util.h"\r
34 #include "vnic_driver.h"\r
35 #include "vnic_viport.h"\r
36 #include "vnic_control.h"\r
37 #include "vnic_data.h"\r
38 #include "vnic_config.h"\r
39 #include "vnic_controlpkt.h"\r
40 \r
41 extern  vnic_globals_t g_vnic;\r
42 \r
43 static void    viport_timeout( void *context );\r
44 static ib_api_status_t viport_initMacAddresses( viport_t *p_viport );\r
45 static void    viport_statemachine( void *context );\r
46 \r
47 uint32_t\r
48 viport_get_adapter_name(\r
49                         IN              viport_t                *p_viport )\r
50 {\r
51         cl_memcpy(p_viport->p_adapter->name, DEFAULT_VNIC_NAME, sizeof(DEFAULT_VNIC_NAME) );\r
52                 return ( sizeof(DEFAULT_VNIC_NAME) );\r
53 }\r
54 \r
55 BOOLEAN\r
56 viport_config_defaults(\r
57                         IN                      viport_t                        *p_viport )\r
58 {\r
59 \r
60         vnic_adapter_t  *p_adapter = p_viport->p_adapter;\r
61         ViportConfig_t  *pConfig = &p_viport->port_config;\r
62         ControlConfig_t *pControlConfig = &p_viport->port_config.controlConfig;\r
63         DataConfig_t    *pDataConfig  = &p_viport->port_config.dataConfig;\r
64 \r
65         VNIC_ENTER( VNIC_DBG_VIPORT );\r
66 \r
67         p_viport->state     = VIPORT_DISCONNECTED;\r
68         p_viport->linkState = LINK_RETRYWAIT;\r
69         p_viport->newMtu    = 1500;\r
70         p_viport->newFlags  = 0;\r
71 \r
72         cl_timer_init( &p_viport->timer, viport_timeout, p_viport );\r
73 \r
74         pConfig->statsInterval  = p_adapter->params.ViportStatsInterval;\r
75         pConfig->hbInterval             = p_adapter->params.ViportHbInterval;\r
76         pConfig->hbTimeout              = p_adapter->params.ViportHbTimeout;\r
77 \r
78         cl_memcpy ( pConfig->ioc_string,\r
79                                 p_adapter->ioc_info.profile.id_string,\r
80                                 min( sizeof( p_adapter->ioc_info.profile.id_string ),\r
81                                          sizeof( pConfig->ioc_string )) );\r
82 \r
83         pControlConfig->ibConfig.sid =\r
84                 0x10ULL << 56 |\r
85                 0x00ULL << 48 |\r
86                 0x06ULL << 40 |\r
87                 0x6aULL << 32 |\r
88                 0x00ULL << 24 |\r
89                 0x00ULL << 16 |\r
90                 0x00ULL << 8 |\r
91                 ( (uint8_t)( p_adapter->ioc_info.profile.ioc_guid >> 24 ) & 0xFF );\r
92 \r
93         pControlConfig->ibConfig.connData.pathId                = 0;\r
94         pControlConfig->ibConfig.connData.inicInstance  = 0;\r
95         pControlConfig->ibConfig.connData.pathNum               = 0;\r
96 \r
97         pControlConfig->ibConfig.retryCount             = p_adapter->params.RetryCount;\r
98         pControlConfig->ibConfig.rnrRetryCount  = p_adapter->params.RetryCount;\r
99         pControlConfig->ibConfig.minRnrTimer    = (uint8_t)p_adapter->params.MinRnrTimer;\r
100         pControlConfig->ibConfig.numRecvs               = 5; /* Not configurable */\r
101         pControlConfig->ibConfig.numSends               = 1; /* Not configurable */\r
102         pControlConfig->ibConfig.recvScatter    = 1; /* Not configurable */\r
103         pControlConfig->ibConfig.sendGather             = 1; /* Not configurable */\r
104 \r
105         /* indicate new features support capabilities */\r
106         pControlConfig->ibConfig.connData.featuresSupported =\r
107                                 hton32((uint32_t)(INIC_FEAT_IGNORE_VLAN | INIC_FEAT_RDMA_IMMED ));\r
108 \r
109         cl_memcpy ( pControlConfig->ibConfig.connData.nodename,\r
110                                 g_vnic.host_name,\r
111                                 min( sizeof( g_vnic.host_name ),\r
112                                         sizeof( pControlConfig->ibConfig.connData.nodename )) );\r
113 \r
114         pControlConfig->numRecvs = pControlConfig->ibConfig.numRecvs;\r
115 \r
116         pControlConfig->inicInstance            = pControlConfig->ibConfig.connData.inicInstance;\r
117         pControlConfig->maxAddressEntries       = (uint16_t)p_adapter->params.MaxAddressEntries;\r
118         pControlConfig->minAddressEntries       = (uint16_t)p_adapter->params.MinAddressEntries;\r
119         pControlConfig->reqRetryCount           = (uint8_t)p_adapter->params.ControlReqRetryCount;\r
120         pControlConfig->rspTimeout                      = p_adapter->params.ControlRspTimeout;\r
121 \r
122         pDataConfig->ibConfig.sid =\r
123                 0x10LL << 56 |\r
124                 0x00LL << 48 |\r
125                 0x06LL << 40 |\r
126                 0x6aLL << 32 |\r
127                 0x00LL << 24 |\r
128                 0x00LL << 16 |\r
129                 0x01LL << 8 |\r
130                 ( (uint8_t)( p_adapter->ioc_info.profile.ioc_guid >> 24 ) & 0xFF );\r
131 \r
132         pDataConfig->ibConfig.connData.pathId           = get_time_stamp_ms();\r
133         pDataConfig->ibConfig.connData.inicInstance     = pControlConfig->inicInstance;\r
134         pDataConfig->ibConfig.connData.pathNum          = 0;\r
135 \r
136         pDataConfig->ibConfig.retryCount                        = p_adapter->params.RetryCount;\r
137         pDataConfig->ibConfig.rnrRetryCount                     = p_adapter->params.RetryCount;\r
138         pDataConfig->ibConfig.minRnrTimer                       = (uint8_t)p_adapter->params.MinRnrTimer;\r
139 \r
140         /*\r
141          * NOTE: The numRecvs size assumes that the EIOC could\r
142          * RDMA enough packets to fill all of the host recv\r
143          * pool entries, plus send a kick message after each\r
144          * packet, plus RDMA new buffers for the size of\r
145          * the EIOC recv buffer pool, plus send kick messages\r
146          * after each MinHostUpdateSz of new buffers all\r
147          * before the Host can even pull off the first completed\r
148          * receive off the completion queue, and repost the\r
149          * receive. NOT LIKELY!\r
150          */\r
151         pDataConfig->ibConfig.numRecvs = p_adapter->params.HostRecvPoolEntries +\r
152                 ( p_adapter->params.MaxEiocPoolSz / p_adapter->params.MinHostUpdateSz );\r
153 \r
154 #if TRUE //defined(LIMIT_OUTSTANDING_SENDS)\r
155 \r
156         pDataConfig->ibConfig.numSends =  (2 * p_adapter->params.NotifyBundleSz ) +\r
157                 ( p_adapter->params.HostRecvPoolEntries / p_adapter->params.MinEiocUpdateSz ) + 1;\r
158 \r
159 #else /* !defined(LIMIT_OUTSTANDING_SENDS) */\r
160         /*\r
161          * NOTE: The numSends size assumes that the HOST could\r
162          * post RDMA sends for every single buffer in the EIOCs\r
163          * receive pool, and allocate a full complement of\r
164          * receive buffers on the host, and RDMA free buffers\r
165          * every MinEiocUpdateSz entries all before the HCA\r
166          * can complete a single RDMA transfer. VERY UNLIKELY,\r
167          * BUT NOT COMPLETELY IMPOSSIBLE IF THERE IS AN IB\r
168          * PROBLEM!\r
169          */\r
170         pDataConfig->ibConfig.numSends = p_adapter->params.MaxEiocPoolSz +\r
171                 ( p_adapter->params.HostRecvPoolEntries / p_adapter->params.MinEiocUpdateSz ) + 1;\r
172 \r
173 #endif /* !defined(LIMIT_OUTSTANDING_SENDS) */\r
174 \r
175         pDataConfig->ibConfig.recvScatter               = 1; /* Not configurable */\r
176         pDataConfig->ibConfig.sendGather                = MAX_NUM_SGE; /* Not configurable */\r
177 \r
178         pDataConfig->numRecvs                   = pDataConfig->ibConfig.numRecvs;\r
179         pDataConfig->pathId                             = pDataConfig->ibConfig.connData.pathId;\r
180 \r
181         pDataConfig->hostMin.sizeRecvPoolEntry =\r
182                 (uint32_t)BUFFER_SIZE(ETH_VLAN_HLEN + p_adapter->params.MinMtu);\r
183         pDataConfig->hostMax.sizeRecvPoolEntry =\r
184                 (uint32_t)BUFFER_SIZE(ETH_VLAN_HLEN + p_adapter->params.MaxMtu);\r
185         pDataConfig->eiocMin.sizeRecvPoolEntry =\r
186                 (uint32_t)BUFFER_SIZE(ETH_VLAN_HLEN + p_adapter->params.MinMtu);\r
187         pDataConfig->eiocMax.sizeRecvPoolEntry = MAX_PARAM_VALUE;\r
188 \r
189         pDataConfig->hostRecvPoolEntries        = p_adapter->params.HostRecvPoolEntries;\r
190         pDataConfig->notifyBundle                       = p_adapter->params.NotifyBundleSz;\r
191 \r
192         pDataConfig->hostMin.numRecvPoolEntries = p_adapter->params.MinHostPoolSz;\r
193         pDataConfig->hostMax.numRecvPoolEntries = MAX_PARAM_VALUE;\r
194         pDataConfig->eiocMin.numRecvPoolEntries = p_adapter->params.MinEiocPoolSz;\r
195         pDataConfig->eiocMax.numRecvPoolEntries = p_adapter->params.MaxEiocPoolSz;\r
196 \r
197         pDataConfig->hostMin.timeoutBeforeKick = p_adapter->params.MinHostKickTimeout;\r
198         pDataConfig->hostMax.timeoutBeforeKick = p_adapter->params.MaxHostKickTimeout;\r
199         pDataConfig->eiocMin.timeoutBeforeKick = 0;\r
200         pDataConfig->eiocMax.timeoutBeforeKick = MAX_PARAM_VALUE;\r
201 \r
202         pDataConfig->hostMin.numRecvPoolEntriesBeforeKick = p_adapter->params.MinHostKickEntries;\r
203         pDataConfig->hostMax.numRecvPoolEntriesBeforeKick = p_adapter->params.MaxHostKickEntries;\r
204         pDataConfig->eiocMin.numRecvPoolEntriesBeforeKick = 0;\r
205         pDataConfig->eiocMax.numRecvPoolEntriesBeforeKick = MAX_PARAM_VALUE;\r
206 \r
207         pDataConfig->hostMin.numRecvPoolBytesBeforeKick = p_adapter->params.MinHostKickBytes;\r
208         pDataConfig->hostMax.numRecvPoolBytesBeforeKick = p_adapter->params.MaxHostKickBytes;\r
209         pDataConfig->eiocMin.numRecvPoolBytesBeforeKick = 0;\r
210         pDataConfig->eiocMax.numRecvPoolBytesBeforeKick = MAX_PARAM_VALUE;\r
211 \r
212         pDataConfig->hostMin.freeRecvPoolEntriesPerUpdate = p_adapter->params.MinHostUpdateSz;\r
213         pDataConfig->hostMax.freeRecvPoolEntriesPerUpdate = p_adapter->params.MaxHostUpdateSz;\r
214         pDataConfig->eiocMin.freeRecvPoolEntriesPerUpdate = p_adapter->params.MinEiocUpdateSz;\r
215         pDataConfig->eiocMax.freeRecvPoolEntriesPerUpdate = p_adapter->params.MaxEiocUpdateSz;\r
216 \r
217         VNIC_EXIT( VNIC_DBG_VIPORT );\r
218         return TRUE;\r
219 }\r
220 \r
221 static BOOLEAN config_isValid(ViportConfig_t *pConfig)\r
222 {\r
223         UNREFERENCED_PARAMETER( pConfig );\r
224         return TRUE;\r
225 }\r
226 \r
227 \r
228 void\r
229 viport_cleanup(\r
230                           viport_t      *p_viport )\r
231 {\r
232         VNIC_ENTER( VNIC_DBG_VIPORT );\r
233 \r
234         if( p_viport )\r
235         {\r
236                 InterlockedExchange( &p_viport->p_adapter->carrier, FALSE );\r
237                 InterlockedExchange( &p_viport->p_netpath->carrier, FALSE );\r
238                 viport_timerStop( p_viport );\r
239 \r
240                 data_disconnect( &p_viport->data );\r
241 \r
242                 control_cleanup( &p_viport->control );\r
243 \r
244                 data_cleanup( &p_viport->data );\r
245 \r
246                 if( p_viport->macAddresses != NULL )\r
247                 {\r
248                         NdisFreeMemory( p_viport->macAddresses,\r
249                                 p_viport->numMacAddresses * sizeof(Inic_AddressOp_t), 0 );\r
250                 }\r
251 \r
252                 cl_timer_destroy( &p_viport->timer );\r
253 \r
254                 NdisFreeMemory ( p_viport, sizeof(viport_t), 0 );\r
255         }\r
256         VNIC_EXIT( VNIC_DBG_VIPORT );\r
257         return;\r
258 }\r
259 \r
260 \r
261 void\r
262 viport_setPath(\r
263                 IN              viport_t                        *p_viport,\r
264                 IN              ib_path_rec_t           *p_path,\r
265                 IN              uint64_t                        *p_guid )\r
266 {\r
267 \r
268         UNUSED_PARAM( p_guid );\r
269 \r
270         VNIC_ENTER( VNIC_DBG_FUNC );\r
271 \r
272         VNIC_TRACE( VNIC_DBG_INFO,\r
273                 ("Using SLID=%d DLID=%d Target:%s\n",\r
274                                                         cl_ntoh16( p_path->slid ),\r
275                                                         cl_ntoh16( p_path->dlid ),\r
276                                                         p_viport->p_adapter->ioc_info.profile.id_string) );\r
277 \r
278         p_viport->portGuid = p_path->sgid.unicast.interface_id;\r
279         p_viport->iocGuid  = *p_guid;\r
280         p_viport->port_config.dataConfig.ibConfig.pathInfo = *p_path;\r
281         p_viport->port_config.controlConfig.ibConfig.pathInfo = *p_path;\r
282         p_viport->port_config.controlConfig.ibConfig.sid =\r
283                                                                 p_viport->p_adapter->p_svc_entries[0].id;\r
284         p_viport->port_config.dataConfig.ibConfig.sid =\r
285                                                                 p_viport->p_adapter->p_svc_entries[1].id;\r
286 \r
287         VNIC_EXIT( VNIC_DBG_FUNC );\r
288 }\r
289 \r
290 BOOLEAN\r
291 viport_setParent(\r
292                 IN              viport_t                *p_viport,\r
293                 IN              Netpath_t               *pNetpath )\r
294 {\r
295         VNIC_ENTER( VNIC_DBG_VIPORT );\r
296 \r
297 \r
298         if(p_viport->p_netpath != NULL)\r
299         {\r
300                 return FALSE;\r
301         }\r
302 \r
303         p_viport->p_netpath = pNetpath;\r
304 \r
305         VNIC_EXIT( VNIC_DBG_VIPORT );\r
306         return TRUE;\r
307 }\r
308 \r
309 BOOLEAN\r
310 viport_unsetParent(\r
311                 IN              viport_t                *p_viport,\r
312                 IN              Netpath_t               *pNetpath )\r
313 {\r
314         VNIC_ENTER( VNIC_DBG_VIPORT );\r
315         if( pNetpath->pViport == p_viport )\r
316                 viport_free( p_viport );\r
317         VNIC_EXIT( VNIC_DBG_VIPORT );\r
318         return TRUE;\r
319 }\r
320 \r
321 void\r
322 viport_free(\r
323                 IN              viport_t                *p_viport )\r
324 {\r
325         VNIC_ENTER( VNIC_DBG_VIPORT );\r
326 \r
327         viport_timerStop( p_viport );\r
328         viport_disconnect(p_viport);\r
329         VNIC_EXIT( VNIC_DBG_VIPORT );\r
330         return;\r
331 }\r
332 \r
333 void\r
334 viport_disconnect(\r
335                 IN              viport_t                *p_viport )\r
336 {\r
337         VNIC_ENTER( VNIC_DBG_VIPORT );\r
338 \r
339         InterlockedExchange( (volatile LONG *)&p_viport->disconnect, TRUE );\r
340         viport_failure( p_viport );\r
341 \r
342         VNIC_EXIT( VNIC_DBG_VIPORT );\r
343         return;\r
344 }\r
345 \r
346 \r
347 NDIS_STATUS\r
348 viport_setLink(\r
349                 IN              viport_t                *p_viport,\r
350                 IN              uint8_t                 flags,\r
351                 IN              uint16_t                mtu     )\r
352 {\r
353         KIRQL           irql;\r
354         NDIS_STATUS     status = NDIS_STATUS_SUCCESS;\r
355 \r
356         VNIC_ENTER( VNIC_DBG_VIPORT );\r
357 \r
358         if(mtu > data_maxMtu(&p_viport->data))\r
359         {\r
360                 viport_failure(p_viport);\r
361                 VNIC_TRACE_EXIT( VNIC_DBG_ERROR,\r
362                         ("Configuration error. Mtu of %d unsupported by %s\n", mtu, p_viport->p_adapter->name ) );\r
363                 return NDIS_STATUS_FAILURE;\r
364         }\r
365 \r
366         KeAcquireSpinLock( &p_viport->lock, &irql );\r
367 \r
368         flags &= ( INIC_FLAG_ENABLE_NIC |\r
369                                 INIC_FLAG_ENABLE_MCAST_ALL |\r
370                                 INIC_FLAG_ENABLE_PROMISC );\r
371 \r
372         if( (p_viport->newFlags != flags) ||\r
373                  (p_viport->newMtu != mtu))\r
374         {\r
375                 p_viport->newFlags = flags;\r
376                 p_viport->newMtu = mtu;\r
377                 InterlockedOr( &p_viport->updates, NEED_LINK_CONFIG );\r
378         }\r
379         KeReleaseSpinLock( &p_viport->lock, irql );\r
380 \r
381         status = _viport_process_query( p_viport, TRUE );\r
382         VNIC_EXIT( VNIC_DBG_VIPORT );\r
383         return status;\r
384 }\r
385 \r
386 BOOLEAN\r
387 viport_setUnicast(\r
388                 IN              viport_t                *p_viport,\r
389                 IN              uint8_t                 *p_address )\r
390 {\r
391         KIRQL flags;\r
392 \r
393         VNIC_ENTER( VNIC_DBG_VIPORT );\r
394 \r
395         if( !p_viport )\r
396                 return FALSE;\r
397 \r
398         KeAcquireSpinLock( &p_viport->lock, &flags );\r
399         if( p_viport->macAddresses == NULL )\r
400         {\r
401                 KeReleaseSpinLock( &p_viport->lock, flags );\r
402                 return FALSE;\r
403         }\r
404         if( cl_memcmp(p_viport->macAddresses[UNICAST_ADDR].address,\r
405                                         p_address, MAC_ADDR_LEN ) )\r
406         {\r
407                 cl_memcpy( p_viport->macAddresses[UNICAST_ADDR].address,\r
408                        p_address, MAC_ADDR_LEN );\r
409                 p_viport->macAddresses[UNICAST_ADDR].operation\r
410                         = INIC_OP_SET_ENTRY;\r
411                 InterlockedOr( &p_viport->updates, NEED_ADDRESS_CONFIG );\r
412         }\r
413         KeReleaseSpinLock( &p_viport->lock, flags );\r
414 \r
415         VNIC_EXIT( VNIC_DBG_VIPORT );\r
416         return TRUE;\r
417 }\r
418 \r
419 \r
420 /* Returns flags for state machine operations. */\r
421 NDIS_STATUS\r
422 viport_setMulticast(\r
423                 IN              viport_t                                *p_viport )\r
424 {\r
425         vnic_adapter_t  *p_adapter = p_viport->p_adapter;\r
426         uint32_t                updates = 0;\r
427         int                             i;\r
428         KIRQL                   flags;\r
429         NDIS_STATUS             status;\r
430 \r
431         VNIC_ENTER( VNIC_DBG_VIPORT );\r
432 \r
433         KeAcquireSpinLock( &p_viport->lock, &flags );\r
434 \r
435         if( p_viport->macAddresses == NULL )\r
436         {\r
437                 KeReleaseSpinLock( &p_viport->lock, flags );\r
438                 return NDIS_STATUS_NOT_ACCEPTED;\r
439         }\r
440 \r
441         ASSERT( (p_viport->updates & ~MCAST_OVERFLOW) == 0 );\r
442 \r
443         if( p_adapter->mc_count > p_viport->numMacAddresses - MCAST_ADDR_START )\r
444         {\r
445                 updates |= NEED_LINK_CONFIG | MCAST_OVERFLOW;\r
446         }\r
447         else if( p_adapter->mc_count == 0 )\r
448         {\r
449                 /* NDIS can send us a NULL array to clear all entries */\r
450                 if( InterlockedAnd(\r
451                         &p_viport->updates, ~MCAST_OVERFLOW ) & MCAST_OVERFLOW )\r
452                 {\r
453                         updates |= NEED_LINK_CONFIG;\r
454                 }\r
455                 /* invalidate all entries for the remote */\r
456                 for (i = MCAST_ADDR_START;\r
457                          i < min( MAX_ADDR_ARRAY, p_viport->numMacAddresses ); i++ )\r
458                 {\r
459                         p_viport->macAddresses[i].valid = 0;\r
460                         p_viport->macAddresses[i].operation = INIC_OP_SET_ENTRY;\r
461                 }\r
462                 updates |= NEED_ADDRESS_CONFIG;\r
463         }\r
464         else\r
465         {\r
466                 if( InterlockedAnd(\r
467                         &p_viport->updates, ~MCAST_OVERFLOW ) & MCAST_OVERFLOW )\r
468                 {\r
469                         updates |= NEED_LINK_CONFIG;\r
470                 }\r
471                 /* Brute force algorithm */\r
472                 for (i = MCAST_ADDR_START;\r
473                         i < min( MAX_ADDR_ARRAY, p_adapter->mc_count + MCAST_ADDR_START );\r
474                         i++ )\r
475                 {\r
476                         if( p_viport->macAddresses[i].valid &&\r
477                                 NdisEqualMemory( p_viport->macAddresses[i].address,\r
478                                 p_adapter->mcast_array[i - MCAST_ADDR_START].addr,\r
479                                 MAC_ADDR_LEN ) )\r
480                         {\r
481                                 continue;\r
482                         }\r
483 \r
484                         NdisMoveMemory( &p_viport->macAddresses[i].address,\r
485                                 p_adapter->mcast_array[i - MCAST_ADDR_START].addr,\r
486                                 MAC_ADDR_LEN );\r
487 \r
488                         p_viport->macAddresses[i].valid = 1;\r
489                         p_viport->macAddresses[i].operation = INIC_OP_SET_ENTRY;\r
490 \r
491                         updates |= NEED_ADDRESS_CONFIG;\r
492                 }\r
493                 for (; i < min( MAX_ADDR_ARRAY, p_viport->numMacAddresses ); i++ )\r
494                 {\r
495                         if( !p_viport->macAddresses[i].valid )\r
496                                 continue;\r
497 \r
498                         updates |= NEED_ADDRESS_CONFIG;\r
499 \r
500                         p_viport->macAddresses[i].valid = 0;\r
501                         p_viport->macAddresses[i].operation = INIC_OP_SET_ENTRY;\r
502                 }\r
503         }\r
504 \r
505         /*\r
506          * Now that the mac array is setup, we can set the update bits\r
507          * to send the request.\r
508          */\r
509         InterlockedOr( &p_viport->updates, updates );\r
510         KeReleaseSpinLock( &p_viport->lock, flags );\r
511 \r
512         status = _viport_process_query( p_viport, FALSE );\r
513 \r
514         VNIC_EXIT( VNIC_DBG_VIPORT );\r
515         return status;\r
516 }\r
517 \r
518 \r
519 NDIS_STATUS\r
520 viport_getStats(\r
521                 IN              viport_t                *p_viport )\r
522 {\r
523         uint64_t                stats_update_ms;\r
524         NDIS_STATUS             status = STATUS_SUCCESS;\r
525 \r
526         VNIC_ENTER( VNIC_DBG_VIPORT );\r
527 \r
528         stats_update_ms = get_time_stamp_ms();\r
529 \r
530         if( stats_update_ms > p_viport->lastStatsTime + p_viport->port_config.statsInterval )\r
531         {\r
532                 p_viport->lastStatsTime = (uint32_t)stats_update_ms;\r
533 \r
534                 InterlockedOr( &p_viport->updates, NEED_STATS );\r
535                 // TODO: Should the following call be synchronous?\r
536                 status = _viport_process_query( p_viport, TRUE );\r
537                 if ( status != NDIS_STATUS_SUCCESS )\r
538                 {\r
539                         VNIC_TRACE( VNIC_DBG_ERROR,\r
540                                         ("Query NEED_STATS Failed\n") );\r
541                 }\r
542         }\r
543 \r
544         VNIC_EXIT( VNIC_DBG_VIPORT );\r
545         return status;\r
546 }\r
547 \r
548 \r
549 BOOLEAN\r
550 viport_xmitPacket(\r
551                 IN              viport_t*       const   p_viport,\r
552                 IN              NDIS_PACKET* const      p_packet )\r
553 {\r
554         BOOLEAN status = FALSE;\r
555     KIRQL               flags;\r
556         cl_list_item_t  *p_list_item;\r
557 \r
558         VNIC_ENTER( VNIC_DBG_VIPORT );\r
559 \r
560         KeAcquireSpinLock( &p_viport->lock, &flags );\r
561 \r
562         if( p_viport->p_adapter->xmitStarted )\r
563         {\r
564                 for( p_list_item = cl_qlist_remove_head( &p_viport->send_pending_list );\r
565                          p_list_item != cl_qlist_end( &p_viport->send_pending_list );\r
566                          p_list_item = cl_qlist_remove_head( &p_viport->send_pending_list ) )\r
567                 {\r
568                         status = data_xmitPacket( &p_viport->data,\r
569                                                         VNIC_PACKET_FROM_LIST_ITEM( p_list_item ));\r
570                 }\r
571                 status = data_xmitPacket( &p_viport->data, p_packet );\r
572         }\r
573         else\r
574         {\r
575                 cl_qlist_insert_tail( &p_viport->send_pending_list,\r
576                         VNIC_LIST_ITEM_FROM_PACKET( p_packet ) );\r
577         }\r
578 \r
579         KeReleaseSpinLock( &p_viport->lock, flags );\r
580 \r
581         VNIC_EXIT( VNIC_DBG_VIPORT );\r
582         return status;\r
583 }\r
584 \r
585 void viport_linkUp(viport_t *p_viport)\r
586 {\r
587         VNIC_ENTER( VNIC_DBG_VIPORT );\r
588         InterlockedExchange( &p_viport->p_adapter->carrier, TRUE );\r
589         NdisMIndicateStatus( p_viport->p_adapter->h_handle,\r
590                                                 NDIS_STATUS_MEDIA_CONNECT, NULL, 0 );\r
591         NdisMIndicateStatusComplete( p_viport->p_adapter->h_handle );\r
592         VNIC_EXIT( VNIC_DBG_VIPORT );\r
593         return;\r
594 }\r
595 \r
596 void viport_linkDown(viport_t *p_viport)\r
597 {\r
598         VNIC_ENTER( VNIC_DBG_VIPORT );\r
599         InterlockedExchange( &p_viport->p_adapter->carrier, FALSE );\r
600         NdisMIndicateStatus( p_viport->p_adapter->h_handle,\r
601                                                 NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0 );\r
602         NdisMIndicateStatusComplete( p_viport->p_adapter->h_handle );\r
603         VNIC_EXIT( VNIC_DBG_VIPORT );\r
604         return;\r
605 }\r
606 \r
607 void viport_stopXmit(viport_t *p_viport)\r
608 {\r
609         VNIC_ENTER( VNIC_DBG_VIPORT );\r
610         netpath_stopXmit( p_viport->p_netpath );\r
611         VNIC_EXIT( VNIC_DBG_VIPORT );\r
612         return;\r
613 }\r
614 \r
615 void viport_restartXmit(viport_t *p_viport)\r
616 {\r
617         VNIC_ENTER( VNIC_DBG_VIPORT );\r
618         netpath_restartXmit( p_viport->p_netpath );\r
619         VNIC_EXIT( VNIC_DBG_VIPORT );\r
620         return;\r
621 }\r
622 \r
623 void\r
624 viport_recvPacket(\r
625                 IN              viport_t        *p_viport,\r
626                 IN              NDIS_PACKET      *p_packet )\r
627 {\r
628         VNIC_ENTER( VNIC_DBG_VIPORT );\r
629         netpath_recvPacket(p_viport->p_netpath, p_packet );\r
630         VNIC_EXIT( VNIC_DBG_VIPORT );\r
631         return;\r
632 }\r
633 \r
634 \r
635 void\r
636 viport_failure(\r
637         IN              viport_t        *p_viport )\r
638 {\r
639         VNIC_ENTER( VNIC_DBG_VIPORT );\r
640 \r
641         InterlockedExchange( (volatile LONG*)&p_viport->errored,  1 );\r
642 \r
643         VNIC_EXIT( VNIC_DBG_VIPORT );\r
644 }\r
645 \r
646 \r
647 void\r
648 viport_timeout(\r
649                 IN              void    *context )\r
650 {\r
651         viport_t        *p_viport = (viport_t *)context;\r
652 \r
653         InterlockedExchange( &p_viport->timerActive, FALSE );\r
654         if( p_viport && p_viport->data.connected )\r
655         {\r
656                 // TODO: What about send failure?\r
657                 if( !p_viport->control.reqOutstanding )\r
658                 {\r
659                         control_heartbeatReq( &p_viport->control,\r
660                                                         p_viport->port_config.hbTimeout );\r
661                 }\r
662                 else\r
663                 {       /* send WQE is taken, send heartbeat later */\r
664                         viport_timer( p_viport, p_viport->port_config.hbInterval );\r
665                 }\r
666         }\r
667 }\r
668 \r
669 \r
670 void\r
671 viport_timer(\r
672                 IN               viport_t       *p_viport,\r
673                 IN              int                     timeout )\r
674 {\r
675         VNIC_ENTER( VNIC_DBG_VIPORT );;\r
676 \r
677         InterlockedExchange( &p_viport->timerActive, TRUE );\r
678         cl_timer_start( &p_viport->timer, (uint32_t)timeout );\r
679 \r
680         VNIC_EXIT( VNIC_DBG_VIPORT );\r
681 }\r
682 \r
683 \r
684 void\r
685 viport_timerStop(\r
686                 IN              viport_t        *p_viport )\r
687 {\r
688         VNIC_ENTER( VNIC_DBG_VIPORT );\r
689 \r
690         if( p_viport )\r
691         {\r
692                 if( InterlockedExchange( &p_viport->timerActive, FALSE ) == TRUE )\r
693                 {\r
694                         cl_timer_stop( &p_viport->timer );\r
695                 }\r
696         }\r
697 \r
698         VNIC_EXIT( VNIC_DBG_VIPORT );\r
699         return;\r
700 }\r
701 \r
702 static ib_api_status_t\r
703 viport_initMacAddresses(\r
704                         IN              viport_t                *p_viport )\r
705 {\r
706         int             i, size;\r
707     KIRQL       flags;\r
708         NDIS_STATUS     status;\r
709         VNIC_ENTER( VNIC_DBG_VIPORT );\r
710 \r
711         size = p_viport->numMacAddresses * sizeof(Inic_AddressOp_t);\r
712         status = NdisAllocateMemoryWithTag( &p_viport->macAddresses, size , 'acam' );\r
713 \r
714         if ( status != NDIS_STATUS_SUCCESS )\r
715         {\r
716                 VNIC_TRACE_EXIT( VNIC_DBG_ERROR,\r
717                         ("Failed allocating MAC address table size %d\n", size) );\r
718                 return IB_INSUFFICIENT_MEMORY;\r
719         }\r
720 \r
721         NdisZeroMemory( p_viport->macAddresses, size );\r
722 \r
723         KeAcquireSpinLock( &p_viport->lock, &flags );\r
724         for( i = 0; i < p_viport->numMacAddresses; i++ )\r
725         {\r
726                 p_viport->macAddresses[i].index = (uint16_t)i;\r
727                 p_viport->macAddresses[i].vlan  = p_viport->defaultVlan;\r
728         }\r
729 \r
730         NdisFillMemory( p_viport->macAddresses[BROADCAST_ADDR].address,\r
731                MAC_ADDR_LEN, 0xFF );\r
732         p_viport->macAddresses[BROADCAST_ADDR].valid = TRUE;\r
733 \r
734         NdisMoveMemory( p_viport->macAddresses[UNICAST_ADDR].address,\r
735                p_viport->hwMacAddress, MAC_ADDR_LEN );\r
736 \r
737         p_viport->macAddresses[UNICAST_ADDR].valid   = TRUE;\r
738         p_viport->p_adapter->macSet = TRUE;\r
739 \r
740         KeReleaseSpinLock( &p_viport->lock, flags );\r
741 \r
742         VNIC_EXIT( VNIC_DBG_VIPORT );\r
743         return IB_SUCCESS;\r
744 }\r
745 \r
746 \r
747 ib_api_status_t\r
748 viport_control_connect(\r
749         IN              viport_t*       const   p_viport )\r
750 {\r
751         ib_api_status_t ib_status;\r
752 \r
753         VNIC_ENTER( VNIC_DBG_VIPORT );\r
754 \r
755         ib_status = control_init( &p_viport->control, p_viport,\r
756                 &p_viport->port_config.controlConfig, p_viport->portGuid );\r
757         if( ib_status != IB_SUCCESS )\r
758         {\r
759                 VNIC_EXIT( VNIC_DBG_VIPORT );\r
760                 return ib_status;\r
761         }\r
762 \r
763         ib_status = ibqp_connect( &p_viport->control.qp );\r
764         if( ib_status != IB_SUCCESS )\r
765         {\r
766                 VNIC_TRACE( VNIC_DBG_INFO,\r
767                                 ("control QP connect failed\n"));\r
768                 goto err1;\r
769         }\r
770 \r
771         InterlockedExchange( (volatile LONG*)&p_viport->linkState,\r
772                 (LONG)LINK_INITINICREQ );\r
773 \r
774         ib_status = control_initInicReq( &p_viport->control );\r
775         if( ib_status != IB_SUCCESS )\r
776         {\r
777                 VNIC_TRACE( VNIC_DBG_INFO, ("CMD_INIT_INIC  REQ failed\n") );\r
778                 goto err2;\r
779         }\r
780         cl_event_wait_on( &p_viport->conn_event,\r
781                                                 (p_viport->control.p_conf->rspTimeout << 11), TRUE );\r
782 \r
783         if( p_viport->linkState != LINK_INITINICRSP )\r
784         {\r
785                 VNIC_TRACE( VNIC_DBG_INFO,\r
786                                         ("CMD_INIT_INIC RSP failed\n"));\r
787                 ib_status = IB_INSUFFICIENT_RESOURCES;\r
788                 goto err2;\r
789         }\r
790 \r
791         vnic_resume_oids( p_viport->p_adapter );\r
792 \r
793         ib_status = viport_initMacAddresses( p_viport );\r
794         if( ib_status != IB_SUCCESS )\r
795         {\r
796                 VNIC_TRACE( VNIC_DBG_INFO,\r
797                                 ("Init MAC Addresses failed\n"));\r
798 err2:\r
799                 control_resetReq( &p_viport->control );\r
800 err1:\r
801                 control_cleanup( &p_viport->control );\r
802         }\r
803 \r
804         VNIC_EXIT( VNIC_DBG_VIPORT );\r
805         return ib_status;\r
806 }\r
807 \r
808 ib_api_status_t\r
809 viport_data_connect(\r
810         IN              viport_t*       const   p_viport )\r
811 {\r
812         NDIS_STATUS             status;\r
813         ib_api_status_t ib_status;\r
814 \r
815         VNIC_ENTER( VNIC_DBG_VIPORT );\r
816 \r
817         ib_status = data_init( &p_viport->data,\r
818                                                  &p_viport->port_config.dataConfig,\r
819                                                  p_viport->portGuid );\r
820         if( ib_status != IB_SUCCESS )\r
821         {\r
822                 VNIC_TRACE( VNIC_DBG_ERROR, ("Data init returned %s\n",\r
823                         p_viport->p_adapter->ifc.get_err_str( ib_status )) );\r
824                 return ib_status;\r
825         }\r
826         InterlockedExchange( (volatile LONG*)&p_viport->linkState,\r
827                                                                 (LONG)LINK_CONFIGDATAPATHREQ );\r
828 \r
829         ib_status = control_configDataPathReq( &p_viport->control,\r
830                 data_pathId(&p_viport->data ), data_hostPoolMax( &p_viport->data ),\r
831                 data_eiocPoolMax( &p_viport->data ) );\r
832         if( ib_status != IB_SUCCESS )\r
833         {\r
834                 VNIC_TRACE( VNIC_DBG_ERROR,\r
835                                 ("command CONFIGDATAPATH REQ failed\n"));\r
836                 return ib_status;\r
837         }\r
838         cl_event_wait_on( &p_viport->conn_event,\r
839                                         (p_viport->control.p_conf->rspTimeout << 11), TRUE );\r
840         \r
841         if( p_viport->linkState != LINK_CONFIGDATAPATHRSP )\r
842         {\r
843                 VNIC_TRACE( VNIC_DBG_ERROR,\r
844                                         ("failed to get CONFIGDATAPATH RSP\n"));\r
845                 return IB_INSUFFICIENT_RESOURCES;\r
846         }\r
847 \r
848         ib_status = data_connect( &p_viport->data );\r
849         if( ib_status != IB_SUCCESS )\r
850         {\r
851                 VNIC_EXIT( VNIC_DBG_VIPORT );\r
852                 return ib_status;\r
853         }\r
854         cl_event_wait_on( &p_viport->conn_event,\r
855                                         (p_viport->control.p_conf->rspTimeout << 11), TRUE );\r
856         if( p_viport->data.qp.qpState != IB_ATTACHED )\r
857         {\r
858                 VNIC_EXIT( VNIC_DBG_VIPORT );\r
859                 return IB_ERROR;\r
860         }\r
861         InterlockedExchange( (volatile LONG*)&p_viport->linkState,\r
862                                                                         (LONG)LINK_XCHGPOOLREQ );\r
863         ib_status = control_exchangePoolsReq( &p_viport->control,\r
864                 data_localPoolAddr(&p_viport->data),\r
865                 data_localPoolRkey(&p_viport->data) );\r
866         if( ib_status != IB_SUCCESS )\r
867         {\r
868                 VNIC_TRACE_EXIT( VNIC_DBG_ERROR,\r
869                                 ("command XCHGPOOL REQ failed\n"));\r
870                 return ib_status;\r
871         }\r
872         cl_event_wait_on( &p_viport->conn_event,\r
873                                         (p_viport->control.p_conf->rspTimeout << 11), TRUE );\r
874 \r
875         if( p_viport->linkState != LINK_XCHGPOOLRSP )\r
876         {\r
877                 VNIC_TRACE_EXIT( VNIC_DBG_ERROR,\r
878                                 ("failed to get LINK_XCHGPOOL RSP\n"));\r
879                 return IB_ERROR;\r
880         }\r
881 \r
882         InterlockedExchange( (volatile LONG*)&p_viport->linkState,\r
883                                                         (LONG)LINK_INITIALIZED );\r
884         p_viport->state = VIPORT_CONNECTED;\r
885 \r
886         data_connected(&p_viport->data);\r
887 \r
888         InterlockedExchange( (volatile LONG *)&p_viport->mtu, 1500 );\r
889         InterlockedExchange( (volatile LONG *)&p_viport->flags, 0 );\r
890         status = viport_setLink( p_viport, INIC_FLAG_ENABLE_NIC, 1500 );\r
891         if( status != NDIS_STATUS_SUCCESS )\r
892         {\r
893                 VNIC_TRACE_EXIT( VNIC_DBG_ERROR,\r
894                                 ("failed to set Link flags\n"));\r
895                 return IB_ERROR;\r
896         }\r
897 \r
898         /* now we have to start periodic heartbeat timer */\r
899         if( p_viport->port_config.hbInterval )\r
900         {\r
901                 viport_timer( p_viport, p_viport->port_config.hbInterval );\r
902         }\r
903 \r
904         VNIC_EXIT( VNIC_DBG_VIPORT );\r
905         return IB_SUCCESS;\r
906 }\r
907 \r
908 \r
909 NDIS_STATUS\r
910 _viport_process_query(\r
911                 IN              viport_t*       const   p_viport,\r
912                 IN              BOOLEAN                         sync )\r
913 {\r
914         NDIS_STATUS             status;\r
915         ib_api_status_t ib_status;\r
916         KIRQL                   irql;\r
917         LinkState_t             expected_state = 0;\r
918 \r
919         VNIC_ENTER( VNIC_DBG_VIPORT );\r
920 \r
921         if ( p_viport->state != VIPORT_CONNECTED ||\r
922                 p_viport->errored != 0 )\r
923         {\r
924                 VNIC_TRACE_EXIT( VNIC_DBG_WARN, ("Invalid state or error.\n") );\r
925                 return NDIS_STATUS_NOT_ACCEPTED;\r
926         }\r
927 \r
928         // Check for updates.  Note that unless sync is set to TRUE, this\r
929         // is the only way for this function to return success.\r
930         if( !InterlockedCompareExchange( &p_viport->updates, 0, 0 ) )\r
931         {\r
932                 VNIC_TRACE_EXIT( VNIC_DBG_VIPORT, ("No updates.\n") );\r
933                 /*  now can restart heartbeats */\r
934                 if( !p_viport->timerActive &&\r
935                         p_viport->port_config.hbInterval )\r
936                 {\r
937                         viport_timer( p_viport, p_viport->port_config.hbInterval );\r
938                 }\r
939                 return NDIS_STATUS_SUCCESS;\r
940         }\r
941 \r
942         if( sync )\r
943         {\r
944                 status = NDIS_STATUS_SUCCESS;\r
945                 InterlockedOr( &p_viport->updates, SYNC_QUERY );\r
946         }\r
947         else\r
948         {\r
949                 status = NDIS_STATUS_PENDING;\r
950         }\r
951         /* stop heartbeat timer to serve another query */\r
952         viport_timerStop( p_viport );\r
953 \r
954         // Handle update bits one at a time.\r
955         if( p_viport->updates & NEED_ADDRESS_CONFIG )\r
956         {\r
957                 VNIC_TRACE( VNIC_DBG_INFO,\r
958                         ("QUERY NEED_ADDRESS_CONFIG\n"));\r
959                 KeAcquireSpinLock(&p_viport->lock, &irql );\r
960                 p_viport->linkState = LINK_CONFIGADDRSREQ;\r
961                 ib_status = control_configAddrsReq(\r
962                         &p_viport->control, p_viport->macAddresses,\r
963                         p_viport->numMacAddresses, &p_viport->addrs_query_done );\r
964                 KeReleaseSpinLock( &p_viport->lock, irql );\r
965                 if ( ib_status != IB_SUCCESS )\r
966                 {\r
967                         InterlockedAnd( &p_viport->updates, ~NEED_ADDRESS_CONFIG );\r
968                         VNIC_EXIT( VNIC_DBG_VIPORT );\r
969                         return NDIS_STATUS_FAILURE;\r
970                 }\r
971                 expected_state = LINK_CONFIGADDRSRSP;\r
972         }\r
973         else if( p_viport->updates & NEED_LINK_CONFIG )\r
974         {\r
975                 VNIC_TRACE( VNIC_DBG_INFO,\r
976                         ("QUERY NEED_LINK_CONFIG\n"));\r
977 \r
978                 KeAcquireSpinLock(&p_viport->lock, &irql );\r
979                 p_viport->linkState = LINK_CONFIGLINKREQ;\r
980 \r
981                 if( (InterlockedAnd(\r
982                         &p_viport->updates, ~MCAST_OVERFLOW ) & MCAST_OVERFLOW) )\r
983                 {\r
984                         p_viport->newFlags |= INIC_FLAG_ENABLE_MCAST_ALL;\r
985                 }\r
986                 else\r
987                 {\r
988                         p_viport->newFlags &= ~INIC_FLAG_ENABLE_MCAST_ALL;\r
989                 }\r
990 \r
991                 if ( p_viport->mtu != p_viport->newMtu )\r
992                         p_viport->mtu = p_viport->newMtu;\r
993 \r
994                 ib_status = control_configLinkReq( &p_viport->control,\r
995                         p_viport->newFlags, p_viport->mtu );\r
996                 KeReleaseSpinLock( &p_viport->lock, irql );\r
997                 if( ib_status != IB_SUCCESS )\r
998                 {\r
999                         InterlockedAnd( &p_viport->updates, ~NEED_LINK_CONFIG );\r
1000                         VNIC_EXIT( VNIC_DBG_VIPORT );\r
1001                         return NDIS_STATUS_FAILURE;\r
1002                 }\r
1003                 expected_state = LINK_CONFIGLINKRSP;\r
1004         }\r
1005         else if( p_viport->updates & NEED_STATS )\r
1006         {\r
1007                 // TODO: This is dead code.\r
1008                 VNIC_TRACE( VNIC_DBG_INFO,\r
1009                         ("QUERY NEED_STATS\n"));\r
1010 \r
1011                 KeAcquireSpinLock( &p_viport->lock, &irql );\r
1012                 p_viport->linkState = LINK_REPORTSTATREQ;\r
1013 \r
1014                 ib_status = control_reportStatisticsReq( &p_viport->control );\r
1015                 KeReleaseSpinLock( &p_viport->lock, irql );\r
1016                 if( ib_status != IB_SUCCESS )\r
1017                 {\r
1018                         InterlockedAnd( &p_viport->updates, ~NEED_STATS );\r
1019                         VNIC_EXIT( VNIC_DBG_VIPORT );\r
1020                         return NDIS_STATUS_FAILURE;\r
1021                 }\r
1022                 expected_state = LINK_REPORTSTATRSP;\r
1023         }\r
1024 \r
1025         if( sync )\r
1026         {\r
1027                 cl_event_wait_on( &p_viport->conn_event, EVENT_NO_TIMEOUT, FALSE );\r
1028 \r
1029                 if( p_viport->linkState != expected_state )\r
1030                 {\r
1031                         status = NDIS_STATUS_FAILURE;\r
1032                         VNIC_TRACE( VNIC_DBG_ERROR,\r
1033                                 ("Link state error: expected %d but got %d\n",\r
1034                                 expected_state, p_viport->linkState));\r
1035                 }\r
1036         }\r
1037         VNIC_EXIT( VNIC_DBG_VIPORT );\r
1038         return status;\r
1039 }\r
1040 \r