2 Copyright (c) 2006, Intel Corporation
3 All rights reserved. This program and the accompanying materials
4 are licensed and made available under the terms and conditions of the BSD License
5 which accompanies this distribution. The full text of the license may be found at
6 http://opensource.org/licenses/bsd-license.php
8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 BOOLEAN SlaveDeviceExist
= FALSE
;
16 BOOLEAN MasterDeviceExist
= FALSE
;
19 TODO: Add function description
21 @param PciIo TODO: add argument description
22 @param Port TODO: add argument description
24 TODO: add return values
29 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
37 // perform 1-byte data read from register
42 EFI_PCI_IO_PASS_THROUGH_BAR
,
51 Reads multiple words of data from the IDE data port.
52 Call the IO abstraction once to do the complete read,
53 not one word at a time
55 @param PciIo Pointer to the EFI_PCI_IO instance
56 @param Port IO port to read
57 @param Count No. of UINT16's to read
58 @param Buffer Pointer to the data buffer for read
62 IDEReadPortWMultiple (
63 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
69 UINT16
*AlignedBuffer
;
70 UINT16
*WorkingBuffer
;
74 // Prepare an 16-bit alligned working buffer. CpuIo will return failure and
75 // not perform actual I/O operations if buffer pointer passed in is not at
76 // natural boundary. The "Buffer" argument is passed in by user and may not
77 // at 16-bit natural boundary.
79 Size
= sizeof (UINT16
) * Count
;
84 (VOID
**)&WorkingBuffer
87 AlignedBuffer
= (UINT16
*) ((UINTN
)(((UINTN
) WorkingBuffer
+ 0x1) & (~0x1)));
90 // Perform UINT16 data read from FIFO
94 EfiPciIoWidthFifoUint16
,
95 EFI_PCI_IO_PASS_THROUGH_BAR
,
98 (UINT16
*)AlignedBuffer
102 // Copy data to user buffer
104 CopyMem (Buffer
, (UINT16
*)AlignedBuffer
, Size
);
105 gBS
->FreePool (WorkingBuffer
);
109 TODO: Add function description
111 @param PciIo TODO: add argument description
112 @param Port TODO: add argument description
113 @param Data TODO: add argument description
115 TODO: add return values
120 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
126 // perform 1-byte data write to register
131 EFI_PCI_IO_PASS_THROUGH_BAR
,
140 TODO: Add function description
142 @param PciIo TODO: add argument description
143 @param Port TODO: add argument description
144 @param Data TODO: add argument description
146 TODO: add return values
151 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
157 // perform 1-word data write to register
162 EFI_PCI_IO_PASS_THROUGH_BAR
,
170 Write multiple words of data to the IDE data port.
171 Call the IO abstraction once to do the complete read,
172 not one word at a time
174 @param PciIo Pointer to the EFI_PCI_IO instance
175 @param Port IO port to read
176 @param Count No. of UINT16's to read
177 @param Buffer Pointer to the data buffer for read
181 IDEWritePortWMultiple (
182 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
188 UINT16
*AlignedBuffer
;
189 UINT32
*WorkingBuffer
;
193 // Prepare an 16-bit alligned working buffer. CpuIo will return failure and
194 // not perform actual I/O operations if buffer pointer passed in is not at
195 // natural boundary. The "Buffer" argument is passed in by user and may not
196 // at 16-bit natural boundary.
198 Size
= sizeof (UINT16
) * Count
;
203 (VOID
**) &WorkingBuffer
206 AlignedBuffer
= (UINT16
*) ((UINTN
)(((UINTN
) WorkingBuffer
+ 0x1) & (~0x1)));
209 // Copy data from user buffer to working buffer
211 CopyMem ((UINT16
*) AlignedBuffer
, Buffer
, Size
);
214 // perform UINT16 data write to the FIFO
218 EfiPciIoWidthFifoUint16
,
219 EFI_PCI_IO_PASS_THROUGH_BAR
,
222 (UINT16
*) AlignedBuffer
225 gBS
->FreePool (WorkingBuffer
);
229 TODO: Add function description
231 @param IdeDev TODO: add argument description
233 TODO: add return values
238 IN IDE_BLK_IO_DEV
*IdeDev
242 // check whether all registers return 0xff,
243 // if so, deem the channel is disabled.
247 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Data
) != 0xff) {
251 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Feature
) != 0xff) {
255 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorCount
) != 0xff) {
259 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorNumber
) != 0xff) {
263 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderLsb
) != 0xff) {
267 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderMsb
) != 0xff) {
271 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Head
) != 0xff) {
275 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Command
) != 0xff) {
279 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
) != 0xff) {
293 // GetIdeRegistersBaseAddr
296 Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,
297 use fixed addresses. In Native-PCI mode, get base addresses from BARs in
298 the PCI IDE controller's Configuration Space.
300 The steps to get IDE IO port registers' base addresses for each channel
303 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE
304 controller's Configuration Space to determine the operating mode.
306 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.
308 ___________________________________________
309 | | Command Block | Control Block |
310 | Channel | Registers | Registers |
311 |___________|_______________|_______________|
312 | Primary | 1F0h - 1F7h | 3F6h - 3F7h |
313 |___________|_______________|_______________|
314 | Secondary | 170h - 177h | 376h - 377h |
315 |___________|_______________|_______________|
317 Table 1. Compatibility resource mappings
320 b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs
321 in IDE controller's PCI Configuration Space, shown in the Table 2 below.
323 ___________________________________________________
324 | | Command Block | Control Block |
325 | Channel | Registers | Registers |
326 |___________|___________________|___________________|
327 | Primary | BAR at offset 0x10| BAR at offset 0x14|
328 |___________|___________________|___________________|
329 | Secondary | BAR at offset 0x18| BAR at offset 0x1C|
330 |___________|___________________|___________________|
332 Table 2. BARs for Register Mapping
334 @note Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for
335 primary, 0374h for secondary. So 2 bytes extra offset should be
336 added to the base addresses read from BARs.
338 For more details, please refer to PCI IDE Controller Specification and Intel
341 @param PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance
342 @param IdeRegsBaseAddr Pointer to IDE_REGISTERS_BASE_ADDR to
343 receive IDE IO port registers' base addresses
347 GetIdeRegistersBaseAddr (
348 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
349 OUT IDE_REGISTERS_BASE_ADDR
*IdeRegsBaseAddr
351 // TODO: EFI_UNSUPPORTED - add return value to function comment
352 // TODO: EFI_UNSUPPORTED - add return value to function comment
353 // TODO: EFI_SUCCESS - add return value to function comment
358 Status
= PciIo
->Pci
.Read (
366 if (EFI_ERROR (Status
)) {
370 if ((PciData
.Hdr
.ClassCode
[0] & IDE_PRIMARY_OPERATING_MODE
) == 0) {
371 IdeRegsBaseAddr
[IdePrimary
].CommandBlockBaseAddr
= 0x1f0;
372 IdeRegsBaseAddr
[IdePrimary
].ControlBlockBaseAddr
= 0x3f6;
373 IdeRegsBaseAddr
[IdePrimary
].BusMasterBaseAddr
=
374 (UINT16
)((PciData
.Device
.Bar
[4] & 0x0000fff0));
377 // The BARs should be of IO type
379 if ((PciData
.Device
.Bar
[0] & bit0
) == 0 ||
380 (PciData
.Device
.Bar
[1] & bit0
) == 0) {
381 return EFI_UNSUPPORTED
;
384 IdeRegsBaseAddr
[IdePrimary
].CommandBlockBaseAddr
=
385 (UINT16
) (PciData
.Device
.Bar
[0] & 0x0000fff8);
386 IdeRegsBaseAddr
[IdePrimary
].ControlBlockBaseAddr
=
387 (UINT16
) ((PciData
.Device
.Bar
[1] & 0x0000fffc) + 2);
388 IdeRegsBaseAddr
[IdePrimary
].BusMasterBaseAddr
=
389 (UINT16
) ((PciData
.Device
.Bar
[4] & 0x0000fff0));
392 if ((PciData
.Hdr
.ClassCode
[0] & IDE_SECONDARY_OPERATING_MODE
) == 0) {
393 IdeRegsBaseAddr
[IdeSecondary
].CommandBlockBaseAddr
= 0x170;
394 IdeRegsBaseAddr
[IdeSecondary
].ControlBlockBaseAddr
= 0x376;
395 IdeRegsBaseAddr
[IdeSecondary
].BusMasterBaseAddr
=
396 (UINT16
) ((PciData
.Device
.Bar
[4] & 0x0000fff0));
399 // The BARs should be of IO type
401 if ((PciData
.Device
.Bar
[2] & bit0
) == 0 ||
402 (PciData
.Device
.Bar
[3] & bit0
) == 0) {
403 return EFI_UNSUPPORTED
;
406 IdeRegsBaseAddr
[IdeSecondary
].CommandBlockBaseAddr
=
407 (UINT16
) (PciData
.Device
.Bar
[2] & 0x0000fff8);
408 IdeRegsBaseAddr
[IdeSecondary
].ControlBlockBaseAddr
=
409 (UINT16
) ((PciData
.Device
.Bar
[3] & 0x0000fffc) + 2);
410 IdeRegsBaseAddr
[IdeSecondary
].BusMasterBaseAddr
=
411 (UINT16
) ((PciData
.Device
.Bar
[4] & 0x0000fff0));
418 This function is used to requery IDE resources. The IDE controller will
419 probably switch between native and legacy modes during the EFI->CSM->OS
420 transfer. We do this everytime before an BlkIo operation to ensure its
423 @param IdeDev The BLK_IO private data which specifies the IDE device
427 ReassignIdeResources (
428 IN IDE_BLK_IO_DEV
*IdeDev
430 // TODO: EFI_SUCCESS - add return value to function comment
433 IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr
[IdeMaxChannel
];
434 UINT16 CommandBlockBaseAddr
;
435 UINT16 ControlBlockBaseAddr
;
438 // Requery IDE IO port registers' base addresses in case of the switch of
439 // native and legacy modes
441 Status
= GetIdeRegistersBaseAddr (IdeDev
->PciIo
, IdeRegsBaseAddr
);
442 if (EFI_ERROR (Status
)) {
446 ZeroMem (IdeDev
->IoPort
, sizeof (IDE_BASE_REGISTERS
));
447 CommandBlockBaseAddr
= IdeRegsBaseAddr
[IdeDev
->Channel
].CommandBlockBaseAddr
;
448 ControlBlockBaseAddr
= IdeRegsBaseAddr
[IdeDev
->Channel
].ControlBlockBaseAddr
;
450 IdeDev
->IoPort
->Data
= CommandBlockBaseAddr
;
451 (*(UINT16
*) &IdeDev
->IoPort
->Reg1
) = (UINT16
) (CommandBlockBaseAddr
+ 0x01);
452 IdeDev
->IoPort
->SectorCount
= (UINT16
) (CommandBlockBaseAddr
+ 0x02);
453 IdeDev
->IoPort
->SectorNumber
= (UINT16
) (CommandBlockBaseAddr
+ 0x03);
454 IdeDev
->IoPort
->CylinderLsb
= (UINT16
) (CommandBlockBaseAddr
+ 0x04);
455 IdeDev
->IoPort
->CylinderMsb
= (UINT16
) (CommandBlockBaseAddr
+ 0x05);
456 IdeDev
->IoPort
->Head
= (UINT16
) (CommandBlockBaseAddr
+ 0x06);
458 (*(UINT16
*) &IdeDev
->IoPort
->Reg
) = (UINT16
) (CommandBlockBaseAddr
+ 0x07);
459 (*(UINT16
*) &IdeDev
->IoPort
->Alt
) = ControlBlockBaseAddr
;
460 IdeDev
->IoPort
->DriveAddress
= (UINT16
) (ControlBlockBaseAddr
+ 0x01);
461 IdeDev
->IoPort
->MasterSlave
= (UINT16
) ((IdeDev
->Device
== IdeMaster
) ? 1 : 0);
463 IdeDev
->IoPort
->BusMasterBaseAddr
= IdeRegsBaseAddr
[IdeDev
->Channel
].BusMasterBaseAddr
;
468 Read SATA registers to detect SATA disks
470 @param IdeDev The BLK_IO private data which specifies the IDE device
475 IDE_BLK_IO_DEV
*IdeDev
477 // TODO: EFI_NOT_FOUND - add return value to function comment
478 // TODO: EFI_SUCCESS - add return value to function comment
479 // TODO: EFI_NOT_FOUND - add return value to function comment
486 IdeDev
->IoPort
->Head
,
487 (UINT8
) ((IdeDev
->Device
<< 4) | 0xe0)
491 // Wait 31 seconds for BSY clear. BSY should be in clear state if there exists
492 // a device (initial state). Normally, BSY is also in clear state if there is
495 Status
= WaitForBSYClear (IdeDev
, 31000);
496 if (EFI_ERROR (Status
)) {
497 return EFI_NOT_FOUND
;
501 // select device, read error register
505 IdeDev
->IoPort
->Head
,
506 (UINT8
) ((IdeDev
->Device
<< 4) | 0xe0)
508 Status
= DRDYReady (IdeDev
, 200);
510 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
511 if ((ErrorRegister
== 0x01) || (ErrorRegister
== 0x81)) {
514 return EFI_NOT_FOUND
;
522 Detect if there is disk connected to this port
524 @param IdeDev The BLK_IO private data which specifies the IDE device
529 IN IDE_BLK_IO_DEV
*IdeDev
531 // TODO: EFI_NOT_FOUND - add return value to function comment
532 // TODO: EFI_NOT_FOUND - add return value to function comment
533 // TODO: EFI_SUCCESS - add return value to function comment
540 // This extra detection is for SATA disks
542 Status
= CheckPowerMode (IdeDev
);
543 if (Status
== EFI_SUCCESS
) {
548 // If a channel has not been checked, check it now. Then set it to "checked" state
549 // After this step, all devices in this channel have been checked.
551 Status
= DetectIDEController (IdeDev
);
553 if ((EFI_ERROR (Status
)) && !SataFlag
) {
554 return EFI_NOT_FOUND
;
558 // Device exists. test if it is an ATA device
560 Status
= ATAIdentify (IdeDev
);
561 if (EFI_ERROR (Status
)) {
563 // if not ATA device, test if it is an ATAPI device
565 Status
= ATAPIIdentify (IdeDev
);
566 if (EFI_ERROR (Status
)) {
568 // if not ATAPI device either, return error.
570 return EFI_NOT_FOUND
;
575 // Init Block I/O interface
577 IdeDev
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION
;
578 IdeDev
->BlkIo
.Reset
= IDEBlkIoReset
;
579 IdeDev
->BlkIo
.ReadBlocks
= IDEBlkIoReadBlocks
;
580 IdeDev
->BlkIo
.WriteBlocks
= IDEBlkIoWriteBlocks
;
581 IdeDev
->BlkIo
.FlushBlocks
= IDEBlkIoFlushBlocks
;
583 IdeDev
->BlkMedia
.LogicalPartition
= FALSE
;
584 IdeDev
->BlkMedia
.WriteCaching
= FALSE
;
587 // Init Disk Info interface
589 gBS
->CopyMem (&IdeDev
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
, sizeof (EFI_GUID
));
590 IdeDev
->DiskInfo
.Inquiry
= IDEDiskInfoInquiry
;
591 IdeDev
->DiskInfo
.Identify
= IDEDiskInfoIdentify
;
592 IdeDev
->DiskInfo
.SenseData
= IDEDiskInfoSenseData
;
593 IdeDev
->DiskInfo
.WhichIde
= IDEDiskInfoWhichIde
;
599 This function is called by DiscoverIdeDevice(). It is used for detect
600 whether the IDE device exists in the specified Channel as the specified
603 There is two IDE channels: one is Primary Channel, the other is
604 Secondary Channel.(Channel is the logical name for the physical "Cable".)
605 Different channel has different register group.
607 On each IDE channel, at most two IDE devices attach,
608 one is called Device 0 (Master device), the other is called Device 1
609 (Slave device). The devices on the same channel co-use the same register
610 group, so before sending out a command for a specified device via command
611 register, it is a must to select the current device to accept the command
612 by set the device number in the Head/Device Register.
615 pointer pointing to IDE_BLK_IO_DEV data structure, used
616 to record all the information of the IDE device.
619 successfully detects device.
622 any failure during detection process will return this
626 TODO: EFI_SUCCESS - add return value to function comment
627 TODO: EFI_NOT_FOUND - add return value to function comment
631 DetectIDEController (
632 IN IDE_BLK_IO_DEV
*IdeDev
639 EFI_STATUS DeviceStatus
;
642 // Slave device has been detected with master device.
644 if ((IdeDev
->Device
) == 1) {
645 if (SlaveDeviceExist
) {
647 // If master not exists but slave exists, slave have to wait a while
649 if (!MasterDeviceExist
) {
651 // if single slave can't be detected, add delay 4s here.
653 gBS
->Stall (4000000);
658 return EFI_NOT_FOUND
;
663 // Select slave device
667 IdeDev
->IoPort
->Head
,
668 (UINT8
) ((1 << 4) | 0xe0)
673 // Save the init slave status register
675 InitStatusReg
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
678 // Select master back
682 IdeDev
->IoPort
->Head
,
683 (UINT8
) ((0 << 4) | 0xe0)
687 // Send ATA Device Execut Diagnostic command.
688 // This command should work no matter DRDY is ready or not
690 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Command
, 0x90);
692 Status
= WaitForBSYClear (IdeDev
, 3500);
694 ErrorReg
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
697 // Master Error register is 0x01. D0 passed, D1 passed or not present.
698 // Master Error register is 0x81. D0 passed, D1 failed. Return.
699 // Master Error register is other value. D0 failed, D1 passed or not present..
701 if (ErrorReg
== 0x01) {
702 MasterDeviceExist
= TRUE
;
703 DeviceStatus
= EFI_SUCCESS
;
704 } else if (ErrorReg
== 0x81) {
706 MasterDeviceExist
= TRUE
;
707 DeviceStatus
= EFI_SUCCESS
;
708 SlaveDeviceExist
= FALSE
;
712 MasterDeviceExist
= FALSE
;
713 DeviceStatus
= EFI_NOT_FOUND
;
717 // Master Error register is not 0x81, Go on check Slave
721 // Stall 10ms to wait for slave device ready
730 IdeDev
->IoPort
->Head
,
731 (UINT8
) ((1 << 4) | 0xe0)
735 ErrorReg
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
738 // Slave Error register is not 0x01, D1 failed. Return.
740 if (ErrorReg
!= 0x01) {
741 SlaveDeviceExist
= FALSE
;
745 StatusReg
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
748 // Most ATAPI devices don't set DRDY bit, so test with a slow but accurate
749 // "ATAPI TEST UNIT READY" command
751 if (((StatusReg
& DRDY
) == 0) && ((InitStatusReg
& DRDY
) == 0)) {
752 Status
= AtapiTestUnitReady (IdeDev
);
755 // Still fail, Slave doesn't exist.
757 if (EFI_ERROR (Status
)) {
758 SlaveDeviceExist
= FALSE
;
764 // Error reg is 0x01 and DRDY is ready,
765 // or ATAPI test unit ready success,
766 // or init Slave status DRDY is ready
769 SlaveDeviceExist
= TRUE
;
776 This function is used to poll for the DRQ bit clear in the Status
777 Register. DRQ is cleared when the device is finished transferring data.
778 So this function is called after data transfer is finished.
781 pointer pointing to IDE_BLK_IO_DEV data structure, used
782 to record all the information of the IDE device.
784 @param[in] TimeoutInMilliSeconds
785 used to designate the timeout for the DRQ clear.
788 DRQ bit clear within the time out.
791 DRQ bit not clear within the time out.
794 Read Status Register will clear interrupt status.
799 IN IDE_BLK_IO_DEV
*IdeDev
,
800 IN UINTN TimeoutInMilliSeconds
802 // TODO: function comment is missing 'Routine Description:'
803 // TODO: function comment is missing 'Arguments:'
804 // TODO: IdeDev - add argument and description to function comment
805 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
806 // TODO: EFI_ABORTED - add return value to function comment
809 UINT8 StatusRegister
;
812 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
815 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
818 // wait for BSY == 0 and DRQ == 0
820 if ((StatusRegister
& (DRQ
| BSY
)) == 0) {
824 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
826 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
827 if ((ErrorRegister
& ABRT_ERR
) == ABRT_ERR
) {
849 This function is used to poll for the DRQ bit clear in the Alternate
850 Status Register. DRQ is cleared when the device is finished
851 transferring data. So this function is called after data transfer
855 pointer pointing to IDE_BLK_IO_DEV data structure, used
856 to record all the information of the IDE device.
858 @param[in] TimeoutInMilliSeconds
859 used to designate the timeout for the DRQ clear.
862 DRQ bit clear within the time out.
865 DRQ bit not clear within the time out.
868 Read Alternate Status Register will not clear interrupt status.
873 IN IDE_BLK_IO_DEV
*IdeDev
,
874 IN UINTN TimeoutInMilliSeconds
876 // TODO: function comment is missing 'Routine Description:'
877 // TODO: function comment is missing 'Arguments:'
878 // TODO: IdeDev - add argument and description to function comment
879 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
880 // TODO: EFI_ABORTED - add return value to function comment
886 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
889 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
892 // wait for BSY == 0 and DRQ == 0
894 if ((AltRegister
& (DRQ
| BSY
)) == 0) {
898 if ((AltRegister
& (BSY
| ERR
)) == ERR
) {
900 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
901 if ((ErrorRegister
& ABRT_ERR
) == ABRT_ERR
) {
923 This function is used to poll for the DRQ bit set in the
925 DRQ is set when the device is ready to transfer data. So this function
926 is called after the command is sent to the device and before required
929 @param[in] IDE_BLK_IO_DEV IN *IdeDev
930 pointer pointing to IDE_BLK_IO_DEV data structure,used
931 to record all the information of the IDE device.
933 @param[in] UINTN IN TimeoutInMilliSeconds
934 used to designate the timeout for the DRQ ready.
937 DRQ bit set within the time out.
940 DRQ bit not set within the time out.
943 DRQ bit not set caused by the command abort.
946 Read Status Register will clear interrupt status.
951 IN IDE_BLK_IO_DEV
*IdeDev
,
952 IN UINTN TimeoutInMilliSeconds
954 // TODO: function comment is missing 'Routine Description:'
955 // TODO: function comment is missing 'Arguments:'
956 // TODO: IdeDev - add argument and description to function comment
957 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
960 UINT8 StatusRegister
;
963 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
966 // read Status Register will clear interrupt
968 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
973 if ((StatusRegister
& (BSY
| DRQ
)) == DRQ
) {
977 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
979 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
980 if ((ErrorRegister
& ABRT_ERR
) == ABRT_ERR
) {
1001 This function is used to poll for the DRQ bit set in the
1002 Alternate Status Register. DRQ is set when the device is ready to
1003 transfer data. So this function is called after the command
1004 is sent to the device and before required data is transferred.
1006 @param[in] IDE_BLK_IO_DEV IN *IdeDev
1007 pointer pointing to IDE_BLK_IO_DEV data structure, used
1008 to record all the information of the IDE device.
1010 @param[in] UINTN IN TimeoutInMilliSeconds
1011 used to designate the timeout for the DRQ ready.
1014 DRQ bit set within the time out.
1017 DRQ bit not set within the time out.
1020 DRQ bit not set caused by the command abort.
1023 Read Alternate Status Register will not clear interrupt status.
1028 IN IDE_BLK_IO_DEV
*IdeDev
,
1029 IN UINTN TimeoutInMilliSeconds
1031 // TODO: function comment is missing 'Routine Description:'
1032 // TODO: function comment is missing 'Arguments:'
1033 // TODO: IdeDev - add argument and description to function comment
1034 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
1038 UINT8 ErrorRegister
;
1040 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1044 // Read Alternate Status Register will not clear interrupt status
1046 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
1048 // BSY == 0 , DRQ == 1
1050 if ((AltRegister
& (BSY
| DRQ
)) == DRQ
) {
1054 if ((AltRegister
& (BSY
| ERR
)) == ERR
) {
1056 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
1057 if ((ErrorRegister
& ABRT_ERR
) == ABRT_ERR
) {
1078 This function is used to poll for the BSY bit clear in the
1079 Status Register. BSY is clear when the device is not busy.
1080 Every command must be sent after device is not busy.
1082 @param[in] IDE_BLK_IO_DEV IN *IdeDev
1083 pointer pointing to IDE_BLK_IO_DEV data structure, used
1084 to record all the information of the IDE device.
1086 @param[in] UINTN IN TimeoutInMilliSeconds
1087 used to designate the timeout for the DRQ ready.
1090 BSY bit clear within the time out.
1093 BSY bit not clear within the time out.
1096 Read Status Register will clear interrupt status.
1101 IN IDE_BLK_IO_DEV
*IdeDev
,
1102 IN UINTN TimeoutInMilliSeconds
1104 // TODO: function comment is missing 'Routine Description:'
1105 // TODO: function comment is missing 'Arguments:'
1106 // TODO: IdeDev - add argument and description to function comment
1107 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
1110 UINT8 StatusRegister
;
1112 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1115 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1116 if ((StatusRegister
& BSY
) == 0x00) {
1139 This function is used to poll for the BSY bit clear in the
1140 Alternate Status Register. BSY is clear when the device is not busy.
1141 Every command must be sent after device is not busy.
1143 @param[in] IDE_BLK_IO_DEV IN *IdeDev
1144 pointer pointing to IDE_BLK_IO_DEV data structure, used
1145 to record all the information of the IDE device.
1147 @param[in] UINTN IN TimeoutInMilliSeconds
1148 used to designate the timeout for the DRQ ready.
1151 BSY bit clear within the time out.
1154 BSY bit not clear within the time out.
1157 Read Alternate Status Register will not clear interrupt status.
1162 IN IDE_BLK_IO_DEV
*IdeDev
,
1163 IN UINTN TimeoutInMilliSeconds
1165 // TODO: function comment is missing 'Routine Description:'
1166 // TODO: function comment is missing 'Arguments:'
1167 // TODO: IdeDev - add argument and description to function comment
1168 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
1173 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1175 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
1176 if ((AltRegister
& BSY
) == 0x00) {
1197 This function is used to poll for the DRDY bit set in the
1198 Status Register. DRDY bit is set when the device is ready
1199 to accept command. Most ATA commands must be sent after
1200 DRDY set except the ATAPI Packet Command.
1202 @param[in] IDE_BLK_IO_DEV IN *IdeDev
1203 pointer pointing to IDE_BLK_IO_DEV data structure, used
1204 to record all the information of the IDE device.
1206 @param[in] UINTN IN TimeoutInMilliSeconds
1207 used to designate the timeout for the DRQ ready.
1210 DRDY bit set within the time out.
1213 DRDY bit not set within the time out.
1216 Read Status Register will clear interrupt status.
1221 IN IDE_BLK_IO_DEV
*IdeDev
,
1222 IN UINTN DelayInMilliSeconds
1224 // TODO: function comment is missing 'Routine Description:'
1225 // TODO: function comment is missing 'Arguments:'
1226 // TODO: IdeDev - add argument and description to function comment
1227 // TODO: DelayInMilliSeconds - add argument and description to function comment
1228 // TODO: EFI_ABORTED - add return value to function comment
1231 UINT8 StatusRegister
;
1232 UINT8 ErrorRegister
;
1234 Delay
= (UINT32
) (((DelayInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1236 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1238 // BSY == 0 , DRDY == 1
1240 if ((StatusRegister
& (DRDY
| BSY
)) == DRDY
) {
1244 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
1246 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
1247 if ((ErrorRegister
& ABRT_ERR
) == ABRT_ERR
) {
1268 This function is used to poll for the DRDY bit set in the
1269 Alternate Status Register. DRDY bit is set when the device is ready
1270 to accept command. Most ATA commands must be sent after
1271 DRDY set except the ATAPI Packet Command.
1273 @param[in] IDE_BLK_IO_DEV IN *IdeDev
1274 pointer pointing to IDE_BLK_IO_DEV data structure, used
1275 to record all the information of the IDE device.
1277 @param[in] UINTN IN TimeoutInMilliSeconds
1278 used to designate the timeout for the DRQ ready.
1281 DRDY bit set within the time out.
1284 DRDY bit not set within the time out.
1287 Read Alternate Status Register will clear interrupt status.
1292 IN IDE_BLK_IO_DEV
*IdeDev
,
1293 IN UINTN DelayInMilliSeconds
1295 // TODO: function comment is missing 'Routine Description:'
1296 // TODO: function comment is missing 'Arguments:'
1297 // TODO: IdeDev - add argument and description to function comment
1298 // TODO: DelayInMilliSeconds - add argument and description to function comment
1299 // TODO: EFI_ABORTED - add return value to function comment
1303 UINT8 ErrorRegister
;
1305 Delay
= (UINT32
) (((DelayInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1307 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
1309 // BSY == 0 , DRDY == 1
1311 if ((AltRegister
& (DRDY
| BSY
)) == DRDY
) {
1315 if ((AltRegister
& (BSY
| ERR
)) == ERR
) {
1317 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
1318 if ((ErrorRegister
& ABRT_ERR
) == ABRT_ERR
) {
1339 This function is a helper function used to change the char order in a
1340 string. It is designed specially for the PrintAtaModuleName() function.
1341 After the IDE device is detected, the IDE driver gets the device module
1342 name by sending ATA command called ATA Identify Command or ATAPI
1343 Identify Command to the specified IDE device. The module name returned
1344 is a string of ASCII characters: the first character is bit8--bit15
1345 of the first word, the second character is bit0--bit7 of the first word
1346 and so on. Thus the string can not be print directly before it is
1347 preprocessed by this func to change the order of characters in
1348 each word in the string.
1350 @param[in] CHAR8 IN *Destination
1351 Indicates the destination string.
1353 @param[in] CHAR8 IN *Source
1354 Indicates the source string.
1356 @param[in] UINT8 IN Size
1357 the length of the string
1362 IN CHAR8
*Destination
,
1370 for (Index
= 0; Index
< Size
; Index
+= 2) {
1372 Temp
= Source
[Index
+ 1];
1373 Destination
[Index
+ 1] = Source
[Index
];
1374 Destination
[Index
] = Temp
;
1379 // ReleaseIdeResources
1382 Release resources of an IDE device before stopping it.
1384 @param[in] *IdeBlkIoDevice Standard IDE device private data structure
1388 ReleaseIdeResources (
1389 IN IDE_BLK_IO_DEV
*IdeBlkIoDevice
1392 if (IdeBlkIoDevice
== NULL
) {
1397 // Release all the resourses occupied by the IDE_BLK_IO_DEV
1400 if (IdeBlkIoDevice
->SenseData
!= NULL
) {
1401 gBS
->FreePool (IdeBlkIoDevice
->SenseData
);
1402 IdeBlkIoDevice
->SenseData
= NULL
;
1405 if (IdeBlkIoDevice
->Cache
!= NULL
) {
1406 gBS
->FreePool (IdeBlkIoDevice
->Cache
);
1407 IdeBlkIoDevice
->Cache
= NULL
;
1410 if (IdeBlkIoDevice
->pIdData
!= NULL
) {
1411 gBS
->FreePool (IdeBlkIoDevice
->pIdData
);
1412 IdeBlkIoDevice
->pIdData
= NULL
;
1415 if (IdeBlkIoDevice
->pInquiryData
!= NULL
) {
1416 gBS
->FreePool (IdeBlkIoDevice
->pInquiryData
);
1417 IdeBlkIoDevice
->pInquiryData
= NULL
;
1420 if (IdeBlkIoDevice
->ControllerNameTable
!= NULL
) {
1421 FreeUnicodeStringTable (IdeBlkIoDevice
->ControllerNameTable
);
1422 IdeBlkIoDevice
->ControllerNameTable
= NULL
;
1425 if (IdeBlkIoDevice
->IoPort
!= NULL
) {
1426 gBS
->FreePool (IdeBlkIoDevice
->IoPort
);
1429 if (IdeBlkIoDevice
->DevicePath
!= NULL
) {
1430 gBS
->FreePool (IdeBlkIoDevice
->DevicePath
);
1433 gBS
->FreePool (IdeBlkIoDevice
);
1434 IdeBlkIoDevice
= NULL
;
1440 // SetDeviceTransferMode
1443 Set the calculated Best transfer mode to a detected device
1445 @param[in] *IdeDev Standard IDE device private data structure
1446 @param[in] *TransferMode The device transfer mode to be set
1448 @return Set transfer mode Command execute status
1452 SetDeviceTransferMode (
1453 IN IDE_BLK_IO_DEV
*IdeDev
,
1454 IN ATA_TRANSFER_MODE
*TransferMode
1456 // TODO: function comment is missing 'Routine Description:'
1463 DeviceSelect
= (UINT8
) ((IdeDev
->Device
) << 4);
1464 SectorCount
= *((UINT8
*) TransferMode
);
1467 // Send SET FEATURE command (sub command 0x03) to set pio mode.
1469 Status
= AtaNonDataCommandIn (
1484 Send ATA command into device with NON_DATA protocol
1486 @param IdeDev Standard IDE device private data structure
1487 @param AtaCommand The ATA command to be sent
1488 @param Device The value in Device register
1489 @param Feature The value in Feature register
1490 @param SectorCount The value in SectorCount register
1491 @param LbaLow The value in LBA_LOW register
1492 @param LbaMiddle The value in LBA_MIDDLE register
1493 @param LbaHigh The value in LBA_HIGH register
1495 @retval EFI_SUCCESS Reading succeed
1496 @retval EFI_ABORTED Command failed
1497 @retval EFI_DEVICE_ERROR Device status error
1501 AtaNonDataCommandIn (
1502 IN IDE_BLK_IO_DEV
*IdeDev
,
1503 IN UINT8 AtaCommand
,
1506 IN UINT8 SectorCount
,
1513 UINT8 StatusRegister
;
1515 Status
= WaitForBSYClear (IdeDev
, ATATIMEOUT
);
1516 if (EFI_ERROR (Status
)) {
1517 return EFI_DEVICE_ERROR
;
1521 // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
1525 IdeDev
->IoPort
->Head
,
1526 (UINT8
) ((IdeDev
->Device
<< 4) | 0xe0)
1530 // ATA commands for ATA device must be issued when DRDY is set
1532 Status
= DRDYReady (IdeDev
, ATATIMEOUT
);
1533 if (EFI_ERROR (Status
)) {
1534 return EFI_DEVICE_ERROR
;
1538 // Pass parameter into device register block
1540 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Head
, Device
);
1541 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Feature
, Feature
);
1542 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorCount
, SectorCount
);
1543 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorNumber
, LbaLow
);
1544 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderLsb
, LbaMiddle
);
1545 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderMsb
, LbaHigh
);
1548 // Send command via Command Register
1550 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Command
, AtaCommand
);
1553 // Wait for command completion
1555 Status
= WaitForBSYClear (IdeDev
, ATATIMEOUT
);
1556 if (EFI_ERROR (Status
)) {
1557 return EFI_DEVICE_ERROR
;
1560 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1561 if ((StatusRegister
& ERR
) == ERR
) {
1563 // Failed to execute command, abort operation
1572 Send ATA Ext command into device with NON_DATA protocol
1574 @param IdeDev Standard IDE device private data structure
1575 @param AtaCommand The ATA command to be sent
1576 @param Device The value in Device register
1577 @param Feature The value in Feature register
1578 @param SectorCount The value in SectorCount register
1579 @param LbaAddress The LBA address in 48-bit mode
1581 @retval EFI_SUCCESS Reading succeed
1582 @retval EFI_ABORTED Command failed
1583 @retval EFI_DEVICE_ERROR Device status error
1587 AtaNonDataCommandInExt (
1588 IN IDE_BLK_IO_DEV
*IdeDev
,
1589 IN UINT8 AtaCommand
,
1592 IN UINT16 SectorCount
,
1593 IN EFI_LBA LbaAddress
1597 UINT8 StatusRegister
;
1604 Status
= WaitForBSYClear (IdeDev
, ATATIMEOUT
);
1605 if (EFI_ERROR (Status
)) {
1606 return EFI_DEVICE_ERROR
;
1610 // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
1614 IdeDev
->IoPort
->Head
,
1615 (UINT8
) ((IdeDev
->Device
<< 4) | 0xe0)
1619 // ATA commands for ATA device must be issued when DRDY is set
1621 Status
= DRDYReady (IdeDev
, ATATIMEOUT
);
1622 if (EFI_ERROR (Status
)) {
1623 return EFI_DEVICE_ERROR
;
1627 // Pass parameter into device register block
1629 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Head
, Device
);
1632 // Fill the feature register, which is a two-byte FIFO. Need write twice.
1634 Feature8
= (UINT8
) (Feature
>> 8);
1635 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Feature
, Feature8
);
1637 Feature8
= (UINT8
) Feature
;
1638 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Feature
, Feature8
);
1641 // Fill the sector count register, which is a two-byte FIFO. Need write twice.
1643 SectorCount8
= (UINT8
) (SectorCount
>> 8);
1644 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorCount
, SectorCount8
);
1646 SectorCount8
= (UINT8
) SectorCount
;
1647 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorCount
, SectorCount8
);
1650 // Fill the start LBA registers, which are also two-byte FIFO
1652 LbaLow
= (UINT8
) RShiftU64 (LbaAddress
, 24);
1653 LbaMid
= (UINT8
) RShiftU64 (LbaAddress
, 32);
1654 LbaHigh
= (UINT8
) RShiftU64 (LbaAddress
, 40);
1655 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorNumber
, LbaLow
);
1656 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderLsb
, LbaMid
);
1657 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderMsb
, LbaHigh
);
1659 LbaLow
= (UINT8
) LbaAddress
;
1660 LbaMid
= (UINT8
) RShiftU64 (LbaAddress
, 8);
1661 LbaHigh
= (UINT8
) RShiftU64 (LbaAddress
, 16);
1662 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorNumber
, LbaLow
);
1663 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderLsb
, LbaMid
);
1664 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderMsb
, LbaHigh
);
1667 // Send command via Command Register
1669 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Command
, AtaCommand
);
1672 // Wait for command completion
1674 Status
= WaitForBSYClear (IdeDev
, ATATIMEOUT
);
1675 if (EFI_ERROR (Status
)) {
1676 return EFI_DEVICE_ERROR
;
1679 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1680 if ((StatusRegister
& ERR
) == ERR
) {
1682 // Failed to execute command, abort operation
1691 // SetDriveParameters
1694 Set drive parameters for devices not support PACKETS command
1696 @param[in] IdeDev Standard IDE device private data structure
1697 @param[in] DriveParameters The device parameters to be set into the disk
1699 @return SetParameters Command execute status
1703 SetDriveParameters (
1704 IN IDE_BLK_IO_DEV
*IdeDev
,
1705 IN ATA_DRIVE_PARMS
*DriveParameters
1712 DeviceSelect
= (UINT8
) ((IdeDev
->Device
) << 4);
1715 // Send Init drive parameters
1717 Status
= AtaPioDataIn (
1721 INIT_DRIVE_PARAM_CMD
,
1722 (UINT8
) (DeviceSelect
+ DriveParameters
->Heads
),
1723 DriveParameters
->Sector
,
1730 // Send Set Multiple parameters
1732 Status
= AtaPioDataIn (
1736 SET_MULTIPLE_MODE_CMD
,
1738 DriveParameters
->MultipleSector
,
1748 TODO: Add function description
1750 @param IdeDev TODO: add argument description
1752 @retval EFI_SUCCESS TODO: Add description for return value
1757 IN IDE_BLK_IO_DEV
*IdeDev
1760 UINT8 DeviceControl
;
1763 // Enable interrupt for DMA operation
1766 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.DeviceControl
, DeviceControl
);