[VNIC] Initial checkin of VNIC code. Not yet fully functional.
[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                 control_heartbeatReq( &p_viport->control,\r
658                                                 p_viport->port_config.hbTimeout );\r
659         }\r
660 }\r
661 \r
662 \r
663 void\r
664 viport_timer(\r
665                 IN               viport_t       *p_viport,\r
666                 IN              int                     timeout )\r
667 {\r
668         VNIC_ENTER( VNIC_DBG_VIPORT );;\r
669 \r
670         InterlockedExchange( &p_viport->timerActive, TRUE );\r
671         cl_timer_start( &p_viport->timer, (uint32_t)timeout );\r
672 \r
673         VNIC_EXIT( VNIC_DBG_VIPORT );\r
674 }\r
675 \r
676 \r
677 void\r
678 viport_timerStop(\r
679                 IN              viport_t        *p_viport )\r
680 {\r
681         VNIC_ENTER( VNIC_DBG_VIPORT );\r
682 \r
683         if( p_viport )\r
684         {\r
685                 if( InterlockedExchange( &p_viport->timerActive, FALSE ) == TRUE )\r
686                 {\r
687                         cl_timer_stop( &p_viport->timer );\r
688                 }\r
689         }\r
690 \r
691         VNIC_EXIT( VNIC_DBG_VIPORT );\r
692         return;\r
693 }\r
694 \r
695 static ib_api_status_t\r
696 viport_initMacAddresses(\r
697                         IN              viport_t                *p_viport )\r
698 {\r
699         int             i, size;\r
700     KIRQL       flags;\r
701         NDIS_STATUS     status;\r
702         VNIC_ENTER( VNIC_DBG_VIPORT );\r
703 \r
704         size = p_viport->numMacAddresses * sizeof(Inic_AddressOp_t);\r
705         status = NdisAllocateMemoryWithTag( &p_viport->macAddresses, size , 'acam' );\r
706 \r
707         if ( status != NDIS_STATUS_SUCCESS )\r
708         {\r
709                 VNIC_TRACE_EXIT( VNIC_DBG_ERROR,\r
710                         ("Failed allocating MAC address table size %d\n", size) );\r
711                 return IB_INSUFFICIENT_MEMORY;\r
712         }\r
713 \r
714         NdisZeroMemory( p_viport->macAddresses, size );\r
715 \r
716         KeAcquireSpinLock( &p_viport->lock, &flags );\r
717         for( i = 0; i < p_viport->numMacAddresses; i++ )\r
718         {\r
719                 p_viport->macAddresses[i].index = (uint16_t)i;\r
720                 p_viport->macAddresses[i].vlan  = p_viport->defaultVlan;\r
721         }\r
722 \r
723         NdisFillMemory( p_viport->macAddresses[BROADCAST_ADDR].address,\r
724                MAC_ADDR_LEN, 0xFF );\r
725         p_viport->macAddresses[BROADCAST_ADDR].valid = TRUE;\r
726 \r
727         NdisMoveMemory( p_viport->macAddresses[UNICAST_ADDR].address,\r
728                p_viport->hwMacAddress, MAC_ADDR_LEN );\r
729 \r
730         p_viport->macAddresses[UNICAST_ADDR].valid   = TRUE;\r
731         p_viport->p_adapter->macSet = TRUE;\r
732 \r
733         KeReleaseSpinLock( &p_viport->lock, flags );\r
734 \r
735         VNIC_EXIT( VNIC_DBG_VIPORT );\r
736         return IB_SUCCESS;\r
737 }\r
738 \r
739 \r
740 ib_api_status_t\r
741 viport_control_connect(\r
742         IN              viport_t*       const   p_viport )\r
743 {\r
744         ib_api_status_t ib_status;\r
745 \r
746         VNIC_ENTER( VNIC_DBG_VIPORT );\r
747 \r
748         ib_status = control_init( &p_viport->control, p_viport,\r
749                 &p_viport->port_config.controlConfig, p_viport->portGuid );\r
750         if( ib_status != IB_SUCCESS )\r
751         {\r
752                 VNIC_EXIT( VNIC_DBG_VIPORT );\r
753                 return ib_status;\r
754         }\r
755 \r
756         ib_status = ibqp_connect( &p_viport->control.qp );\r
757         if( ib_status != IB_SUCCESS )\r
758         {\r
759                 VNIC_TRACE( VNIC_DBG_INFO,\r
760                                 ("control QP connect failed\n"));\r
761                 goto err1;\r
762         }\r
763 \r
764         InterlockedExchange( (volatile LONG*)&p_viport->linkState,\r
765                 (LONG)LINK_INITINICREQ );\r
766 \r
767         ib_status = control_initInicReq( &p_viport->control );\r
768         if( ib_status != IB_SUCCESS )\r
769         {\r
770                 VNIC_TRACE( VNIC_DBG_INFO, ("CMD_INIT_INIC  REQ failed\n") );\r
771                 goto err2;\r
772         }\r
773         cl_event_wait_on( &p_viport->conn_event,\r
774                                                 (p_viport->control.p_conf->rspTimeout << 11), TRUE );\r
775 \r
776         if( p_viport->linkState != LINK_INITINICRSP )\r
777         {\r
778                 VNIC_TRACE( VNIC_DBG_INFO,\r
779                                         ("CMD_INIT_INIC RSP failed\n"));\r
780                 ib_status = IB_INSUFFICIENT_RESOURCES;\r
781                 goto err2;\r
782         }\r
783 \r
784         vnic_resume_oids( p_viport->p_adapter );\r
785 \r
786         ib_status = viport_initMacAddresses( p_viport );\r
787         if( ib_status != IB_SUCCESS )\r
788         {\r
789                 VNIC_TRACE( VNIC_DBG_INFO,\r
790                                 ("Init MAC Addresses failed\n"));\r
791 err2:\r
792                 control_resetReq( &p_viport->control );\r
793 err1:\r
794                 control_cleanup( &p_viport->control );\r
795         }\r
796 \r
797         VNIC_EXIT( VNIC_DBG_VIPORT );\r
798         return ib_status;\r
799 }\r
800 \r
801 ib_api_status_t\r
802 viport_data_connect(\r
803         IN              viport_t*       const   p_viport )\r
804 {\r
805         NDIS_STATUS             status;\r
806         ib_api_status_t ib_status;\r
807 \r
808         VNIC_ENTER( VNIC_DBG_VIPORT );\r
809 \r
810         ib_status = data_init( &p_viport->data,\r
811                                                  &p_viport->port_config.dataConfig,\r
812                                                  p_viport->portGuid );\r
813         if( ib_status != IB_SUCCESS )\r
814         {\r
815                 VNIC_TRACE( VNIC_DBG_ERROR, ("Data init returned %s\n",\r
816                         p_viport->p_adapter->ifc.get_err_str( ib_status )) );\r
817                 return ib_status;\r
818         }\r
819         InterlockedExchange( (volatile LONG*)&p_viport->linkState,\r
820                                                                 (LONG)LINK_CONFIGDATAPATHREQ );\r
821 \r
822         ib_status = control_configDataPathReq( &p_viport->control,\r
823                 data_pathId(&p_viport->data ), data_hostPoolMax( &p_viport->data ),\r
824                 data_eiocPoolMax( &p_viport->data ) );\r
825         if( ib_status != IB_SUCCESS )\r
826         {\r
827                 VNIC_TRACE( VNIC_DBG_ERROR,\r
828                                 ("command CONFIGDATAPATH REQ failed\n"));\r
829                 return ib_status;\r
830         }\r
831         cl_event_wait_on( &p_viport->conn_event,\r
832                                         (p_viport->control.p_conf->rspTimeout << 11), TRUE );\r
833         \r
834         if( p_viport->linkState != LINK_CONFIGDATAPATHRSP )\r
835         {\r
836                 VNIC_TRACE( VNIC_DBG_ERROR,\r
837                                         ("failed to get CONFIGDATAPATH RSP\n"));\r
838                 return IB_INSUFFICIENT_RESOURCES;\r
839         }\r
840 \r
841         ib_status = data_connect( &p_viport->data );\r
842         if( ib_status != IB_SUCCESS )\r
843         {\r
844                 VNIC_EXIT( VNIC_DBG_VIPORT );\r
845                 return ib_status;\r
846         }\r
847         cl_event_wait_on( &p_viport->conn_event,\r
848                                         (p_viport->control.p_conf->rspTimeout << 11), TRUE );\r
849         if( p_viport->data.qp.qpState != IB_ATTACHED )\r
850         {\r
851                 VNIC_EXIT( VNIC_DBG_VIPORT );\r
852                 return IB_ERROR;\r
853         }\r
854         InterlockedExchange( (volatile LONG*)&p_viport->linkState,\r
855                                                                         (LONG)LINK_XCHGPOOLREQ );\r
856         ib_status = control_exchangePoolsReq( &p_viport->control,\r
857                 data_localPoolAddr(&p_viport->data),\r
858                 data_localPoolRkey(&p_viport->data) );\r
859         if( ib_status != IB_SUCCESS )\r
860         {\r
861                 VNIC_TRACE_EXIT( VNIC_DBG_ERROR,\r
862                                 ("command XCHGPOOL REQ failed\n"));\r
863                 return ib_status;\r
864         }\r
865         cl_event_wait_on( &p_viport->conn_event,\r
866                                         (p_viport->control.p_conf->rspTimeout << 11), TRUE );\r
867 \r
868         if( p_viport->linkState != LINK_XCHGPOOLRSP )\r
869         {\r
870                 VNIC_TRACE_EXIT( VNIC_DBG_ERROR,\r
871                                 ("failed to get LINK_XCHGPOOL RSP\n"));\r
872                 return IB_ERROR;\r
873         }\r
874 \r
875         InterlockedExchange( (volatile LONG*)&p_viport->linkState,\r
876                                                         (LONG)LINK_INITIALIZED );\r
877         p_viport->state = VIPORT_CONNECTED;\r
878 \r
879         data_connected(&p_viport->data);\r
880 \r
881         InterlockedExchange( (volatile LONG *)&p_viport->mtu, 1500 );\r
882         InterlockedExchange( (volatile LONG *)&p_viport->flags, 0 );\r
883         status = viport_setLink( p_viport, INIC_FLAG_ENABLE_NIC, 1500 );\r
884         if( status != NDIS_STATUS_SUCCESS )\r
885         {\r
886                 VNIC_TRACE_EXIT( VNIC_DBG_ERROR,\r
887                                 ("failed to set Link flags\n"));\r
888                 return IB_ERROR;\r
889         }\r
890 \r
891         /* now we have to start periodic heartbeat timer */\r
892         if( p_viport->port_config.hbInterval )\r
893         {\r
894                 viport_timer( p_viport, p_viport->port_config.hbInterval );\r
895         }\r
896 \r
897         VNIC_EXIT( VNIC_DBG_VIPORT );\r
898         return IB_SUCCESS;\r
899 }\r
900 \r
901 \r
902 NDIS_STATUS\r
903 _viport_process_query(\r
904                 IN              viport_t*       const   p_viport,\r
905                 IN              BOOLEAN                         sync )\r
906 {\r
907         NDIS_STATUS             status;\r
908         ib_api_status_t ib_status;\r
909         KIRQL                   irql;\r
910         LinkState_t             expected_state = 0;\r
911 \r
912         VNIC_ENTER( VNIC_DBG_VIPORT );\r
913 \r
914         if ( p_viport->state != VIPORT_CONNECTED ||\r
915                 p_viport->errored != 0 )\r
916         {\r
917                 VNIC_TRACE_EXIT( VNIC_DBG_WARN, ("Invalid state or error.\n") );\r
918                 return NDIS_STATUS_NOT_ACCEPTED;\r
919         }\r
920 \r
921         // Check for updates.  Note that unless sync is set to TRUE, this\r
922         // is the only way for this function to return success.\r
923         if( !InterlockedCompareExchange( &p_viport->updates, 0, 0 ) )\r
924         {\r
925                 VNIC_TRACE_EXIT( VNIC_DBG_VIPORT, ("No updates.\n") );\r
926                 return NDIS_STATUS_SUCCESS;\r
927         }\r
928 \r
929         if( sync )\r
930         {\r
931                 status = NDIS_STATUS_SUCCESS;\r
932                 InterlockedOr( &p_viport->updates, SYNC_QUERY );\r
933         }\r
934         else\r
935         {\r
936                 status = NDIS_STATUS_PENDING;\r
937         }\r
938 \r
939         // Handle update bits one at a time.\r
940         if( p_viport->updates & NEED_ADDRESS_CONFIG )\r
941         {\r
942                 VNIC_TRACE( VNIC_DBG_INFO,\r
943                         ("QUERY NEED_ADDRESS_CONFIG\n"));\r
944                 KeAcquireSpinLock(&p_viport->lock, &irql );\r
945                 p_viport->linkState = LINK_CONFIGADDRSREQ;\r
946                 ib_status = control_configAddrsReq(\r
947                         &p_viport->control, p_viport->macAddresses,\r
948                         p_viport->numMacAddresses, &p_viport->addrs_query_done );\r
949                 KeReleaseSpinLock( &p_viport->lock, irql );\r
950                 if ( ib_status != IB_SUCCESS )\r
951                 {\r
952                         InterlockedAnd( &p_viport->updates, ~NEED_ADDRESS_CONFIG );\r
953                         VNIC_EXIT( VNIC_DBG_VIPORT );\r
954                         return NDIS_STATUS_FAILURE;\r
955                 }\r
956                 expected_state = LINK_CONFIGADDRSRSP;\r
957         }\r
958         else if( p_viport->updates & NEED_LINK_CONFIG )\r
959         {\r
960                 VNIC_TRACE( VNIC_DBG_INFO,\r
961                         ("QUERY NEED_LINK_CONFIG\n"));\r
962 \r
963                 KeAcquireSpinLock(&p_viport->lock, &irql );\r
964                 p_viport->linkState = LINK_CONFIGLINKREQ;\r
965 \r
966                 if( (InterlockedAnd(\r
967                         &p_viport->updates, ~MCAST_OVERFLOW ) & MCAST_OVERFLOW) )\r
968                 {\r
969                         p_viport->newFlags |= INIC_FLAG_ENABLE_MCAST_ALL;\r
970                 }\r
971                 else\r
972                 {\r
973                         p_viport->newFlags &= ~INIC_FLAG_ENABLE_MCAST_ALL;\r
974                 }\r
975 \r
976                 if ( p_viport->mtu != p_viport->newMtu )\r
977                         p_viport->mtu = p_viport->newMtu;\r
978 \r
979                 ib_status = control_configLinkReq( &p_viport->control,\r
980                         p_viport->newFlags, p_viport->mtu );\r
981                 KeReleaseSpinLock( &p_viport->lock, irql );\r
982                 if( ib_status != IB_SUCCESS )\r
983                 {\r
984                         InterlockedAnd( &p_viport->updates, ~NEED_LINK_CONFIG );\r
985                         VNIC_EXIT( VNIC_DBG_VIPORT );\r
986                         return NDIS_STATUS_FAILURE;\r
987                 }\r
988                 expected_state = LINK_CONFIGLINKRSP;\r
989         }\r
990         else if( p_viport->updates & NEED_STATS )\r
991         {\r
992                 // TODO: This is dead code.\r
993                 VNIC_TRACE( VNIC_DBG_INFO,\r
994                         ("QUERY NEED_STATS\n"));\r
995 \r
996                 KeAcquireSpinLock( &p_viport->lock, &irql );\r
997                 p_viport->linkState = LINK_REPORTSTATREQ;\r
998 \r
999                 ib_status = control_reportStatisticsReq( &p_viport->control );\r
1000                 KeReleaseSpinLock( &p_viport->lock, irql );\r
1001                 if( ib_status != IB_SUCCESS )\r
1002                 {\r
1003                         InterlockedAnd( &p_viport->updates, ~NEED_STATS );\r
1004                         VNIC_EXIT( VNIC_DBG_VIPORT );\r
1005                         return NDIS_STATUS_FAILURE;\r
1006                 }\r
1007                 expected_state = LINK_REPORTSTATRSP;\r
1008         }\r
1009 \r
1010         if( sync )\r
1011         {\r
1012                 cl_event_wait_on( &p_viport->conn_event, EVENT_NO_TIMEOUT, FALSE );\r
1013 \r
1014                 if( p_viport->linkState != expected_state )\r
1015                 {\r
1016                         status = NDIS_STATUS_FAILURE;\r
1017                         VNIC_TRACE( VNIC_DBG_ERROR,\r
1018                                 ("Link state error: expected %d but got %d\n",\r
1019                                 expected_state, p_viport->linkState));\r
1020                 }\r
1021         }\r
1022         VNIC_EXIT( VNIC_DBG_VIPORT );\r
1023         return status;\r
1024 }\r
1025 \r