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 SPDX-License-Identifier: BSD-2-Clause-Patent
11 BOOLEAN ChannelDeviceDetected
= FALSE
;
12 BOOLEAN SlaveDeviceExist
= FALSE
;
13 UINT8 SlaveDeviceType
= INVALID_DEVICE_TYPE
;
14 BOOLEAN MasterDeviceExist
= FALSE
;
15 UINT8 MasterDeviceType
= INVALID_DEVICE_TYPE
;
18 read a one-byte data from a IDE port.
20 @param PciIo The PCI IO protocol instance
21 @param Port the IDE Port number
23 @return the one-byte data read from IDE port
27 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
35 // perform 1-byte data read from register
40 EFI_PCI_IO_PASS_THROUGH_BAR
,
48 Reads multiple words of data from the IDE data port.
49 Call the IO abstraction once to do the complete read,
50 not one word at a time
52 @param PciIo Pointer to the EFI_PCI_IO instance
53 @param Port IO port to read
54 @param Count No. of UINT16's to read
55 @param Buffer Pointer to the data buffer for read
59 IDEReadPortWMultiple (
60 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
66 UINT16
*AlignedBuffer
;
67 UINT16
*WorkingBuffer
;
71 // Prepare an 16-bit alligned working buffer. CpuIo will return failure and
72 // not perform actual I/O operations if buffer pointer passed in is not at
73 // natural boundary. The "Buffer" argument is passed in by user and may not
74 // at 16-bit natural boundary.
76 Size
= sizeof (UINT16
) * Count
;
81 (VOID
**)&WorkingBuffer
84 AlignedBuffer
= (UINT16
*) ((UINTN
)(((UINTN
) WorkingBuffer
+ 0x1) & (~0x1)));
87 // Perform UINT16 data read from FIFO
91 EfiPciIoWidthFifoUint16
,
92 EFI_PCI_IO_PASS_THROUGH_BAR
,
95 (UINT16
*)AlignedBuffer
99 // Copy data to user buffer
101 CopyMem (Buffer
, (UINT16
*)AlignedBuffer
, Size
);
102 gBS
->FreePool (WorkingBuffer
);
106 write a 1-byte data to a specific IDE port.
108 @param PciIo PCI IO protocol instance
109 @param Port The IDE port to be writen
110 @param Data The data to write to the port
114 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
120 // perform 1-byte data write to register
125 EFI_PCI_IO_PASS_THROUGH_BAR
,
134 write a 1-word data to a specific IDE port.
136 @param PciIo PCI IO protocol instance
137 @param Port The IDE port to be writen
138 @param Data The data to write to the port
142 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
148 // perform 1-word data write to register
153 EFI_PCI_IO_PASS_THROUGH_BAR
,
161 Write multiple words of data to the IDE data port.
162 Call the IO abstraction once to do the complete read,
163 not one word at a time
165 @param PciIo Pointer to the EFI_PCI_IO instance
166 @param Port IO port to read
167 @param Count No. of UINT16's to read
168 @param Buffer Pointer to the data buffer for read
172 IDEWritePortWMultiple (
173 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
179 UINT16
*AlignedBuffer
;
180 UINT32
*WorkingBuffer
;
184 // Prepare an 16-bit alligned working buffer. CpuIo will return failure and
185 // not perform actual I/O operations if buffer pointer passed in is not at
186 // natural boundary. The "Buffer" argument is passed in by user and may not
187 // at 16-bit natural boundary.
189 Size
= sizeof (UINT16
) * Count
;
194 (VOID
**) &WorkingBuffer
197 AlignedBuffer
= (UINT16
*) ((UINTN
)(((UINTN
) WorkingBuffer
+ 0x1) & (~0x1)));
200 // Copy data from user buffer to working buffer
202 CopyMem ((UINT16
*) AlignedBuffer
, Buffer
, Size
);
205 // perform UINT16 data write to the FIFO
209 EfiPciIoWidthFifoUint16
,
210 EFI_PCI_IO_PASS_THROUGH_BAR
,
213 (UINT16
*) AlignedBuffer
216 gBS
->FreePool (WorkingBuffer
);
219 Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,
220 use fixed addresses. In Native-PCI mode, get base addresses from BARs in
221 the PCI IDE controller's Configuration Space.
223 The steps to get IDE IO port registers' base addresses for each channel
226 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE
227 controller's Configuration Space to determine the operating mode.
229 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.
231 ___________________________________________
232 | | Command Block | Control Block |
233 | Channel | Registers | Registers |
234 |___________|_______________|_______________|
235 | Primary | 1F0h - 1F7h | 3F6h - 3F7h |
236 |___________|_______________|_______________|
237 | Secondary | 170h - 177h | 376h - 377h |
238 |___________|_______________|_______________|
240 Table 1. Compatibility resource mappings
243 b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs
244 in IDE controller's PCI Configuration Space, shown in the Table 2 below.
246 ___________________________________________________
247 | | Command Block | Control Block |
248 | Channel | Registers | Registers |
249 |___________|___________________|___________________|
250 | Primary | BAR at offset 0x10| BAR at offset 0x14|
251 |___________|___________________|___________________|
252 | Secondary | BAR at offset 0x18| BAR at offset 0x1C|
253 |___________|___________________|___________________|
255 Table 2. BARs for Register Mapping
257 @note Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for
258 primary, 0374h for secondary. So 2 bytes extra offset should be
259 added to the base addresses read from BARs.
261 For more details, please refer to PCI IDE Controller Specification and Intel
264 @param PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance
265 @param IdeRegsBaseAddr Pointer to IDE_REGISTERS_BASE_ADDR to
266 receive IDE IO port registers' base addresses
268 @retval EFI_UNSUPPORTED return this value when the BARs is not IO type
269 @retval EFI_SUCCESS Get the Base address successfully
270 @retval other read the pci configureation data error
274 GetIdeRegistersBaseAddr (
275 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
276 OUT IDE_REGISTERS_BASE_ADDR
*IdeRegsBaseAddr
282 Status
= PciIo
->Pci
.Read (
290 if (EFI_ERROR (Status
)) {
294 if ((PciData
.Hdr
.ClassCode
[0] & IDE_PRIMARY_OPERATING_MODE
) == 0) {
295 IdeRegsBaseAddr
[IdePrimary
].CommandBlockBaseAddr
= 0x1f0;
296 IdeRegsBaseAddr
[IdePrimary
].ControlBlockBaseAddr
= 0x3f6;
297 IdeRegsBaseAddr
[IdePrimary
].BusMasterBaseAddr
=
298 (UINT16
)((PciData
.Device
.Bar
[4] & 0x0000fff0));
301 // The BARs should be of IO type
303 if ((PciData
.Device
.Bar
[0] & BIT0
) == 0 ||
304 (PciData
.Device
.Bar
[1] & BIT0
) == 0) {
305 return EFI_UNSUPPORTED
;
308 IdeRegsBaseAddr
[IdePrimary
].CommandBlockBaseAddr
=
309 (UINT16
) (PciData
.Device
.Bar
[0] & 0x0000fff8);
310 IdeRegsBaseAddr
[IdePrimary
].ControlBlockBaseAddr
=
311 (UINT16
) ((PciData
.Device
.Bar
[1] & 0x0000fffc) + 2);
312 IdeRegsBaseAddr
[IdePrimary
].BusMasterBaseAddr
=
313 (UINT16
) ((PciData
.Device
.Bar
[4] & 0x0000fff0));
316 if ((PciData
.Hdr
.ClassCode
[0] & IDE_SECONDARY_OPERATING_MODE
) == 0) {
317 IdeRegsBaseAddr
[IdeSecondary
].CommandBlockBaseAddr
= 0x170;
318 IdeRegsBaseAddr
[IdeSecondary
].ControlBlockBaseAddr
= 0x376;
319 IdeRegsBaseAddr
[IdeSecondary
].BusMasterBaseAddr
=
320 (UINT16
) ((PciData
.Device
.Bar
[4] & 0x0000fff0));
323 // The BARs should be of IO type
325 if ((PciData
.Device
.Bar
[2] & BIT0
) == 0 ||
326 (PciData
.Device
.Bar
[3] & BIT0
) == 0) {
327 return EFI_UNSUPPORTED
;
330 IdeRegsBaseAddr
[IdeSecondary
].CommandBlockBaseAddr
=
331 (UINT16
) (PciData
.Device
.Bar
[2] & 0x0000fff8);
332 IdeRegsBaseAddr
[IdeSecondary
].ControlBlockBaseAddr
=
333 (UINT16
) ((PciData
.Device
.Bar
[3] & 0x0000fffc) + 2);
334 IdeRegsBaseAddr
[IdeSecondary
].BusMasterBaseAddr
=
335 (UINT16
) ((PciData
.Device
.Bar
[4] & 0x0000fff0));
342 This function is used to requery IDE resources. The IDE controller will
343 probably switch between native and legacy modes during the EFI->CSM->OS
344 transfer. We do this everytime before an BlkIo operation to ensure its
347 @param IdeDev The BLK_IO private data which specifies the IDE device
349 @retval EFI_INVALID_PARAMETER return this value when the channel is invalid
350 @retval EFI_SUCCESS reassign the IDE IO resource successfully
351 @retval other get the IDE current base address effor
355 ReassignIdeResources (
356 IN IDE_BLK_IO_DEV
*IdeDev
360 IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr
[IdeMaxChannel
];
361 UINT16 CommandBlockBaseAddr
;
362 UINT16 ControlBlockBaseAddr
;
364 if (IdeDev
->Channel
>= IdeMaxChannel
) {
365 return EFI_INVALID_PARAMETER
;
369 // Requery IDE IO port registers' base addresses in case of the switch of
370 // native and legacy modes
372 Status
= GetIdeRegistersBaseAddr (IdeDev
->PciIo
, IdeRegsBaseAddr
);
373 if (EFI_ERROR (Status
)) {
377 ZeroMem (IdeDev
->IoPort
, sizeof (IDE_BASE_REGISTERS
));
378 CommandBlockBaseAddr
= IdeRegsBaseAddr
[IdeDev
->Channel
].CommandBlockBaseAddr
;
379 ControlBlockBaseAddr
= IdeRegsBaseAddr
[IdeDev
->Channel
].ControlBlockBaseAddr
;
381 IdeDev
->IoPort
->Data
= CommandBlockBaseAddr
;
382 (*(UINT16
*) &IdeDev
->IoPort
->Reg1
) = (UINT16
) (CommandBlockBaseAddr
+ 0x01);
383 IdeDev
->IoPort
->SectorCount
= (UINT16
) (CommandBlockBaseAddr
+ 0x02);
384 IdeDev
->IoPort
->SectorNumber
= (UINT16
) (CommandBlockBaseAddr
+ 0x03);
385 IdeDev
->IoPort
->CylinderLsb
= (UINT16
) (CommandBlockBaseAddr
+ 0x04);
386 IdeDev
->IoPort
->CylinderMsb
= (UINT16
) (CommandBlockBaseAddr
+ 0x05);
387 IdeDev
->IoPort
->Head
= (UINT16
) (CommandBlockBaseAddr
+ 0x06);
389 (*(UINT16
*) &IdeDev
->IoPort
->Reg
) = (UINT16
) (CommandBlockBaseAddr
+ 0x07);
390 (*(UINT16
*) &IdeDev
->IoPort
->Alt
) = ControlBlockBaseAddr
;
391 IdeDev
->IoPort
->DriveAddress
= (UINT16
) (ControlBlockBaseAddr
+ 0x01);
392 IdeDev
->IoPort
->MasterSlave
= (UINT16
) ((IdeDev
->Device
== IdeMaster
) ? 1 : 0);
394 IdeDev
->IoPort
->BusMasterBaseAddr
= IdeRegsBaseAddr
[IdeDev
->Channel
].BusMasterBaseAddr
;
399 This function is called by DiscoverIdeDevice(). It is used for detect
400 whether the IDE device exists in the specified Channel as the specified
403 There is two IDE channels: one is Primary Channel, the other is
404 Secondary Channel.(Channel is the logical name for the physical "Cable".)
405 Different channel has different register group.
407 On each IDE channel, at most two IDE devices attach,
408 one is called Device 0 (Master device), the other is called Device 1
409 (Slave device). The devices on the same channel co-use the same register
410 group, so before sending out a command for a specified device via command
411 register, it is a must to select the current device to accept the command
412 by set the device number in the Head/Device Register.
414 @param IdeDev pointer to IDE_BLK_IO_DEV data structure, used to record all the
415 information of the IDE device.
417 @retval EFI_SUCCESS successfully detects device.
419 @retval other any failure during detection process will return this value.
423 DetectIDEController (
424 IN IDE_BLK_IO_DEV
*IdeDev
428 UINT8 SectorCountReg
;
436 // Select slave device
440 IdeDev
->IoPort
->Head
,
441 (UINT8
) ((1 << 4) | 0xe0)
446 // Save the init slave status register
448 InitStatusReg
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
451 // Select Master back
455 IdeDev
->IoPort
->Head
,
456 (UINT8
) ((0 << 4) | 0xe0)
461 // Send ATA Device Execut Diagnostic command.
462 // This command should work no matter DRDY is ready or not
464 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Command
, 0x90);
466 Status
= WaitForBSYClear (IdeDev
, 3500);
467 if (EFI_ERROR (Status
)) {
468 DEBUG((EFI_D_ERROR
, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status
));
472 // Read device signature
479 IdeDev
->IoPort
->Head
,
480 (UINT8
) ((0 << 4) | 0xe0)
483 SectorCountReg
= IDEReadPortB (
485 IdeDev
->IoPort
->SectorCount
487 LBALowReg
= IDEReadPortB (
489 IdeDev
->IoPort
->SectorNumber
491 LBAMidReg
= IDEReadPortB (
493 IdeDev
->IoPort
->CylinderLsb
495 LBAHighReg
= IDEReadPortB (
497 IdeDev
->IoPort
->CylinderMsb
499 if ((SectorCountReg
== 0x1) &&
500 (LBALowReg
== 0x1) &&
501 (LBAMidReg
== 0x0) &&
502 (LBAHighReg
== 0x0)) {
503 MasterDeviceExist
= TRUE
;
504 MasterDeviceType
= ATA_DEVICE_TYPE
;
506 if ((LBAMidReg
== 0x14) &&
507 (LBAHighReg
== 0xeb)) {
508 MasterDeviceExist
= TRUE
;
509 MasterDeviceType
= ATAPI_DEVICE_TYPE
;
514 // For some Hard Drive, it takes some time to get
515 // the right signature when operating in single slave mode.
516 // We stall 20ms to work around this.
518 if (!MasterDeviceExist
) {
527 IdeDev
->IoPort
->Head
,
528 (UINT8
) ((1 << 4) | 0xe0)
531 SectorCountReg
= IDEReadPortB (
533 IdeDev
->IoPort
->SectorCount
535 LBALowReg
= IDEReadPortB (
537 IdeDev
->IoPort
->SectorNumber
539 LBAMidReg
= IDEReadPortB (
541 IdeDev
->IoPort
->CylinderLsb
543 LBAHighReg
= IDEReadPortB (
545 IdeDev
->IoPort
->CylinderMsb
547 StatusReg
= IDEReadPortB (
549 IdeDev
->IoPort
->Reg
.Status
551 if ((SectorCountReg
== 0x1) &&
552 (LBALowReg
== 0x1) &&
553 (LBAMidReg
== 0x0) &&
554 (LBAHighReg
== 0x0)) {
555 SlaveDeviceExist
= TRUE
;
556 SlaveDeviceType
= ATA_DEVICE_TYPE
;
558 if ((LBAMidReg
== 0x14) &&
559 (LBAHighReg
== 0xeb)) {
560 SlaveDeviceExist
= TRUE
;
561 SlaveDeviceType
= ATAPI_DEVICE_TYPE
;
566 // When single master is plugged, slave device
567 // will be wrongly detected. Here's the workaround
568 // for ATA devices by detecting DRY bit in status
570 // NOTE: This workaround doesn't apply to ATAPI.
572 if (MasterDeviceExist
&& SlaveDeviceExist
&&
573 (StatusReg
& ATA_STSREG_DRDY
) == 0 &&
574 (InitStatusReg
& ATA_STSREG_DRDY
) == 0 &&
575 MasterDeviceType
== SlaveDeviceType
&&
576 SlaveDeviceType
!= ATAPI_DEVICE_TYPE
) {
577 SlaveDeviceExist
= FALSE
;
581 // Indicate this channel has been detected
583 ChannelDeviceDetected
= TRUE
;
587 Detect if there is disk attached to this port
589 @param IdeDev The BLK_IO private data which specifies the IDE device.
591 @retval EFI_NOT_FOUND The device or channel is not found
592 @retval EFI_SUCCESS The device is found
597 IN IDE_BLK_IO_DEV
*IdeDev
601 EFI_STATUS LongPhyStatus
;
604 // If a channel has not been checked, check it now. Then set it to "checked" state
605 // After this step, all devices in this channel have been checked.
607 if (!ChannelDeviceDetected
) {
608 Status
= DetectIDEController (IdeDev
);
609 if (EFI_ERROR (Status
)) {
610 return EFI_NOT_FOUND
;
614 Status
= EFI_NOT_FOUND
;
617 // Device exists. test if it is an ATA device.
618 // Prefer the result from DetectIDEController,
619 // if failed, try another device type to handle
620 // devices that not follow the spec.
622 if ((IdeDev
->Device
== IdeMaster
) && (MasterDeviceExist
)) {
623 if (MasterDeviceType
== ATA_DEVICE_TYPE
) {
624 Status
= ATAIdentify (IdeDev
);
625 if (EFI_ERROR (Status
)) {
626 Status
= ATAPIIdentify (IdeDev
);
627 if (!EFI_ERROR (Status
)) {
628 MasterDeviceType
= ATAPI_DEVICE_TYPE
;
632 Status
= ATAPIIdentify (IdeDev
);
633 if (EFI_ERROR (Status
)) {
634 Status
= ATAIdentify (IdeDev
);
635 if (!EFI_ERROR (Status
)) {
636 MasterDeviceType
= ATA_DEVICE_TYPE
;
641 if ((IdeDev
->Device
== IdeSlave
) && (SlaveDeviceExist
)) {
642 if (SlaveDeviceType
== ATA_DEVICE_TYPE
) {
643 Status
= ATAIdentify (IdeDev
);
644 if (EFI_ERROR (Status
)) {
645 Status
= ATAPIIdentify (IdeDev
);
646 if (!EFI_ERROR (Status
)) {
647 SlaveDeviceType
= ATAPI_DEVICE_TYPE
;
651 Status
= ATAPIIdentify (IdeDev
);
652 if (EFI_ERROR (Status
)) {
653 Status
= ATAIdentify (IdeDev
);
654 if (!EFI_ERROR (Status
)) {
655 SlaveDeviceType
= ATA_DEVICE_TYPE
;
660 if (EFI_ERROR (Status
)) {
661 return EFI_NOT_FOUND
;
664 // Init Block I/O interface
666 LongPhyStatus
= AtaEnableLongPhysicalSector (IdeDev
);
667 if (!EFI_ERROR (LongPhyStatus
)) {
668 IdeDev
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION2
;
670 IdeDev
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION
;
672 IdeDev
->BlkIo
.Reset
= IDEBlkIoReset
;
673 IdeDev
->BlkIo
.ReadBlocks
= IDEBlkIoReadBlocks
;
674 IdeDev
->BlkIo
.WriteBlocks
= IDEBlkIoWriteBlocks
;
675 IdeDev
->BlkIo
.FlushBlocks
= IDEBlkIoFlushBlocks
;
677 IdeDev
->BlkMedia
.LogicalPartition
= FALSE
;
678 IdeDev
->BlkMedia
.WriteCaching
= FALSE
;
681 // Init Disk Info interface
683 gBS
->CopyMem (&IdeDev
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
, sizeof (EFI_GUID
));
684 IdeDev
->DiskInfo
.Inquiry
= IDEDiskInfoInquiry
;
685 IdeDev
->DiskInfo
.Identify
= IDEDiskInfoIdentify
;
686 IdeDev
->DiskInfo
.SenseData
= IDEDiskInfoSenseData
;
687 IdeDev
->DiskInfo
.WhichIde
= IDEDiskInfoWhichIde
;
693 This interface is used to initialize all state data related to the detection of one
697 InitializeIDEChannelData (
701 ChannelDeviceDetected
= FALSE
;
702 MasterDeviceExist
= FALSE
;
703 MasterDeviceType
= 0xff;
704 SlaveDeviceExist
= FALSE
;
705 SlaveDeviceType
= 0xff;
708 This function is used to poll for the DRQ bit clear in the Status
709 Register. DRQ is cleared when the device is finished transferring data.
710 So this function is called after data transfer is finished.
712 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
713 to record all the information of the IDE device.
714 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ clear.
716 @retval EFI_SUCCESS DRQ bit clear within the time out.
718 @retval EFI_TIMEOUT DRQ bit not clear within the time out.
721 Read Status Register will clear interrupt status.
726 IN IDE_BLK_IO_DEV
*IdeDev
,
727 IN UINTN TimeoutInMilliSeconds
731 UINT8 StatusRegister
;
734 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
737 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
740 // wait for BSY == 0 and DRQ == 0
742 if ((StatusRegister
& (ATA_STSREG_DRQ
| ATA_STSREG_BSY
)) == 0) {
746 if ((StatusRegister
& (ATA_STSREG_BSY
| ATA_STSREG_ERR
)) == ATA_STSREG_ERR
) {
748 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
749 if ((ErrorRegister
& ATA_ERRREG_ABRT
) == ATA_ERRREG_ABRT
) {
770 This function is used to poll for the DRQ bit clear in the Alternate
771 Status Register. DRQ is cleared when the device is finished
772 transferring data. So this function is called after data transfer
775 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
776 to record all the information of the IDE device.
778 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ clear.
780 @retval EFI_SUCCESS DRQ bit clear within the time out.
782 @retval EFI_TIMEOUT DRQ bit not clear within the time out.
783 @note Read Alternate Status Register will not clear interrupt status.
788 IN IDE_BLK_IO_DEV
*IdeDev
,
789 IN UINTN TimeoutInMilliSeconds
796 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
799 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
802 // wait for BSY == 0 and DRQ == 0
804 if ((AltRegister
& (ATA_STSREG_DRQ
| ATA_STSREG_BSY
)) == 0) {
808 if ((AltRegister
& (ATA_STSREG_BSY
| ATA_STSREG_ERR
)) == ATA_STSREG_ERR
) {
810 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
811 if ((ErrorRegister
& ATA_ERRREG_ABRT
) == ATA_ERRREG_ABRT
) {
833 This function is used to poll for the DRQ bit set in the
835 DRQ is set when the device is ready to transfer data. So this function
836 is called after the command is sent to the device and before required
839 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure,used to
840 record all the information of the IDE device.
841 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
843 @retval EFI_SUCCESS DRQ bit set within the time out.
844 @retval EFI_TIMEOUT DRQ bit not set within the time out.
845 @retval EFI_ABORTED DRQ bit not set caused by the command abort.
847 @note Read Status Register will clear interrupt status.
852 IN IDE_BLK_IO_DEV
*IdeDev
,
853 IN UINTN TimeoutInMilliSeconds
857 UINT8 StatusRegister
;
860 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
863 // read Status Register will clear interrupt
865 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
870 if ((StatusRegister
& (ATA_STSREG_BSY
| ATA_STSREG_DRQ
)) == ATA_STSREG_DRQ
) {
874 if ((StatusRegister
& (ATA_STSREG_BSY
| ATA_STSREG_ERR
)) == ATA_STSREG_ERR
) {
876 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
877 if ((ErrorRegister
& ATA_ERRREG_ABRT
) == ATA_ERRREG_ABRT
) {
897 This function is used to poll for the DRQ bit set in the Alternate Status Register.
898 DRQ is set when the device is ready to transfer data. So this function is called after
899 the command is sent to the device and before required data is transferred.
901 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to
902 record all the information of the IDE device.
904 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
906 @retval EFI_SUCCESS DRQ bit set within the time out.
907 @retval EFI_TIMEOUT DRQ bit not set within the time out.
908 @retval EFI_ABORTED DRQ bit not set caused by the command abort.
909 @note Read Alternate Status Register will not clear interrupt status.
914 IN IDE_BLK_IO_DEV
*IdeDev
,
915 IN UINTN TimeoutInMilliSeconds
922 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
926 // Read Alternate Status Register will not clear interrupt status
928 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
930 // BSY == 0 , DRQ == 1
932 if ((AltRegister
& (ATA_STSREG_BSY
| ATA_STSREG_DRQ
)) == ATA_STSREG_DRQ
) {
936 if ((AltRegister
& (ATA_STSREG_BSY
| ATA_STSREG_ERR
)) == ATA_STSREG_ERR
) {
938 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
939 if ((ErrorRegister
& ATA_ERRREG_ABRT
) == ATA_ERRREG_ABRT
) {
960 This function is used to poll for the BSY bit clear in the Status Register. BSY
961 is clear when the device is not busy. Every command must be sent after device is not busy.
963 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
964 to record all the information of the IDE device.
965 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
967 @retval EFI_SUCCESS BSY bit clear within the time out.
968 @retval EFI_TIMEOUT BSY bit not clear within the time out.
970 @note Read Status Register will clear interrupt status.
974 IN IDE_BLK_IO_DEV
*IdeDev
,
975 IN UINTN TimeoutInMilliSeconds
979 UINT8 StatusRegister
;
981 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
984 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
985 if ((StatusRegister
& ATA_STSREG_BSY
) == 0x00) {
1005 This function is used to poll for the BSY bit clear in the Alternate Status Register.
1006 BSY is clear when the device is not busy. Every command must be sent after device is
1009 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record
1010 all the information of the IDE device.
1011 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
1013 @retval EFI_SUCCESS BSY bit clear within the time out.
1014 @retval EFI_TIMEOUT BSY bit not clear within the time out.
1015 @note Read Alternate Status Register will not clear interrupt status.
1020 IN IDE_BLK_IO_DEV
*IdeDev
,
1021 IN UINTN TimeoutInMilliSeconds
1027 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1029 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
1030 if ((AltRegister
& ATA_STSREG_BSY
) == 0x00) {
1038 } while (Delay
> 0);
1047 This function is used to poll for the DRDY bit set in the Status Register. DRDY
1048 bit is set when the device is ready to accept command. Most ATA commands must be
1049 sent after DRDY set except the ATAPI Packet Command.
1051 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
1052 to record all the information of the IDE device.
1053 @param DelayInMilliSeconds used to designate the timeout for the DRQ ready.
1055 @retval EFI_SUCCESS DRDY bit set within the time out.
1056 @retval EFI_TIMEOUT DRDY bit not set within the time out.
1058 @note Read Status Register will clear interrupt status.
1062 IN IDE_BLK_IO_DEV
*IdeDev
,
1063 IN UINTN DelayInMilliSeconds
1067 UINT8 StatusRegister
;
1068 UINT8 ErrorRegister
;
1070 Delay
= (UINT32
) (((DelayInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1072 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1074 // BSY == 0 , DRDY == 1
1076 if ((StatusRegister
& (ATA_STSREG_DRDY
| ATA_STSREG_BSY
)) == ATA_STSREG_DRDY
) {
1080 if ((StatusRegister
& (ATA_STSREG_BSY
| ATA_STSREG_ERR
)) == ATA_STSREG_ERR
) {
1082 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
1083 if ((ErrorRegister
& ATA_ERRREG_ABRT
) == ATA_ERRREG_ABRT
) {
1091 } while (Delay
> 0);
1100 This function is used to poll for the DRDY bit set in the Alternate Status Register.
1101 DRDY bit is set when the device is ready to accept command. Most ATA commands must
1102 be sent after DRDY set except the ATAPI Packet Command.
1104 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
1105 to record all the information of the IDE device.
1106 @param DelayInMilliSeconds used to designate the timeout for the DRQ ready.
1108 @retval EFI_SUCCESS DRDY bit set within the time out.
1109 @retval EFI_TIMEOUT DRDY bit not set within the time out.
1111 @note Read Alternate Status Register will clear interrupt status.
1116 IN IDE_BLK_IO_DEV
*IdeDev
,
1117 IN UINTN DelayInMilliSeconds
1122 UINT8 ErrorRegister
;
1124 Delay
= (UINT32
) (((DelayInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1126 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
1128 // BSY == 0 , DRDY == 1
1130 if ((AltRegister
& (ATA_STSREG_DRDY
| ATA_STSREG_BSY
)) == ATA_STSREG_DRDY
) {
1134 if ((AltRegister
& (ATA_STSREG_BSY
| ATA_STSREG_ERR
)) == ATA_STSREG_ERR
) {
1136 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
1137 if ((ErrorRegister
& ATA_ERRREG_ABRT
) == ATA_ERRREG_ABRT
) {
1145 } while (Delay
> 0);
1154 Release resources of an IDE device before stopping it.
1156 @param IdeBlkIoDevice Standard IDE device private data structure
1160 ReleaseIdeResources (
1161 IN IDE_BLK_IO_DEV
*IdeBlkIoDevice
1164 if (IdeBlkIoDevice
== NULL
) {
1169 // Release all the resourses occupied by the IDE_BLK_IO_DEV
1172 if (IdeBlkIoDevice
->SenseData
!= NULL
) {
1173 gBS
->FreePool (IdeBlkIoDevice
->SenseData
);
1174 IdeBlkIoDevice
->SenseData
= NULL
;
1177 if (IdeBlkIoDevice
->Cache
!= NULL
) {
1178 gBS
->FreePool (IdeBlkIoDevice
->Cache
);
1179 IdeBlkIoDevice
->Cache
= NULL
;
1182 if (IdeBlkIoDevice
->IdData
!= NULL
) {
1183 gBS
->FreePool (IdeBlkIoDevice
->IdData
);
1184 IdeBlkIoDevice
->IdData
= NULL
;
1187 if (IdeBlkIoDevice
->InquiryData
!= NULL
) {
1188 gBS
->FreePool (IdeBlkIoDevice
->InquiryData
);
1189 IdeBlkIoDevice
->InquiryData
= NULL
;
1192 if (IdeBlkIoDevice
->ControllerNameTable
!= NULL
) {
1193 FreeUnicodeStringTable (IdeBlkIoDevice
->ControllerNameTable
);
1194 IdeBlkIoDevice
->ControllerNameTable
= NULL
;
1197 if (IdeBlkIoDevice
->IoPort
!= NULL
) {
1198 gBS
->FreePool (IdeBlkIoDevice
->IoPort
);
1201 if (IdeBlkIoDevice
->DevicePath
!= NULL
) {
1202 gBS
->FreePool (IdeBlkIoDevice
->DevicePath
);
1205 if (IdeBlkIoDevice
->ExitBootServiceEvent
!= NULL
) {
1206 gBS
->CloseEvent (IdeBlkIoDevice
->ExitBootServiceEvent
);
1207 IdeBlkIoDevice
->ExitBootServiceEvent
= NULL
;
1210 gBS
->FreePool (IdeBlkIoDevice
);
1211 IdeBlkIoDevice
= NULL
;
1216 Set the calculated Best transfer mode to a detected device.
1218 @param IdeDev Standard IDE device private data structure
1219 @param TransferMode The device transfer mode to be set
1220 @return Set transfer mode Command execute status.
1224 SetDeviceTransferMode (
1225 IN IDE_BLK_IO_DEV
*IdeDev
,
1226 IN ATA_TRANSFER_MODE
*TransferMode
1234 DeviceSelect
= (UINT8
) ((IdeDev
->Device
) << 4);
1235 SectorCount
= *((UINT8
*) TransferMode
);
1238 // Send SET FEATURE command (sub command 0x03) to set pio mode.
1240 Status
= AtaNonDataCommandIn (
1242 ATA_CMD_SET_FEATURES
,
1254 Set drive parameters for devices not support PACKETS command.
1256 @param IdeDev Standard IDE device private data structure
1257 @param DriveParameters The device parameters to be set into the disk
1258 @return SetParameters Command execute status.
1262 SetDriveParameters (
1263 IN IDE_BLK_IO_DEV
*IdeDev
,
1264 IN ATA_DRIVE_PARMS
*DriveParameters
1271 DeviceSelect
= (UINT8
) ((IdeDev
->Device
) << 4);
1274 // Send Init drive parameters
1276 Status
= AtaNonDataCommandIn (
1278 ATA_CMD_INIT_DRIVE_PARAM
,
1279 (UINT8
) (DeviceSelect
+ DriveParameters
->Heads
),
1281 DriveParameters
->Sector
,
1288 // Send Set Multiple parameters
1290 Status
= AtaNonDataCommandIn (
1292 ATA_CMD_SET_MULTIPLE_MODE
,
1295 DriveParameters
->MultipleSector
,
1304 Enable Interrupt on IDE controller.
1306 @param IdeDev Standard IDE device private data structure
1308 @retval EFI_SUCCESS Enable Interrupt successfully
1312 IN IDE_BLK_IO_DEV
*IdeDev
1315 UINT8 DeviceControl
;
1318 // Enable interrupt for DMA operation
1321 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.DeviceControl
, DeviceControl
);