1 /** @file
2   Provides the basic UNID functions.
3 
4 Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution.  The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9 
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include "Undi32.h"
16 
17 //
18 // Global variables defined in this file
19 //
20 UNDI_CALL_TABLE api_table[PXE_OPCODE_LAST_VALID+1] = { \
21   {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,0, (UINT16)(ANY_STATE),UNDI_GetState },\
22   {(UINT16)(DONT_CHECK),PXE_DBSIZE_NOT_USED,0,(UINT16)(ANY_STATE),UNDI_Start },\
23   {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,0,MUST_BE_STARTED,UNDI_Stop },\
24   {PXE_CPBSIZE_NOT_USED,sizeof(PXE_DB_GET_INIT_INFO),0,MUST_BE_STARTED, UNDI_GetInitInfo },\
25   {PXE_CPBSIZE_NOT_USED,sizeof(PXE_DB_GET_CONFIG_INFO),0,MUST_BE_STARTED, UNDI_GetConfigInfo },\
26   {sizeof(PXE_CPB_INITIALIZE),(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK),MUST_BE_STARTED,UNDI_Initialize },\
27   {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED,UNDI_Reset },\
28   {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,0, MUST_BE_INITIALIZED,UNDI_Shutdown },\
29   {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED,UNDI_Interrupt },\
30   {(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_RecFilter },\
31   {(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_StnAddr },\
32   {PXE_CPBSIZE_NOT_USED, (UINT16)(DONT_CHECK), (UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_Statistics },\
33   {sizeof(PXE_CPB_MCAST_IP_TO_MAC),sizeof(PXE_DB_MCAST_IP_TO_MAC), (UINT16)(DONT_CHECK),MUST_BE_INITIALIZED, UNDI_ip2mac },\
34   {(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_NVData },\
35   {PXE_CPBSIZE_NOT_USED,(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_Status },\
36   {(UINT16)(DONT_CHECK),PXE_DBSIZE_NOT_USED,(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_FillHeader },\
37   {(UINT16)(DONT_CHECK),PXE_DBSIZE_NOT_USED,(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_Transmit },\
38   {sizeof(PXE_CPB_RECEIVE),sizeof(PXE_DB_RECEIVE),0,MUST_BE_INITIALIZED, UNDI_Receive } \
39 };
40 
41 //
42 // end of global variables
43 //
44 
45 
46 /**
47   This routine determines the operational state of the UNDI.  It updates the state flags in the
48   Command Descriptor Block based on information derived from the AdapterInfo instance data.
49   To ensure the command has completed successfully, CdbPtr->StatCode will contain the result of
50   the command execution.
51   The CdbPtr->StatFlags will contain a STOPPED, STARTED, or INITIALIZED state once the command
52   has successfully completed.
53   Keep in mind the AdapterInfo->State is the active state of the adapter (based on software
54   interrogation), and the CdbPtr->StateFlags is the passed back information that is reflected
55   to the caller of the UNDI API.
56 
57   @param  CdbPtr               Pointer to the command descriptor block.
58   @param  AdapterInfo          Pointer to the NIC data structure information which
59                                the UNDI driver is layering on..
60 
61   @return None
62 
63 **/
64 VOID
UNDI_GetState(IN PXE_CDB * CdbPtr,IN NIC_DATA_INSTANCE * AdapterInfo)65 UNDI_GetState (
66   IN  PXE_CDB           *CdbPtr,
67   IN  NIC_DATA_INSTANCE *AdapterInfo
68   )
69 {
70   CdbPtr->StatFlags = (PXE_STATFLAGS) (CdbPtr->StatFlags | AdapterInfo->State);
71   return ;
72 }
73 
74 
75 /**
76   This routine is used to change the operational state of the UNDI from stopped to started.
77   It will do this as long as the adapter's state is PXE_STATFLAGS_GET_STATE_STOPPED, otherwise
78   the CdbPtr->StatFlags will reflect a command failure, and the CdbPtr->StatCode will reflect the
79   UNDI as having already been started.
80   This routine is modified to reflect the undi 1.1 specification changes. The
81   changes in the spec are mainly in the callback routines, the new spec adds
82   3 more callbacks and a unique id.
83   Since this UNDI supports both old and new undi specifications,
84   The NIC's data structure is filled in with the callback routines (depending
85   on the version) pointed to in the caller's CpbPtr.  This seeds the Delay,
86   Virt2Phys, Block, and Mem_IO for old and new versions and Map_Mem, UnMap_Mem
87   and Sync_Mem routines and a unique id variable for the new version.
88   This is the function which an external entity (SNP, O/S, etc) would call
89   to provide it's I/O abstraction to the UNDI.
90   It's final action is to change the AdapterInfo->State to PXE_STATFLAGS_GET_STATE_STARTED.
91 
92   @param  CdbPtr               Pointer to the command descriptor block.
93   @param  AdapterInfo          Pointer to the NIC data structure information which
94                                the UNDI driver is layering on..
95 
96   @return None
97 
98 **/
99 VOID
UNDI_Start(IN PXE_CDB * CdbPtr,IN NIC_DATA_INSTANCE * AdapterInfo)100 UNDI_Start (
101   IN  PXE_CDB           *CdbPtr,
102   IN  NIC_DATA_INSTANCE *AdapterInfo
103   )
104 {
105   PXE_CPB_START_30  *CpbPtr;
106   PXE_CPB_START_31  *CpbPtr_31;
107 
108   //
109   // check if it is already started.
110   //
111   if (AdapterInfo->State != PXE_STATFLAGS_GET_STATE_STOPPED) {
112     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
113     CdbPtr->StatCode  = PXE_STATCODE_ALREADY_STARTED;
114     return ;
115   }
116 
117   if (CdbPtr->CPBsize != sizeof(PXE_CPB_START_30) &&
118       CdbPtr->CPBsize != sizeof(PXE_CPB_START_31)) {
119 
120     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
121     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;
122     return ;
123   }
124 
125   CpbPtr    = (PXE_CPB_START_30 *) (UINTN) (CdbPtr->CPBaddr);
126   CpbPtr_31 = (PXE_CPB_START_31 *) (UINTN) (CdbPtr->CPBaddr);
127 
128   if (AdapterInfo->VersionFlag == 0x30) {
129     AdapterInfo->Delay_30     = (bsptr_30) (UINTN) CpbPtr->Delay;
130     AdapterInfo->Virt2Phys_30 = (virtphys_30) (UINTN) CpbPtr->Virt2Phys;
131     AdapterInfo->Block_30     = (block_30) (UINTN) CpbPtr->Block;
132     //
133     // patch for old buggy 3.0 code:
134     // In EFI1.0 undi used to provide the full (absolute) I/O address to the
135     // i/o calls and SNP used to provide a callback that used GlobalIoFncs and
136     // everything worked fine! In EFI 1.1, UNDI is not using the full
137     // i/o or memory address to access the device, The base values for the i/o
138     // and memory address is abstracted by the device specific PciIoFncs and
139     // UNDI only uses the offset values. Since UNDI3.0 cannot provide any
140     // identification to SNP, SNP cannot use nic specific PciIoFncs callback!
141     //
142     // To fix this and make undi3.0 work with SNP in EFI1.1 we
143     // use a TmpMemIo function that is defined in init.c
144     // This breaks the runtime driver feature of undi, but what to do
145     // if we have to provide the 3.0 compatibility (including the 3.0 bugs)
146     //
147     // This TmpMemIo function also takes a UniqueId parameter
148     // (as in undi3.1 design) and so initialize the UniqueId as well here
149     // Note: AdapterInfo->Mem_Io_30 is just filled for consistency with other
150     // parameters but never used, we only use Mem_Io field in the In/Out routines
151     // inside e100b.c.
152     //
153     AdapterInfo->Mem_Io_30  = (mem_io_30) (UINTN) CpbPtr->Mem_IO;
154     AdapterInfo->Mem_Io     = (mem_io) (UINTN) TmpMemIo;
155     AdapterInfo->Unique_ID  = (UINT64) (UINTN) AdapterInfo;
156 
157   } else {
158     AdapterInfo->Delay      = (bsptr) (UINTN) CpbPtr_31->Delay;
159     AdapterInfo->Virt2Phys  = (virtphys) (UINTN) CpbPtr_31->Virt2Phys;
160     AdapterInfo->Block      = (block) (UINTN) CpbPtr_31->Block;
161     AdapterInfo->Mem_Io     = (mem_io) (UINTN) CpbPtr_31->Mem_IO;
162 
163     AdapterInfo->Map_Mem    = (map_mem) (UINTN) CpbPtr_31->Map_Mem;
164     AdapterInfo->UnMap_Mem  = (unmap_mem) (UINTN) CpbPtr_31->UnMap_Mem;
165     AdapterInfo->Sync_Mem   = (sync_mem) (UINTN) CpbPtr_31->Sync_Mem;
166     AdapterInfo->Unique_ID  = CpbPtr_31->Unique_ID;
167   }
168 
169   AdapterInfo->State = PXE_STATFLAGS_GET_STATE_STARTED;
170 
171   return ;
172 }
173 
174 
175 /**
176   This routine is used to change the operational state of the UNDI from started to stopped.
177   It will not do this if the adapter's state is PXE_STATFLAGS_GET_STATE_INITIALIZED, otherwise
178   the CdbPtr->StatFlags will reflect a command failure, and the CdbPtr->StatCode will reflect the
179   UNDI as having already not been shut down.
180   The NIC's data structure will have the Delay, Virt2Phys, and Block, pointers zero'd out..
181   It's final action is to change the AdapterInfo->State to PXE_STATFLAGS_GET_STATE_STOPPED.
182 
183   @param  CdbPtr               Pointer to the command descriptor block.
184   @param  AdapterInfo          Pointer to the NIC data structure information which
185                                the UNDI driver is layering on..
186 
187   @return None
188 
189 **/
190 VOID
UNDI_Stop(IN PXE_CDB * CdbPtr,IN NIC_DATA_INSTANCE * AdapterInfo)191 UNDI_Stop (
192   IN  PXE_CDB           *CdbPtr,
193   IN  NIC_DATA_INSTANCE *AdapterInfo
194   )
195 {
196   if (AdapterInfo->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
197     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
198     CdbPtr->StatCode  = PXE_STATCODE_NOT_SHUTDOWN;
199     return ;
200   }
201 
202   AdapterInfo->Delay_30     = 0;
203   AdapterInfo->Virt2Phys_30 = 0;
204   AdapterInfo->Block_30     = 0;
205 
206   AdapterInfo->Delay        = 0;
207   AdapterInfo->Virt2Phys    = 0;
208   AdapterInfo->Block        = 0;
209 
210   AdapterInfo->Map_Mem      = 0;
211   AdapterInfo->UnMap_Mem    = 0;
212   AdapterInfo->Sync_Mem     = 0;
213 
214   AdapterInfo->State        = PXE_STATFLAGS_GET_STATE_STOPPED;
215 
216   return ;
217 }
218 
219 
220 /**
221   This routine is used to retrieve the initialization information that is needed by drivers and
222   applications to initialize the UNDI.  This will fill in data in the Data Block structure that is
223   pointed to by the caller's CdbPtr->DBaddr.  The fields filled in are as follows:
224   MemoryRequired, FrameDataLen, LinkSpeeds[0-3], NvCount, NvWidth, MediaHeaderLen, HWaddrLen,
225   MCastFilterCnt, TxBufCnt, TxBufSize, RxBufCnt, RxBufSize, IFtype, Duplex, and LoopBack.
226   In addition, the CdbPtr->StatFlags ORs in that this NIC supports cable detection.  (APRIORI knowledge)
227 
228   @param  CdbPtr               Pointer to the command descriptor block.
229   @param  AdapterInfo          Pointer to the NIC data structure information which
230                                the UNDI driver is layering on..
231 
232   @return None
233 
234 **/
235 VOID
UNDI_GetInitInfo(IN PXE_CDB * CdbPtr,IN NIC_DATA_INSTANCE * AdapterInfo)236 UNDI_GetInitInfo (
237   IN  PXE_CDB           *CdbPtr,
238   IN  NIC_DATA_INSTANCE *AdapterInfo
239   )
240 {
241   PXE_DB_GET_INIT_INFO  *DbPtr;
242 
243   DbPtr = (PXE_DB_GET_INIT_INFO *) (UINTN) (CdbPtr->DBaddr);
244 
245   DbPtr->MemoryRequired = MEMORY_NEEDED;
246   DbPtr->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;
247   DbPtr->LinkSpeeds[0] = 10;
248   DbPtr->LinkSpeeds[1] = 100;
249   DbPtr->LinkSpeeds[2] = DbPtr->LinkSpeeds[3] = 0;
250   DbPtr->NvCount = MAX_EEPROM_LEN;
251   DbPtr->NvWidth = 4;
252   DbPtr->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
253   DbPtr->HWaddrLen = PXE_HWADDR_LEN_ETHER;
254   DbPtr->MCastFilterCnt = MAX_MCAST_ADDRESS_CNT;
255 
256   DbPtr->TxBufCnt = TX_BUFFER_COUNT;
257   DbPtr->TxBufSize = (UINT16) sizeof (TxCB);
258   DbPtr->RxBufCnt = RX_BUFFER_COUNT;
259   DbPtr->RxBufSize = (UINT16) sizeof (RxFD);
260 
261   DbPtr->IFtype = PXE_IFTYPE_ETHERNET;
262   DbPtr->SupportedDuplexModes = PXE_DUPLEX_ENABLE_FULL_SUPPORTED |
263                   PXE_DUPLEX_FORCE_FULL_SUPPORTED;
264   DbPtr->SupportedLoopBackModes = PXE_LOOPBACK_INTERNAL_SUPPORTED |
265                     PXE_LOOPBACK_EXTERNAL_SUPPORTED;
266 
267   CdbPtr->StatFlags |= (PXE_STATFLAGS_CABLE_DETECT_SUPPORTED |
268                         PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED);
269   return ;
270 }
271 
272 
273 /**
274   This routine is used to retrieve the configuration information about the NIC being controlled by
275   this driver.  This will fill in data in the Data Block structure that is pointed to by the caller's CdbPtr->DBaddr.
276   The fields filled in are as follows:
277   DbPtr->pci.BusType, DbPtr->pci.Bus, DbPtr->pci.Device, and DbPtr->pci.
278   In addition, the DbPtr->pci.Config.Dword[0-63] grabs a copy of this NIC's PCI configuration space.
279 
280   @param  CdbPtr               Pointer to the command descriptor block.
281   @param  AdapterInfo          Pointer to the NIC data structure information which
282                                the UNDI driver is layering on..
283 
284   @return None
285 
286 **/
287 VOID
UNDI_GetConfigInfo(IN PXE_CDB * CdbPtr,IN NIC_DATA_INSTANCE * AdapterInfo)288 UNDI_GetConfigInfo (
289   IN  PXE_CDB           *CdbPtr,
290   IN  NIC_DATA_INSTANCE *AdapterInfo
291   )
292 {
293   UINT16                  Index;
294   PXE_DB_GET_CONFIG_INFO  *DbPtr;
295 
296   DbPtr               = (PXE_DB_GET_CONFIG_INFO *) (UINTN) (CdbPtr->DBaddr);
297 
298   DbPtr->pci.BusType  = PXE_BUSTYPE_PCI;
299   DbPtr->pci.Bus      = AdapterInfo->Bus;
300   DbPtr->pci.Device   = AdapterInfo->Device;
301   DbPtr->pci.Function = AdapterInfo->Function;
302 
303   for (Index = 0; Index < MAX_PCI_CONFIG_LEN; Index++) {
304     DbPtr->pci.Config.Dword[Index] = AdapterInfo->Config[Index];
305   }
306 
307   return ;
308 }
309 
310 
311 /**
312   This routine resets the network adapter and initializes the UNDI using the parameters supplied in
313   the CPB.  This command must be issued before the network adapter can be setup to transmit and
314   receive packets.
315   Once the memory requirements of the UNDI are obtained by using the GetInitInfo command, a block
316   of non-swappable memory may need to be allocated.  The address of this memory must be passed to
317   UNDI during the Initialize in the CPB.  This memory is used primarily for transmit and receive buffers.
318   The fields CableDetect, LinkSpeed, Duplex, LoopBack, MemoryPtr, and MemoryLength are set with information
319   that was passed in the CPB and the NIC is initialized.
320   If the NIC initialization fails, the CdbPtr->StatFlags are updated with PXE_STATFLAGS_COMMAND_FAILED
321   Otherwise, AdapterInfo->State is updated with PXE_STATFLAGS_GET_STATE_INITIALIZED showing the state of
322   the UNDI is now initialized.
323 
324   @param  CdbPtr               Pointer to the command descriptor block.
325   @param  AdapterInfo          Pointer to the NIC data structure information which
326                                the UNDI driver is layering on..
327 
328   @return None
329 
330 **/
331 VOID
UNDI_Initialize(IN PXE_CDB * CdbPtr,NIC_DATA_INSTANCE * AdapterInfo)332 UNDI_Initialize (
333   IN  PXE_CDB       *CdbPtr,
334   NIC_DATA_INSTANCE *AdapterInfo
335   )
336 {
337   PXE_CPB_INITIALIZE  *CpbPtr;
338 
339   if ((CdbPtr->OpFlags != PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) &&
340       (CdbPtr->OpFlags != PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE)) {
341     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
342     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;
343     return ;
344   }
345 
346   //
347   // check if it is already initialized
348   //
349   if (AdapterInfo->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
350     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
351     CdbPtr->StatCode  = PXE_STATCODE_ALREADY_INITIALIZED;
352     return ;
353   }
354 
355   CpbPtr  = (PXE_CPB_INITIALIZE *) (UINTN) CdbPtr->CPBaddr;
356 
357   if (CpbPtr->MemoryLength < (UINT32) MEMORY_NEEDED) {
358     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
359     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CPB;
360     return ;
361   }
362 
363   //
364   // default behaviour is to detect the cable, if the 3rd param is 1,
365   // do not do that
366   //
367   AdapterInfo->CableDetect = (UINT8) ((CdbPtr->OpFlags == (UINT16) PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE) ? (UINT8) 0 : (UINT8) 1);
368   AdapterInfo->LinkSpeedReq = (UINT16) CpbPtr->LinkSpeed;
369   AdapterInfo->DuplexReq    = CpbPtr->DuplexMode;
370   AdapterInfo->LoopBack     = CpbPtr->LoopBackMode;
371   AdapterInfo->MemoryPtr    = CpbPtr->MemoryAddr;
372   AdapterInfo->MemoryLength = CpbPtr->MemoryLength;
373 
374   CdbPtr->StatCode          = (PXE_STATCODE) E100bInit (AdapterInfo);
375 
376   if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {
377     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
378   } else {
379     AdapterInfo->State = PXE_STATFLAGS_GET_STATE_INITIALIZED;
380   }
381 
382   return ;
383 }
384 
385 
386 /**
387   This routine resets the network adapter and initializes the UNDI using the parameters supplied in
388   the CPB.  The transmit and receive queues are emptied and any pending interrupts are cleared.
389   If the NIC reset fails, the CdbPtr->StatFlags are updated with PXE_STATFLAGS_COMMAND_FAILED
390 
391   @param  CdbPtr               Pointer to the command descriptor block.
392   @param  AdapterInfo          Pointer to the NIC data structure information which
393                                the UNDI driver is layering on..
394 
395   @return None
396 
397 **/
398 VOID
UNDI_Reset(IN PXE_CDB * CdbPtr,IN NIC_DATA_INSTANCE * AdapterInfo)399 UNDI_Reset (
400   IN  PXE_CDB           *CdbPtr,
401   IN  NIC_DATA_INSTANCE *AdapterInfo
402   )
403 {
404   if (CdbPtr->OpFlags != PXE_OPFLAGS_NOT_USED &&
405       CdbPtr->OpFlags != PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS &&
406       CdbPtr->OpFlags != PXE_OPFLAGS_RESET_DISABLE_FILTERS ) {
407 
408     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
409     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;
410     return ;
411   }
412 
413   CdbPtr->StatCode = (UINT16) E100bReset (AdapterInfo, CdbPtr->OpFlags);
414 
415   if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {
416     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
417   }
418 }
419 
420 
421 /**
422   This routine resets the network adapter and leaves it in a safe state for another driver to
423   initialize.  Any pending transmits or receives are lost.  Receive filters and external
424   interrupt enables are disabled.  Once the UNDI has been shutdown, it can then be stopped
425   or initialized again.
426   If the NIC reset fails, the CdbPtr->StatFlags are updated with PXE_STATFLAGS_COMMAND_FAILED
427   Otherwise, AdapterInfo->State is updated with PXE_STATFLAGS_GET_STATE_STARTED showing the state of
428   the NIC as being started.
429 
430   @param  CdbPtr               Pointer to the command descriptor block.
431   @param  AdapterInfo          Pointer to the NIC data structure information which
432                                the UNDI driver is layering on..
433 
434   @return None
435 
436 **/
437 VOID
UNDI_Shutdown(IN PXE_CDB * CdbPtr,IN NIC_DATA_INSTANCE * AdapterInfo)438 UNDI_Shutdown (
439   IN  PXE_CDB           *CdbPtr,
440   IN  NIC_DATA_INSTANCE *AdapterInfo
441   )
442 {
443   //
444   // do the shutdown stuff here
445   //
446   CdbPtr->StatCode = (UINT16) E100bShutdown (AdapterInfo);
447 
448   if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {
449     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
450   } else {
451     AdapterInfo->State = PXE_STATFLAGS_GET_STATE_STARTED;
452   }
453 
454   return ;
455 }
456 
457 
458 /**
459   This routine can be used to read and/or change the current external interrupt enable
460   settings.  Disabling an external interrupt enable prevents and external (hardware)
461   interrupt from being signaled by the network device.  Internally the interrupt events
462   can still be polled by using the UNDI_GetState command.
463   The resulting information on the interrupt state will be passed back in the CdbPtr->StatFlags.
464 
465   @param  CdbPtr               Pointer to the command descriptor block.
466   @param  AdapterInfo          Pointer to the NIC data structure information which
467                                the UNDI driver is layering on..
468 
469   @return None
470 
471 **/
472 VOID
UNDI_Interrupt(IN PXE_CDB * CdbPtr,IN NIC_DATA_INSTANCE * AdapterInfo)473 UNDI_Interrupt (
474   IN  PXE_CDB           *CdbPtr,
475   IN  NIC_DATA_INSTANCE *AdapterInfo
476   )
477 {
478   UINT8 IntMask;
479 
480   IntMask = (UINT8)(UINTN)(CdbPtr->OpFlags & (PXE_OPFLAGS_INTERRUPT_RECEIVE |
481                                               PXE_OPFLAGS_INTERRUPT_TRANSMIT |
482                                               PXE_OPFLAGS_INTERRUPT_COMMAND |
483                                               PXE_OPFLAGS_INTERRUPT_SOFTWARE));
484 
485   switch (CdbPtr->OpFlags & PXE_OPFLAGS_INTERRUPT_OPMASK) {
486   case PXE_OPFLAGS_INTERRUPT_READ:
487     break;
488 
489   case PXE_OPFLAGS_INTERRUPT_ENABLE:
490     if (IntMask == 0) {
491       CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
492       CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;
493       return ;
494     }
495 
496     AdapterInfo->int_mask = IntMask;
497     E100bSetInterruptState (AdapterInfo);
498     break;
499 
500   case PXE_OPFLAGS_INTERRUPT_DISABLE:
501     if (IntMask != 0) {
502       AdapterInfo->int_mask = (UINT16) (AdapterInfo->int_mask & ~(IntMask));
503       E100bSetInterruptState (AdapterInfo);
504       break;
505     }
506 
507   //
508   // else fall thru.
509   //
510   default:
511     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
512     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;
513     return ;
514   }
515 
516   if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_RECEIVE) != 0) {
517     CdbPtr->StatFlags |= PXE_STATFLAGS_INTERRUPT_RECEIVE;
518 
519   }
520 
521   if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_TRANSMIT) != 0) {
522     CdbPtr->StatFlags |= PXE_STATFLAGS_INTERRUPT_TRANSMIT;
523 
524   }
525 
526   if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_COMMAND) != 0) {
527     CdbPtr->StatFlags |= PXE_STATFLAGS_INTERRUPT_COMMAND;
528 
529   }
530 
531   return ;
532 }
533 
534 
535 /**
536   This routine is used to read and change receive filters and, if supported, read
537   and change multicast MAC address filter list.
538 
539   @param  CdbPtr               Pointer to the command descriptor block.
540   @param  AdapterInfo          Pointer to the NIC data structure information which
541                                the UNDI driver is layering on..
542 
543   @return None
544 
545 **/
546 VOID
UNDI_RecFilter(IN PXE_CDB * CdbPtr,IN NIC_DATA_INSTANCE * AdapterInfo)547 UNDI_RecFilter (
548   IN  PXE_CDB           *CdbPtr,
549   IN  NIC_DATA_INSTANCE *AdapterInfo
550   )
551 {
552   UINT16                  NewFilter;
553   UINT16                  OpFlags;
554   PXE_DB_RECEIVE_FILTERS  *DbPtr;
555   UINT8                   *MacAddr;
556   UINTN                   MacCount;
557   UINT16                  Index;
558   UINT16                  copy_len;
559   UINT8                   *ptr1;
560   UINT8                   *ptr2;
561   BOOLEAN                 InvalidMacAddr;
562 
563   OpFlags   = CdbPtr->OpFlags;
564   NewFilter = (UINT16) (OpFlags & 0x1F);
565 
566   switch (OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_OPMASK) {
567   case PXE_OPFLAGS_RECEIVE_FILTER_READ:
568 
569     //
570     // not expecting a cpb, not expecting any filter bits
571     //
572     if ((NewFilter != 0) || (CdbPtr->CPBsize != 0)) {
573       goto BadCdb;
574 
575     }
576 
577     if ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) == 0) {
578       goto JustRead;
579 
580     }
581 
582     NewFilter = (UINT16) (NewFilter | AdapterInfo->Rx_Filter);
583     //
584     // all other flags are ignored except mcast_reset
585     //
586     break;
587 
588   case PXE_OPFLAGS_RECEIVE_FILTER_ENABLE:
589     //
590     // there should be atleast one other filter bit set.
591     //
592     if (NewFilter == 0) {
593       //
594       // nothing to enable
595       //
596       goto BadCdb;
597     }
598 
599     if (CdbPtr->CPBsize != 0) {
600       //
601       // this must be a multicast address list!
602       // don't accept the list unless selective_mcast is set
603       // don't accept confusing mcast settings with this
604       //
605       if (((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) == 0) ||
606           ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
607           ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) ||
608           ((CdbPtr->CPBsize % sizeof (PXE_MAC_ADDR)) != 0) ) {
609         goto BadCdb;
610       }
611 
612       MacAddr   = (UINT8 *) ((UINTN) (CdbPtr->CPBaddr));
613       MacCount  = CdbPtr->CPBsize / sizeof (PXE_MAC_ADDR);
614 
615       //
616       // The format of Ethernet multicast address for IPv6 is defined in RFC2464,
617       // for IPv4 is defined in RFC1112. Check whether the address is valid.
618       //
619       InvalidMacAddr = FALSE;
620 
621       for (; MacCount-- != 0; MacAddr += sizeof (PXE_MAC_ADDR)) {
622         if (MacAddr[0] == 0x01) {
623           //
624           // This multicast MAC address is mapped from IPv4 address.
625           //
626           if (MacAddr[1] != 0x00 || MacAddr[2] != 0x5E || (MacAddr[3] & 0x80) != 0) {
627             InvalidMacAddr = TRUE;
628           }
629         } else if (MacAddr[0] == 0x33) {
630           //
631           // This multicast MAC address is mapped from IPv6 address.
632           //
633           if (MacAddr[1] != 0x33) {
634             InvalidMacAddr = TRUE;
635           }
636         } else {
637           InvalidMacAddr = TRUE;
638         }
639 
640         if (InvalidMacAddr) {
641           CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
642           CdbPtr->StatCode  = PXE_STATCODE_INVALID_CPB;
643           return ;
644         }
645       }
646     }
647 
648     //
649     // check selective mcast case enable case
650     //
651     if ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
652       if (((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||
653           ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) ) {
654         goto BadCdb;
655 
656       }
657       //
658       // if no cpb, make sure we have an old list
659       //
660       if ((CdbPtr->CPBsize == 0) && (AdapterInfo->mcast_list.list_len == 0)) {
661         goto BadCdb;
662       }
663     }
664     //
665     // if you want to enable anything, you got to have unicast
666     // and you have what you already enabled!
667     //
668     NewFilter = (UINT16) (NewFilter | (PXE_OPFLAGS_RECEIVE_FILTER_UNICAST | AdapterInfo->Rx_Filter));
669 
670     break;
671 
672   case PXE_OPFLAGS_RECEIVE_FILTER_DISABLE:
673 
674     //
675     // mcast list not expected, i.e. no cpb here!
676     //
677     if (CdbPtr->CPBsize != PXE_CPBSIZE_NOT_USED) {
678       goto BadCdb;
679     }
680 
681     NewFilter = (UINT16) ((~(CdbPtr->OpFlags & 0x1F)) & AdapterInfo->Rx_Filter);
682 
683     break;
684 
685   default:
686     goto BadCdb;
687   }
688 
689   if ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) {
690     AdapterInfo->mcast_list.list_len = 0;
691     NewFilter &= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST);
692   }
693 
694   E100bSetfilter (AdapterInfo, NewFilter, CdbPtr->CPBaddr, CdbPtr->CPBsize);
695 
696 JustRead:
697   //
698   // give the current mcast list
699   //
700   if ((CdbPtr->DBsize != 0) && (AdapterInfo->mcast_list.list_len != 0)) {
701     //
702     // copy the mc list to db
703     //
704 
705     DbPtr = (PXE_DB_RECEIVE_FILTERS *) (UINTN) CdbPtr->DBaddr;
706     ptr1  = (UINT8 *) (&DbPtr->MCastList[0]);
707 
708     //
709     // DbPtr->mc_count = AdapterInfo->mcast_list.list_len;
710     //
711     copy_len = (UINT16) (AdapterInfo->mcast_list.list_len * PXE_MAC_LENGTH);
712 
713     if (copy_len > CdbPtr->DBsize) {
714       copy_len = CdbPtr->DBsize;
715 
716     }
717 
718     ptr2 = (UINT8 *) (&AdapterInfo->mcast_list.mc_list[0]);
719     for (Index = 0; Index < copy_len; Index++) {
720       ptr1[Index] = ptr2[Index];
721     }
722   }
723   //
724   // give the stat flags here
725   //
726   if (AdapterInfo->Receive_Started) {
727     CdbPtr->StatFlags = (PXE_STATFLAGS) (CdbPtr->StatFlags | AdapterInfo->Rx_Filter);
728 
729   }
730 
731   return ;
732 
733 BadCdb:
734   CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
735   CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;
736 }
737 
738 
739 /**
740   This routine is used to get the current station and broadcast MAC addresses, and to change the
741   current station MAC address.
742 
743   @param  CdbPtr               Pointer to the command descriptor block.
744   @param  AdapterInfo          Pointer to the NIC data structure information which
745                                the UNDI driver is layering on..
746 
747   @return None
748 
749 **/
750 VOID
UNDI_StnAddr(IN PXE_CDB * CdbPtr,IN NIC_DATA_INSTANCE * AdapterInfo)751 UNDI_StnAddr (
752   IN  PXE_CDB           *CdbPtr,
753   IN  NIC_DATA_INSTANCE *AdapterInfo
754   )
755 {
756   PXE_CPB_STATION_ADDRESS *CpbPtr;
757   PXE_DB_STATION_ADDRESS  *DbPtr;
758   UINT16                  Index;
759 
760   if (CdbPtr->OpFlags == PXE_OPFLAGS_STATION_ADDRESS_RESET) {
761     //
762     // configure the permanent address.
763     // change the AdapterInfo->CurrentNodeAddress field.
764     //
765     if (CompareMem (
766           &AdapterInfo->CurrentNodeAddress[0],
767           &AdapterInfo->PermNodeAddress[0],
768           PXE_MAC_LENGTH
769           ) != 0) {
770       for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
771         AdapterInfo->CurrentNodeAddress[Index] = AdapterInfo->PermNodeAddress[Index];
772       }
773 
774       E100bSetupIAAddr (AdapterInfo);
775     }
776   }
777 
778   if (CdbPtr->CPBaddr != (UINT64) 0) {
779     CpbPtr = (PXE_CPB_STATION_ADDRESS *) (UINTN) (CdbPtr->CPBaddr);
780     //
781     // configure the new address
782     //
783     for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
784       AdapterInfo->CurrentNodeAddress[Index] = CpbPtr->StationAddr[Index];
785     }
786 
787     E100bSetupIAAddr (AdapterInfo);
788   }
789 
790   if (CdbPtr->DBaddr != (UINT64) 0) {
791     DbPtr = (PXE_DB_STATION_ADDRESS *) (UINTN) (CdbPtr->DBaddr);
792     //
793     // fill it with the new values
794     //
795     for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {
796       DbPtr->StationAddr[Index]   = AdapterInfo->CurrentNodeAddress[Index];
797       DbPtr->BroadcastAddr[Index] = AdapterInfo->BroadcastNodeAddress[Index];
798       DbPtr->PermanentAddr[Index] = AdapterInfo->PermNodeAddress[Index];
799     }
800   }
801 
802   return ;
803 }
804 
805 
806 /**
807   This routine is used to read and clear the NIC traffic statistics.  This command is supported only
808   if the !PXE structure's Implementation flags say so.
809   Results will be parsed out in the following manner:
810   CdbPtr->DBaddr.Data[0]   R  Total Frames (Including frames with errors and dropped frames)
811   CdbPtr->DBaddr.Data[1]   R  Good Frames (All frames copied into receive buffer)
812   CdbPtr->DBaddr.Data[2]   R  Undersize Frames (Frames below minimum length for media <64 for ethernet)
813   CdbPtr->DBaddr.Data[4]   R  Dropped Frames (Frames that were dropped because receive buffers were full)
814   CdbPtr->DBaddr.Data[8]   R  CRC Error Frames (Frames with alignment or CRC errors)
815   CdbPtr->DBaddr.Data[A]   T  Total Frames (Including frames with errors and dropped frames)
816   CdbPtr->DBaddr.Data[B]   T  Good Frames (All frames copied into transmit buffer)
817   CdbPtr->DBaddr.Data[C]   T  Undersize Frames (Frames below minimum length for media <64 for ethernet)
818   CdbPtr->DBaddr.Data[E]   T  Dropped Frames (Frames that were dropped because of collisions)
819   CdbPtr->DBaddr.Data[14]  T  Total Collision Frames (Total collisions on this subnet)
820 
821   @param  CdbPtr               Pointer to the command descriptor block.
822   @param  AdapterInfo          Pointer to the NIC data structure information which
823                                the UNDI driver is layering on..
824 
825   @return None
826 
827 **/
828 VOID
UNDI_Statistics(IN PXE_CDB * CdbPtr,IN NIC_DATA_INSTANCE * AdapterInfo)829 UNDI_Statistics (
830   IN  PXE_CDB           *CdbPtr,
831   IN  NIC_DATA_INSTANCE *AdapterInfo
832   )
833 {
834   if ((CdbPtr->OpFlags &~(PXE_OPFLAGS_STATISTICS_RESET)) != 0) {
835     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
836     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;
837     return ;
838   }
839 
840   if ((CdbPtr->OpFlags & PXE_OPFLAGS_STATISTICS_RESET) != 0) {
841     //
842     // Reset the statistics
843     //
844     CdbPtr->StatCode = (UINT16) E100bStatistics (AdapterInfo, 0, 0);
845   } else {
846     CdbPtr->StatCode = (UINT16) E100bStatistics (AdapterInfo, CdbPtr->DBaddr, CdbPtr->DBsize);
847   }
848 
849   return ;
850 }
851 
852 
853 /**
854   This routine is used to translate a multicast IP address to a multicast MAC address.
855   This results in a MAC address composed of 25 bits of fixed data with the upper 23 bits of the IP
856   address being appended to it.  Results passed back in the equivalent of CdbPtr->DBaddr->MAC[0-5].
857 
858   @param  CdbPtr               Pointer to the command descriptor block.
859   @param  AdapterInfo          Pointer to the NIC data structure information which
860                                the UNDI driver is layering on..
861 
862   @return None
863 
864 **/
865 VOID
UNDI_ip2mac(IN PXE_CDB * CdbPtr,IN NIC_DATA_INSTANCE * AdapterInfo)866 UNDI_ip2mac (
867   IN  PXE_CDB           *CdbPtr,
868   IN  NIC_DATA_INSTANCE *AdapterInfo
869   )
870 {
871   PXE_CPB_MCAST_IP_TO_MAC *CpbPtr;
872   PXE_DB_MCAST_IP_TO_MAC  *DbPtr;
873   UINT8                   *TmpPtr;
874 
875   CpbPtr  = (PXE_CPB_MCAST_IP_TO_MAC *) (UINTN) CdbPtr->CPBaddr;
876   DbPtr   = (PXE_DB_MCAST_IP_TO_MAC *) (UINTN) CdbPtr->DBaddr;
877 
878   if ((CdbPtr->OpFlags & PXE_OPFLAGS_MCAST_IPV6_TO_MAC) != 0) {
879     //
880     // for now this is not supported
881     //
882     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
883     CdbPtr->StatCode  = PXE_STATCODE_UNSUPPORTED;
884     return ;
885   }
886 
887   TmpPtr = (UINT8 *) (&CpbPtr->IP.IPv4);
888   //
889   // check if the ip given is a mcast IP
890   //
891   if ((TmpPtr[0] & 0xF0) != 0xE0) {
892     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
893     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CPB;
894   }
895   //
896   // take the last 23 bits in IP.
897   // be very careful. accessing word on a non-word boundary will hang motherboard codenamed Big Sur
898   // casting the mac array (in the middle) to a UINT32 pointer and accessing
899   // the UINT32 content hung the system...
900   //
901   DbPtr->MAC[0] = 0x01;
902   DbPtr->MAC[1] = 0x00;
903   DbPtr->MAC[2] = 0x5e;
904   DbPtr->MAC[3] = (UINT8) (TmpPtr[1] & 0x7f);
905   DbPtr->MAC[4] = (UINT8) TmpPtr[2];
906   DbPtr->MAC[5] = (UINT8) TmpPtr[3];
907 
908   return ;
909 }
910 
911 
912 /**
913   This routine is used to read and write non-volatile storage on the NIC (if supported).  The NVRAM
914   could be EEPROM, FLASH, or battery backed RAM.
915   This is an optional function according to the UNDI specification  (or will be......)
916 
917   @param  CdbPtr               Pointer to the command descriptor block.
918   @param  AdapterInfo          Pointer to the NIC data structure information which
919                                the UNDI driver is layering on..
920 
921   @return None
922 
923 **/
924 VOID
UNDI_NVData(IN PXE_CDB * CdbPtr,IN NIC_DATA_INSTANCE * AdapterInfo)925 UNDI_NVData (
926   IN  PXE_CDB           *CdbPtr,
927   IN  NIC_DATA_INSTANCE *AdapterInfo
928   )
929 {
930   PXE_DB_NVDATA *DbPtr;
931   UINT16        Index;
932 
933   if ((CdbPtr->OpFlags == PXE_OPFLAGS_NVDATA_READ) != 0) {
934 
935     if ((CdbPtr->DBsize == PXE_DBSIZE_NOT_USED) != 0) {
936       CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
937       CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;
938       return ;
939     }
940 
941     DbPtr = (PXE_DB_NVDATA *) (UINTN) CdbPtr->DBaddr;
942 
943     for (Index = 0; Index < MAX_PCI_CONFIG_LEN; Index++) {
944       DbPtr->Data.Dword[Index] = AdapterInfo->NVData[Index];
945 
946     }
947 
948   } else {
949     //
950     // no write for now
951     //
952     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
953     CdbPtr->StatCode  = PXE_STATCODE_UNSUPPORTED;
954   }
955 
956   return ;
957 }
958 
959 
960 /**
961   This routine returns the current interrupt status and/or the transmitted buffer addresses.
962   If the current interrupt status is returned, pending interrupts will be acknowledged by this
963   command.  Transmitted buffer addresses that are written to the DB are removed from the transmit
964   buffer queue.
965   Normally, this command would be polled with interrupts disabled.
966   The transmit buffers are returned in CdbPtr->DBaddr->TxBufer[0 - NumEntries].
967   The interrupt status is returned in CdbPtr->StatFlags.
968 
969   @param  CdbPtr               Pointer to the command descriptor block.
970   @param  AdapterInfo          Pointer to the NIC data structure information which
971                                the UNDI driver is layering on..
972 
973   @return None
974 
975 **/
976 VOID
UNDI_Status(IN PXE_CDB * CdbPtr,IN NIC_DATA_INSTANCE * AdapterInfo)977 UNDI_Status (
978   IN  PXE_CDB           *CdbPtr,
979   IN  NIC_DATA_INSTANCE *AdapterInfo
980   )
981 {
982   PXE_DB_GET_STATUS *DbPtr;
983   PXE_DB_GET_STATUS TmpGetStatus;
984   UINT16            Index;
985   UINT16            Status;
986   UINT16            NumEntries;
987   RxFD              *RxPtr;
988 
989   //
990   // Fill in temporary GetStatus storage.
991   //
992   RxPtr = &AdapterInfo->rx_ring[AdapterInfo->cur_rx_ind];
993 
994   if ((RxPtr->cb_header.status & RX_COMPLETE) != 0) {
995     TmpGetStatus.RxFrameLen = RxPtr->ActualCount & 0x3fff;
996   } else {
997     TmpGetStatus.RxFrameLen = 0;
998   }
999 
1000   TmpGetStatus.reserved = 0;
1001 
1002   //
1003   // Fill in size of next available receive packet and
1004   // reserved field in caller's DB storage.
1005   //
1006   DbPtr = (PXE_DB_GET_STATUS *) (UINTN) CdbPtr->DBaddr;
1007 
1008   if (CdbPtr->DBsize > 0 && CdbPtr->DBsize < sizeof (UINT32) * 2) {
1009     CopyMem (DbPtr, &TmpGetStatus, CdbPtr->DBsize);
1010   } else {
1011     CopyMem (DbPtr, &TmpGetStatus, sizeof (UINT32) * 2);
1012   }
1013 
1014   //
1015   //
1016   //
1017   if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS) != 0) {
1018     //
1019     // DBsize of zero is invalid if Tx buffers are requested.
1020     //
1021     if (CdbPtr->DBsize == 0) {
1022       CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1023       CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;
1024       return ;
1025     }
1026 
1027     //
1028     // remember this b4 we overwrite
1029     //
1030     NumEntries = (UINT16) (CdbPtr->DBsize - sizeof (UINT64));
1031 
1032     //
1033     // We already filled in 2 UINT32s.
1034     //
1035     CdbPtr->DBsize = (UINT16) (sizeof (UINT32) * 2);
1036 
1037     //
1038     // will claim any hanging free CBs
1039     //
1040     CheckCBList (AdapterInfo);
1041 
1042     if (AdapterInfo->xmit_done_head == AdapterInfo->xmit_done_tail) {
1043       CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_TXBUF_QUEUE_EMPTY;
1044     } else {
1045       for (Index = 0; ((Index < MAX_XMIT_BUFFERS) && (NumEntries >= sizeof (UINT64))); Index++, NumEntries -= sizeof (UINT64)) {
1046         if (AdapterInfo->xmit_done_head != AdapterInfo->xmit_done_tail) {
1047           DbPtr->TxBuffer[Index]      = AdapterInfo->xmit_done[AdapterInfo->xmit_done_head];
1048           AdapterInfo->xmit_done_head = next (AdapterInfo->xmit_done_head);
1049           CdbPtr->DBsize += sizeof (UINT64);
1050         } else {
1051           break;
1052         }
1053       }
1054     }
1055 
1056     if (AdapterInfo->xmit_done_head != AdapterInfo->xmit_done_tail) {
1057       CdbPtr->StatFlags |= PXE_STATFLAGS_DB_WRITE_TRUNCATED;
1058 
1059     }
1060     //
1061     // check for a receive buffer and give it's size in db
1062     //
1063   }
1064   //
1065   //
1066   //
1067   if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_INTERRUPT_STATUS) != 0) {
1068 
1069     Status = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus);
1070     AdapterInfo->Int_Status = (UINT16) (AdapterInfo->Int_Status | Status);
1071 
1072     //
1073     // acknoledge the interrupts
1074     //
1075     OutWord (AdapterInfo, (UINT16) (Status & 0xfc00), (UINT32) (AdapterInfo->ioaddr + SCBStatus));
1076 
1077     //
1078     // report all the outstanding interrupts
1079     //
1080     Status = AdapterInfo->Int_Status;
1081     if ((Status & SCB_STATUS_FR) != 0) {
1082       CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_RECEIVE;
1083     }
1084 
1085     if ((Status & SCB_STATUS_SWI) != 0) {
1086       CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_SOFTWARE;
1087     }
1088   }
1089 
1090   //
1091   // Return current media status
1092   //
1093   if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_MEDIA_STATUS) != 0) {
1094     AdapterInfo->PhyAddress = 0xFF;
1095     AdapterInfo->CableDetect = 1;
1096 
1097     if (!PhyDetect (AdapterInfo)) {
1098       CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_MEDIA;
1099     }
1100   }
1101 
1102   return ;
1103 }
1104 
1105 
1106 /**
1107   This routine is used to fill media header(s) in transmit packet(s).
1108   Copies the MAC address into the media header whether it is dealing
1109   with fragmented or non-fragmented packets.
1110 
1111   @param  CdbPtr               Pointer to the command descriptor block.
1112   @param  AdapterInfo          Pointer to the NIC data structure information which
1113                                the UNDI driver is layering on..
1114 
1115   @return None
1116 
1117 **/
1118 VOID
UNDI_FillHeader(IN PXE_CDB * CdbPtr,IN NIC_DATA_INSTANCE * AdapterInfo)1119 UNDI_FillHeader (
1120   IN  PXE_CDB           *CdbPtr,
1121   IN  NIC_DATA_INSTANCE *AdapterInfo
1122   )
1123 {
1124   PXE_CPB_FILL_HEADER             *Cpb;
1125   PXE_CPB_FILL_HEADER_FRAGMENTED  *Cpbf;
1126   EtherHeader                     *MacHeader;
1127   UINTN                           Index;
1128 
1129   if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) {
1130     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1131     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;
1132     return ;
1133   }
1134 
1135   if ((CdbPtr->OpFlags & PXE_OPFLAGS_FILL_HEADER_FRAGMENTED) != 0) {
1136     Cpbf = (PXE_CPB_FILL_HEADER_FRAGMENTED *) (UINTN) CdbPtr->CPBaddr;
1137 
1138     //
1139     // assume 1st fragment is big enough for the mac header
1140     //
1141     if ((Cpbf->FragCnt == 0) || (Cpbf->FragDesc[0].FragLen < PXE_MAC_HEADER_LEN_ETHER)) {
1142       //
1143       // no buffers given
1144       //
1145       CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1146       CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;
1147       return ;
1148     }
1149 
1150     MacHeader = (EtherHeader *) (UINTN) Cpbf->FragDesc[0].FragAddr;
1151     //
1152     // we don't swap the protocol bytes
1153     //
1154     MacHeader->type = Cpbf->Protocol;
1155 
1156     for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
1157       MacHeader->dest_addr[Index] = Cpbf->DestAddr[Index];
1158       MacHeader->src_addr[Index]  = Cpbf->SrcAddr[Index];
1159     }
1160   } else {
1161     Cpb       = (PXE_CPB_FILL_HEADER *) (UINTN) CdbPtr->CPBaddr;
1162 
1163     MacHeader = (EtherHeader *) (UINTN) Cpb->MediaHeader;
1164     //
1165     // we don't swap the protocol bytes
1166     //
1167     MacHeader->type = Cpb->Protocol;
1168 
1169     for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
1170       MacHeader->dest_addr[Index] = Cpb->DestAddr[Index];
1171       MacHeader->src_addr[Index]  = Cpb->SrcAddr[Index];
1172     }
1173   }
1174 
1175   return ;
1176 }
1177 
1178 
1179 /**
1180   This routine is used to place a packet into the transmit queue.  The data buffers given to
1181   this command are to be considered locked and the application or network driver loses
1182   ownership of these buffers and must not free or relocate them until the ownership returns.
1183   When the packets are transmitted, a transmit complete interrupt is generated (if interrupts
1184   are disabled, the transmit interrupt status is still set and can be checked using the UNDI_Status
1185   command.
1186   Some implementations and adapters support transmitting multiple packets with one transmit
1187   command.  If this feature is supported, the transmit CPBs can be linked in one transmit
1188   command.
1189   All UNDIs support fragmented frames, now all network devices or protocols do.  If a fragmented
1190   frame CPB is given to UNDI and the network device does not support fragmented frames
1191   (see !PXE.Implementation flag), the UNDI will have to copy the fragments into a local buffer
1192   before transmitting.
1193 
1194   @param  CdbPtr               Pointer to the command descriptor block.
1195   @param  AdapterInfo          Pointer to the NIC data structure information which
1196                                the UNDI driver is layering on..
1197 
1198   @return None
1199 
1200 **/
1201 VOID
UNDI_Transmit(IN PXE_CDB * CdbPtr,IN NIC_DATA_INSTANCE * AdapterInfo)1202 UNDI_Transmit (
1203   IN  PXE_CDB           *CdbPtr,
1204   IN  NIC_DATA_INSTANCE *AdapterInfo
1205   )
1206 {
1207 
1208   if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) {
1209     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1210     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;
1211     return ;
1212   }
1213 
1214   CdbPtr->StatCode = (PXE_STATCODE) E100bTransmit (AdapterInfo, CdbPtr->CPBaddr, CdbPtr->OpFlags);
1215 
1216   if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {
1217     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1218   }
1219 
1220   return ;
1221 }
1222 
1223 
1224 /**
1225   When the network adapter has received a frame, this command is used to copy the frame
1226   into the driver/application storage location.  Once a frame has been copied, it is
1227   removed from the receive queue.
1228 
1229   @param  CdbPtr               Pointer to the command descriptor block.
1230   @param  AdapterInfo          Pointer to the NIC data structure information which
1231                                the UNDI driver is layering on..
1232 
1233   @return None
1234 
1235 **/
1236 VOID
UNDI_Receive(IN PXE_CDB * CdbPtr,IN NIC_DATA_INSTANCE * AdapterInfo)1237 UNDI_Receive (
1238   IN  PXE_CDB           *CdbPtr,
1239   IN  NIC_DATA_INSTANCE *AdapterInfo
1240   )
1241 {
1242 
1243   //
1244   // check if RU has started...
1245   //
1246   if (!AdapterInfo->Receive_Started) {
1247     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1248     CdbPtr->StatCode  = PXE_STATCODE_NOT_INITIALIZED;
1249     return ;
1250   }
1251 
1252 
1253   CdbPtr->StatCode  = (UINT16) E100bReceive (AdapterInfo, CdbPtr->CPBaddr, CdbPtr->DBaddr);
1254   if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {
1255     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1256 
1257   }
1258 
1259   return ;
1260 }
1261 
1262 
1263 
1264 /**
1265   This is the main SW UNDI API entry using the newer nii protocol.
1266   The parameter passed in is a 64 bit flat model virtual
1267   address of the cdb.  We then jump into the common routine for both old and
1268   new nii protocol entries.
1269 
1270   @param  CdbPtr               Pointer to the command descriptor block.
1271   @param  AdapterInfo          Pointer to the NIC data structure information which
1272                                the UNDI driver is layering on..
1273 
1274   @return None
1275 
1276 **/
1277 // TODO:    cdb - add argument and description to function comment
1278 VOID
UNDI_APIEntry_new(IN UINT64 cdb)1279 UNDI_APIEntry_new (
1280   IN  UINT64 cdb
1281   )
1282 {
1283   PXE_CDB           *CdbPtr;
1284   NIC_DATA_INSTANCE *AdapterInfo;
1285 
1286   if (cdb == (UINT64) 0) {
1287     return ;
1288 
1289   }
1290 
1291   CdbPtr = (PXE_CDB *) (UINTN) cdb;
1292 
1293   if (CdbPtr->IFnum >= (pxe_31->IFcnt | pxe_31->IFcntExt << 8) ) {
1294     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1295     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;
1296     return ;
1297   }
1298 
1299   AdapterInfo               = &(UNDI32DeviceList[CdbPtr->IFnum]->NicInfo);
1300   //
1301   // entering from older entry point
1302   //
1303   AdapterInfo->VersionFlag  = 0x31;
1304   UNDI_APIEntry_Common (cdb);
1305 }
1306 
1307 
1308 /**
1309   This is the common routine for both old and new entry point procedures.
1310   The parameter passed in is a 64 bit flat model virtual
1311   address of the cdb.  We then jump into the service routine pointed to by the
1312   Api_Table[OpCode].
1313 
1314   @param  CdbPtr               Pointer to the command descriptor block.
1315   @param  AdapterInfo          Pointer to the NIC data structure information which
1316                                the UNDI driver is layering on..
1317 
1318   @return None
1319 
1320 **/
1321 // TODO:    cdb - add argument and description to function comment
1322 VOID
UNDI_APIEntry_Common(IN UINT64 cdb)1323 UNDI_APIEntry_Common (
1324   IN  UINT64 cdb
1325   )
1326 {
1327   PXE_CDB           *CdbPtr;
1328   NIC_DATA_INSTANCE *AdapterInfo;
1329   UNDI_CALL_TABLE   *tab_ptr;
1330 
1331   CdbPtr = (PXE_CDB *) (UINTN) cdb;
1332 
1333   //
1334   // check the OPCODE range
1335   //
1336   if ((CdbPtr->OpCode > PXE_OPCODE_LAST_VALID) ||
1337       (CdbPtr->StatCode != PXE_STATCODE_INITIALIZE) ||
1338       (CdbPtr->StatFlags != PXE_STATFLAGS_INITIALIZE) ||
1339       (CdbPtr->IFnum >= (pxe_31->IFcnt |  pxe_31->IFcntExt << 8))) {
1340     goto badcdb;
1341 
1342   }
1343 
1344   if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) {
1345     if (CdbPtr->CPBaddr != PXE_CPBADDR_NOT_USED) {
1346       goto badcdb;
1347     }
1348   } else if (CdbPtr->CPBaddr == PXE_CPBADDR_NOT_USED) {
1349     goto badcdb;
1350   }
1351 
1352   if (CdbPtr->DBsize == PXE_DBSIZE_NOT_USED) {
1353     if (CdbPtr->DBaddr != PXE_DBADDR_NOT_USED) {
1354       goto badcdb;
1355     }
1356   } else if (CdbPtr->DBaddr == PXE_DBADDR_NOT_USED) {
1357     goto badcdb;
1358   }
1359 
1360   //
1361   // check if cpbsize and dbsize are as needed
1362   // check if opflags are as expected
1363   //
1364   tab_ptr = &api_table[CdbPtr->OpCode];
1365 
1366   if (tab_ptr->cpbsize != (UINT16) (DONT_CHECK) && tab_ptr->cpbsize != CdbPtr->CPBsize) {
1367     goto badcdb;
1368   }
1369 
1370   if (tab_ptr->dbsize != (UINT16) (DONT_CHECK) && tab_ptr->dbsize != CdbPtr->DBsize) {
1371     goto badcdb;
1372   }
1373 
1374   if (tab_ptr->opflags != (UINT16) (DONT_CHECK) && tab_ptr->opflags != CdbPtr->OpFlags) {
1375     goto badcdb;
1376 
1377   }
1378 
1379   AdapterInfo = &(UNDI32DeviceList[CdbPtr->IFnum]->NicInfo);
1380 
1381   //
1382   // check if UNDI_State is valid for this call
1383   //
1384   if (tab_ptr->state != (UINT16) (-1)) {
1385     //
1386     // should atleast be started
1387     //
1388     if (AdapterInfo->State == PXE_STATFLAGS_GET_STATE_STOPPED) {
1389       CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1390       CdbPtr->StatCode  = PXE_STATCODE_NOT_STARTED;
1391       return ;
1392     }
1393     //
1394     // check if it should be initialized
1395     //
1396     if (tab_ptr->state == 2) {
1397       if (AdapterInfo->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {
1398         CdbPtr->StatCode  = PXE_STATCODE_NOT_INITIALIZED;
1399         CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1400         return ;
1401       }
1402     }
1403   }
1404   //
1405   // set the return variable for success case here
1406   //
1407   CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
1408   CdbPtr->StatCode  = PXE_STATCODE_SUCCESS;
1409 
1410   tab_ptr->api_ptr (CdbPtr, AdapterInfo);
1411   return ;
1412   //
1413   // %% AVL - check for command linking
1414   //
1415 badcdb:
1416   CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1417   CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;
1418   return ;
1419 }
1420 
1421 
1422 /**
1423   When called with a null NicPtr, this routine decrements the number of NICs
1424   this UNDI is supporting and removes the NIC_DATA_POINTER from the array.
1425   Otherwise, it increments the number of NICs this UNDI is supported and
1426   updates the pxe.Fudge to ensure a proper check sum results.
1427 
1428   @param  NicPtr               Pointer to the NIC data structure.
1429 
1430   @return None
1431 
1432 **/
1433 VOID
PxeUpdate(IN NIC_DATA_INSTANCE * NicPtr,IN PXE_SW_UNDI * PxePtr)1434 PxeUpdate (
1435   IN  NIC_DATA_INSTANCE *NicPtr,
1436   IN PXE_SW_UNDI        *PxePtr
1437   )
1438 {
1439   UINT16 NicNum;
1440   NicNum = (PxePtr->IFcnt | PxePtr->IFcntExt << 8);
1441 
1442   if (NicPtr == NULL) {
1443     if (NicNum > 0) {
1444       //
1445       // number of NICs this undi supports
1446       //
1447       NicNum --;
1448     }
1449     goto done;
1450   }
1451 
1452   //
1453   // number of NICs this undi supports
1454   //
1455   NicNum++;
1456 
1457 done:
1458   PxePtr->IFcnt = (UINT8)(NicNum & 0xFF);
1459   PxePtr->IFcntExt = (UINT8) ((NicNum & 0xFF00) >> 8);
1460   PxePtr->Fudge = (UINT8) (PxePtr->Fudge - CalculateSum8 ((VOID *) PxePtr, PxePtr->Len));
1461   return ;
1462 }
1463 
1464 
1465 /**
1466   Initialize the !PXE structure
1467 
1468   @param  PxePtr               Pointer to SW_UNDI data structure.
1469 
1470   @retval EFI_SUCCESS          This driver is added to Controller.
1471   @retval other                This driver does not support this device.
1472 
1473 **/
1474 VOID
PxeStructInit(IN PXE_SW_UNDI * PxePtr)1475 PxeStructInit (
1476   IN PXE_SW_UNDI *PxePtr
1477   )
1478 {
1479   //
1480   // Initialize the !PXE structure
1481   //
1482   PxePtr->Signature = PXE_ROMID_SIGNATURE;
1483   PxePtr->Len       = (UINT8) sizeof (PXE_SW_UNDI);
1484   //
1485   // cksum
1486   //
1487   PxePtr->Fudge     = 0;
1488   //
1489   // number of NICs this undi supports
1490   //
1491   PxePtr->IFcnt = 0;
1492   PxePtr->IFcntExt = 0;
1493   PxePtr->Rev       = PXE_ROMID_REV;
1494   PxePtr->MajorVer  = PXE_ROMID_MAJORVER;
1495   PxePtr->MinorVer  = PXE_ROMID_MINORVER;
1496   PxePtr->reserved1 = 0;
1497 
1498   PxePtr->Implementation = PXE_ROMID_IMP_SW_VIRT_ADDR |
1499     PXE_ROMID_IMP_FRAG_SUPPORTED |
1500     PXE_ROMID_IMP_CMD_LINK_SUPPORTED |
1501     PXE_ROMID_IMP_NVDATA_READ_ONLY |
1502     PXE_ROMID_IMP_STATION_ADDR_SETTABLE |
1503     PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED |
1504     PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED |
1505     PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED |
1506     PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED |
1507     PXE_ROMID_IMP_SOFTWARE_INT_SUPPORTED |
1508     PXE_ROMID_IMP_PACKET_RX_INT_SUPPORTED;
1509 
1510   PxePtr->EntryPoint  = (UINT64) (UINTN) UNDI_APIEntry_new;
1511   PxePtr->MinorVer    = PXE_ROMID_MINORVER_31;
1512 
1513   PxePtr->reserved2[0]  = 0;
1514   PxePtr->reserved2[1]  = 0;
1515   PxePtr->reserved2[2]  = 0;
1516   PxePtr->BusCnt        = 1;
1517   PxePtr->BusType[0]    = PXE_BUSTYPE_PCI;
1518 
1519   PxePtr->Fudge         = (UINT8) (PxePtr->Fudge - CalculateSum8 ((VOID *) PxePtr, PxePtr->Len));
1520 }
1521 
1522