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