From 10fbfd85b9b3115965cfee9ab1805599f2fc6956 Mon Sep 17 00:00:00 2001 From: vanjeff Date: Wed, 2 Jul 2008 03:19:13 +0000 Subject: rename to meet naming rules git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@5397 6f19259b-4bc3-4df7-8a09-765794883524 --- IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Atapi.c | 2140 +++++++++++++++++++++ IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/atapi.c | 2140 --------------------- 2 files changed, 2140 insertions(+), 2140 deletions(-) create mode 100644 IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Atapi.c delete mode 100644 IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/atapi.c diff --git a/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Atapi.c b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Atapi.c new file mode 100644 index 0000000..210d9dd --- /dev/null +++ b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Atapi.c @@ -0,0 +1,2140 @@ +/** @file + Copyright (c) 2006 - 2007, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "idebus.h" + +/** + This function is used to get the current status of the media residing + in the LS-120 drive or ZIP drive. The media status is returned in the + Error Status. + + @param[in] *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + @retval EFI_SUCCESS + The media status is achieved successfully and the media + can be read/written. + + @retval EFI_DEVICE_ERROR + Get Media Status Command is failed. + + @retval EFI_NO_MEDIA + There is no media in the drive. + + @retval EFI_WRITE_PROTECTED + The media is writing protected. + + @note + This function must be called after the LS120EnableMediaStatus() + with second parameter set to TRUE + (means enable media status notification) is called. + +**/ +STATIC +EFI_STATUS +LS120GetMediaStatus ( + IN IDE_BLK_IO_DEV *IdeDev + ) +{ + UINT8 DeviceSelect; + UINT8 StatusValue; + EFI_STATUS EfiStatus; + // + // Poll Alternate Register for BSY clear within timeout. + // + EfiStatus = WaitForBSYClear2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (EfiStatus)) { + return EFI_DEVICE_ERROR; + } + + // + // Select device via Device/Head Register. + // + DeviceSelect = (UINT8) ((IdeDev->Device) << 4 | 0xe0); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect); + + // + // Poll Alternate Register for DRDY set within timeout. + // After device is selected, DRDY set indicates the device is ready to + // accept command. + // + EfiStatus = DRDYReady2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (EfiStatus)) { + return EFI_DEVICE_ERROR; + } + + // + // Get Media Status Command is sent + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0xDA); + + // + // BSY bit will clear after command is complete. + // + EfiStatus = WaitForBSYClear2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (EfiStatus)) { + return EFI_DEVICE_ERROR; + } + + // + // the media status is returned by the command in the ERROR register + // + StatusValue = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); + + if (StatusValue & BIT1) { + return EFI_NO_MEDIA; + } + + if (StatusValue & BIT6) { + return EFI_WRITE_PROTECTED; + } else { + return EFI_SUCCESS; + } +} + +/** + This function is used to send Enable Media Status Notification Command + or Disable Media Status Notification Command. + + @param[in] *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + @param[in] Enable + a flag that indicates whether enable or disable media + status notification. + + @retval EFI_SUCCESS + If command completes successfully. + + @retval EFI_DEVICE_ERROR + If command failed. + +**/ +STATIC +EFI_STATUS +LS120EnableMediaStatus ( + IN IDE_BLK_IO_DEV *IdeDev, + IN BOOLEAN Enable + ) +{ + UINT8 DeviceSelect; + EFI_STATUS Status; + + // + // Poll Alternate Register for BSY clear within timeout. + // + Status = WaitForBSYClear2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Select device via Device/Head Register. + // + DeviceSelect = (UINT8) ((IdeDev->Device) << 4 | 0xe0); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect); + + // + // Poll Alternate Register for DRDY set within timeout. + // After device is selected, DRDY set indicates the device is ready to + // accept command. + // + Status = DRDYReady2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + if (Enable) { + // + // 0x95: Enable media status notification + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x95); + } else { + // + // 0x31: Disable media status notification + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x31); + } + // + // Set Feature Command is sent + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0xEF); + + // + // BSY bit will clear after command is complete. + // + Status = WaitForBSYClear (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + This function is called by DiscoverIdeDevice() during its device + identification. + + Its main purpose is to get enough information for the device media + to fill in the Media data structure of the Block I/O Protocol interface. + + There are 5 steps to reach such objective: + + 1. Sends out the ATAPI Identify Command to the specified device. + Only ATAPI device responses to this command. If the command succeeds, + it returns the Identify data structure which filled with information + about the device. Since the ATAPI device contains removable media, + the only meaningful information is the device module name. + + 2. Sends out ATAPI Inquiry Packet Command to the specified device. + This command will return inquiry data of the device, which contains + the device type information. + + 3. Allocate sense data space for future use. We don't detect the media + presence here to improvement boot performance, especially when CD + media is present. The media detection will be performed just before + each BLK_IO read/write + + @param[in] *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + @retval EFI_SUCCESS + Identify ATAPI device successfully. + + @retval EFI_DEVICE_ERROR + ATAPI Identify Device Command failed or device type + is not supported by this IDE driver. + + @note + Parameter "IdeDev" will be updated in this function. + + TODO: EFI_OUT_OF_RESOURCES - add return value to function comment + TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +**/ +EFI_STATUS +ATAPIIdentify ( + IN IDE_BLK_IO_DEV *IdeDev + ) +{ + EFI_IDENTIFY_DATA *AtapiIdentifyPointer; + UINT8 DeviceSelect; + EFI_STATUS Status; + + // + // device select bit + // + DeviceSelect = (UINT8) ((IdeDev->Device) << 4); + + AtapiIdentifyPointer = AllocatePool (sizeof (EFI_IDENTIFY_DATA)); + if (AtapiIdentifyPointer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Send ATAPI Identify Command to get IDENTIFY data. + // + Status = AtaPioDataIn ( + IdeDev, + (VOID *) AtapiIdentifyPointer, + sizeof (EFI_IDENTIFY_DATA), + ATA_CMD_IDENTIFY_DEVICE, + DeviceSelect, + 0, + 0, + 0, + 0 + ); + + if (EFI_ERROR (Status)) { + gBS->FreePool (AtapiIdentifyPointer); + return EFI_DEVICE_ERROR; + } + + IdeDev->pIdData = AtapiIdentifyPointer; + PrintAtaModuleName (IdeDev); + + // + // Send ATAPI Inquiry Packet Command to get INQUIRY data. + // + Status = AtapiInquiry (IdeDev); + if (EFI_ERROR (Status)) { + gBS->FreePool (IdeDev->pIdData); + // + // Make sure the pIdData will not be freed again. + // + IdeDev->pIdData = NULL; + return EFI_DEVICE_ERROR; + } + // + // Get media removable info from INQUIRY data. + // + IdeDev->BlkIo.Media->RemovableMedia = (UINT8) ((IdeDev->pInquiryData->RMB & 0x80) == 0x80); + + // + // Identify device type via INQUIRY data. + // + switch (IdeDev->pInquiryData->peripheral_type & 0x1f) { + + // + // Magnetic Disk + // + case 0x00: + + // + // device is LS120 or ZIP drive. + // + IdeDev->Type = IdeMagnetic; + + IdeDev->BlkIo.Media->MediaId = 0; + // + // Give initial value + // + IdeDev->BlkIo.Media->MediaPresent = FALSE; + + IdeDev->BlkIo.Media->LastBlock = 0; + IdeDev->BlkIo.Media->BlockSize = 0x200; + break; + + // + // CD-ROM + // + case 0x05: + + IdeDev->Type = IdeCdRom; + IdeDev->BlkIo.Media->MediaId = 0; + // + // Give initial value + // + IdeDev->BlkIo.Media->MediaPresent = FALSE; + + IdeDev->BlkIo.Media->LastBlock = 0; + IdeDev->BlkIo.Media->BlockSize = 0x800; + IdeDev->BlkIo.Media->ReadOnly = TRUE; + break; + + // + // Tape + // + case 0x01: + + // + // WORM + // + case 0x04: + + // + // Optical + // + case 0x07: + + default: + IdeDev->Type = IdeUnknown; + gBS->FreePool (IdeDev->pIdData); + gBS->FreePool (IdeDev->pInquiryData); + // + // Make sure the pIdData and pInquiryData will not be freed again. + // + IdeDev->pIdData = NULL; + IdeDev->pInquiryData = NULL; + return EFI_DEVICE_ERROR; + } + + // + // original sense data numbers + // + IdeDev->SenseDataNumber = 20; + + IdeDev->SenseData = AllocatePool (IdeDev->SenseDataNumber * sizeof (ATAPI_REQUEST_SENSE_DATA)); + if (IdeDev->SenseData == NULL) { + gBS->FreePool (IdeDev->pIdData); + gBS->FreePool (IdeDev->pInquiryData); + // + // Make sure the pIdData and pInquiryData will not be freed again. + // + IdeDev->pIdData = NULL; + IdeDev->pInquiryData = NULL; + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +/** + Sends out ATAPI Inquiry Packet Command to the specified device. + This command will return INQUIRY data of the device. + + @param[in] *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + @retval EFI_SUCCESS + Inquiry command completes successfully. + + @retval EFI_DEVICE_ERROR + Inquiry command failed. + + @note + Parameter "IdeDev" will be updated in this function. + +**/ +EFI_STATUS +AtapiInquiry ( + IN IDE_BLK_IO_DEV *IdeDev + ) +{ + ATAPI_PACKET_COMMAND Packet; + EFI_STATUS Status; + ATAPI_INQUIRY_DATA *InquiryData; + + // + // prepare command packet for the ATAPI Inquiry Packet Command. + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.Inquiry.opcode = ATA_CMD_INQUIRY; + Packet.Inquiry.page_code = 0; + Packet.Inquiry.allocation_length = sizeof (ATAPI_INQUIRY_DATA); + + InquiryData = AllocatePool (sizeof (ATAPI_INQUIRY_DATA)); + if (InquiryData == NULL) { + return EFI_DEVICE_ERROR; + } + + // + // Send command packet and get requested Inquiry data. + // + Status = AtapiPacketCommandIn ( + IdeDev, + &Packet, + (UINT16 *) InquiryData, + sizeof (ATAPI_INQUIRY_DATA), + ATAPITIMEOUT + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (InquiryData); + return EFI_DEVICE_ERROR; + } + + IdeDev->pInquiryData = InquiryData; + + return EFI_SUCCESS; +} + +/** + This function is used to send out ATAPI commands conforms to the + Packet Command with PIO Data In Protocol. + + @param[in] *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + @param[in] *Packet + pointer pointing to ATAPI_PACKET_COMMAND data structure + which contains the contents of the command. + + @param[in] *Buffer + buffer contained data transferred from device to host. + + @param[in] ByteCount + data size in byte unit of the buffer. + + @param[in] TimeOut + this parameter is used to specify the timeout + value for the PioReadWriteData() function. + + @retval EFI_SUCCESS + send out the ATAPI packet command successfully + and device sends data successfully. + + @retval EFI_DEVICE_ERROR + the device failed to send data. + +**/ +EFI_STATUS +AtapiPacketCommandIn ( + IN IDE_BLK_IO_DEV *IdeDev, + IN ATAPI_PACKET_COMMAND *Packet, + IN UINT16 *Buffer, + IN UINT32 ByteCount, + IN UINTN TimeOut + ) +{ + UINT16 *CommandIndex; + EFI_STATUS Status; + UINT32 Count; + + // + // Set all the command parameters by fill related registers. + // Before write to all the following registers, BSY and DRQ must be 0. + // + Status = DRQClear2 (IdeDev, ATAPITIMEOUT); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Select device via Device/Head Register. + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((IdeDev->Device << 4) | ATA_DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000) + ); + + // + // No OVL; No DMA + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00); + + // + // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device + // determine how many data should be transferred. + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->CylinderLsb, + (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff) + ); + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->CylinderMsb, + (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8) + ); + + // + // ATA_DEFAULT_CTL:0x0a (0000,1010) + // Disable interrupt + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, ATA_DEFAULT_CTL); + + // + // Send Packet command to inform device + // that the following data bytes are command packet. + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, ATA_CMD_PACKET); + + Status = DRQReady (IdeDev, ATAPITIMEOUT); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Send out command packet + // + CommandIndex = Packet->Data16; + for (Count = 0; Count < 6; Count++, CommandIndex++) { + + IDEWritePortW (IdeDev->PciIo, IdeDev->IoPort->Data, *CommandIndex); + gBS->Stall (10); + } + + // + // call PioReadWriteData() function to get + // requested transfer data form device. + // + return PioReadWriteData (IdeDev, Buffer, ByteCount, 1, TimeOut); +} + +/** + This function is used to send out ATAPI commands conforms to the + Packet Command with PIO Data Out Protocol. + + @param[in] *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + @param[in] *Packet + pointer pointing to ATAPI_PACKET_COMMAND data structure + which contains the contents of the command. + + @param[in] *Buffer + buffer contained data transferred from host to device. + + @param[in] ByteCount + data size in byte unit of the buffer. + + @param[in] TimeOut + this parameter is used to specify the timeout + value for the PioReadWriteData() function. + + @retval EFI_SUCCESS + send out the ATAPI packet command successfully + and device received data successfully. + + @retval EFI_DEVICE_ERROR + the device failed to send data. + +**/ +EFI_STATUS +AtapiPacketCommandOut ( + IN IDE_BLK_IO_DEV *IdeDev, + IN ATAPI_PACKET_COMMAND *Packet, + IN UINT16 *Buffer, + IN UINT32 ByteCount, + IN UINTN TimeOut + ) +{ + UINT16 *CommandIndex; + EFI_STATUS Status; + UINT32 Count; + + // + // set all the command parameters + // Before write to all the following registers, BSY and DRQ must be 0. + // + Status = DRQClear2 (IdeDev, ATAPITIMEOUT); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Select device via Device/Head Register. + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((IdeDev->Device << 4) | ATA_DEFAULT_CMD) // ATA_DEFAULT_CMD: 0xa0 (1010,0000) + ); + + // + // No OVL; No DMA + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00); + + // + // set the transfersize to ATAPI_MAX_BYTE_COUNT to + // let the device determine how many data should be transferred. + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->CylinderLsb, + (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff) + ); + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->CylinderMsb, + (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8) + ); + + // + // DEFAULT_CTL:0x0a (0000,1010) + // Disable interrupt + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, ATA_DEFAULT_CTL); + + // + // Send Packet command to inform device + // that the following data bytes are command packet. + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, ATA_CMD_PACKET); + + Status = DRQReady2 (IdeDev, ATAPITIMEOUT); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Send out command packet + // + CommandIndex = Packet->Data16; + for (Count = 0; Count < 6; Count++, CommandIndex++) { + IDEWritePortW (IdeDev->PciIo, IdeDev->IoPort->Data, *CommandIndex); + gBS->Stall (10); + } + + // + // call PioReadWriteData() function to send requested transfer data to device. + // + return PioReadWriteData (IdeDev, Buffer, ByteCount, 0, TimeOut); +} + +/** + This function is called by either AtapiPacketCommandIn() or + AtapiPacketCommandOut(). It is used to transfer data between + host and device. The data direction is specified by the fourth + parameter. + + @param[in] *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + @param[in] *Buffer + buffer contained data transferred between host and device. + + @param[in] ByteCount + data size in byte unit of the buffer. + + @param[in] Read + flag used to determine the data transfer direction. + Read equals 1, means data transferred from device to host; + Read equals 0, means data transferred from host to device. + + @param[in] TimeOut + timeout value for wait DRQ ready before each data + stream's transfer. + + @retval EFI_SUCCESS + data is transferred successfully. + + @retval EFI_DEVICE_ERROR + the device failed to transfer data. + +**/ +EFI_STATUS +PioReadWriteData ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINT16 *Buffer, + IN UINT32 ByteCount, + IN BOOLEAN Read, + IN UINTN TimeOut + ) +{ + // + // required transfer data in word unit. + // + UINT32 RequiredWordCount; + + // + // actual transfer data in word unit. + // + UINT32 ActualWordCount; + UINT32 WordCount; + EFI_STATUS Status; + UINT16 *PtrBuffer; + + // + // No data transfer is premitted. + // + if (ByteCount == 0) { + return EFI_SUCCESS; + } + // + // for performance, we assert the ByteCount is an even number + // which is actually a resonable assumption + ASSERT((ByteCount%2) == 0); + + PtrBuffer = Buffer; + RequiredWordCount = ByteCount / 2; + // + // ActuralWordCount means the word count of data really transferred. + // + ActualWordCount = 0; + + while (ActualWordCount < RequiredWordCount) { + + // + // before each data transfer stream, the host should poll DRQ bit ready, + // to see whether indicates device is ready to transfer data. + // + Status = DRQReady2 (IdeDev, TimeOut); + if (EFI_ERROR (Status)) { + return CheckErrorStatus (IdeDev); + } + + // + // read Status Register will clear interrupt + // + IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status); + + // + // get current data transfer size from Cylinder Registers. + // + WordCount = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb) << 8; + WordCount = WordCount | IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb); + WordCount = WordCount & 0xffff; + WordCount /= 2; + + WordCount = MIN (WordCount, (RequiredWordCount - ActualWordCount)); + + if (Read) { + IDEReadPortWMultiple ( + IdeDev->PciIo, + IdeDev->IoPort->Data, + WordCount, + PtrBuffer + ); + } else { + IDEWritePortWMultiple ( + IdeDev->PciIo, + IdeDev->IoPort->Data, + WordCount, + PtrBuffer + ); + } + + PtrBuffer += WordCount; + ActualWordCount += WordCount; + } + + if (Read) { + // + // In the case where the drive wants to send more data than we need to read, + // the DRQ bit will be set and cause delays from DRQClear2(). + // We need to read data from the drive until it clears DRQ so we can move on. + // + AtapiReadPendingData (IdeDev); + } + + // + // After data transfer is completed, normally, DRQ bit should clear. + // + Status = DRQClear2 (IdeDev, ATAPITIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // read status register to check whether error happens. + // + return CheckErrorStatus (IdeDev); +} + +/** + Sends out ATAPI Test Unit Ready Packet Command to the specified device + to find out whether device is accessible. + + @param[in] *IdeDev Pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + @param[in] *SenseCount Sense count for this packet command + + @retval EFI_SUCCESS Device is accessible. + @retval EFI_DEVICE_ERROR Device is not accessible. + +**/ +EFI_STATUS +AtapiTestUnitReady ( + IN IDE_BLK_IO_DEV *IdeDev, + OUT UINTN *SenseCount + ) +{ + ATAPI_PACKET_COMMAND Packet; + EFI_STATUS Status; + + *SenseCount = 0; + + // + // fill command packet + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.TestUnitReady.opcode = ATA_CMD_TEST_UNIT_READY; + + // + // send command packet + // + Status = AtapiPacketCommandIn (IdeDev, &Packet, NULL, 0, ATAPITIMEOUT); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = AtapiRequestSense (IdeDev, SenseCount); + if (EFI_ERROR (Status)) { + *SenseCount = 0; + return Status; + } + + return EFI_SUCCESS; +} + +/** + Sends out ATAPI Request Sense Packet Command to the specified device. + This command will return all the current Sense data in the device. + This function will pack all the Sense data in one single buffer. + + @param[in] *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + @param[out] **SenseBuffers + allocated in this function, and freed by the calling function. + This buffer is used to accommodate all the sense data returned + by the device. + + @param[out] *BufUnit + record the unit size of the sense data block in the SenseBuffers, + + @param[out] *BufNumbers + record the number of units in the SenseBuffers. + + @retval EFI_SUCCESS + Request Sense command completes successfully. + + @retval EFI_DEVICE_ERROR + Request Sense command failed. + +**/ +EFI_STATUS +AtapiRequestSense ( + IN IDE_BLK_IO_DEV *IdeDev, + OUT UINTN *SenseCounts + ) +{ + EFI_STATUS Status; + ATAPI_REQUEST_SENSE_DATA *Sense; + UINT16 *Ptr; + BOOLEAN FetchSenseData; + ATAPI_PACKET_COMMAND Packet; + + *SenseCounts = 0; + + ZeroMem (IdeDev->SenseData, sizeof (ATAPI_REQUEST_SENSE_DATA) * (IdeDev->SenseDataNumber)); + // + // fill command packet for Request Sense Packet Command + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.RequestSence.opcode = ATA_CMD_REQUEST_SENSE; + Packet.RequestSence.allocation_length = sizeof (ATAPI_REQUEST_SENSE_DATA); + + // + // initialize pointer + // + Ptr = (UINT16 *) IdeDev->SenseData; + // + // request sense data from device continuously until no sense data + // exists in the device. + // + for (FetchSenseData = TRUE; FetchSenseData;) { + + Sense = (ATAPI_REQUEST_SENSE_DATA *) Ptr; + + // + // send out Request Sense Packet Command and get one Sense data form device + // + Status = AtapiPacketCommandIn ( + IdeDev, + &Packet, + Ptr, + sizeof (ATAPI_REQUEST_SENSE_DATA), + ATAPITIMEOUT + ); + // + // failed to get Sense data + // + if (EFI_ERROR (Status)) { + if (*SenseCounts == 0) { + return EFI_DEVICE_ERROR; + } else { + return EFI_SUCCESS; + } + } + + (*SenseCounts)++; + // + // We limit MAX sense data count to 20 in order to avoid dead loop. Some + // incompatible ATAPI devices don't retrive NO_SENSE when there is no media. + // In this case, dead loop occurs if we don't have a gatekeeper. 20 is + // supposed to be large enough for any ATAPI device. + // + if ((Sense->sense_key != ATA_SK_NO_SENSE) && ((*SenseCounts) < 20)) { + // + // Ptr is word-based pointer + // + Ptr += (sizeof (ATAPI_REQUEST_SENSE_DATA) + 1) >> 1; + + } else { + // + // when no sense key, skip out the loop + // + FetchSenseData = FALSE; + } + } + + return EFI_SUCCESS; +} + +/** + Sends out ATAPI Read Capacity Packet Command to the specified device. + This command will return the information regarding the capacity of the + media in the device. + + Current device status will impact device's response to the Read Capacity + Command. For example, if the device once reset, the Read Capacity + Command will fail. The Sense data record the current device status, so + if the Read Capacity Command failed, the Sense data must be requested + and be analyzed to determine if the Read Capacity Command should retry. + + @param[in] *IdeDev Pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + @param[in] SenseCount Sense count for this packet command + + @retval EFI_SUCCESS Read Capacity Command finally completes successfully. + @retval EFI_DEVICE_ERROR Read Capacity Command failed because of device error. + + @note Parameter "IdeDev" will be updated in this function. + + TODO: EFI_NOT_READY - add return value to function comment +**/ +EFI_STATUS +AtapiReadCapacity ( + IN IDE_BLK_IO_DEV *IdeDev, + OUT UINTN *SenseCount + ) +{ + // + // status returned by Read Capacity Packet Command + // + EFI_STATUS Status; + EFI_STATUS SenseStatus; + ATAPI_PACKET_COMMAND Packet; + + // + // used for capacity data returned from ATAPI device + // + ATAPI_READ_CAPACITY_DATA Data; + ATAPI_READ_FORMAT_CAPACITY_DATA FormatData; + + *SenseCount = 0; + + ZeroMem (&Data, sizeof (Data)); + ZeroMem (&FormatData, sizeof (FormatData)); + + if (IdeDev->Type == IdeCdRom) { + + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.Inquiry.opcode = ATA_CMD_READ_CAPACITY; + Status = AtapiPacketCommandIn ( + IdeDev, + &Packet, + (UINT16 *) &Data, + sizeof (ATAPI_READ_CAPACITY_DATA), + ATAPITIMEOUT + ); + + } else { + // + // Type == IdeMagnetic + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.ReadFormatCapacity.opcode = ATA_CMD_READ_FORMAT_CAPACITY; + Packet.ReadFormatCapacity.allocation_length_lo = 12; + Status = AtapiPacketCommandIn ( + IdeDev, + &Packet, + (UINT16 *) &FormatData, + sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA), + ATAPITIMEOUT + ); + } + + if (Status == EFI_TIMEOUT) { + *SenseCount = 0; + return Status; + } + + SenseStatus = AtapiRequestSense (IdeDev, SenseCount); + + if (!EFI_ERROR (SenseStatus)) { + + if (!EFI_ERROR (Status)) { + + if (IdeDev->Type == IdeCdRom) { + + IdeDev->BlkIo.Media->LastBlock = (Data.LastLba3 << 24) | + (Data.LastLba2 << 16) | + (Data.LastLba1 << 8) | + Data.LastLba0; + + if (IdeDev->BlkIo.Media->LastBlock != 0) { + + IdeDev->BlkIo.Media->BlockSize = (Data.BlockSize3 << 24) | + (Data.BlockSize2 << 16) | + (Data.BlockSize1 << 8) | + Data.BlockSize0; + + IdeDev->BlkIo.Media->MediaPresent = TRUE; + } else { + IdeDev->BlkIo.Media->MediaPresent = FALSE; + return EFI_DEVICE_ERROR; + } + + IdeDev->BlkIo.Media->ReadOnly = TRUE; + + // + // Because the user data portion in the sector of the Data CD supported + // is always 0x800 + // + IdeDev->BlkIo.Media->BlockSize = 0x800; + } + + if (IdeDev->Type == IdeMagnetic) { + + if (FormatData.DesCode == 3) { + IdeDev->BlkIo.Media->MediaPresent = FALSE; + IdeDev->BlkIo.Media->LastBlock = 0; + } else { + + IdeDev->BlkIo.Media->LastBlock = (FormatData.LastLba3 << 24) | + (FormatData.LastLba2 << 16) | + (FormatData.LastLba1 << 8) | + FormatData.LastLba0; + if (IdeDev->BlkIo.Media->LastBlock != 0) { + IdeDev->BlkIo.Media->LastBlock--; + + IdeDev->BlkIo.Media->BlockSize = (FormatData.BlockSize2 << 16) | + (FormatData.BlockSize1 << 8) | + FormatData.BlockSize0; + + IdeDev->BlkIo.Media->MediaPresent = TRUE; + } else { + IdeDev->BlkIo.Media->MediaPresent = FALSE; + // + // Return EFI_NOT_READY operation succeeds but returned capacity is 0 + // + return EFI_NOT_READY; + } + + IdeDev->BlkIo.Media->BlockSize = 0x200; + + } + } + } + + return EFI_SUCCESS; + + } else { + *SenseCount = 0; + return EFI_DEVICE_ERROR; + } +} + +/** + Used before read/write blocks from/to ATAPI device media. + Since ATAPI device media is removable, it is necessary to detect + whether media is present and get current present media's + information, and if media has been changed, Block I/O Protocol + need to be reinstalled. + + @param[in] *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + @param[out] *MediaChange + return value that indicates if the media of the device has been + changed. + + @retval EFI_SUCCESS + media found successfully. + + @retval EFI_DEVICE_ERROR + any error encounters during media detection. + + @retval EFI_NO_MEDIA + media not found. + + @note + parameter IdeDev may be updated in this function. + +**/ +EFI_STATUS +AtapiDetectMedia ( + IN IDE_BLK_IO_DEV *IdeDev, + OUT BOOLEAN *MediaChange + ) +{ + EFI_STATUS Status; + EFI_STATUS CleanStateStatus; + EFI_BLOCK_IO_MEDIA OldMediaInfo; + UINTN RetryTimes; + UINTN RetryNotReady; + UINTN SenseCount; + SENSE_RESULT SResult; + BOOLEAN WriteProtected; + + CopyMem (&OldMediaInfo, IdeDev->BlkIo.Media, sizeof (EFI_BLOCK_IO_MEDIA)); + *MediaChange = FALSE; + // + // Retry for SenseDeviceNotReadyNeedRetry. + // Each retry takes 1s and we limit the upper boundary to + // 120 times about 2 min. + // + RetryNotReady = 120; + + // + // Do Test Unit Ready + // + DoTUR: + // + // Retry 5 times + // + RetryTimes = 5; + while (RetryTimes != 0) { + + Status = AtapiTestUnitReady (IdeDev, &SenseCount); + + if (EFI_ERROR (Status)) { + // + // Test Unit Ready error without sense data. + // For some devices, this means there's extra data + // that has not been read, so we read these extra + // data out before going on. + // + CleanStateStatus = AtapiReadPendingData (IdeDev); + if (EFI_ERROR (CleanStateStatus)) { + // + // Busy wait failed, try again + // + RetryTimes--; + } + // + // Try again without counting down RetryTimes + // + continue; + } else { + + ParseSenseData (IdeDev, SenseCount, &SResult); + + switch (SResult) { + case SenseNoSenseKey: + if (IdeDev->BlkIo.Media->MediaPresent) { + goto Done; + } else { + // + // Media present but the internal structure need refreshed. + // Try Read Capacity + // + goto DoRC; + } + break; + + case SenseDeviceNotReadyNeedRetry: + if (--RetryNotReady == 0) { + return EFI_DEVICE_ERROR; + } + gBS->Stall (1000 * STALL_1_MILLI_SECOND); + continue; + break; + + case SenseNoMedia: + IdeDev->BlkIo.Media->MediaPresent = FALSE; + IdeDev->BlkIo.Media->LastBlock = 0; + goto Done; + break; + + case SenseDeviceNotReadyNoRetry: + case SenseMediaError: + return EFI_DEVICE_ERROR; + + case SenseMediaChange: + IdeDev->BlkIo.Media->MediaId++; + goto DoRC; + break; + + default: + RetryTimes--; + break; + } + } + } + + return EFI_DEVICE_ERROR; + + // + // Do Read Capacity + // + DoRC: + RetryTimes = 5; + + while (RetryTimes != 0) { + + Status = AtapiReadCapacity (IdeDev, &SenseCount); + + if (EFI_ERROR (Status)) { + RetryTimes--; + continue; + } else { + + ParseSenseData (IdeDev, SenseCount, &SResult); + + switch (SResult) { + case SenseNoSenseKey: + goto Done; + break; + + case SenseDeviceNotReadyNeedRetry: + // + // We use Test Unit Ready to retry which + // is faster. + // + goto DoTUR; + break; + + case SenseNoMedia: + IdeDev->BlkIo.Media->MediaPresent = FALSE; + IdeDev->BlkIo.Media->LastBlock = 0; + goto Done; + break; + + case SenseDeviceNotReadyNoRetry: + case SenseMediaError: + return EFI_DEVICE_ERROR; + + case SenseMediaChange: + IdeDev->BlkIo.Media->MediaId++; + continue; + break; + + default: + RetryTimes--; + break; + } + } + } + + return EFI_DEVICE_ERROR; + + Done: + // + // the following code is to check the write-protected for LS120 media + // + if ((IdeDev->BlkIo.Media->MediaPresent) && (IdeDev->Type == IdeMagnetic)) { + + Status = IsLS120orZipWriteProtected (IdeDev, &WriteProtected); + if (!EFI_ERROR (Status)) { + + if (WriteProtected) { + + IdeDev->BlkIo.Media->ReadOnly = TRUE; + } else { + + IdeDev->BlkIo.Media->ReadOnly = FALSE; + } + + } + } + + if (IdeDev->BlkIo.Media->MediaId != OldMediaInfo.MediaId) { + // + // Media change information got from the device + // + *MediaChange = TRUE; + } + + if (IdeDev->BlkIo.Media->ReadOnly != OldMediaInfo.ReadOnly) { + *MediaChange = TRUE; + IdeDev->BlkIo.Media->MediaId += 1; + } + + if (IdeDev->BlkIo.Media->BlockSize != OldMediaInfo.BlockSize) { + *MediaChange = TRUE; + IdeDev->BlkIo.Media->MediaId += 1; + } + + if (IdeDev->BlkIo.Media->LastBlock != OldMediaInfo.LastBlock) { + *MediaChange = TRUE; + IdeDev->BlkIo.Media->MediaId += 1; + } + + if (IdeDev->BlkIo.Media->MediaPresent != OldMediaInfo.MediaPresent) { + if (IdeDev->BlkIo.Media->MediaPresent) { + // + // when change from no media to media present, reset the MediaId to 1. + // + IdeDev->BlkIo.Media->MediaId = 1; + } else { + // + // when no media, reset the MediaId to zero. + // + IdeDev->BlkIo.Media->MediaId = 0; + } + + *MediaChange = TRUE; + } + + // + // if any change on current existing media, + // the Block I/O protocol need to be reinstalled. + // + if (*MediaChange) { + gBS->ReinstallProtocolInterface ( + IdeDev->Handle, + &gEfiBlockIoProtocolGuid, + &IdeDev->BlkIo, + &IdeDev->BlkIo + ); + } + + if (IdeDev->BlkIo.Media->MediaPresent) { + return EFI_SUCCESS; + } else { + return EFI_NO_MEDIA; + } +} + +/** + This function is called by the AtapiBlkIoReadBlocks() to perform + read from media in block unit. + + The main command used to access media here is READ(10) Command. + READ(10) Command requests that the ATAPI device media transfer + specified data to the host. Data is transferred in block(sector) + unit. The maximum number of blocks that can be transferred once is + 65536. This is the main difference between READ(10) and READ(12) + Command. The maximum number of blocks in READ(12) is 2 power 32. + + @param[in] *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + @param[in] *Buffer + A pointer to the destination buffer for the data. + + @param[in] Lba + The starting logical block address to read from + on the device media. + + @param[in] NumberOfBlocks + The number of transfer data blocks. + + @return status is fully dependent on the return status + of AtapiPacketCommandIn() function. + +**/ +EFI_STATUS +AtapiReadSectors ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *Buffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ) +{ + + ATAPI_PACKET_COMMAND Packet; + ATAPI_READ10_CMD *Read10Packet; + EFI_STATUS Status; + UINTN BlocksRemaining; + UINT32 Lba32; + UINT32 BlockSize; + UINT32 ByteCount; + UINT16 SectorCount; + VOID *PtrBuffer; + UINT16 MaxBlock; + UINTN TimeOut; + + // + // fill command packet for Read(10) command + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Read10Packet = &Packet.Read10; + Lba32 = (UINT32) Lba; + PtrBuffer = Buffer; + + BlockSize = IdeDev->BlkIo.Media->BlockSize; + + // + // limit the data bytes that can be transferred by one Read(10) Command + // + MaxBlock = 65535; + + BlocksRemaining = NumberOfBlocks; + + Status = EFI_SUCCESS; + while (BlocksRemaining > 0) { + + if (BlocksRemaining <= MaxBlock) { + + SectorCount = (UINT16) BlocksRemaining; + } else { + + SectorCount = MaxBlock; + } + + // + // fill the Packet data structure + // + + Read10Packet->opcode = ATA_CMD_READ_10; + + // + // Lba0 ~ Lba3 specify the start logical block address of the data transfer. + // Lba0 is MSB, Lba3 is LSB + // + Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff); + Read10Packet->Lba2 = (UINT8) (Lba32 >> 8); + Read10Packet->Lba1 = (UINT8) (Lba32 >> 16); + Read10Packet->Lba0 = (UINT8) (Lba32 >> 24); + + // + // TranLen0 ~ TranLen1 specify the transfer length in block unit. + // TranLen0 is MSB, TranLen is LSB + // + Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff); + Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8); + + ByteCount = SectorCount * BlockSize; + + if (IdeDev->Type == IdeCdRom) { + TimeOut = CDROMLONGTIMEOUT; + } else { + TimeOut = ATAPILONGTIMEOUT; + } + + Status = AtapiPacketCommandIn ( + IdeDev, + &Packet, + (UINT16 *) PtrBuffer, + ByteCount, + TimeOut + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Lba32 += SectorCount; + PtrBuffer = (UINT8 *) PtrBuffer + SectorCount * BlockSize; + BlocksRemaining -= SectorCount; + } + + return Status; +} + +/** + This function is called by the AtapiBlkIoWriteBlocks() to perform + write onto media in block unit. + The main command used to access media here is Write(10) Command. + Write(10) Command requests that the ATAPI device media transfer + specified data to the host. Data is transferred in block (sector) + unit. The maximum number of blocks that can be transferred once is + 65536. + + @param[in] *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + @param[in] *Buffer + A pointer to the source buffer for the data. + + @param[in] Lba + The starting logical block address to write onto + the device media. + + @param[in] NumberOfBlocks + The number of transfer data blocks. + + @return status is fully dependent on the return status + of AtapiPacketCommandOut() function. + +**/ +EFI_STATUS +AtapiWriteSectors ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *Buffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ) +{ + + ATAPI_PACKET_COMMAND Packet; + ATAPI_READ10_CMD *Read10Packet; + + EFI_STATUS Status; + UINTN BlocksRemaining; + UINT32 Lba32; + UINT32 BlockSize; + UINT32 ByteCount; + UINT16 SectorCount; + VOID *PtrBuffer; + UINT16 MaxBlock; + + // + // fill command packet for Write(10) command + // Write(10) command packet has the same data structure as + // Read(10) command packet, + // so here use the Read10Packet data structure + // for the Write(10) command packet. + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Read10Packet = &Packet.Read10; + + Lba32 = (UINT32) Lba; + PtrBuffer = Buffer; + + BlockSize = IdeDev->BlkIo.Media->BlockSize; + + // + // limit the data bytes that can be transferred by one Read(10) Command + // + MaxBlock = (UINT16) (65536 / BlockSize); + + BlocksRemaining = NumberOfBlocks; + + Status = EFI_SUCCESS; + while (BlocksRemaining > 0) { + + if (BlocksRemaining >= MaxBlock) { + SectorCount = MaxBlock; + } else { + SectorCount = (UINT16) BlocksRemaining; + } + + // + // Command code is WRITE_10. + // + Read10Packet->opcode = ATA_CMD_WRITE_10; + + // + // Lba0 ~ Lba3 specify the start logical block address of the data transfer. + // Lba0 is MSB, Lba3 is LSB + // + Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff); + Read10Packet->Lba2 = (UINT8) (Lba32 >> 8); + Read10Packet->Lba1 = (UINT8) (Lba32 >> 16); + Read10Packet->Lba0 = (UINT8) (Lba32 >> 24); + + // + // TranLen0 ~ TranLen1 specify the transfer length in block unit. + // TranLen0 is MSB, TranLen is LSB + // + Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff); + Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8); + + ByteCount = SectorCount * BlockSize; + + Status = AtapiPacketCommandOut ( + IdeDev, + &Packet, + (UINT16 *) PtrBuffer, + ByteCount, + ATAPILONGTIMEOUT + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Lba32 += SectorCount; + PtrBuffer = ((UINT8 *) PtrBuffer + SectorCount * BlockSize); + BlocksRemaining -= SectorCount; + } + + return Status; +} + +/** + This function is used to implement the Soft Reset on the specified + ATAPI device. Different from the AtaSoftReset(), here reset is a ATA + Soft Reset Command special for ATAPI device, and it only take effects + on the specified ATAPI device, not on the whole IDE bus. + Since the ATAPI soft reset is needed when device is in exceptional + condition (such as BSY bit is always set ), I think the Soft Reset + command should be sent without waiting for the BSY clear and DRDY + set. + This function is called by IdeBlkIoReset(), + a interface function of Block I/O protocol. + + @param[in] *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + @retval EFI_SUCCESS + Soft reset completes successfully. + + @retval EFI_DEVICE_ERROR + Any step during the reset process is failed. + +**/ +EFI_STATUS +AtapiSoftReset ( + IN IDE_BLK_IO_DEV *IdeDev + ) +{ + UINT8 Command; + UINT8 DeviceSelect; + EFI_STATUS Status; + + // + // for ATAPI device, no need to wait DRDY ready after device selecting. + // (bit7 and bit5 are both set to 1 for backward compatibility) + // + DeviceSelect = (UINT8) (((BIT7 | BIT5) | (IdeDev->Device << 4))); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect); + + Command = ATA_CMD_SOFT_RESET; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, Command); + + // + // BSY cleared is the only status return to the host by the device + // when reset is completed. + // slave device needs at most 31s to clear BSY + // + Status = WaitForBSYClear (IdeDev, 31000); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // stall 5 seconds to make the device status stable + // + gBS->Stall (5000000); + + return EFI_SUCCESS; +} + +/** + This function is the ATAPI implementation for ReadBlocks in the + Block I/O Protocol interface. + + @param[in] *IdeBlkIoDev + Indicates the calling context. + + @param[in] MediaId + The media id that the read request is for. + + @param[in] LBA + The starting logical block address to read from + on the device. + + @param[in] BufferSize + The size of the Buffer in bytes. This must be a + multiple of the intrinsic block size of the device. + + @param[out] *Buffer + A pointer to the destination buffer for the data. + The caller is responsible for either having implicit + or explicit ownership of the memory that data is read into. + + @retval EFI_SUCCESS + Read Blocks successfully. + + @retval EFI_DEVICE_ERROR + Read Blocks failed. + + @retval EFI_NO_MEDIA + There is no media in the device. + + @retval EFI_MEDIA_CHANGED + The MediaId is not for the current media. + + @retval EFI_BAD_BUFFER_SIZE + The BufferSize parameter is not a multiple of the + intrinsic block size of the device. + + @retval EFI_INVALID_PARAMETER + The read request contains LBAs that are not valid, + or the data buffer is not valid. + +**/ +EFI_STATUS +AtapiBlkIoReadBlocks ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevice, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + EFI_BLOCK_IO_MEDIA *Media; + UINTN BlockSize; + UINTN NumberOfBlocks; + EFI_STATUS Status; + + BOOLEAN MediaChange; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (BufferSize == 0) { + return EFI_SUCCESS; + } + + // + // ATAPI device media is removable, so it is a must + // to detect media first before read operation + // + MediaChange = FALSE; + Status = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange); + if (EFI_ERROR (Status)) { + + if (IdeBlkIoDevice->Cache != NULL) { + gBS->FreePool (IdeBlkIoDevice->Cache); + IdeBlkIoDevice->Cache = NULL; + } + + return Status; + } + // + // Get the intrinsic block size + // + Media = IdeBlkIoDevice->BlkIo.Media; + BlockSize = Media->BlockSize; + + NumberOfBlocks = BufferSize / BlockSize; + + if (!(Media->MediaPresent)) { + + if (IdeBlkIoDevice->Cache != NULL) { + gBS->FreePool (IdeBlkIoDevice->Cache); + IdeBlkIoDevice->Cache = NULL; + } + return EFI_NO_MEDIA; + + } + + if ((MediaId != Media->MediaId) || MediaChange) { + + if (IdeBlkIoDevice->Cache != NULL) { + gBS->FreePool (IdeBlkIoDevice->Cache); + IdeBlkIoDevice->Cache = NULL; + } + return EFI_MEDIA_CHANGED; + } + + if (BufferSize % BlockSize != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + if (LBA > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) { + return EFI_INVALID_PARAMETER; + } + + // + // if all the parameters are valid, then perform read sectors command + // to transfer data from device to host. + // + Status = AtapiReadSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Read blocks succeeded + // + + // + // save the first block to the cache for performance + // + if (LBA == 0 && !IdeBlkIoDevice->Cache) { + IdeBlkIoDevice->Cache = AllocatePool (BlockSize); + if (IdeBlkIoDevice != NULL) { + CopyMem ((UINT8 *) IdeBlkIoDevice->Cache, (UINT8 *) Buffer, BlockSize); + } + } + + return EFI_SUCCESS; + +} + +/** + This function is the ATAPI implementation for WriteBlocks in the + Block I/O Protocol interface. + + @param[in] *This + Indicates the calling context. + + @param[in] MediaId + The media id that the write request is for. + + @param[in] LBA + The starting logical block address to write onto + the device. + + @param[in] BufferSize + The size of the Buffer in bytes. This must be a + multiple of the intrinsic block size of the device. + + @param[out] *Buffer + A pointer to the source buffer for the data. + The caller is responsible for either having implicit + or explicit ownership of the memory that data is + written from. + + @retval EFI_SUCCESS + Write Blocks successfully. + + @retval EFI_DEVICE_ERROR + Write Blocks failed. + + @retval EFI_NO_MEDIA + There is no media in the device. + + @retval EFI_MEDIA_CHANGE + The MediaId is not for the current media. + + @retval EFI_BAD_BUFFER_SIZE + The BufferSize parameter is not a multiple of the + intrinsic block size of the device. + + @retval EFI_INVALID_PARAMETER + The write request contains LBAs that are not valid, + or the data buffer is not valid. + + TODO: EFI_MEDIA_CHANGED - add return value to function comment + TODO: EFI_WRITE_PROTECTED - add return value to function comment +**/ +EFI_STATUS +AtapiBlkIoWriteBlocks ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevice, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + + EFI_BLOCK_IO_MEDIA *Media; + UINTN BlockSize; + UINTN NumberOfBlocks; + EFI_STATUS Status; + BOOLEAN MediaChange; + + if (LBA == 0 && IdeBlkIoDevice->Cache) { + gBS->FreePool (IdeBlkIoDevice->Cache); + IdeBlkIoDevice->Cache = NULL; + } + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (BufferSize == 0) { + return EFI_SUCCESS; + } + + // + // ATAPI device media is removable, + // so it is a must to detect media first before write operation + // + MediaChange = FALSE; + Status = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange); + if (EFI_ERROR (Status)) { + + if (LBA == 0 && IdeBlkIoDevice->Cache) { + gBS->FreePool (IdeBlkIoDevice->Cache); + IdeBlkIoDevice->Cache = NULL; + } + return Status; + } + + // + // Get the intrinsic block size + // + Media = IdeBlkIoDevice->BlkIo.Media; + BlockSize = Media->BlockSize; + NumberOfBlocks = BufferSize / BlockSize; + + if (!(Media->MediaPresent)) { + + if (LBA == 0 && IdeBlkIoDevice->Cache) { + gBS->FreePool (IdeBlkIoDevice->Cache); + IdeBlkIoDevice->Cache = NULL; + } + return EFI_NO_MEDIA; + } + + if ((MediaId != Media->MediaId) || MediaChange) { + + if (LBA == 0 && IdeBlkIoDevice->Cache) { + gBS->FreePool (IdeBlkIoDevice->Cache); + IdeBlkIoDevice->Cache = NULL; + } + return EFI_MEDIA_CHANGED; + } + + if (Media->ReadOnly) { + return EFI_WRITE_PROTECTED; + } + + if (BufferSize % BlockSize != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + if (LBA > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) { + return EFI_INVALID_PARAMETER; + } + + // + // if all the parameters are valid, + // then perform write sectors command to transfer data from host to device. + // + Status = AtapiWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; + +} + +/** + This function is used to parse sense data. Only the first + sense data is honoured. + + @param[in] IdeDev Indicates the calling context. + @param[in] SenseCount Count of sense data. + @param[out] Result The parsed result. + + @retval EFI_SUCCESS Successfully parsed. + @retval EFI_INVALID_PARAMETER Count of sense data is zero. + +**/ +EFI_STATUS +ParseSenseData ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN SenseCount, + OUT SENSE_RESULT *Result + ) +{ + ATAPI_REQUEST_SENSE_DATA *SenseData; + + if (SenseCount == 0) { + return EFI_INVALID_PARAMETER; + } + + // + // Only use the first sense data + // + SenseData = IdeDev->SenseData; + *Result = SenseOtherSense; + + switch (SenseData->sense_key) { + case ATA_SK_NO_SENSE: + *Result = SenseNoSenseKey; + break; + case ATA_SK_NOT_READY: + switch (SenseData->addnl_sense_code) { + case ATA_ASC_NO_MEDIA: + *Result = SenseNoMedia; + break; + case ATA_ASC_MEDIA_UPSIDE_DOWN: + *Result = SenseMediaError; + break; + case ATA_ASC_NOT_READY: + if (SenseData->addnl_sense_code_qualifier == ATA_ASCQ_IN_PROGRESS) { + *Result = SenseDeviceNotReadyNeedRetry; + } else { + *Result = SenseDeviceNotReadyNoRetry; + } + break; + } + break; + case ATA_SK_UNIT_ATTENTION: + if (SenseData->addnl_sense_code == ATA_ASC_MEDIA_CHANGE) { + *Result = SenseMediaChange; + } + break; + case ATA_SK_MEDIUM_ERROR: + switch (SenseData->addnl_sense_code) { + case ATA_ASC_MEDIA_ERR1: + case ATA_ASC_MEDIA_ERR2: + case ATA_ASC_MEDIA_ERR3: + case ATA_ASC_MEDIA_ERR4: + *Result = SenseMediaError; + break; + } + break; + default: + break; + } + + return EFI_SUCCESS; +} + +/** + This function reads the pending data in the device. + + @param[in] IdeDev Indicates the calling context. + + @retval EFI_SUCCESS Successfully read. + @retval EFI_NOT_READY The BSY is set avoiding reading. + +**/ +EFI_STATUS +AtapiReadPendingData ( + IN IDE_BLK_IO_DEV *IdeDev + ) +{ + UINT8 AltRegister; + UINT16 TempWordBuffer; + + AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus); + if ((AltRegister & ATA_STSREG_BSY) == ATA_STSREG_BSY) { + return EFI_NOT_READY; + } + if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) { + TempWordBuffer = IDEReadPortB (IdeDev->PciIo,IdeDev->IoPort->Alt.AltStatus); + while ((TempWordBuffer & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) { + IDEReadPortWMultiple ( + IdeDev->PciIo, + IdeDev->IoPort->Data, + 1, + &TempWordBuffer + ); + TempWordBuffer = IDEReadPortB (IdeDev->PciIo,IdeDev->IoPort->Alt.AltStatus); + } + } + return EFI_SUCCESS; +} + +/** + TODO: Add function description + + @param IdeDev TODO: add argument description + @param WriteProtected TODO: add argument description + + @retval EFI_DEVICE_ERROR TODO: Add description for return value + @retval EFI_DEVICE_ERROR TODO: Add description for return value + @retval EFI_SUCCESS TODO: Add description for return value + +**/ +EFI_STATUS +IsLS120orZipWriteProtected ( + IN IDE_BLK_IO_DEV *IdeDev, + OUT BOOLEAN *WriteProtected + ) +{ + EFI_STATUS Status; + + *WriteProtected = FALSE; + + Status = LS120EnableMediaStatus (IdeDev, TRUE); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // the Get Media Status Command is only valid + // if a Set Features/Enable Media Status Command has been priviously issued. + // + if (LS120GetMediaStatus (IdeDev) == EFI_WRITE_PROTECTED) { + + *WriteProtected = TRUE; + } else { + + *WriteProtected = FALSE; + } + + // + // After Get Media Status Command completes, + // Set Features/Disable Media Command should be sent. + // + Status = LS120EnableMediaStatus (IdeDev, FALSE); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} diff --git a/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/atapi.c b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/atapi.c deleted file mode 100644 index 210d9dd..0000000 --- a/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/atapi.c +++ /dev/null @@ -1,2140 +0,0 @@ -/** @file - Copyright (c) 2006 - 2007, Intel Corporation - All rights reserved. This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include "idebus.h" - -/** - This function is used to get the current status of the media residing - in the LS-120 drive or ZIP drive. The media status is returned in the - Error Status. - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @retval EFI_SUCCESS - The media status is achieved successfully and the media - can be read/written. - - @retval EFI_DEVICE_ERROR - Get Media Status Command is failed. - - @retval EFI_NO_MEDIA - There is no media in the drive. - - @retval EFI_WRITE_PROTECTED - The media is writing protected. - - @note - This function must be called after the LS120EnableMediaStatus() - with second parameter set to TRUE - (means enable media status notification) is called. - -**/ -STATIC -EFI_STATUS -LS120GetMediaStatus ( - IN IDE_BLK_IO_DEV *IdeDev - ) -{ - UINT8 DeviceSelect; - UINT8 StatusValue; - EFI_STATUS EfiStatus; - // - // Poll Alternate Register for BSY clear within timeout. - // - EfiStatus = WaitForBSYClear2 (IdeDev, ATATIMEOUT); - if (EFI_ERROR (EfiStatus)) { - return EFI_DEVICE_ERROR; - } - - // - // Select device via Device/Head Register. - // - DeviceSelect = (UINT8) ((IdeDev->Device) << 4 | 0xe0); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect); - - // - // Poll Alternate Register for DRDY set within timeout. - // After device is selected, DRDY set indicates the device is ready to - // accept command. - // - EfiStatus = DRDYReady2 (IdeDev, ATATIMEOUT); - if (EFI_ERROR (EfiStatus)) { - return EFI_DEVICE_ERROR; - } - - // - // Get Media Status Command is sent - // - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0xDA); - - // - // BSY bit will clear after command is complete. - // - EfiStatus = WaitForBSYClear2 (IdeDev, ATATIMEOUT); - if (EFI_ERROR (EfiStatus)) { - return EFI_DEVICE_ERROR; - } - - // - // the media status is returned by the command in the ERROR register - // - StatusValue = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); - - if (StatusValue & BIT1) { - return EFI_NO_MEDIA; - } - - if (StatusValue & BIT6) { - return EFI_WRITE_PROTECTED; - } else { - return EFI_SUCCESS; - } -} - -/** - This function is used to send Enable Media Status Notification Command - or Disable Media Status Notification Command. - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @param[in] Enable - a flag that indicates whether enable or disable media - status notification. - - @retval EFI_SUCCESS - If command completes successfully. - - @retval EFI_DEVICE_ERROR - If command failed. - -**/ -STATIC -EFI_STATUS -LS120EnableMediaStatus ( - IN IDE_BLK_IO_DEV *IdeDev, - IN BOOLEAN Enable - ) -{ - UINT8 DeviceSelect; - EFI_STATUS Status; - - // - // Poll Alternate Register for BSY clear within timeout. - // - Status = WaitForBSYClear2 (IdeDev, ATATIMEOUT); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - // - // Select device via Device/Head Register. - // - DeviceSelect = (UINT8) ((IdeDev->Device) << 4 | 0xe0); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect); - - // - // Poll Alternate Register for DRDY set within timeout. - // After device is selected, DRDY set indicates the device is ready to - // accept command. - // - Status = DRDYReady2 (IdeDev, ATATIMEOUT); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - if (Enable) { - // - // 0x95: Enable media status notification - // - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x95); - } else { - // - // 0x31: Disable media status notification - // - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x31); - } - // - // Set Feature Command is sent - // - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0xEF); - - // - // BSY bit will clear after command is complete. - // - Status = WaitForBSYClear (IdeDev, ATATIMEOUT); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - return EFI_SUCCESS; -} - -/** - This function is called by DiscoverIdeDevice() during its device - identification. - - Its main purpose is to get enough information for the device media - to fill in the Media data structure of the Block I/O Protocol interface. - - There are 5 steps to reach such objective: - - 1. Sends out the ATAPI Identify Command to the specified device. - Only ATAPI device responses to this command. If the command succeeds, - it returns the Identify data structure which filled with information - about the device. Since the ATAPI device contains removable media, - the only meaningful information is the device module name. - - 2. Sends out ATAPI Inquiry Packet Command to the specified device. - This command will return inquiry data of the device, which contains - the device type information. - - 3. Allocate sense data space for future use. We don't detect the media - presence here to improvement boot performance, especially when CD - media is present. The media detection will be performed just before - each BLK_IO read/write - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @retval EFI_SUCCESS - Identify ATAPI device successfully. - - @retval EFI_DEVICE_ERROR - ATAPI Identify Device Command failed or device type - is not supported by this IDE driver. - - @note - Parameter "IdeDev" will be updated in this function. - - TODO: EFI_OUT_OF_RESOURCES - add return value to function comment - TODO: EFI_OUT_OF_RESOURCES - add return value to function comment -**/ -EFI_STATUS -ATAPIIdentify ( - IN IDE_BLK_IO_DEV *IdeDev - ) -{ - EFI_IDENTIFY_DATA *AtapiIdentifyPointer; - UINT8 DeviceSelect; - EFI_STATUS Status; - - // - // device select bit - // - DeviceSelect = (UINT8) ((IdeDev->Device) << 4); - - AtapiIdentifyPointer = AllocatePool (sizeof (EFI_IDENTIFY_DATA)); - if (AtapiIdentifyPointer == NULL) { - return EFI_OUT_OF_RESOURCES; - } - // - // Send ATAPI Identify Command to get IDENTIFY data. - // - Status = AtaPioDataIn ( - IdeDev, - (VOID *) AtapiIdentifyPointer, - sizeof (EFI_IDENTIFY_DATA), - ATA_CMD_IDENTIFY_DEVICE, - DeviceSelect, - 0, - 0, - 0, - 0 - ); - - if (EFI_ERROR (Status)) { - gBS->FreePool (AtapiIdentifyPointer); - return EFI_DEVICE_ERROR; - } - - IdeDev->pIdData = AtapiIdentifyPointer; - PrintAtaModuleName (IdeDev); - - // - // Send ATAPI Inquiry Packet Command to get INQUIRY data. - // - Status = AtapiInquiry (IdeDev); - if (EFI_ERROR (Status)) { - gBS->FreePool (IdeDev->pIdData); - // - // Make sure the pIdData will not be freed again. - // - IdeDev->pIdData = NULL; - return EFI_DEVICE_ERROR; - } - // - // Get media removable info from INQUIRY data. - // - IdeDev->BlkIo.Media->RemovableMedia = (UINT8) ((IdeDev->pInquiryData->RMB & 0x80) == 0x80); - - // - // Identify device type via INQUIRY data. - // - switch (IdeDev->pInquiryData->peripheral_type & 0x1f) { - - // - // Magnetic Disk - // - case 0x00: - - // - // device is LS120 or ZIP drive. - // - IdeDev->Type = IdeMagnetic; - - IdeDev->BlkIo.Media->MediaId = 0; - // - // Give initial value - // - IdeDev->BlkIo.Media->MediaPresent = FALSE; - - IdeDev->BlkIo.Media->LastBlock = 0; - IdeDev->BlkIo.Media->BlockSize = 0x200; - break; - - // - // CD-ROM - // - case 0x05: - - IdeDev->Type = IdeCdRom; - IdeDev->BlkIo.Media->MediaId = 0; - // - // Give initial value - // - IdeDev->BlkIo.Media->MediaPresent = FALSE; - - IdeDev->BlkIo.Media->LastBlock = 0; - IdeDev->BlkIo.Media->BlockSize = 0x800; - IdeDev->BlkIo.Media->ReadOnly = TRUE; - break; - - // - // Tape - // - case 0x01: - - // - // WORM - // - case 0x04: - - // - // Optical - // - case 0x07: - - default: - IdeDev->Type = IdeUnknown; - gBS->FreePool (IdeDev->pIdData); - gBS->FreePool (IdeDev->pInquiryData); - // - // Make sure the pIdData and pInquiryData will not be freed again. - // - IdeDev->pIdData = NULL; - IdeDev->pInquiryData = NULL; - return EFI_DEVICE_ERROR; - } - - // - // original sense data numbers - // - IdeDev->SenseDataNumber = 20; - - IdeDev->SenseData = AllocatePool (IdeDev->SenseDataNumber * sizeof (ATAPI_REQUEST_SENSE_DATA)); - if (IdeDev->SenseData == NULL) { - gBS->FreePool (IdeDev->pIdData); - gBS->FreePool (IdeDev->pInquiryData); - // - // Make sure the pIdData and pInquiryData will not be freed again. - // - IdeDev->pIdData = NULL; - IdeDev->pInquiryData = NULL; - return EFI_OUT_OF_RESOURCES; - } - - return EFI_SUCCESS; -} - -/** - Sends out ATAPI Inquiry Packet Command to the specified device. - This command will return INQUIRY data of the device. - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @retval EFI_SUCCESS - Inquiry command completes successfully. - - @retval EFI_DEVICE_ERROR - Inquiry command failed. - - @note - Parameter "IdeDev" will be updated in this function. - -**/ -EFI_STATUS -AtapiInquiry ( - IN IDE_BLK_IO_DEV *IdeDev - ) -{ - ATAPI_PACKET_COMMAND Packet; - EFI_STATUS Status; - ATAPI_INQUIRY_DATA *InquiryData; - - // - // prepare command packet for the ATAPI Inquiry Packet Command. - // - ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); - Packet.Inquiry.opcode = ATA_CMD_INQUIRY; - Packet.Inquiry.page_code = 0; - Packet.Inquiry.allocation_length = sizeof (ATAPI_INQUIRY_DATA); - - InquiryData = AllocatePool (sizeof (ATAPI_INQUIRY_DATA)); - if (InquiryData == NULL) { - return EFI_DEVICE_ERROR; - } - - // - // Send command packet and get requested Inquiry data. - // - Status = AtapiPacketCommandIn ( - IdeDev, - &Packet, - (UINT16 *) InquiryData, - sizeof (ATAPI_INQUIRY_DATA), - ATAPITIMEOUT - ); - if (EFI_ERROR (Status)) { - gBS->FreePool (InquiryData); - return EFI_DEVICE_ERROR; - } - - IdeDev->pInquiryData = InquiryData; - - return EFI_SUCCESS; -} - -/** - This function is used to send out ATAPI commands conforms to the - Packet Command with PIO Data In Protocol. - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @param[in] *Packet - pointer pointing to ATAPI_PACKET_COMMAND data structure - which contains the contents of the command. - - @param[in] *Buffer - buffer contained data transferred from device to host. - - @param[in] ByteCount - data size in byte unit of the buffer. - - @param[in] TimeOut - this parameter is used to specify the timeout - value for the PioReadWriteData() function. - - @retval EFI_SUCCESS - send out the ATAPI packet command successfully - and device sends data successfully. - - @retval EFI_DEVICE_ERROR - the device failed to send data. - -**/ -EFI_STATUS -AtapiPacketCommandIn ( - IN IDE_BLK_IO_DEV *IdeDev, - IN ATAPI_PACKET_COMMAND *Packet, - IN UINT16 *Buffer, - IN UINT32 ByteCount, - IN UINTN TimeOut - ) -{ - UINT16 *CommandIndex; - EFI_STATUS Status; - UINT32 Count; - - // - // Set all the command parameters by fill related registers. - // Before write to all the following registers, BSY and DRQ must be 0. - // - Status = DRQClear2 (IdeDev, ATAPITIMEOUT); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // Select device via Device/Head Register. - // - IDEWritePortB ( - IdeDev->PciIo, - IdeDev->IoPort->Head, - (UINT8) ((IdeDev->Device << 4) | ATA_DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000) - ); - - // - // No OVL; No DMA - // - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00); - - // - // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device - // determine how many data should be transferred. - // - IDEWritePortB ( - IdeDev->PciIo, - IdeDev->IoPort->CylinderLsb, - (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff) - ); - IDEWritePortB ( - IdeDev->PciIo, - IdeDev->IoPort->CylinderMsb, - (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8) - ); - - // - // ATA_DEFAULT_CTL:0x0a (0000,1010) - // Disable interrupt - // - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, ATA_DEFAULT_CTL); - - // - // Send Packet command to inform device - // that the following data bytes are command packet. - // - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, ATA_CMD_PACKET); - - Status = DRQReady (IdeDev, ATAPITIMEOUT); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // Send out command packet - // - CommandIndex = Packet->Data16; - for (Count = 0; Count < 6; Count++, CommandIndex++) { - - IDEWritePortW (IdeDev->PciIo, IdeDev->IoPort->Data, *CommandIndex); - gBS->Stall (10); - } - - // - // call PioReadWriteData() function to get - // requested transfer data form device. - // - return PioReadWriteData (IdeDev, Buffer, ByteCount, 1, TimeOut); -} - -/** - This function is used to send out ATAPI commands conforms to the - Packet Command with PIO Data Out Protocol. - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @param[in] *Packet - pointer pointing to ATAPI_PACKET_COMMAND data structure - which contains the contents of the command. - - @param[in] *Buffer - buffer contained data transferred from host to device. - - @param[in] ByteCount - data size in byte unit of the buffer. - - @param[in] TimeOut - this parameter is used to specify the timeout - value for the PioReadWriteData() function. - - @retval EFI_SUCCESS - send out the ATAPI packet command successfully - and device received data successfully. - - @retval EFI_DEVICE_ERROR - the device failed to send data. - -**/ -EFI_STATUS -AtapiPacketCommandOut ( - IN IDE_BLK_IO_DEV *IdeDev, - IN ATAPI_PACKET_COMMAND *Packet, - IN UINT16 *Buffer, - IN UINT32 ByteCount, - IN UINTN TimeOut - ) -{ - UINT16 *CommandIndex; - EFI_STATUS Status; - UINT32 Count; - - // - // set all the command parameters - // Before write to all the following registers, BSY and DRQ must be 0. - // - Status = DRQClear2 (IdeDev, ATAPITIMEOUT); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // Select device via Device/Head Register. - // - IDEWritePortB ( - IdeDev->PciIo, - IdeDev->IoPort->Head, - (UINT8) ((IdeDev->Device << 4) | ATA_DEFAULT_CMD) // ATA_DEFAULT_CMD: 0xa0 (1010,0000) - ); - - // - // No OVL; No DMA - // - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00); - - // - // set the transfersize to ATAPI_MAX_BYTE_COUNT to - // let the device determine how many data should be transferred. - // - IDEWritePortB ( - IdeDev->PciIo, - IdeDev->IoPort->CylinderLsb, - (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff) - ); - IDEWritePortB ( - IdeDev->PciIo, - IdeDev->IoPort->CylinderMsb, - (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8) - ); - - // - // DEFAULT_CTL:0x0a (0000,1010) - // Disable interrupt - // - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, ATA_DEFAULT_CTL); - - // - // Send Packet command to inform device - // that the following data bytes are command packet. - // - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, ATA_CMD_PACKET); - - Status = DRQReady2 (IdeDev, ATAPITIMEOUT); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // Send out command packet - // - CommandIndex = Packet->Data16; - for (Count = 0; Count < 6; Count++, CommandIndex++) { - IDEWritePortW (IdeDev->PciIo, IdeDev->IoPort->Data, *CommandIndex); - gBS->Stall (10); - } - - // - // call PioReadWriteData() function to send requested transfer data to device. - // - return PioReadWriteData (IdeDev, Buffer, ByteCount, 0, TimeOut); -} - -/** - This function is called by either AtapiPacketCommandIn() or - AtapiPacketCommandOut(). It is used to transfer data between - host and device. The data direction is specified by the fourth - parameter. - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @param[in] *Buffer - buffer contained data transferred between host and device. - - @param[in] ByteCount - data size in byte unit of the buffer. - - @param[in] Read - flag used to determine the data transfer direction. - Read equals 1, means data transferred from device to host; - Read equals 0, means data transferred from host to device. - - @param[in] TimeOut - timeout value for wait DRQ ready before each data - stream's transfer. - - @retval EFI_SUCCESS - data is transferred successfully. - - @retval EFI_DEVICE_ERROR - the device failed to transfer data. - -**/ -EFI_STATUS -PioReadWriteData ( - IN IDE_BLK_IO_DEV *IdeDev, - IN UINT16 *Buffer, - IN UINT32 ByteCount, - IN BOOLEAN Read, - IN UINTN TimeOut - ) -{ - // - // required transfer data in word unit. - // - UINT32 RequiredWordCount; - - // - // actual transfer data in word unit. - // - UINT32 ActualWordCount; - UINT32 WordCount; - EFI_STATUS Status; - UINT16 *PtrBuffer; - - // - // No data transfer is premitted. - // - if (ByteCount == 0) { - return EFI_SUCCESS; - } - // - // for performance, we assert the ByteCount is an even number - // which is actually a resonable assumption - ASSERT((ByteCount%2) == 0); - - PtrBuffer = Buffer; - RequiredWordCount = ByteCount / 2; - // - // ActuralWordCount means the word count of data really transferred. - // - ActualWordCount = 0; - - while (ActualWordCount < RequiredWordCount) { - - // - // before each data transfer stream, the host should poll DRQ bit ready, - // to see whether indicates device is ready to transfer data. - // - Status = DRQReady2 (IdeDev, TimeOut); - if (EFI_ERROR (Status)) { - return CheckErrorStatus (IdeDev); - } - - // - // read Status Register will clear interrupt - // - IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status); - - // - // get current data transfer size from Cylinder Registers. - // - WordCount = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb) << 8; - WordCount = WordCount | IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb); - WordCount = WordCount & 0xffff; - WordCount /= 2; - - WordCount = MIN (WordCount, (RequiredWordCount - ActualWordCount)); - - if (Read) { - IDEReadPortWMultiple ( - IdeDev->PciIo, - IdeDev->IoPort->Data, - WordCount, - PtrBuffer - ); - } else { - IDEWritePortWMultiple ( - IdeDev->PciIo, - IdeDev->IoPort->Data, - WordCount, - PtrBuffer - ); - } - - PtrBuffer += WordCount; - ActualWordCount += WordCount; - } - - if (Read) { - // - // In the case where the drive wants to send more data than we need to read, - // the DRQ bit will be set and cause delays from DRQClear2(). - // We need to read data from the drive until it clears DRQ so we can move on. - // - AtapiReadPendingData (IdeDev); - } - - // - // After data transfer is completed, normally, DRQ bit should clear. - // - Status = DRQClear2 (IdeDev, ATAPITIMEOUT); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - // - // read status register to check whether error happens. - // - return CheckErrorStatus (IdeDev); -} - -/** - Sends out ATAPI Test Unit Ready Packet Command to the specified device - to find out whether device is accessible. - - @param[in] *IdeDev Pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - @param[in] *SenseCount Sense count for this packet command - - @retval EFI_SUCCESS Device is accessible. - @retval EFI_DEVICE_ERROR Device is not accessible. - -**/ -EFI_STATUS -AtapiTestUnitReady ( - IN IDE_BLK_IO_DEV *IdeDev, - OUT UINTN *SenseCount - ) -{ - ATAPI_PACKET_COMMAND Packet; - EFI_STATUS Status; - - *SenseCount = 0; - - // - // fill command packet - // - ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); - Packet.TestUnitReady.opcode = ATA_CMD_TEST_UNIT_READY; - - // - // send command packet - // - Status = AtapiPacketCommandIn (IdeDev, &Packet, NULL, 0, ATAPITIMEOUT); - if (EFI_ERROR (Status)) { - return Status; - } - - Status = AtapiRequestSense (IdeDev, SenseCount); - if (EFI_ERROR (Status)) { - *SenseCount = 0; - return Status; - } - - return EFI_SUCCESS; -} - -/** - Sends out ATAPI Request Sense Packet Command to the specified device. - This command will return all the current Sense data in the device. - This function will pack all the Sense data in one single buffer. - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @param[out] **SenseBuffers - allocated in this function, and freed by the calling function. - This buffer is used to accommodate all the sense data returned - by the device. - - @param[out] *BufUnit - record the unit size of the sense data block in the SenseBuffers, - - @param[out] *BufNumbers - record the number of units in the SenseBuffers. - - @retval EFI_SUCCESS - Request Sense command completes successfully. - - @retval EFI_DEVICE_ERROR - Request Sense command failed. - -**/ -EFI_STATUS -AtapiRequestSense ( - IN IDE_BLK_IO_DEV *IdeDev, - OUT UINTN *SenseCounts - ) -{ - EFI_STATUS Status; - ATAPI_REQUEST_SENSE_DATA *Sense; - UINT16 *Ptr; - BOOLEAN FetchSenseData; - ATAPI_PACKET_COMMAND Packet; - - *SenseCounts = 0; - - ZeroMem (IdeDev->SenseData, sizeof (ATAPI_REQUEST_SENSE_DATA) * (IdeDev->SenseDataNumber)); - // - // fill command packet for Request Sense Packet Command - // - ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); - Packet.RequestSence.opcode = ATA_CMD_REQUEST_SENSE; - Packet.RequestSence.allocation_length = sizeof (ATAPI_REQUEST_SENSE_DATA); - - // - // initialize pointer - // - Ptr = (UINT16 *) IdeDev->SenseData; - // - // request sense data from device continuously until no sense data - // exists in the device. - // - for (FetchSenseData = TRUE; FetchSenseData;) { - - Sense = (ATAPI_REQUEST_SENSE_DATA *) Ptr; - - // - // send out Request Sense Packet Command and get one Sense data form device - // - Status = AtapiPacketCommandIn ( - IdeDev, - &Packet, - Ptr, - sizeof (ATAPI_REQUEST_SENSE_DATA), - ATAPITIMEOUT - ); - // - // failed to get Sense data - // - if (EFI_ERROR (Status)) { - if (*SenseCounts == 0) { - return EFI_DEVICE_ERROR; - } else { - return EFI_SUCCESS; - } - } - - (*SenseCounts)++; - // - // We limit MAX sense data count to 20 in order to avoid dead loop. Some - // incompatible ATAPI devices don't retrive NO_SENSE when there is no media. - // In this case, dead loop occurs if we don't have a gatekeeper. 20 is - // supposed to be large enough for any ATAPI device. - // - if ((Sense->sense_key != ATA_SK_NO_SENSE) && ((*SenseCounts) < 20)) { - // - // Ptr is word-based pointer - // - Ptr += (sizeof (ATAPI_REQUEST_SENSE_DATA) + 1) >> 1; - - } else { - // - // when no sense key, skip out the loop - // - FetchSenseData = FALSE; - } - } - - return EFI_SUCCESS; -} - -/** - Sends out ATAPI Read Capacity Packet Command to the specified device. - This command will return the information regarding the capacity of the - media in the device. - - Current device status will impact device's response to the Read Capacity - Command. For example, if the device once reset, the Read Capacity - Command will fail. The Sense data record the current device status, so - if the Read Capacity Command failed, the Sense data must be requested - and be analyzed to determine if the Read Capacity Command should retry. - - @param[in] *IdeDev Pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - @param[in] SenseCount Sense count for this packet command - - @retval EFI_SUCCESS Read Capacity Command finally completes successfully. - @retval EFI_DEVICE_ERROR Read Capacity Command failed because of device error. - - @note Parameter "IdeDev" will be updated in this function. - - TODO: EFI_NOT_READY - add return value to function comment -**/ -EFI_STATUS -AtapiReadCapacity ( - IN IDE_BLK_IO_DEV *IdeDev, - OUT UINTN *SenseCount - ) -{ - // - // status returned by Read Capacity Packet Command - // - EFI_STATUS Status; - EFI_STATUS SenseStatus; - ATAPI_PACKET_COMMAND Packet; - - // - // used for capacity data returned from ATAPI device - // - ATAPI_READ_CAPACITY_DATA Data; - ATAPI_READ_FORMAT_CAPACITY_DATA FormatData; - - *SenseCount = 0; - - ZeroMem (&Data, sizeof (Data)); - ZeroMem (&FormatData, sizeof (FormatData)); - - if (IdeDev->Type == IdeCdRom) { - - ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); - Packet.Inquiry.opcode = ATA_CMD_READ_CAPACITY; - Status = AtapiPacketCommandIn ( - IdeDev, - &Packet, - (UINT16 *) &Data, - sizeof (ATAPI_READ_CAPACITY_DATA), - ATAPITIMEOUT - ); - - } else { - // - // Type == IdeMagnetic - // - ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); - Packet.ReadFormatCapacity.opcode = ATA_CMD_READ_FORMAT_CAPACITY; - Packet.ReadFormatCapacity.allocation_length_lo = 12; - Status = AtapiPacketCommandIn ( - IdeDev, - &Packet, - (UINT16 *) &FormatData, - sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA), - ATAPITIMEOUT - ); - } - - if (Status == EFI_TIMEOUT) { - *SenseCount = 0; - return Status; - } - - SenseStatus = AtapiRequestSense (IdeDev, SenseCount); - - if (!EFI_ERROR (SenseStatus)) { - - if (!EFI_ERROR (Status)) { - - if (IdeDev->Type == IdeCdRom) { - - IdeDev->BlkIo.Media->LastBlock = (Data.LastLba3 << 24) | - (Data.LastLba2 << 16) | - (Data.LastLba1 << 8) | - Data.LastLba0; - - if (IdeDev->BlkIo.Media->LastBlock != 0) { - - IdeDev->BlkIo.Media->BlockSize = (Data.BlockSize3 << 24) | - (Data.BlockSize2 << 16) | - (Data.BlockSize1 << 8) | - Data.BlockSize0; - - IdeDev->BlkIo.Media->MediaPresent = TRUE; - } else { - IdeDev->BlkIo.Media->MediaPresent = FALSE; - return EFI_DEVICE_ERROR; - } - - IdeDev->BlkIo.Media->ReadOnly = TRUE; - - // - // Because the user data portion in the sector of the Data CD supported - // is always 0x800 - // - IdeDev->BlkIo.Media->BlockSize = 0x800; - } - - if (IdeDev->Type == IdeMagnetic) { - - if (FormatData.DesCode == 3) { - IdeDev->BlkIo.Media->MediaPresent = FALSE; - IdeDev->BlkIo.Media->LastBlock = 0; - } else { - - IdeDev->BlkIo.Media->LastBlock = (FormatData.LastLba3 << 24) | - (FormatData.LastLba2 << 16) | - (FormatData.LastLba1 << 8) | - FormatData.LastLba0; - if (IdeDev->BlkIo.Media->LastBlock != 0) { - IdeDev->BlkIo.Media->LastBlock--; - - IdeDev->BlkIo.Media->BlockSize = (FormatData.BlockSize2 << 16) | - (FormatData.BlockSize1 << 8) | - FormatData.BlockSize0; - - IdeDev->BlkIo.Media->MediaPresent = TRUE; - } else { - IdeDev->BlkIo.Media->MediaPresent = FALSE; - // - // Return EFI_NOT_READY operation succeeds but returned capacity is 0 - // - return EFI_NOT_READY; - } - - IdeDev->BlkIo.Media->BlockSize = 0x200; - - } - } - } - - return EFI_SUCCESS; - - } else { - *SenseCount = 0; - return EFI_DEVICE_ERROR; - } -} - -/** - Used before read/write blocks from/to ATAPI device media. - Since ATAPI device media is removable, it is necessary to detect - whether media is present and get current present media's - information, and if media has been changed, Block I/O Protocol - need to be reinstalled. - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @param[out] *MediaChange - return value that indicates if the media of the device has been - changed. - - @retval EFI_SUCCESS - media found successfully. - - @retval EFI_DEVICE_ERROR - any error encounters during media detection. - - @retval EFI_NO_MEDIA - media not found. - - @note - parameter IdeDev may be updated in this function. - -**/ -EFI_STATUS -AtapiDetectMedia ( - IN IDE_BLK_IO_DEV *IdeDev, - OUT BOOLEAN *MediaChange - ) -{ - EFI_STATUS Status; - EFI_STATUS CleanStateStatus; - EFI_BLOCK_IO_MEDIA OldMediaInfo; - UINTN RetryTimes; - UINTN RetryNotReady; - UINTN SenseCount; - SENSE_RESULT SResult; - BOOLEAN WriteProtected; - - CopyMem (&OldMediaInfo, IdeDev->BlkIo.Media, sizeof (EFI_BLOCK_IO_MEDIA)); - *MediaChange = FALSE; - // - // Retry for SenseDeviceNotReadyNeedRetry. - // Each retry takes 1s and we limit the upper boundary to - // 120 times about 2 min. - // - RetryNotReady = 120; - - // - // Do Test Unit Ready - // - DoTUR: - // - // Retry 5 times - // - RetryTimes = 5; - while (RetryTimes != 0) { - - Status = AtapiTestUnitReady (IdeDev, &SenseCount); - - if (EFI_ERROR (Status)) { - // - // Test Unit Ready error without sense data. - // For some devices, this means there's extra data - // that has not been read, so we read these extra - // data out before going on. - // - CleanStateStatus = AtapiReadPendingData (IdeDev); - if (EFI_ERROR (CleanStateStatus)) { - // - // Busy wait failed, try again - // - RetryTimes--; - } - // - // Try again without counting down RetryTimes - // - continue; - } else { - - ParseSenseData (IdeDev, SenseCount, &SResult); - - switch (SResult) { - case SenseNoSenseKey: - if (IdeDev->BlkIo.Media->MediaPresent) { - goto Done; - } else { - // - // Media present but the internal structure need refreshed. - // Try Read Capacity - // - goto DoRC; - } - break; - - case SenseDeviceNotReadyNeedRetry: - if (--RetryNotReady == 0) { - return EFI_DEVICE_ERROR; - } - gBS->Stall (1000 * STALL_1_MILLI_SECOND); - continue; - break; - - case SenseNoMedia: - IdeDev->BlkIo.Media->MediaPresent = FALSE; - IdeDev->BlkIo.Media->LastBlock = 0; - goto Done; - break; - - case SenseDeviceNotReadyNoRetry: - case SenseMediaError: - return EFI_DEVICE_ERROR; - - case SenseMediaChange: - IdeDev->BlkIo.Media->MediaId++; - goto DoRC; - break; - - default: - RetryTimes--; - break; - } - } - } - - return EFI_DEVICE_ERROR; - - // - // Do Read Capacity - // - DoRC: - RetryTimes = 5; - - while (RetryTimes != 0) { - - Status = AtapiReadCapacity (IdeDev, &SenseCount); - - if (EFI_ERROR (Status)) { - RetryTimes--; - continue; - } else { - - ParseSenseData (IdeDev, SenseCount, &SResult); - - switch (SResult) { - case SenseNoSenseKey: - goto Done; - break; - - case SenseDeviceNotReadyNeedRetry: - // - // We use Test Unit Ready to retry which - // is faster. - // - goto DoTUR; - break; - - case SenseNoMedia: - IdeDev->BlkIo.Media->MediaPresent = FALSE; - IdeDev->BlkIo.Media->LastBlock = 0; - goto Done; - break; - - case SenseDeviceNotReadyNoRetry: - case SenseMediaError: - return EFI_DEVICE_ERROR; - - case SenseMediaChange: - IdeDev->BlkIo.Media->MediaId++; - continue; - break; - - default: - RetryTimes--; - break; - } - } - } - - return EFI_DEVICE_ERROR; - - Done: - // - // the following code is to check the write-protected for LS120 media - // - if ((IdeDev->BlkIo.Media->MediaPresent) && (IdeDev->Type == IdeMagnetic)) { - - Status = IsLS120orZipWriteProtected (IdeDev, &WriteProtected); - if (!EFI_ERROR (Status)) { - - if (WriteProtected) { - - IdeDev->BlkIo.Media->ReadOnly = TRUE; - } else { - - IdeDev->BlkIo.Media->ReadOnly = FALSE; - } - - } - } - - if (IdeDev->BlkIo.Media->MediaId != OldMediaInfo.MediaId) { - // - // Media change information got from the device - // - *MediaChange = TRUE; - } - - if (IdeDev->BlkIo.Media->ReadOnly != OldMediaInfo.ReadOnly) { - *MediaChange = TRUE; - IdeDev->BlkIo.Media->MediaId += 1; - } - - if (IdeDev->BlkIo.Media->BlockSize != OldMediaInfo.BlockSize) { - *MediaChange = TRUE; - IdeDev->BlkIo.Media->MediaId += 1; - } - - if (IdeDev->BlkIo.Media->LastBlock != OldMediaInfo.LastBlock) { - *MediaChange = TRUE; - IdeDev->BlkIo.Media->MediaId += 1; - } - - if (IdeDev->BlkIo.Media->MediaPresent != OldMediaInfo.MediaPresent) { - if (IdeDev->BlkIo.Media->MediaPresent) { - // - // when change from no media to media present, reset the MediaId to 1. - // - IdeDev->BlkIo.Media->MediaId = 1; - } else { - // - // when no media, reset the MediaId to zero. - // - IdeDev->BlkIo.Media->MediaId = 0; - } - - *MediaChange = TRUE; - } - - // - // if any change on current existing media, - // the Block I/O protocol need to be reinstalled. - // - if (*MediaChange) { - gBS->ReinstallProtocolInterface ( - IdeDev->Handle, - &gEfiBlockIoProtocolGuid, - &IdeDev->BlkIo, - &IdeDev->BlkIo - ); - } - - if (IdeDev->BlkIo.Media->MediaPresent) { - return EFI_SUCCESS; - } else { - return EFI_NO_MEDIA; - } -} - -/** - This function is called by the AtapiBlkIoReadBlocks() to perform - read from media in block unit. - - The main command used to access media here is READ(10) Command. - READ(10) Command requests that the ATAPI device media transfer - specified data to the host. Data is transferred in block(sector) - unit. The maximum number of blocks that can be transferred once is - 65536. This is the main difference between READ(10) and READ(12) - Command. The maximum number of blocks in READ(12) is 2 power 32. - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @param[in] *Buffer - A pointer to the destination buffer for the data. - - @param[in] Lba - The starting logical block address to read from - on the device media. - - @param[in] NumberOfBlocks - The number of transfer data blocks. - - @return status is fully dependent on the return status - of AtapiPacketCommandIn() function. - -**/ -EFI_STATUS -AtapiReadSectors ( - IN IDE_BLK_IO_DEV *IdeDev, - IN VOID *Buffer, - IN EFI_LBA Lba, - IN UINTN NumberOfBlocks - ) -{ - - ATAPI_PACKET_COMMAND Packet; - ATAPI_READ10_CMD *Read10Packet; - EFI_STATUS Status; - UINTN BlocksRemaining; - UINT32 Lba32; - UINT32 BlockSize; - UINT32 ByteCount; - UINT16 SectorCount; - VOID *PtrBuffer; - UINT16 MaxBlock; - UINTN TimeOut; - - // - // fill command packet for Read(10) command - // - ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); - Read10Packet = &Packet.Read10; - Lba32 = (UINT32) Lba; - PtrBuffer = Buffer; - - BlockSize = IdeDev->BlkIo.Media->BlockSize; - - // - // limit the data bytes that can be transferred by one Read(10) Command - // - MaxBlock = 65535; - - BlocksRemaining = NumberOfBlocks; - - Status = EFI_SUCCESS; - while (BlocksRemaining > 0) { - - if (BlocksRemaining <= MaxBlock) { - - SectorCount = (UINT16) BlocksRemaining; - } else { - - SectorCount = MaxBlock; - } - - // - // fill the Packet data structure - // - - Read10Packet->opcode = ATA_CMD_READ_10; - - // - // Lba0 ~ Lba3 specify the start logical block address of the data transfer. - // Lba0 is MSB, Lba3 is LSB - // - Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff); - Read10Packet->Lba2 = (UINT8) (Lba32 >> 8); - Read10Packet->Lba1 = (UINT8) (Lba32 >> 16); - Read10Packet->Lba0 = (UINT8) (Lba32 >> 24); - - // - // TranLen0 ~ TranLen1 specify the transfer length in block unit. - // TranLen0 is MSB, TranLen is LSB - // - Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff); - Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8); - - ByteCount = SectorCount * BlockSize; - - if (IdeDev->Type == IdeCdRom) { - TimeOut = CDROMLONGTIMEOUT; - } else { - TimeOut = ATAPILONGTIMEOUT; - } - - Status = AtapiPacketCommandIn ( - IdeDev, - &Packet, - (UINT16 *) PtrBuffer, - ByteCount, - TimeOut - ); - if (EFI_ERROR (Status)) { - return Status; - } - - Lba32 += SectorCount; - PtrBuffer = (UINT8 *) PtrBuffer + SectorCount * BlockSize; - BlocksRemaining -= SectorCount; - } - - return Status; -} - -/** - This function is called by the AtapiBlkIoWriteBlocks() to perform - write onto media in block unit. - The main command used to access media here is Write(10) Command. - Write(10) Command requests that the ATAPI device media transfer - specified data to the host. Data is transferred in block (sector) - unit. The maximum number of blocks that can be transferred once is - 65536. - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @param[in] *Buffer - A pointer to the source buffer for the data. - - @param[in] Lba - The starting logical block address to write onto - the device media. - - @param[in] NumberOfBlocks - The number of transfer data blocks. - - @return status is fully dependent on the return status - of AtapiPacketCommandOut() function. - -**/ -EFI_STATUS -AtapiWriteSectors ( - IN IDE_BLK_IO_DEV *IdeDev, - IN VOID *Buffer, - IN EFI_LBA Lba, - IN UINTN NumberOfBlocks - ) -{ - - ATAPI_PACKET_COMMAND Packet; - ATAPI_READ10_CMD *Read10Packet; - - EFI_STATUS Status; - UINTN BlocksRemaining; - UINT32 Lba32; - UINT32 BlockSize; - UINT32 ByteCount; - UINT16 SectorCount; - VOID *PtrBuffer; - UINT16 MaxBlock; - - // - // fill command packet for Write(10) command - // Write(10) command packet has the same data structure as - // Read(10) command packet, - // so here use the Read10Packet data structure - // for the Write(10) command packet. - // - ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); - Read10Packet = &Packet.Read10; - - Lba32 = (UINT32) Lba; - PtrBuffer = Buffer; - - BlockSize = IdeDev->BlkIo.Media->BlockSize; - - // - // limit the data bytes that can be transferred by one Read(10) Command - // - MaxBlock = (UINT16) (65536 / BlockSize); - - BlocksRemaining = NumberOfBlocks; - - Status = EFI_SUCCESS; - while (BlocksRemaining > 0) { - - if (BlocksRemaining >= MaxBlock) { - SectorCount = MaxBlock; - } else { - SectorCount = (UINT16) BlocksRemaining; - } - - // - // Command code is WRITE_10. - // - Read10Packet->opcode = ATA_CMD_WRITE_10; - - // - // Lba0 ~ Lba3 specify the start logical block address of the data transfer. - // Lba0 is MSB, Lba3 is LSB - // - Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff); - Read10Packet->Lba2 = (UINT8) (Lba32 >> 8); - Read10Packet->Lba1 = (UINT8) (Lba32 >> 16); - Read10Packet->Lba0 = (UINT8) (Lba32 >> 24); - - // - // TranLen0 ~ TranLen1 specify the transfer length in block unit. - // TranLen0 is MSB, TranLen is LSB - // - Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff); - Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8); - - ByteCount = SectorCount * BlockSize; - - Status = AtapiPacketCommandOut ( - IdeDev, - &Packet, - (UINT16 *) PtrBuffer, - ByteCount, - ATAPILONGTIMEOUT - ); - if (EFI_ERROR (Status)) { - return Status; - } - - Lba32 += SectorCount; - PtrBuffer = ((UINT8 *) PtrBuffer + SectorCount * BlockSize); - BlocksRemaining -= SectorCount; - } - - return Status; -} - -/** - This function is used to implement the Soft Reset on the specified - ATAPI device. Different from the AtaSoftReset(), here reset is a ATA - Soft Reset Command special for ATAPI device, and it only take effects - on the specified ATAPI device, not on the whole IDE bus. - Since the ATAPI soft reset is needed when device is in exceptional - condition (such as BSY bit is always set ), I think the Soft Reset - command should be sent without waiting for the BSY clear and DRDY - set. - This function is called by IdeBlkIoReset(), - a interface function of Block I/O protocol. - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @retval EFI_SUCCESS - Soft reset completes successfully. - - @retval EFI_DEVICE_ERROR - Any step during the reset process is failed. - -**/ -EFI_STATUS -AtapiSoftReset ( - IN IDE_BLK_IO_DEV *IdeDev - ) -{ - UINT8 Command; - UINT8 DeviceSelect; - EFI_STATUS Status; - - // - // for ATAPI device, no need to wait DRDY ready after device selecting. - // (bit7 and bit5 are both set to 1 for backward compatibility) - // - DeviceSelect = (UINT8) (((BIT7 | BIT5) | (IdeDev->Device << 4))); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect); - - Command = ATA_CMD_SOFT_RESET; - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, Command); - - // - // BSY cleared is the only status return to the host by the device - // when reset is completed. - // slave device needs at most 31s to clear BSY - // - Status = WaitForBSYClear (IdeDev, 31000); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - // - // stall 5 seconds to make the device status stable - // - gBS->Stall (5000000); - - return EFI_SUCCESS; -} - -/** - This function is the ATAPI implementation for ReadBlocks in the - Block I/O Protocol interface. - - @param[in] *IdeBlkIoDev - Indicates the calling context. - - @param[in] MediaId - The media id that the read request is for. - - @param[in] LBA - The starting logical block address to read from - on the device. - - @param[in] BufferSize - The size of the Buffer in bytes. This must be a - multiple of the intrinsic block size of the device. - - @param[out] *Buffer - A pointer to the destination buffer for the data. - The caller is responsible for either having implicit - or explicit ownership of the memory that data is read into. - - @retval EFI_SUCCESS - Read Blocks successfully. - - @retval EFI_DEVICE_ERROR - Read Blocks failed. - - @retval EFI_NO_MEDIA - There is no media in the device. - - @retval EFI_MEDIA_CHANGED - The MediaId is not for the current media. - - @retval EFI_BAD_BUFFER_SIZE - The BufferSize parameter is not a multiple of the - intrinsic block size of the device. - - @retval EFI_INVALID_PARAMETER - The read request contains LBAs that are not valid, - or the data buffer is not valid. - -**/ -EFI_STATUS -AtapiBlkIoReadBlocks ( - IN IDE_BLK_IO_DEV *IdeBlkIoDevice, - IN UINT32 MediaId, - IN EFI_LBA LBA, - IN UINTN BufferSize, - OUT VOID *Buffer - ) -{ - EFI_BLOCK_IO_MEDIA *Media; - UINTN BlockSize; - UINTN NumberOfBlocks; - EFI_STATUS Status; - - BOOLEAN MediaChange; - - if (Buffer == NULL) { - return EFI_INVALID_PARAMETER; - } - - if (BufferSize == 0) { - return EFI_SUCCESS; - } - - // - // ATAPI device media is removable, so it is a must - // to detect media first before read operation - // - MediaChange = FALSE; - Status = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange); - if (EFI_ERROR (Status)) { - - if (IdeBlkIoDevice->Cache != NULL) { - gBS->FreePool (IdeBlkIoDevice->Cache); - IdeBlkIoDevice->Cache = NULL; - } - - return Status; - } - // - // Get the intrinsic block size - // - Media = IdeBlkIoDevice->BlkIo.Media; - BlockSize = Media->BlockSize; - - NumberOfBlocks = BufferSize / BlockSize; - - if (!(Media->MediaPresent)) { - - if (IdeBlkIoDevice->Cache != NULL) { - gBS->FreePool (IdeBlkIoDevice->Cache); - IdeBlkIoDevice->Cache = NULL; - } - return EFI_NO_MEDIA; - - } - - if ((MediaId != Media->MediaId) || MediaChange) { - - if (IdeBlkIoDevice->Cache != NULL) { - gBS->FreePool (IdeBlkIoDevice->Cache); - IdeBlkIoDevice->Cache = NULL; - } - return EFI_MEDIA_CHANGED; - } - - if (BufferSize % BlockSize != 0) { - return EFI_BAD_BUFFER_SIZE; - } - - if (LBA > Media->LastBlock) { - return EFI_INVALID_PARAMETER; - } - - if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) { - return EFI_INVALID_PARAMETER; - } - - if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) { - return EFI_INVALID_PARAMETER; - } - - // - // if all the parameters are valid, then perform read sectors command - // to transfer data from device to host. - // - Status = AtapiReadSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - // - // Read blocks succeeded - // - - // - // save the first block to the cache for performance - // - if (LBA == 0 && !IdeBlkIoDevice->Cache) { - IdeBlkIoDevice->Cache = AllocatePool (BlockSize); - if (IdeBlkIoDevice != NULL) { - CopyMem ((UINT8 *) IdeBlkIoDevice->Cache, (UINT8 *) Buffer, BlockSize); - } - } - - return EFI_SUCCESS; - -} - -/** - This function is the ATAPI implementation for WriteBlocks in the - Block I/O Protocol interface. - - @param[in] *This - Indicates the calling context. - - @param[in] MediaId - The media id that the write request is for. - - @param[in] LBA - The starting logical block address to write onto - the device. - - @param[in] BufferSize - The size of the Buffer in bytes. This must be a - multiple of the intrinsic block size of the device. - - @param[out] *Buffer - A pointer to the source buffer for the data. - The caller is responsible for either having implicit - or explicit ownership of the memory that data is - written from. - - @retval EFI_SUCCESS - Write Blocks successfully. - - @retval EFI_DEVICE_ERROR - Write Blocks failed. - - @retval EFI_NO_MEDIA - There is no media in the device. - - @retval EFI_MEDIA_CHANGE - The MediaId is not for the current media. - - @retval EFI_BAD_BUFFER_SIZE - The BufferSize parameter is not a multiple of the - intrinsic block size of the device. - - @retval EFI_INVALID_PARAMETER - The write request contains LBAs that are not valid, - or the data buffer is not valid. - - TODO: EFI_MEDIA_CHANGED - add return value to function comment - TODO: EFI_WRITE_PROTECTED - add return value to function comment -**/ -EFI_STATUS -AtapiBlkIoWriteBlocks ( - IN IDE_BLK_IO_DEV *IdeBlkIoDevice, - IN UINT32 MediaId, - IN EFI_LBA LBA, - IN UINTN BufferSize, - OUT VOID *Buffer - ) -{ - - EFI_BLOCK_IO_MEDIA *Media; - UINTN BlockSize; - UINTN NumberOfBlocks; - EFI_STATUS Status; - BOOLEAN MediaChange; - - if (LBA == 0 && IdeBlkIoDevice->Cache) { - gBS->FreePool (IdeBlkIoDevice->Cache); - IdeBlkIoDevice->Cache = NULL; - } - - if (Buffer == NULL) { - return EFI_INVALID_PARAMETER; - } - - if (BufferSize == 0) { - return EFI_SUCCESS; - } - - // - // ATAPI device media is removable, - // so it is a must to detect media first before write operation - // - MediaChange = FALSE; - Status = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange); - if (EFI_ERROR (Status)) { - - if (LBA == 0 && IdeBlkIoDevice->Cache) { - gBS->FreePool (IdeBlkIoDevice->Cache); - IdeBlkIoDevice->Cache = NULL; - } - return Status; - } - - // - // Get the intrinsic block size - // - Media = IdeBlkIoDevice->BlkIo.Media; - BlockSize = Media->BlockSize; - NumberOfBlocks = BufferSize / BlockSize; - - if (!(Media->MediaPresent)) { - - if (LBA == 0 && IdeBlkIoDevice->Cache) { - gBS->FreePool (IdeBlkIoDevice->Cache); - IdeBlkIoDevice->Cache = NULL; - } - return EFI_NO_MEDIA; - } - - if ((MediaId != Media->MediaId) || MediaChange) { - - if (LBA == 0 && IdeBlkIoDevice->Cache) { - gBS->FreePool (IdeBlkIoDevice->Cache); - IdeBlkIoDevice->Cache = NULL; - } - return EFI_MEDIA_CHANGED; - } - - if (Media->ReadOnly) { - return EFI_WRITE_PROTECTED; - } - - if (BufferSize % BlockSize != 0) { - return EFI_BAD_BUFFER_SIZE; - } - - if (LBA > Media->LastBlock) { - return EFI_INVALID_PARAMETER; - } - - if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) { - return EFI_INVALID_PARAMETER; - } - - if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) { - return EFI_INVALID_PARAMETER; - } - - // - // if all the parameters are valid, - // then perform write sectors command to transfer data from host to device. - // - Status = AtapiWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - return EFI_SUCCESS; - -} - -/** - This function is used to parse sense data. Only the first - sense data is honoured. - - @param[in] IdeDev Indicates the calling context. - @param[in] SenseCount Count of sense data. - @param[out] Result The parsed result. - - @retval EFI_SUCCESS Successfully parsed. - @retval EFI_INVALID_PARAMETER Count of sense data is zero. - -**/ -EFI_STATUS -ParseSenseData ( - IN IDE_BLK_IO_DEV *IdeDev, - IN UINTN SenseCount, - OUT SENSE_RESULT *Result - ) -{ - ATAPI_REQUEST_SENSE_DATA *SenseData; - - if (SenseCount == 0) { - return EFI_INVALID_PARAMETER; - } - - // - // Only use the first sense data - // - SenseData = IdeDev->SenseData; - *Result = SenseOtherSense; - - switch (SenseData->sense_key) { - case ATA_SK_NO_SENSE: - *Result = SenseNoSenseKey; - break; - case ATA_SK_NOT_READY: - switch (SenseData->addnl_sense_code) { - case ATA_ASC_NO_MEDIA: - *Result = SenseNoMedia; - break; - case ATA_ASC_MEDIA_UPSIDE_DOWN: - *Result = SenseMediaError; - break; - case ATA_ASC_NOT_READY: - if (SenseData->addnl_sense_code_qualifier == ATA_ASCQ_IN_PROGRESS) { - *Result = SenseDeviceNotReadyNeedRetry; - } else { - *Result = SenseDeviceNotReadyNoRetry; - } - break; - } - break; - case ATA_SK_UNIT_ATTENTION: - if (SenseData->addnl_sense_code == ATA_ASC_MEDIA_CHANGE) { - *Result = SenseMediaChange; - } - break; - case ATA_SK_MEDIUM_ERROR: - switch (SenseData->addnl_sense_code) { - case ATA_ASC_MEDIA_ERR1: - case ATA_ASC_MEDIA_ERR2: - case ATA_ASC_MEDIA_ERR3: - case ATA_ASC_MEDIA_ERR4: - *Result = SenseMediaError; - break; - } - break; - default: - break; - } - - return EFI_SUCCESS; -} - -/** - This function reads the pending data in the device. - - @param[in] IdeDev Indicates the calling context. - - @retval EFI_SUCCESS Successfully read. - @retval EFI_NOT_READY The BSY is set avoiding reading. - -**/ -EFI_STATUS -AtapiReadPendingData ( - IN IDE_BLK_IO_DEV *IdeDev - ) -{ - UINT8 AltRegister; - UINT16 TempWordBuffer; - - AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus); - if ((AltRegister & ATA_STSREG_BSY) == ATA_STSREG_BSY) { - return EFI_NOT_READY; - } - if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) { - TempWordBuffer = IDEReadPortB (IdeDev->PciIo,IdeDev->IoPort->Alt.AltStatus); - while ((TempWordBuffer & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) { - IDEReadPortWMultiple ( - IdeDev->PciIo, - IdeDev->IoPort->Data, - 1, - &TempWordBuffer - ); - TempWordBuffer = IDEReadPortB (IdeDev->PciIo,IdeDev->IoPort->Alt.AltStatus); - } - } - return EFI_SUCCESS; -} - -/** - TODO: Add function description - - @param IdeDev TODO: add argument description - @param WriteProtected TODO: add argument description - - @retval EFI_DEVICE_ERROR TODO: Add description for return value - @retval EFI_DEVICE_ERROR TODO: Add description for return value - @retval EFI_SUCCESS TODO: Add description for return value - -**/ -EFI_STATUS -IsLS120orZipWriteProtected ( - IN IDE_BLK_IO_DEV *IdeDev, - OUT BOOLEAN *WriteProtected - ) -{ - EFI_STATUS Status; - - *WriteProtected = FALSE; - - Status = LS120EnableMediaStatus (IdeDev, TRUE); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - // - // the Get Media Status Command is only valid - // if a Set Features/Enable Media Status Command has been priviously issued. - // - if (LS120GetMediaStatus (IdeDev) == EFI_WRITE_PROTECTED) { - - *WriteProtected = TRUE; - } else { - - *WriteProtected = FALSE; - } - - // - // After Get Media Status Command completes, - // Set Features/Disable Media Command should be sent. - // - Status = LS120EnableMediaStatus (IdeDev, FALSE); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - return EFI_SUCCESS; -} -- cgit v1.1