2 The file ontaining the helper functions implement of the Ide Bus driver
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 BOOLEAN ChannelDeviceDetected
= FALSE
;
18 BOOLEAN SlaveDeviceExist
= FALSE
;
19 UINT8 SlaveDeviceType
= INVALID_DEVICE_TYPE
;
20 BOOLEAN MasterDeviceExist
= FALSE
;
21 UINT8 MasterDeviceType
= INVALID_DEVICE_TYPE
;
24 read a one-byte data from a IDE port.
26 @param PciIo The PCI IO protocol instance
27 @param Port the IDE Port number
29 @return the one-byte data read from IDE port
33 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
41 // perform 1-byte data read from register
46 EFI_PCI_IO_PASS_THROUGH_BAR
,
54 Reads multiple words of data from the IDE data port.
55 Call the IO abstraction once to do the complete read,
56 not one word at a time
58 @param PciIo Pointer to the EFI_PCI_IO instance
59 @param Port IO port to read
60 @param Count No. of UINT16's to read
61 @param Buffer Pointer to the data buffer for read
65 IDEReadPortWMultiple (
66 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
72 UINT16
*AlignedBuffer
;
73 UINT16
*WorkingBuffer
;
77 // Prepare an 16-bit alligned working buffer. CpuIo will return failure and
78 // not perform actual I/O operations if buffer pointer passed in is not at
79 // natural boundary. The "Buffer" argument is passed in by user and may not
80 // at 16-bit natural boundary.
82 Size
= sizeof (UINT16
) * Count
;
87 (VOID
**)&WorkingBuffer
90 AlignedBuffer
= (UINT16
*) ((UINTN
)(((UINTN
) WorkingBuffer
+ 0x1) & (~0x1)));
93 // Perform UINT16 data read from FIFO
97 EfiPciIoWidthFifoUint16
,
98 EFI_PCI_IO_PASS_THROUGH_BAR
,
101 (UINT16
*)AlignedBuffer
105 // Copy data to user buffer
107 CopyMem (Buffer
, (UINT16
*)AlignedBuffer
, Size
);
108 gBS
->FreePool (WorkingBuffer
);
112 write a 1-byte data to a specific IDE port.
114 @param PciIo PCI IO protocol instance
115 @param Port The IDE port to be writen
116 @param Data The data to write to the port
120 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
126 // perform 1-byte data write to register
131 EFI_PCI_IO_PASS_THROUGH_BAR
,
140 write a 1-word data to a specific IDE port.
142 @param PciIo PCI IO protocol instance
143 @param Port The IDE port to be writen
144 @param Data The data to write to the port
148 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
154 // perform 1-word data write to register
159 EFI_PCI_IO_PASS_THROUGH_BAR
,
167 Write multiple words of data to the IDE data port.
168 Call the IO abstraction once to do the complete read,
169 not one word at a time
171 @param PciIo Pointer to the EFI_PCI_IO instance
172 @param Port IO port to read
173 @param Count No. of UINT16's to read
174 @param Buffer Pointer to the data buffer for read
178 IDEWritePortWMultiple (
179 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
185 UINT16
*AlignedBuffer
;
186 UINT32
*WorkingBuffer
;
190 // Prepare an 16-bit alligned working buffer. CpuIo will return failure and
191 // not perform actual I/O operations if buffer pointer passed in is not at
192 // natural boundary. The "Buffer" argument is passed in by user and may not
193 // at 16-bit natural boundary.
195 Size
= sizeof (UINT16
) * Count
;
200 (VOID
**) &WorkingBuffer
203 AlignedBuffer
= (UINT16
*) ((UINTN
)(((UINTN
) WorkingBuffer
+ 0x1) & (~0x1)));
206 // Copy data from user buffer to working buffer
208 CopyMem ((UINT16
*) AlignedBuffer
, Buffer
, Size
);
211 // perform UINT16 data write to the FIFO
215 EfiPciIoWidthFifoUint16
,
216 EFI_PCI_IO_PASS_THROUGH_BAR
,
219 (UINT16
*) AlignedBuffer
222 gBS
->FreePool (WorkingBuffer
);
225 Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,
226 use fixed addresses. In Native-PCI mode, get base addresses from BARs in
227 the PCI IDE controller's Configuration Space.
229 The steps to get IDE IO port registers' base addresses for each channel
232 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE
233 controller's Configuration Space to determine the operating mode.
235 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.
237 ___________________________________________
238 | | Command Block | Control Block |
239 | Channel | Registers | Registers |
240 |___________|_______________|_______________|
241 | Primary | 1F0h - 1F7h | 3F6h - 3F7h |
242 |___________|_______________|_______________|
243 | Secondary | 170h - 177h | 376h - 377h |
244 |___________|_______________|_______________|
246 Table 1. Compatibility resource mappings
249 b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs
250 in IDE controller's PCI Configuration Space, shown in the Table 2 below.
252 ___________________________________________________
253 | | Command Block | Control Block |
254 | Channel | Registers | Registers |
255 |___________|___________________|___________________|
256 | Primary | BAR at offset 0x10| BAR at offset 0x14|
257 |___________|___________________|___________________|
258 | Secondary | BAR at offset 0x18| BAR at offset 0x1C|
259 |___________|___________________|___________________|
261 Table 2. BARs for Register Mapping
263 @note Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for
264 primary, 0374h for secondary. So 2 bytes extra offset should be
265 added to the base addresses read from BARs.
267 For more details, please refer to PCI IDE Controller Specification and Intel
270 @param PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance
271 @param IdeRegsBaseAddr Pointer to IDE_REGISTERS_BASE_ADDR to
272 receive IDE IO port registers' base addresses
274 @retval EFI_UNSUPPORTED return this value when the BARs is not IO type
275 @retval EFI_SUCCESS Get the Base address successfully
276 @retval other read the pci configureation data error
280 GetIdeRegistersBaseAddr (
281 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
282 OUT IDE_REGISTERS_BASE_ADDR
*IdeRegsBaseAddr
288 Status
= PciIo
->Pci
.Read (
296 if (EFI_ERROR (Status
)) {
300 if ((PciData
.Hdr
.ClassCode
[0] & IDE_PRIMARY_OPERATING_MODE
) == 0) {
301 IdeRegsBaseAddr
[IdePrimary
].CommandBlockBaseAddr
= 0x1f0;
302 IdeRegsBaseAddr
[IdePrimary
].ControlBlockBaseAddr
= 0x3f6;
303 IdeRegsBaseAddr
[IdePrimary
].BusMasterBaseAddr
=
304 (UINT16
)((PciData
.Device
.Bar
[4] & 0x0000fff0));
307 // The BARs should be of IO type
309 if ((PciData
.Device
.Bar
[0] & BIT0
) == 0 ||
310 (PciData
.Device
.Bar
[1] & BIT0
) == 0) {
311 return EFI_UNSUPPORTED
;
314 IdeRegsBaseAddr
[IdePrimary
].CommandBlockBaseAddr
=
315 (UINT16
) (PciData
.Device
.Bar
[0] & 0x0000fff8);
316 IdeRegsBaseAddr
[IdePrimary
].ControlBlockBaseAddr
=
317 (UINT16
) ((PciData
.Device
.Bar
[1] & 0x0000fffc) + 2);
318 IdeRegsBaseAddr
[IdePrimary
].BusMasterBaseAddr
=
319 (UINT16
) ((PciData
.Device
.Bar
[4] & 0x0000fff0));
322 if ((PciData
.Hdr
.ClassCode
[0] & IDE_SECONDARY_OPERATING_MODE
) == 0) {
323 IdeRegsBaseAddr
[IdeSecondary
].CommandBlockBaseAddr
= 0x170;
324 IdeRegsBaseAddr
[IdeSecondary
].ControlBlockBaseAddr
= 0x376;
325 IdeRegsBaseAddr
[IdeSecondary
].BusMasterBaseAddr
=
326 (UINT16
) ((PciData
.Device
.Bar
[4] & 0x0000fff0));
329 // The BARs should be of IO type
331 if ((PciData
.Device
.Bar
[2] & BIT0
) == 0 ||
332 (PciData
.Device
.Bar
[3] & BIT0
) == 0) {
333 return EFI_UNSUPPORTED
;
336 IdeRegsBaseAddr
[IdeSecondary
].CommandBlockBaseAddr
=
337 (UINT16
) (PciData
.Device
.Bar
[2] & 0x0000fff8);
338 IdeRegsBaseAddr
[IdeSecondary
].ControlBlockBaseAddr
=
339 (UINT16
) ((PciData
.Device
.Bar
[3] & 0x0000fffc) + 2);
340 IdeRegsBaseAddr
[IdeSecondary
].BusMasterBaseAddr
=
341 (UINT16
) ((PciData
.Device
.Bar
[4] & 0x0000fff0));
348 This function is used to requery IDE resources. The IDE controller will
349 probably switch between native and legacy modes during the EFI->CSM->OS
350 transfer. We do this everytime before an BlkIo operation to ensure its
353 @param IdeDev The BLK_IO private data which specifies the IDE device
355 @retval EFI_INVALID_PARAMETER return this value when the channel is invalid
356 @retval EFI_SUCCESS reassign the IDE IO resource successfully
357 @retval other get the IDE current base address effor
361 ReassignIdeResources (
362 IN IDE_BLK_IO_DEV
*IdeDev
366 IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr
[IdeMaxChannel
];
367 UINT16 CommandBlockBaseAddr
;
368 UINT16 ControlBlockBaseAddr
;
370 if (IdeDev
->Channel
>= IdeMaxChannel
) {
371 return EFI_INVALID_PARAMETER
;
375 // Requery IDE IO port registers' base addresses in case of the switch of
376 // native and legacy modes
378 Status
= GetIdeRegistersBaseAddr (IdeDev
->PciIo
, IdeRegsBaseAddr
);
379 if (EFI_ERROR (Status
)) {
383 ZeroMem (IdeDev
->IoPort
, sizeof (IDE_BASE_REGISTERS
));
384 CommandBlockBaseAddr
= IdeRegsBaseAddr
[IdeDev
->Channel
].CommandBlockBaseAddr
;
385 ControlBlockBaseAddr
= IdeRegsBaseAddr
[IdeDev
->Channel
].ControlBlockBaseAddr
;
387 IdeDev
->IoPort
->Data
= CommandBlockBaseAddr
;
388 (*(UINT16
*) &IdeDev
->IoPort
->Reg1
) = (UINT16
) (CommandBlockBaseAddr
+ 0x01);
389 IdeDev
->IoPort
->SectorCount
= (UINT16
) (CommandBlockBaseAddr
+ 0x02);
390 IdeDev
->IoPort
->SectorNumber
= (UINT16
) (CommandBlockBaseAddr
+ 0x03);
391 IdeDev
->IoPort
->CylinderLsb
= (UINT16
) (CommandBlockBaseAddr
+ 0x04);
392 IdeDev
->IoPort
->CylinderMsb
= (UINT16
) (CommandBlockBaseAddr
+ 0x05);
393 IdeDev
->IoPort
->Head
= (UINT16
) (CommandBlockBaseAddr
+ 0x06);
395 (*(UINT16
*) &IdeDev
->IoPort
->Reg
) = (UINT16
) (CommandBlockBaseAddr
+ 0x07);
396 (*(UINT16
*) &IdeDev
->IoPort
->Alt
) = ControlBlockBaseAddr
;
397 IdeDev
->IoPort
->DriveAddress
= (UINT16
) (ControlBlockBaseAddr
+ 0x01);
398 IdeDev
->IoPort
->MasterSlave
= (UINT16
) ((IdeDev
->Device
== IdeMaster
) ? 1 : 0);
400 IdeDev
->IoPort
->BusMasterBaseAddr
= IdeRegsBaseAddr
[IdeDev
->Channel
].BusMasterBaseAddr
;
405 This function is called by DiscoverIdeDevice(). It is used for detect
406 whether the IDE device exists in the specified Channel as the specified
409 There is two IDE channels: one is Primary Channel, the other is
410 Secondary Channel.(Channel is the logical name for the physical "Cable".)
411 Different channel has different register group.
413 On each IDE channel, at most two IDE devices attach,
414 one is called Device 0 (Master device), the other is called Device 1
415 (Slave device). The devices on the same channel co-use the same register
416 group, so before sending out a command for a specified device via command
417 register, it is a must to select the current device to accept the command
418 by set the device number in the Head/Device Register.
420 @param IdeDev pointer to IDE_BLK_IO_DEV data structure, used to record all the
421 information of the IDE device.
423 @retval EFI_SUCCESS successfully detects device.
425 @retval other any failure during detection process will return this value.
429 DetectIDEController (
430 IN IDE_BLK_IO_DEV
*IdeDev
434 UINT8 SectorCountReg
;
442 // Select slave device
446 IdeDev
->IoPort
->Head
,
447 (UINT8
) ((1 << 4) | 0xe0)
452 // Save the init slave status register
454 InitStatusReg
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
457 // Select Master back
461 IdeDev
->IoPort
->Head
,
462 (UINT8
) ((0 << 4) | 0xe0)
467 // Send ATA Device Execut Diagnostic command.
468 // This command should work no matter DRDY is ready or not
470 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Command
, 0x90);
472 Status
= WaitForBSYClear (IdeDev
, 3500);
473 if (EFI_ERROR (Status
)) {
474 DEBUG((EFI_D_ERROR
, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status
));
478 // Read device signature
485 IdeDev
->IoPort
->Head
,
486 (UINT8
) ((0 << 4) | 0xe0)
489 SectorCountReg
= IDEReadPortB (
491 IdeDev
->IoPort
->SectorCount
493 LBALowReg
= IDEReadPortB (
495 IdeDev
->IoPort
->SectorNumber
497 LBAMidReg
= IDEReadPortB (
499 IdeDev
->IoPort
->CylinderLsb
501 LBAHighReg
= IDEReadPortB (
503 IdeDev
->IoPort
->CylinderMsb
505 if ((SectorCountReg
== 0x1) &&
506 (LBALowReg
== 0x1) &&
507 (LBAMidReg
== 0x0) &&
508 (LBAHighReg
== 0x0)) {
509 MasterDeviceExist
= TRUE
;
510 MasterDeviceType
= ATA_DEVICE_TYPE
;
512 if ((LBAMidReg
== 0x14) &&
513 (LBAHighReg
== 0xeb)) {
514 MasterDeviceExist
= TRUE
;
515 MasterDeviceType
= ATAPI_DEVICE_TYPE
;
520 // For some Hard Drive, it takes some time to get
521 // the right signature when operating in single slave mode.
522 // We stall 20ms to work around this.
524 if (!MasterDeviceExist
) {
533 IdeDev
->IoPort
->Head
,
534 (UINT8
) ((1 << 4) | 0xe0)
537 SectorCountReg
= IDEReadPortB (
539 IdeDev
->IoPort
->SectorCount
541 LBALowReg
= IDEReadPortB (
543 IdeDev
->IoPort
->SectorNumber
545 LBAMidReg
= IDEReadPortB (
547 IdeDev
->IoPort
->CylinderLsb
549 LBAHighReg
= IDEReadPortB (
551 IdeDev
->IoPort
->CylinderMsb
553 StatusReg
= IDEReadPortB (
555 IdeDev
->IoPort
->Reg
.Status
557 if ((SectorCountReg
== 0x1) &&
558 (LBALowReg
== 0x1) &&
559 (LBAMidReg
== 0x0) &&
560 (LBAHighReg
== 0x0)) {
561 SlaveDeviceExist
= TRUE
;
562 SlaveDeviceType
= ATA_DEVICE_TYPE
;
564 if ((LBAMidReg
== 0x14) &&
565 (LBAHighReg
== 0xeb)) {
566 SlaveDeviceExist
= TRUE
;
567 SlaveDeviceType
= ATAPI_DEVICE_TYPE
;
572 // When single master is plugged, slave device
573 // will be wrongly detected. Here's the workaround
574 // for ATA devices by detecting DRY bit in status
576 // NOTE: This workaround doesn't apply to ATAPI.
578 if (MasterDeviceExist
&& SlaveDeviceExist
&&
579 (StatusReg
& ATA_STSREG_DRDY
) == 0 &&
580 (InitStatusReg
& ATA_STSREG_DRDY
) == 0 &&
581 MasterDeviceType
== SlaveDeviceType
&&
582 SlaveDeviceType
!= ATAPI_DEVICE_TYPE
) {
583 SlaveDeviceExist
= FALSE
;
587 // Indicate this channel has been detected
589 ChannelDeviceDetected
= TRUE
;
593 Detect if there is disk attached to this port
595 @param IdeDev The BLK_IO private data which specifies the IDE device.
597 @retval EFI_NOT_FOUND The device or channel is not found
598 @retval EFI_SUCCESS The device is found
603 IN IDE_BLK_IO_DEV
*IdeDev
607 EFI_STATUS LongPhyStatus
;
610 // If a channel has not been checked, check it now. Then set it to "checked" state
611 // After this step, all devices in this channel have been checked.
613 if (!ChannelDeviceDetected
) {
614 Status
= DetectIDEController (IdeDev
);
615 if (EFI_ERROR (Status
)) {
616 return EFI_NOT_FOUND
;
620 Status
= EFI_NOT_FOUND
;
623 // Device exists. test if it is an ATA device.
624 // Prefer the result from DetectIDEController,
625 // if failed, try another device type to handle
626 // devices that not follow the spec.
628 if ((IdeDev
->Device
== IdeMaster
) && (MasterDeviceExist
)) {
629 if (MasterDeviceType
== ATA_DEVICE_TYPE
) {
630 Status
= ATAIdentify (IdeDev
);
631 if (EFI_ERROR (Status
)) {
632 Status
= ATAPIIdentify (IdeDev
);
633 if (!EFI_ERROR (Status
)) {
634 MasterDeviceType
= ATAPI_DEVICE_TYPE
;
638 Status
= ATAPIIdentify (IdeDev
);
639 if (EFI_ERROR (Status
)) {
640 Status
= ATAIdentify (IdeDev
);
641 if (!EFI_ERROR (Status
)) {
642 MasterDeviceType
= ATA_DEVICE_TYPE
;
647 if ((IdeDev
->Device
== IdeSlave
) && (SlaveDeviceExist
)) {
648 if (SlaveDeviceType
== ATA_DEVICE_TYPE
) {
649 Status
= ATAIdentify (IdeDev
);
650 if (EFI_ERROR (Status
)) {
651 Status
= ATAPIIdentify (IdeDev
);
652 if (!EFI_ERROR (Status
)) {
653 SlaveDeviceType
= ATAPI_DEVICE_TYPE
;
657 Status
= ATAPIIdentify (IdeDev
);
658 if (EFI_ERROR (Status
)) {
659 Status
= ATAIdentify (IdeDev
);
660 if (!EFI_ERROR (Status
)) {
661 SlaveDeviceType
= ATA_DEVICE_TYPE
;
666 if (EFI_ERROR (Status
)) {
667 return EFI_NOT_FOUND
;
670 // Init Block I/O interface
672 LongPhyStatus
= AtaEnableLongPhysicalSector (IdeDev
);
673 if (!EFI_ERROR (LongPhyStatus
)) {
674 IdeDev
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION2
;
676 IdeDev
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION
;
678 IdeDev
->BlkIo
.Reset
= IDEBlkIoReset
;
679 IdeDev
->BlkIo
.ReadBlocks
= IDEBlkIoReadBlocks
;
680 IdeDev
->BlkIo
.WriteBlocks
= IDEBlkIoWriteBlocks
;
681 IdeDev
->BlkIo
.FlushBlocks
= IDEBlkIoFlushBlocks
;
683 IdeDev
->BlkMedia
.LogicalPartition
= FALSE
;
684 IdeDev
->BlkMedia
.WriteCaching
= FALSE
;
687 // Init Disk Info interface
689 gBS
->CopyMem (&IdeDev
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
, sizeof (EFI_GUID
));
690 IdeDev
->DiskInfo
.Inquiry
= IDEDiskInfoInquiry
;
691 IdeDev
->DiskInfo
.Identify
= IDEDiskInfoIdentify
;
692 IdeDev
->DiskInfo
.SenseData
= IDEDiskInfoSenseData
;
693 IdeDev
->DiskInfo
.WhichIde
= IDEDiskInfoWhichIde
;
699 This interface is used to initialize all state data related to the detection of one
703 InitializeIDEChannelData (
707 ChannelDeviceDetected
= FALSE
;
708 MasterDeviceExist
= FALSE
;
709 MasterDeviceType
= 0xff;
710 SlaveDeviceExist
= FALSE
;
711 SlaveDeviceType
= 0xff;
714 This function is used to poll for the DRQ bit clear in the Status
715 Register. DRQ is cleared when the device is finished transferring data.
716 So this function is called after data transfer is finished.
718 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
719 to record all the information of the IDE device.
720 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ clear.
722 @retval EFI_SUCCESS DRQ bit clear within the time out.
724 @retval EFI_TIMEOUT DRQ bit not clear within the time out.
727 Read Status Register will clear interrupt status.
732 IN IDE_BLK_IO_DEV
*IdeDev
,
733 IN UINTN TimeoutInMilliSeconds
737 UINT8 StatusRegister
;
740 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
743 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
746 // wait for BSY == 0 and DRQ == 0
748 if ((StatusRegister
& (ATA_STSREG_DRQ
| ATA_STSREG_BSY
)) == 0) {
752 if ((StatusRegister
& (ATA_STSREG_BSY
| ATA_STSREG_ERR
)) == ATA_STSREG_ERR
) {
754 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
755 if ((ErrorRegister
& ATA_ERRREG_ABRT
) == ATA_ERRREG_ABRT
) {
776 This function is used to poll for the DRQ bit clear in the Alternate
777 Status Register. DRQ is cleared when the device is finished
778 transferring data. So this function is called after data transfer
781 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
782 to record all the information of the IDE device.
784 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ clear.
786 @retval EFI_SUCCESS DRQ bit clear within the time out.
788 @retval EFI_TIMEOUT DRQ bit not clear within the time out.
789 @note Read Alternate Status Register will not clear interrupt status.
794 IN IDE_BLK_IO_DEV
*IdeDev
,
795 IN UINTN TimeoutInMilliSeconds
802 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
805 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
808 // wait for BSY == 0 and DRQ == 0
810 if ((AltRegister
& (ATA_STSREG_DRQ
| ATA_STSREG_BSY
)) == 0) {
814 if ((AltRegister
& (ATA_STSREG_BSY
| ATA_STSREG_ERR
)) == ATA_STSREG_ERR
) {
816 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
817 if ((ErrorRegister
& ATA_ERRREG_ABRT
) == ATA_ERRREG_ABRT
) {
839 This function is used to poll for the DRQ bit set in the
841 DRQ is set when the device is ready to transfer data. So this function
842 is called after the command is sent to the device and before required
845 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure,used to
846 record all the information of the IDE device.
847 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
849 @retval EFI_SUCCESS DRQ bit set within the time out.
850 @retval EFI_TIMEOUT DRQ bit not set within the time out.
851 @retval EFI_ABORTED DRQ bit not set caused by the command abort.
853 @note Read Status Register will clear interrupt status.
858 IN IDE_BLK_IO_DEV
*IdeDev
,
859 IN UINTN TimeoutInMilliSeconds
863 UINT8 StatusRegister
;
866 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
869 // read Status Register will clear interrupt
871 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
876 if ((StatusRegister
& (ATA_STSREG_BSY
| ATA_STSREG_DRQ
)) == ATA_STSREG_DRQ
) {
880 if ((StatusRegister
& (ATA_STSREG_BSY
| ATA_STSREG_ERR
)) == ATA_STSREG_ERR
) {
882 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
883 if ((ErrorRegister
& ATA_ERRREG_ABRT
) == ATA_ERRREG_ABRT
) {
903 This function is used to poll for the DRQ bit set in the Alternate Status Register.
904 DRQ is set when the device is ready to transfer data. So this function is called after
905 the command is sent to the device and before required data is transferred.
907 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to
908 record all the information of the IDE device.
910 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
912 @retval EFI_SUCCESS DRQ bit set within the time out.
913 @retval EFI_TIMEOUT DRQ bit not set within the time out.
914 @retval EFI_ABORTED DRQ bit not set caused by the command abort.
915 @note Read Alternate Status Register will not clear interrupt status.
920 IN IDE_BLK_IO_DEV
*IdeDev
,
921 IN UINTN TimeoutInMilliSeconds
928 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
932 // Read Alternate Status Register will not clear interrupt status
934 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
936 // BSY == 0 , DRQ == 1
938 if ((AltRegister
& (ATA_STSREG_BSY
| ATA_STSREG_DRQ
)) == ATA_STSREG_DRQ
) {
942 if ((AltRegister
& (ATA_STSREG_BSY
| ATA_STSREG_ERR
)) == ATA_STSREG_ERR
) {
944 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
945 if ((ErrorRegister
& ATA_ERRREG_ABRT
) == ATA_ERRREG_ABRT
) {
966 This function is used to poll for the BSY bit clear in the Status Register. BSY
967 is clear when the device is not busy. Every command must be sent after device is not busy.
969 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
970 to record all the information of the IDE device.
971 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
973 @retval EFI_SUCCESS BSY bit clear within the time out.
974 @retval EFI_TIMEOUT BSY bit not clear within the time out.
976 @note Read Status Register will clear interrupt status.
980 IN IDE_BLK_IO_DEV
*IdeDev
,
981 IN UINTN TimeoutInMilliSeconds
985 UINT8 StatusRegister
;
987 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
990 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
991 if ((StatusRegister
& ATA_STSREG_BSY
) == 0x00) {
1002 } while (Delay
> 0);
1011 This function is used to poll for the BSY bit clear in the Alternate Status Register.
1012 BSY is clear when the device is not busy. Every command must be sent after device is
1015 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record
1016 all the information of the IDE device.
1017 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
1019 @retval EFI_SUCCESS BSY bit clear within the time out.
1020 @retval EFI_TIMEOUT BSY bit not clear within the time out.
1021 @note Read Alternate Status Register will not clear interrupt status.
1026 IN IDE_BLK_IO_DEV
*IdeDev
,
1027 IN UINTN TimeoutInMilliSeconds
1033 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1035 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
1036 if ((AltRegister
& ATA_STSREG_BSY
) == 0x00) {
1044 } while (Delay
> 0);
1053 This function is used to poll for the DRDY bit set in the Status Register. DRDY
1054 bit is set when the device is ready to accept command. Most ATA commands must be
1055 sent after DRDY set except the ATAPI Packet Command.
1057 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
1058 to record all the information of the IDE device.
1059 @param DelayInMilliSeconds used to designate the timeout for the DRQ ready.
1061 @retval EFI_SUCCESS DRDY bit set within the time out.
1062 @retval EFI_TIMEOUT DRDY bit not set within the time out.
1064 @note Read Status Register will clear interrupt status.
1068 IN IDE_BLK_IO_DEV
*IdeDev
,
1069 IN UINTN DelayInMilliSeconds
1073 UINT8 StatusRegister
;
1074 UINT8 ErrorRegister
;
1076 Delay
= (UINT32
) (((DelayInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1078 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1080 // BSY == 0 , DRDY == 1
1082 if ((StatusRegister
& (ATA_STSREG_DRDY
| ATA_STSREG_BSY
)) == ATA_STSREG_DRDY
) {
1086 if ((StatusRegister
& (ATA_STSREG_BSY
| ATA_STSREG_ERR
)) == ATA_STSREG_ERR
) {
1088 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
1089 if ((ErrorRegister
& ATA_ERRREG_ABRT
) == ATA_ERRREG_ABRT
) {
1097 } while (Delay
> 0);
1106 This function is used to poll for the DRDY bit set in the Alternate Status Register.
1107 DRDY bit is set when the device is ready to accept command. Most ATA commands must
1108 be sent after DRDY set except the ATAPI Packet Command.
1110 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
1111 to record all the information of the IDE device.
1112 @param DelayInMilliSeconds used to designate the timeout for the DRQ ready.
1114 @retval EFI_SUCCESS DRDY bit set within the time out.
1115 @retval EFI_TIMEOUT DRDY bit not set within the time out.
1117 @note Read Alternate Status Register will clear interrupt status.
1122 IN IDE_BLK_IO_DEV
*IdeDev
,
1123 IN UINTN DelayInMilliSeconds
1128 UINT8 ErrorRegister
;
1130 Delay
= (UINT32
) (((DelayInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1132 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
1134 // BSY == 0 , DRDY == 1
1136 if ((AltRegister
& (ATA_STSREG_DRDY
| ATA_STSREG_BSY
)) == ATA_STSREG_DRDY
) {
1140 if ((AltRegister
& (ATA_STSREG_BSY
| ATA_STSREG_ERR
)) == ATA_STSREG_ERR
) {
1142 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
1143 if ((ErrorRegister
& ATA_ERRREG_ABRT
) == ATA_ERRREG_ABRT
) {
1151 } while (Delay
> 0);
1160 Release resources of an IDE device before stopping it.
1162 @param IdeBlkIoDevice Standard IDE device private data structure
1166 ReleaseIdeResources (
1167 IN IDE_BLK_IO_DEV
*IdeBlkIoDevice
1170 if (IdeBlkIoDevice
== NULL
) {
1175 // Release all the resourses occupied by the IDE_BLK_IO_DEV
1178 if (IdeBlkIoDevice
->SenseData
!= NULL
) {
1179 gBS
->FreePool (IdeBlkIoDevice
->SenseData
);
1180 IdeBlkIoDevice
->SenseData
= NULL
;
1183 if (IdeBlkIoDevice
->Cache
!= NULL
) {
1184 gBS
->FreePool (IdeBlkIoDevice
->Cache
);
1185 IdeBlkIoDevice
->Cache
= NULL
;
1188 if (IdeBlkIoDevice
->IdData
!= NULL
) {
1189 gBS
->FreePool (IdeBlkIoDevice
->IdData
);
1190 IdeBlkIoDevice
->IdData
= NULL
;
1193 if (IdeBlkIoDevice
->InquiryData
!= NULL
) {
1194 gBS
->FreePool (IdeBlkIoDevice
->InquiryData
);
1195 IdeBlkIoDevice
->InquiryData
= NULL
;
1198 if (IdeBlkIoDevice
->ControllerNameTable
!= NULL
) {
1199 FreeUnicodeStringTable (IdeBlkIoDevice
->ControllerNameTable
);
1200 IdeBlkIoDevice
->ControllerNameTable
= NULL
;
1203 if (IdeBlkIoDevice
->IoPort
!= NULL
) {
1204 gBS
->FreePool (IdeBlkIoDevice
->IoPort
);
1207 if (IdeBlkIoDevice
->DevicePath
!= NULL
) {
1208 gBS
->FreePool (IdeBlkIoDevice
->DevicePath
);
1211 if (IdeBlkIoDevice
->ExitBootServiceEvent
!= NULL
) {
1212 gBS
->CloseEvent (IdeBlkIoDevice
->ExitBootServiceEvent
);
1213 IdeBlkIoDevice
->ExitBootServiceEvent
= NULL
;
1216 gBS
->FreePool (IdeBlkIoDevice
);
1217 IdeBlkIoDevice
= NULL
;
1222 Set the calculated Best transfer mode to a detected device.
1224 @param IdeDev Standard IDE device private data structure
1225 @param TransferMode The device transfer mode to be set
1226 @return Set transfer mode Command execute status.
1230 SetDeviceTransferMode (
1231 IN IDE_BLK_IO_DEV
*IdeDev
,
1232 IN ATA_TRANSFER_MODE
*TransferMode
1240 DeviceSelect
= (UINT8
) ((IdeDev
->Device
) << 4);
1241 SectorCount
= *((UINT8
*) TransferMode
);
1244 // Send SET FEATURE command (sub command 0x03) to set pio mode.
1246 Status
= AtaNonDataCommandIn (
1248 ATA_CMD_SET_FEATURES
,
1260 Set drive parameters for devices not support PACKETS command.
1262 @param IdeDev Standard IDE device private data structure
1263 @param DriveParameters The device parameters to be set into the disk
1264 @return SetParameters Command execute status.
1268 SetDriveParameters (
1269 IN IDE_BLK_IO_DEV
*IdeDev
,
1270 IN ATA_DRIVE_PARMS
*DriveParameters
1277 DeviceSelect
= (UINT8
) ((IdeDev
->Device
) << 4);
1280 // Send Init drive parameters
1282 Status
= AtaNonDataCommandIn (
1284 ATA_CMD_INIT_DRIVE_PARAM
,
1285 (UINT8
) (DeviceSelect
+ DriveParameters
->Heads
),
1287 DriveParameters
->Sector
,
1294 // Send Set Multiple parameters
1296 Status
= AtaNonDataCommandIn (
1298 ATA_CMD_SET_MULTIPLE_MODE
,
1301 DriveParameters
->MultipleSector
,
1310 Enable Interrupt on IDE controller.
1312 @param IdeDev Standard IDE device private data structure
1314 @retval EFI_SUCCESS Enable Interrupt successfully
1318 IN IDE_BLK_IO_DEV
*IdeDev
1321 UINT8 DeviceControl
;
1324 // Enable interrupt for DMA operation
1327 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.DeviceControl
, DeviceControl
);