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