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
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.
24 BOOLEAN SlaveDeviceExist
= FALSE
;
25 BOOLEAN MasterDeviceExist
= FALSE
;
29 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
36 TODO: Add function description
40 PciIo - TODO: add argument description
41 Port - TODO: add argument description
45 TODO: add return values
53 // perform 1-byte data read from register
58 EFI_PCI_IO_PASS_THROUGH_BAR
,
67 IDEReadPortWMultiple (
68 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
76 Reads multiple words of data from the IDE data port.
77 Call the IO abstraction once to do the complete read,
78 not one word at a time
82 PciIo - Pointer to the EFI_PCI_IO instance
83 Port - IO port to read
84 Count - No. of UINT16's to read
85 Buffer - Pointer to the data buffer for read
88 // TODO: function comment should end with '--*/'
89 // TODO: function comment is missing 'Returns:'
91 UINT16
*AlignedBuffer
;
92 UINT16
*WorkingBuffer
;
96 // Prepare an 16-bit alligned working buffer. CpuIo will return failure and
97 // not perform actual I/O operations if buffer pointer passed in is not at
98 // natural boundary. The "Buffer" argument is passed in by user and may not
99 // at 16-bit natural boundary.
101 Size
= sizeof (UINT16
) * Count
;
106 (VOID
**)&WorkingBuffer
109 AlignedBuffer
= (UINT16
*) ((UINTN
)(((UINTN
) WorkingBuffer
+ 0x1) & (~0x1)));
112 // Perform UINT16 data read from FIFO
116 EfiPciIoWidthFifoUint16
,
117 EFI_PCI_IO_PASS_THROUGH_BAR
,
120 (UINT16
*)AlignedBuffer
124 // Copy data to user buffer
126 CopyMem (Buffer
, (UINT16
*)AlignedBuffer
, Size
);
127 gBS
->FreePool (WorkingBuffer
);
132 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
140 TODO: Add function description
144 PciIo - TODO: add argument description
145 Port - TODO: add argument description
146 Data - TODO: add argument description
150 TODO: add return values
155 // perform 1-byte data write to register
160 EFI_PCI_IO_PASS_THROUGH_BAR
,
170 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
178 TODO: Add function description
182 PciIo - TODO: add argument description
183 Port - TODO: add argument description
184 Data - TODO: add argument description
188 TODO: add return values
193 // perform 1-word data write to register
198 EFI_PCI_IO_PASS_THROUGH_BAR
,
206 IDEWritePortWMultiple (
207 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
215 Write multiple words of data to the IDE data port.
216 Call the IO abstraction once to do the complete read,
217 not one word at a time
221 PciIo - Pointer to the EFI_PCI_IO instance
222 Port - IO port to read
223 Count - No. of UINT16's to read
224 Buffer - Pointer to the data buffer for read
227 // TODO: function comment should end with '--*/'
228 // TODO: function comment is missing 'Returns:'
230 UINT16
*AlignedBuffer
;
231 UINT32
*WorkingBuffer
;
235 // Prepare an 16-bit alligned working buffer. CpuIo will return failure and
236 // not perform actual I/O operations if buffer pointer passed in is not at
237 // natural boundary. The "Buffer" argument is passed in by user and may not
238 // at 16-bit natural boundary.
240 Size
= sizeof (UINT16
) * Count
;
245 (VOID
**) &WorkingBuffer
248 AlignedBuffer
= (UINT16
*) ((UINTN
)(((UINTN
) WorkingBuffer
+ 0x1) & (~0x1)));
251 // Copy data from user buffer to working buffer
253 CopyMem ((UINT16
*) AlignedBuffer
, Buffer
, Size
);
256 // perform UINT16 data write to the FIFO
260 EfiPciIoWidthFifoUint16
,
261 EFI_PCI_IO_PASS_THROUGH_BAR
,
264 (UINT16
*) AlignedBuffer
267 gBS
->FreePool (WorkingBuffer
);
272 IN IDE_BLK_IO_DEV
*IdeDev
278 TODO: Add function description
282 IdeDev - TODO: add argument description
286 TODO: add return values
291 // check whether all registers return 0xff,
292 // if so, deem the channel is disabled.
296 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Data
) != 0xff) {
300 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Feature
) != 0xff) {
304 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorCount
) != 0xff) {
308 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorNumber
) != 0xff) {
312 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderLsb
) != 0xff) {
316 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderMsb
) != 0xff) {
320 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Head
) != 0xff) {
324 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Command
) != 0xff) {
328 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
) != 0xff) {
342 // GetIdeRegistersBaseAddr
345 GetIdeRegistersBaseAddr (
346 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
347 OUT IDE_REGISTERS_BASE_ADDR
*IdeRegsBaseAddr
352 Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,
353 use fixed addresses. In Native-PCI mode, get base addresses from BARs in
354 the PCI IDE controller's Configuration Space.
356 The steps to get IDE IO port registers' base addresses for each channel
359 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE
360 controller's Configuration Space to determine the operating mode.
362 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.
363 ___________________________________________
364 | | Command Block | Control Block |
365 | Channel | Registers | Registers |
366 |___________|_______________|_______________|
367 | Primary | 1F0h - 1F7h | 3F6h - 3F7h |
368 |___________|_______________|_______________|
369 | Secondary | 170h - 177h | 376h - 377h |
370 |___________|_______________|_______________|
372 Table 1. Compatibility resource mappings
374 b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs
375 in IDE controller's PCI Configuration Space, shown in the Table 2 below.
376 ___________________________________________________
377 | | Command Block | Control Block |
378 | Channel | Registers | Registers |
379 |___________|___________________|___________________|
380 | Primary | BAR at offset 0x10| BAR at offset 0x14|
381 |___________|___________________|___________________|
382 | Secondary | BAR at offset 0x18| BAR at offset 0x1C|
383 |___________|___________________|___________________|
385 Table 2. BARs for Register Mapping
386 Note: Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for
387 primary, 0374h for secondary. So 2 bytes extra offset should be
388 added to the base addresses read from BARs.
390 For more details, please refer to PCI IDE Controller Specification and Intel
394 PciIo - Pointer to the EFI_PCI_IO_PROTOCOL instance
395 IdeRegsBaseAddr - Pointer to IDE_REGISTERS_BASE_ADDR to
396 receive IDE IO port registers' base addresses
401 // TODO: EFI_UNSUPPORTED - add return value to function comment
402 // TODO: EFI_UNSUPPORTED - add return value to function comment
403 // TODO: EFI_SUCCESS - add return value to function comment
408 Status
= PciIo
->Pci
.Read (
416 if (EFI_ERROR (Status
)) {
420 if ((PciData
.Hdr
.ClassCode
[0] & IDE_PRIMARY_OPERATING_MODE
) == 0) {
421 IdeRegsBaseAddr
[IdePrimary
].CommandBlockBaseAddr
= 0x1f0;
422 IdeRegsBaseAddr
[IdePrimary
].ControlBlockBaseAddr
= 0x3f6;
423 IdeRegsBaseAddr
[IdePrimary
].BusMasterBaseAddr
=
424 (UINT16
)((PciData
.Device
.Bar
[4] & 0x0000fff0));
427 // The BARs should be of IO type
429 if ((PciData
.Device
.Bar
[0] & bit0
) == 0 ||
430 (PciData
.Device
.Bar
[1] & bit0
) == 0) {
431 return EFI_UNSUPPORTED
;
434 IdeRegsBaseAddr
[IdePrimary
].CommandBlockBaseAddr
=
435 (UINT16
) (PciData
.Device
.Bar
[0] & 0x0000fff8);
436 IdeRegsBaseAddr
[IdePrimary
].ControlBlockBaseAddr
=
437 (UINT16
) ((PciData
.Device
.Bar
[1] & 0x0000fffc) + 2);
438 IdeRegsBaseAddr
[IdePrimary
].BusMasterBaseAddr
=
439 (UINT16
) ((PciData
.Device
.Bar
[4] & 0x0000fff0));
442 if ((PciData
.Hdr
.ClassCode
[0] & IDE_SECONDARY_OPERATING_MODE
) == 0) {
443 IdeRegsBaseAddr
[IdeSecondary
].CommandBlockBaseAddr
= 0x170;
444 IdeRegsBaseAddr
[IdeSecondary
].ControlBlockBaseAddr
= 0x376;
445 IdeRegsBaseAddr
[IdeSecondary
].BusMasterBaseAddr
=
446 (UINT16
) ((PciData
.Device
.Bar
[4] & 0x0000fff0));
449 // The BARs should be of IO type
451 if ((PciData
.Device
.Bar
[2] & bit0
) == 0 ||
452 (PciData
.Device
.Bar
[3] & bit0
) == 0) {
453 return EFI_UNSUPPORTED
;
456 IdeRegsBaseAddr
[IdeSecondary
].CommandBlockBaseAddr
=
457 (UINT16
) (PciData
.Device
.Bar
[2] & 0x0000fff8);
458 IdeRegsBaseAddr
[IdeSecondary
].ControlBlockBaseAddr
=
459 (UINT16
) ((PciData
.Device
.Bar
[3] & 0x0000fffc) + 2);
460 IdeRegsBaseAddr
[IdeSecondary
].BusMasterBaseAddr
=
461 (UINT16
) ((PciData
.Device
.Bar
[4] & 0x0000fff0));
468 ReassignIdeResources (
469 IN IDE_BLK_IO_DEV
*IdeDev
474 This function is used to requery IDE resources. The IDE controller will
475 probably switch between native and legacy modes during the EFI->CSM->OS
476 transfer. We do this everytime before an BlkIo operation to ensure its
480 IdeDev - The BLK_IO private data which specifies the IDE device
483 // TODO: function comment should end with '--*/'
484 // TODO: function comment is missing 'Returns:'
485 // TODO: EFI_SUCCESS - add return value to function comment
488 IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr
[IdeMaxChannel
];
489 UINT16 CommandBlockBaseAddr
;
490 UINT16 ControlBlockBaseAddr
;
493 // Requery IDE IO port registers' base addresses in case of the switch of
494 // native and legacy modes
496 Status
= GetIdeRegistersBaseAddr (IdeDev
->PciIo
, IdeRegsBaseAddr
);
497 if (EFI_ERROR (Status
)) {
501 ZeroMem (IdeDev
->IoPort
, sizeof (IDE_BASE_REGISTERS
));
502 CommandBlockBaseAddr
= IdeRegsBaseAddr
[IdeDev
->Channel
].CommandBlockBaseAddr
;
503 ControlBlockBaseAddr
= IdeRegsBaseAddr
[IdeDev
->Channel
].ControlBlockBaseAddr
;
505 IdeDev
->IoPort
->Data
= CommandBlockBaseAddr
;
506 (*(UINT16
*) &IdeDev
->IoPort
->Reg1
) = (UINT16
) (CommandBlockBaseAddr
+ 0x01);
507 IdeDev
->IoPort
->SectorCount
= (UINT16
) (CommandBlockBaseAddr
+ 0x02);
508 IdeDev
->IoPort
->SectorNumber
= (UINT16
) (CommandBlockBaseAddr
+ 0x03);
509 IdeDev
->IoPort
->CylinderLsb
= (UINT16
) (CommandBlockBaseAddr
+ 0x04);
510 IdeDev
->IoPort
->CylinderMsb
= (UINT16
) (CommandBlockBaseAddr
+ 0x05);
511 IdeDev
->IoPort
->Head
= (UINT16
) (CommandBlockBaseAddr
+ 0x06);
513 (*(UINT16
*) &IdeDev
->IoPort
->Reg
) = (UINT16
) (CommandBlockBaseAddr
+ 0x07);
514 (*(UINT16
*) &IdeDev
->IoPort
->Alt
) = ControlBlockBaseAddr
;
515 IdeDev
->IoPort
->DriveAddress
= (UINT16
) (ControlBlockBaseAddr
+ 0x01);
516 IdeDev
->IoPort
->MasterSlave
= (UINT16
) ((IdeDev
->Device
== IdeMaster
) ? 1 : 0);
518 IdeDev
->IoPort
->BusMasterBaseAddr
= IdeRegsBaseAddr
[IdeDev
->Channel
].BusMasterBaseAddr
;
524 IDE_BLK_IO_DEV
*IdeDev
529 Read SATA registers to detect SATA disks
533 IdeDev - The BLK_IO private data which specifies the IDE device
536 // TODO: function comment should end with '--*/'
537 // TODO: function comment is missing 'Returns:'
538 // TODO: EFI_NOT_FOUND - add return value to function comment
539 // TODO: EFI_SUCCESS - add return value to function comment
540 // TODO: EFI_NOT_FOUND - add return value to function comment
547 IdeDev
->IoPort
->Head
,
548 (UINT8
) ((IdeDev
->Device
<< 4) | 0xe0)
552 // Wait 31 seconds for BSY clear. BSY should be in clear state if there exists
553 // a device (initial state). Normally, BSY is also in clear state if there is
556 Status
= WaitForBSYClear (IdeDev
, 31000);
557 if (EFI_ERROR (Status
)) {
558 return EFI_NOT_FOUND
;
562 // select device, read error register
566 IdeDev
->IoPort
->Head
,
567 (UINT8
) ((IdeDev
->Device
<< 4) | 0xe0)
569 Status
= DRDYReady (IdeDev
, 200);
571 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
572 if ((ErrorRegister
== 0x01) || (ErrorRegister
== 0x81)) {
575 return EFI_NOT_FOUND
;
584 IN IDE_BLK_IO_DEV
*IdeDev
589 Detect if there is disk connected to this port
593 IdeDev - The BLK_IO private data which specifies the IDE device
596 // TODO: function comment should end with '--*/'
597 // TODO: function comment is missing 'Returns:'
598 // TODO: EFI_NOT_FOUND - add return value to function comment
599 // TODO: EFI_NOT_FOUND - add return value to function comment
600 // TODO: EFI_SUCCESS - add return value to function comment
607 // This extra detection is for SATA disks
609 Status
= CheckPowerMode (IdeDev
);
610 if (Status
== EFI_SUCCESS
) {
615 // If a channel has not been checked, check it now. Then set it to "checked" state
616 // After this step, all devices in this channel have been checked.
618 Status
= DetectIDEController (IdeDev
);
620 if ((EFI_ERROR (Status
)) && !SataFlag
) {
621 return EFI_NOT_FOUND
;
625 // Device exists. test if it is an ATA device
627 Status
= ATAIdentify (IdeDev
);
628 if (EFI_ERROR (Status
)) {
630 // if not ATA device, test if it is an ATAPI device
632 Status
= ATAPIIdentify (IdeDev
);
633 if (EFI_ERROR (Status
)) {
635 // if not ATAPI device either, return error.
637 return EFI_NOT_FOUND
;
642 // Init Block I/O interface
644 IdeDev
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION
;
645 IdeDev
->BlkIo
.Reset
= IDEBlkIoReset
;
646 IdeDev
->BlkIo
.ReadBlocks
= IDEBlkIoReadBlocks
;
647 IdeDev
->BlkIo
.WriteBlocks
= IDEBlkIoWriteBlocks
;
648 IdeDev
->BlkIo
.FlushBlocks
= IDEBlkIoFlushBlocks
;
650 IdeDev
->BlkMedia
.LogicalPartition
= FALSE
;
651 IdeDev
->BlkMedia
.WriteCaching
= FALSE
;
654 // Init Disk Info interface
656 gBS
->CopyMem (&IdeDev
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
, sizeof (EFI_GUID
));
657 IdeDev
->DiskInfo
.Inquiry
= IDEDiskInfoInquiry
;
658 IdeDev
->DiskInfo
.Identify
= IDEDiskInfoIdentify
;
659 IdeDev
->DiskInfo
.SenseData
= IDEDiskInfoSenseData
;
660 IdeDev
->DiskInfo
.WhichIde
= IDEDiskInfoWhichIde
;
666 DetectIDEController (
667 IN IDE_BLK_IO_DEV
*IdeDev
671 Name: DetectIDEController
675 This function is called by DiscoverIdeDevice(). It is used for detect
676 whether the IDE device exists in the specified Channel as the specified
679 There is two IDE channels: one is Primary Channel, the other is
680 Secondary Channel.(Channel is the logical name for the physical "Cable".)
681 Different channel has different register group.
683 On each IDE channel, at most two IDE devices attach,
684 one is called Device 0 (Master device), the other is called Device 1
685 (Slave device). The devices on the same channel co-use the same register
686 group, so before sending out a command for a specified device via command
687 register, it is a must to select the current device to accept the command
688 by set the device number in the Head/Device Register.
692 IDE_BLK_IO_DEV IN *IdeDev
693 pointer pointing to IDE_BLK_IO_DEV data structure, used
694 to record all the information of the IDE device.
699 successfully detects device.
702 any failure during detection process will return this
708 // TODO: function comment is missing 'Routine Description:'
709 // TODO: function comment is missing 'Arguments:'
710 // TODO: IdeDev - add argument and description to function comment
711 // TODO: EFI_SUCCESS - add return value to function comment
712 // TODO: EFI_NOT_FOUND - add return value to function comment
718 EFI_STATUS DeviceStatus
;
721 // Slave device has been detected with master device.
723 if ((IdeDev
->Device
) == 1) {
724 if (SlaveDeviceExist
) {
726 // If master not exists but slave exists, slave have to wait a while
728 if (!MasterDeviceExist
) {
730 // if single slave can't be detected, add delay 4s here.
732 gBS
->Stall (4000000);
737 return EFI_NOT_FOUND
;
742 // Select slave device
746 IdeDev
->IoPort
->Head
,
747 (UINT8
) ((1 << 4) | 0xe0)
752 // Save the init slave status register
754 InitStatusReg
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
757 // Select master back
761 IdeDev
->IoPort
->Head
,
762 (UINT8
) ((0 << 4) | 0xe0)
766 // Send ATA Device Execut Diagnostic command.
767 // This command should work no matter DRDY is ready or not
769 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Command
, 0x90);
771 Status
= WaitForBSYClear (IdeDev
, 3500);
773 ErrorReg
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
776 // Master Error register is 0x01. D0 passed, D1 passed or not present.
777 // Master Error register is 0x81. D0 passed, D1 failed. Return.
778 // Master Error register is other value. D0 failed, D1 passed or not present..
780 if (ErrorReg
== 0x01) {
781 MasterDeviceExist
= TRUE
;
782 DeviceStatus
= EFI_SUCCESS
;
783 } else if (ErrorReg
== 0x81) {
785 MasterDeviceExist
= TRUE
;
786 DeviceStatus
= EFI_SUCCESS
;
787 SlaveDeviceExist
= FALSE
;
791 MasterDeviceExist
= FALSE
;
792 DeviceStatus
= EFI_NOT_FOUND
;
796 // Master Error register is not 0x81, Go on check Slave
804 IdeDev
->IoPort
->Head
,
805 (UINT8
) ((1 << 4) | 0xe0)
809 ErrorReg
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
812 // Slave Error register is not 0x01, D1 failed. Return.
814 if (ErrorReg
!= 0x01) {
815 SlaveDeviceExist
= FALSE
;
819 StatusReg
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
822 // Most ATAPI devices don't set DRDY bit, so test with a slow but accurate
823 // "ATAPI TEST UNIT READY" command
825 if (((StatusReg
& DRDY
) == 0) && ((InitStatusReg
& DRDY
) == 0)) {
826 Status
= AtapiTestUnitReady (IdeDev
);
829 // Still fail, Slave doesn't exist.
831 if (EFI_ERROR (Status
)) {
832 SlaveDeviceExist
= FALSE
;
838 // Error reg is 0x01 and DRDY is ready,
839 // or ATAPI test unit ready success,
840 // or init Slave status DRDY is ready
843 SlaveDeviceExist
= TRUE
;
851 IN IDE_BLK_IO_DEV
*IdeDev
,
852 IN UINTN TimeoutInMilliSeconds
859 This function is used to poll for the DRQ bit clear in the Status
860 Register. DRQ is cleared when the device is finished transferring data.
861 So this function is called after data transfer is finished.
865 IDE_BLK_IO_DEV IN *IdeDev
866 pointer pointing to IDE_BLK_IO_DEV data structure, used
867 to record all the information of the IDE device.
869 UINTN IN TimeoutInMilliSeconds
870 used to designate the timeout for the DRQ clear.
874 DRQ bit clear within the time out.
877 DRQ bit not clear within the time out.
881 Read Status Register will clear interrupt status.
883 // TODO: function comment is missing 'Routine Description:'
884 // TODO: function comment is missing 'Arguments:'
885 // TODO: IdeDev - add argument and description to function comment
886 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
887 // TODO: EFI_ABORTED - add return value to function comment
890 UINT8 StatusRegister
;
893 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
896 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
899 // wait for BSY == 0 and DRQ == 0
901 if ((StatusRegister
& (DRQ
| BSY
)) == 0) {
905 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
907 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
908 if ((ErrorRegister
& ABRT_ERR
) == ABRT_ERR
) {
931 IN IDE_BLK_IO_DEV
*IdeDev
,
932 IN UINTN TimeoutInMilliSeconds
939 This function is used to poll for the DRQ bit clear in the Alternate
940 Status Register. DRQ is cleared when the device is finished
941 transferring data. So this function is called after data transfer
946 IDE_BLK_IO_DEV IN *IdeDev
947 pointer pointing to IDE_BLK_IO_DEV data structure, used
948 to record all the information of the IDE device.
950 UINTN IN TimeoutInMilliSeconds
951 used to designate the timeout for the DRQ clear.
955 DRQ bit clear within the time out.
958 DRQ bit not clear within the time out.
962 Read Alternate Status Register will not clear interrupt status.
964 // TODO: function comment is missing 'Routine Description:'
965 // TODO: function comment is missing 'Arguments:'
966 // TODO: IdeDev - add argument and description to function comment
967 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
968 // TODO: EFI_ABORTED - add return value to function comment
974 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
977 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
980 // wait for BSY == 0 and DRQ == 0
982 if ((AltRegister
& (DRQ
| BSY
)) == 0) {
986 if ((AltRegister
& (BSY
| ERR
)) == ERR
) {
988 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
989 if ((ErrorRegister
& ABRT_ERR
) == ABRT_ERR
) {
1012 IN IDE_BLK_IO_DEV
*IdeDev
,
1013 IN UINTN TimeoutInMilliSeconds
1020 This function is used to poll for the DRQ bit set in the
1022 DRQ is set when the device is ready to transfer data. So this function
1023 is called after the command is sent to the device and before required
1024 data is transferred.
1028 IDE_BLK_IO_DEV IN *IdeDev
1029 pointer pointing to IDE_BLK_IO_DEV data structure,used
1030 to record all the information of the IDE device.
1032 UINTN IN TimeoutInMilliSeconds
1033 used to designate the timeout for the DRQ ready.
1038 DRQ bit set within the time out.
1041 DRQ bit not set within the time out.
1044 DRQ bit not set caused by the command abort.
1047 Read Status Register will clear interrupt status.
1050 // TODO: function comment is missing 'Routine Description:'
1051 // TODO: function comment is missing 'Arguments:'
1052 // TODO: IdeDev - add argument and description to function comment
1053 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
1056 UINT8 StatusRegister
;
1057 UINT8 ErrorRegister
;
1059 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1062 // read Status Register will clear interrupt
1064 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1069 if ((StatusRegister
& (BSY
| DRQ
)) == DRQ
) {
1073 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
1075 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
1076 if ((ErrorRegister
& ABRT_ERR
) == ABRT_ERR
) {
1098 IN IDE_BLK_IO_DEV
*IdeDev
,
1099 IN UINTN TimeoutInMilliSeconds
1106 This function is used to poll for the DRQ bit set in the
1107 Alternate Status Register. DRQ is set when the device is ready to
1108 transfer data. So this function is called after the command
1109 is sent to the device and before required data is transferred.
1113 IDE_BLK_IO_DEV IN *IdeDev
1114 pointer pointing to IDE_BLK_IO_DEV data structure, used
1115 to record all the information of the IDE device.
1117 UINTN IN TimeoutInMilliSeconds
1118 used to designate the timeout for the DRQ ready.
1122 DRQ bit set within the time out.
1125 DRQ bit not set within the time out.
1128 DRQ bit not set caused by the command abort.
1131 Read Alternate Status Register will not clear interrupt status.
1133 // TODO: function comment is missing 'Routine Description:'
1134 // TODO: function comment is missing 'Arguments:'
1135 // TODO: IdeDev - add argument and description to function comment
1136 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
1140 UINT8 ErrorRegister
;
1142 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1146 // Read Alternate Status Register will not clear interrupt status
1148 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
1150 // BSY == 0 , DRQ == 1
1152 if ((AltRegister
& (BSY
| DRQ
)) == DRQ
) {
1156 if ((AltRegister
& (BSY
| ERR
)) == ERR
) {
1158 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
1159 if ((ErrorRegister
& ABRT_ERR
) == ABRT_ERR
) {
1181 IN IDE_BLK_IO_DEV
*IdeDev
,
1182 IN UINTN TimeoutInMilliSeconds
1190 This function is used to poll for the BSY bit clear in the
1191 Status Register. BSY is clear when the device is not busy.
1192 Every command must be sent after device is not busy.
1196 IDE_BLK_IO_DEV IN *IdeDev
1197 pointer pointing to IDE_BLK_IO_DEV data structure, used
1198 to record all the information of the IDE device.
1200 UINTN IN TimeoutInMilliSeconds
1201 used to designate the timeout for the DRQ ready.
1205 BSY bit clear within the time out.
1208 BSY bit not clear within the time out.
1212 Read Status Register will clear interrupt status.
1214 // TODO: function comment is missing 'Routine Description:'
1215 // TODO: function comment is missing 'Arguments:'
1216 // TODO: IdeDev - add argument and description to function comment
1217 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
1220 UINT8 StatusRegister
;
1222 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1225 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1226 if ((StatusRegister
& BSY
) == 0x00) {
1250 IN IDE_BLK_IO_DEV
*IdeDev
,
1251 IN UINTN TimeoutInMilliSeconds
1259 This function is used to poll for the BSY bit clear in the
1260 Alternate Status Register. BSY is clear when the device is not busy.
1261 Every command must be sent after device is not busy.
1265 IDE_BLK_IO_DEV IN *IdeDev
1266 pointer pointing to IDE_BLK_IO_DEV data structure, used
1267 to record all the information of the IDE device.
1269 UINTN IN TimeoutInMilliSeconds
1270 used to designate the timeout for the DRQ ready.
1274 BSY bit clear within the time out.
1277 BSY bit not clear within the time out.
1281 Read Alternate Status Register will not clear interrupt status.
1283 // TODO: function comment is missing 'Routine Description:'
1284 // TODO: function comment is missing 'Arguments:'
1285 // TODO: IdeDev - add argument and description to function comment
1286 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
1291 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1293 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
1294 if ((AltRegister
& BSY
) == 0x00) {
1316 IN IDE_BLK_IO_DEV
*IdeDev
,
1317 IN UINTN DelayInMilliSeconds
1325 This function is used to poll for the DRDY bit set in the
1326 Status Register. DRDY bit is set when the device is ready
1327 to accept command. Most ATA commands must be sent after
1328 DRDY set except the ATAPI Packet Command.
1332 IDE_BLK_IO_DEV IN *IdeDev
1333 pointer pointing to IDE_BLK_IO_DEV data structure, used
1334 to record all the information of the IDE device.
1336 UINTN IN TimeoutInMilliSeconds
1337 used to designate the timeout for the DRQ ready.
1341 DRDY bit set within the time out.
1344 DRDY bit not set within the time out.
1348 Read Status Register will clear interrupt status.
1350 // TODO: function comment is missing 'Routine Description:'
1351 // TODO: function comment is missing 'Arguments:'
1352 // TODO: IdeDev - add argument and description to function comment
1353 // TODO: DelayInMilliSeconds - add argument and description to function comment
1354 // TODO: EFI_ABORTED - add return value to function comment
1357 UINT8 StatusRegister
;
1358 UINT8 ErrorRegister
;
1360 Delay
= (UINT32
) (((DelayInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1362 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1364 // BSY == 0 , DRDY == 1
1366 if ((StatusRegister
& (DRDY
| BSY
)) == DRDY
) {
1370 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
1372 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
1373 if ((ErrorRegister
& ABRT_ERR
) == ABRT_ERR
) {
1395 IN IDE_BLK_IO_DEV
*IdeDev
,
1396 IN UINTN DelayInMilliSeconds
1404 This function is used to poll for the DRDY bit set in the
1405 Alternate Status Register. DRDY bit is set when the device is ready
1406 to accept command. Most ATA commands must be sent after
1407 DRDY set except the ATAPI Packet Command.
1411 IDE_BLK_IO_DEV IN *IdeDev
1412 pointer pointing to IDE_BLK_IO_DEV data structure, used
1413 to record all the information of the IDE device.
1415 UINTN IN TimeoutInMilliSeconds
1416 used to designate the timeout for the DRQ ready.
1420 DRDY bit set within the time out.
1423 DRDY bit not set within the time out.
1427 Read Alternate Status Register will clear interrupt status.
1429 // TODO: function comment is missing 'Routine Description:'
1430 // TODO: function comment is missing 'Arguments:'
1431 // TODO: IdeDev - add argument and description to function comment
1432 // TODO: DelayInMilliSeconds - add argument and description to function comment
1433 // TODO: EFI_ABORTED - add return value to function comment
1437 UINT8 ErrorRegister
;
1439 Delay
= (UINT32
) (((DelayInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1441 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
1443 // BSY == 0 , DRDY == 1
1445 if ((AltRegister
& (DRDY
| BSY
)) == DRDY
) {
1449 if ((AltRegister
& (BSY
| ERR
)) == ERR
) {
1451 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
1452 if ((ErrorRegister
& ABRT_ERR
) == ABRT_ERR
) {
1474 IN CHAR8
*Destination
,
1484 This function is a helper function used to change the char order in a
1485 string. It is designed specially for the PrintAtaModuleName() function.
1486 After the IDE device is detected, the IDE driver gets the device module
1487 name by sending ATA command called ATA Identify Command or ATAPI
1488 Identify Command to the specified IDE device. The module name returned
1489 is a string of ASCII characters: the first character is bit8--bit15
1490 of the first word, the second character is bit0--bit7 of the first word
1491 and so on. Thus the string can not be print directly before it is
1492 preprocessed by this func to change the order of characters in
1493 each word in the string.
1497 CHAR8 IN *Destination
1498 Indicates the destination string.
1501 Indicates the source string.
1504 the length of the string
1513 // TODO: function comment is missing 'Routine Description:'
1514 // TODO: function comment is missing 'Arguments:'
1515 // TODO: Destination - add argument and description to function comment
1516 // TODO: Source - add argument and description to function comment
1517 // TODO: Size - add argument and description to function comment
1522 for (Index
= 0; Index
< Size
; Index
+= 2) {
1524 Temp
= Source
[Index
+ 1];
1525 Destination
[Index
+ 1] = Source
[Index
];
1526 Destination
[Index
] = Temp
;
1531 // ReleaseIdeResources
1534 ReleaseIdeResources (
1535 IN IDE_BLK_IO_DEV
*IdeBlkIoDevice
1538 Routing Description:
1540 Release resources of an IDE device before stopping it.
1544 IdeBlkIoDevice -- Standard IDE device private data structure
1552 // TODO: function comment is missing 'Routine Description:'
1554 if (IdeBlkIoDevice
== NULL
) {
1559 // Release all the resourses occupied by the IDE_BLK_IO_DEV
1562 if (IdeBlkIoDevice
->SenseData
!= NULL
) {
1563 gBS
->FreePool (IdeBlkIoDevice
->SenseData
);
1564 IdeBlkIoDevice
->SenseData
= NULL
;
1567 if (IdeBlkIoDevice
->Cache
!= NULL
) {
1568 gBS
->FreePool (IdeBlkIoDevice
->Cache
);
1569 IdeBlkIoDevice
->Cache
= NULL
;
1572 if (IdeBlkIoDevice
->pIdData
!= NULL
) {
1573 gBS
->FreePool (IdeBlkIoDevice
->pIdData
);
1574 IdeBlkIoDevice
->pIdData
= NULL
;
1577 if (IdeBlkIoDevice
->pInquiryData
!= NULL
) {
1578 gBS
->FreePool (IdeBlkIoDevice
->pInquiryData
);
1579 IdeBlkIoDevice
->pInquiryData
= NULL
;
1582 if (IdeBlkIoDevice
->ControllerNameTable
!= NULL
) {
1583 FreeUnicodeStringTable (IdeBlkIoDevice
->ControllerNameTable
);
1584 IdeBlkIoDevice
->ControllerNameTable
= NULL
;
1587 if (IdeBlkIoDevice
->IoPort
!= NULL
) {
1588 gBS
->FreePool (IdeBlkIoDevice
->IoPort
);
1591 if (IdeBlkIoDevice
->DevicePath
!= NULL
) {
1592 gBS
->FreePool (IdeBlkIoDevice
->DevicePath
);
1595 gBS
->FreePool (IdeBlkIoDevice
);
1596 IdeBlkIoDevice
= NULL
;
1602 // SetDeviceTransferMode
1605 SetDeviceTransferMode (
1606 IN IDE_BLK_IO_DEV
*IdeDev
,
1607 IN ATA_TRANSFER_MODE
*TransferMode
1610 Routing Description:
1612 Set the calculated Best transfer mode to a detected device
1616 IdeDev -- Standard IDE device private data structure
1617 TransferMode -- The device transfer mode to be set
1621 Set transfer mode Command execute status
1624 // TODO: function comment is missing 'Routine Description:'
1631 DeviceSelect
= (UINT8
) ((IdeDev
->Device
) << 4);
1632 SectorCount
= *((UINT8
*) TransferMode
);
1635 // Send SET FEATURE command (sub command 0x03) to set pio mode.
1637 Status
= AtaNonDataCommandIn (
1652 AtaNonDataCommandIn (
1653 IN IDE_BLK_IO_DEV
*IdeDev
,
1654 IN UINT8 AtaCommand
,
1657 IN UINT8 SectorCount
,
1664 Routine Description:
1666 Send ATA command into device with NON_DATA protocol
1670 IdeDev - Standard IDE device private data structure
1671 AtaCommand - The ATA command to be sent
1672 Device - The value in Device register
1673 Feature - The value in Feature register
1674 SectorCount - The value in SectorCount register
1675 LbaLow - The value in LBA_LOW register
1676 LbaMiddle - The value in LBA_MIDDLE register
1677 LbaHigh - The value in LBA_HIGH register
1681 EFI_SUCCESS - Reading succeed
1682 EFI_ABORTED - Command failed
1683 EFI_DEVICE_ERROR - Device status error
1688 UINT8 StatusRegister
;
1690 Status
= WaitForBSYClear (IdeDev
, ATATIMEOUT
);
1691 if (EFI_ERROR (Status
)) {
1692 return EFI_DEVICE_ERROR
;
1696 // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
1700 IdeDev
->IoPort
->Head
,
1701 (UINT8
) ((IdeDev
->Device
<< 4) | 0xe0)
1705 // ATA commands for ATA device must be issued when DRDY is set
1707 Status
= DRDYReady (IdeDev
, ATATIMEOUT
);
1708 if (EFI_ERROR (Status
)) {
1709 return EFI_DEVICE_ERROR
;
1713 // Pass parameter into device register block
1715 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Head
, Device
);
1716 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Feature
, Feature
);
1717 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorCount
, SectorCount
);
1718 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorNumber
, LbaLow
);
1719 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderLsb
, LbaMiddle
);
1720 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderMsb
, LbaHigh
);
1723 // Send command via Command Register
1725 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Command
, AtaCommand
);
1728 // Wait for command completion
1730 Status
= WaitForBSYClear (IdeDev
, ATATIMEOUT
);
1731 if (EFI_ERROR (Status
)) {
1732 return EFI_DEVICE_ERROR
;
1735 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1736 if ((StatusRegister
& ERR
) == ERR
) {
1738 // Failed to execute command, abort operation
1747 AtaNonDataCommandInExt (
1748 IN IDE_BLK_IO_DEV
*IdeDev
,
1749 IN UINT8 AtaCommand
,
1752 IN UINT16 SectorCount
,
1753 IN EFI_LBA LbaAddress
1757 Routine Description:
1759 Send ATA Ext command into device with NON_DATA protocol
1763 IdeDev - Standard IDE device private data structure
1764 AtaCommand - The ATA command to be sent
1765 Device - The value in Device register
1766 Feature - The value in Feature register
1767 SectorCount - The value in SectorCount register
1768 LbaAddress - The LBA address in 48-bit mode
1772 EFI_SUCCESS - Reading succeed
1773 EFI_ABORTED - Command failed
1774 EFI_DEVICE_ERROR - Device status error
1779 UINT8 StatusRegister
;
1786 Status
= WaitForBSYClear (IdeDev
, ATATIMEOUT
);
1787 if (EFI_ERROR (Status
)) {
1788 return EFI_DEVICE_ERROR
;
1792 // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
1796 IdeDev
->IoPort
->Head
,
1797 (UINT8
) ((IdeDev
->Device
<< 4) | 0xe0)
1801 // ATA commands for ATA device must be issued when DRDY is set
1803 Status
= DRDYReady (IdeDev
, ATATIMEOUT
);
1804 if (EFI_ERROR (Status
)) {
1805 return EFI_DEVICE_ERROR
;
1809 // Pass parameter into device register block
1811 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Head
, Device
);
1814 // Fill the feature register, which is a two-byte FIFO. Need write twice.
1816 Feature8
= (UINT8
) (Feature
>> 8);
1817 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Feature
, Feature8
);
1819 Feature8
= (UINT8
) Feature
;
1820 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Feature
, Feature8
);
1823 // Fill the sector count register, which is a two-byte FIFO. Need write twice.
1825 SectorCount8
= (UINT8
) (SectorCount
>> 8);
1826 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorCount
, SectorCount8
);
1828 SectorCount8
= (UINT8
) SectorCount
;
1829 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorCount
, SectorCount8
);
1832 // Fill the start LBA registers, which are also two-byte FIFO
1834 LbaLow
= (UINT8
) RShiftU64 (LbaAddress
, 24);
1835 LbaMid
= (UINT8
) RShiftU64 (LbaAddress
, 32);
1836 LbaHigh
= (UINT8
) RShiftU64 (LbaAddress
, 40);
1837 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorNumber
, LbaLow
);
1838 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderLsb
, LbaMid
);
1839 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderMsb
, LbaHigh
);
1841 LbaLow
= (UINT8
) LbaAddress
;
1842 LbaMid
= (UINT8
) RShiftU64 (LbaAddress
, 8);
1843 LbaHigh
= (UINT8
) RShiftU64 (LbaAddress
, 16);
1844 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorNumber
, LbaLow
);
1845 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderLsb
, LbaMid
);
1846 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderMsb
, LbaHigh
);
1849 // Send command via Command Register
1851 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Command
, AtaCommand
);
1854 // Wait for command completion
1856 Status
= WaitForBSYClear (IdeDev
, ATATIMEOUT
);
1857 if (EFI_ERROR (Status
)) {
1858 return EFI_DEVICE_ERROR
;
1861 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1862 if ((StatusRegister
& ERR
) == ERR
) {
1864 // Failed to execute command, abort operation
1873 // SetDriveParameters
1876 SetDriveParameters (
1877 IN IDE_BLK_IO_DEV
*IdeDev
,
1878 IN ATA_DRIVE_PARMS
*DriveParameters
1881 Routine Description:
1883 Set drive parameters for devices not support PACKETS command
1887 IdeDev -- Standard IDE device private data structure
1888 DriveParameters -- The device parameters to be set into the disk
1892 SetParameters Command execute status
1900 DeviceSelect
= (UINT8
) ((IdeDev
->Device
) << 4);
1903 // Send Init drive parameters
1905 Status
= AtaPioDataIn (
1909 INIT_DRIVE_PARAM_CMD
,
1910 (UINT8
) (DeviceSelect
+ DriveParameters
->Heads
),
1911 DriveParameters
->Sector
,
1918 // Send Set Multiple parameters
1920 Status
= AtaPioDataIn (
1924 SET_MULTIPLE_MODE_CMD
,
1926 DriveParameters
->MultipleSector
,
1937 IN IDE_BLK_IO_DEV
*IdeDev
1941 Routine Description:
1943 TODO: Add function description
1947 IdeDev - TODO: add argument description
1951 EFI_SUCCESS - TODO: Add description for return value
1955 UINT8 DeviceControl
;
1958 // Enable interrupt for DMA operation
1961 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.DeviceControl
, DeviceControl
);