--- /dev/null
+/** @file\r
+ Copyright (c) 2006 - 2007, Intel Corporation \r
+ All rights reserved. This program and the accompanying materials \r
+ are licensed and made available under the terms and conditions of the BSD License \r
+ which accompanies this distribution. The full text of the license may be found at \r
+ http://opensource.org/licenses/bsd-license.php \r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \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[in] *IdeDev\r
+ 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\r
+ The media status is achieved successfully and the media\r
+ can be read/written.\r
+ \r
+ @retval EFI_DEVICE_ERROR\r
+ Get Media Status Command is failed.\r
+ \r
+ @retval EFI_NO_MEDIA\r
+ There is no media in the drive.\r
+ \r
+ @retval EFI_WRITE_PROTECTED\r
+ The media is writing protected.\r
+\r
+ @note\r
+ 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
+**/\r
+STATIC\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) {\r
+ return EFI_NO_MEDIA;\r
+ }\r
+\r
+ if (StatusValue & BIT6) {\r
+ return EFI_WRITE_PROTECTED;\r
+ } else {\r
+ return EFI_SUCCESS;\r
+ }\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[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] Enable\r
+ a flag that indicates whether enable or disable media\r
+ status notification.\r
+\r
+ @retval EFI_SUCCESS\r
+ If command completes successfully.\r
+ \r
+ @retval EFI_DEVICE_ERROR\r
+ If command failed.\r
+\r
+**/\r
+STATIC\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
+/**\r
+ This function is called by DiscoverIdeDevice() during its device\r
+ identification.\r
+\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
+\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
+\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
+\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[in] *IdeDev\r
+ 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\r
+ Identify ATAPI device successfully.\r
+ \r
+ @retval EFI_DEVICE_ERROR\r
+ ATAPI Identify Device Command failed or device type\r
+ is not supported by this IDE driver.\r
+\r
+ @note\r
+ Parameter "IdeDev" will be updated in this function.\r
+\r
+ TODO: EFI_OUT_OF_RESOURCES - add return value to function comment\r
+ TODO: EFI_OUT_OF_RESOURCES - add return value to function comment\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->pIdData = 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->pIdData);\r
+ //\r
+ // Make sure the pIdData will not be freed again.\r
+ //\r
+ IdeDev->pIdData = NULL;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Get media removable info from INQUIRY data.\r
+ //\r
+ IdeDev->BlkIo.Media->RemovableMedia = (UINT8) ((IdeDev->pInquiryData->RMB & 0x80) == 0x80);\r
+\r
+ //\r
+ // Identify device type via INQUIRY data.\r
+ //\r
+ switch (IdeDev->pInquiryData->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->pIdData);\r
+ gBS->FreePool (IdeDev->pInquiryData);\r
+ //\r
+ // Make sure the pIdData and pInquiryData will not be freed again.\r
+ //\r
+ IdeDev->pIdData = NULL;\r
+ IdeDev->pInquiryData = 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->pIdData);\r
+ gBS->FreePool (IdeDev->pInquiryData);\r
+ //\r
+ // Make sure the pIdData and pInquiryData will not be freed again.\r
+ //\r
+ IdeDev->pIdData = NULL;\r
+ IdeDev->pInquiryData = NULL;\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Sends out ATAPI Inquiry Packet Command to the specified device.\r
+ This command will return INQUIRY data of the device.\r
+\r
+ @param[in] *IdeDev\r
+ 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\r
+ Inquiry command completes successfully.\r
+ \r
+ @retval EFI_DEVICE_ERROR\r
+ Inquiry command failed.\r
+\r
+ @note\r
+ 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 = 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->pInquiryData = InquiryData;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is used to send out ATAPI commands conforms to the \r
+ Packet Command with PIO Data In Protocol.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *Packet\r
+ pointer pointing to ATAPI_PACKET_COMMAND data structure\r
+ which contains the contents of the command. \r
+\r
+ @param[in] *Buffer\r
+ buffer contained data transferred from device to host.\r
+\r
+ @param[in] ByteCount\r
+ data size in byte unit of the buffer.\r
+\r
+ @param[in] TimeOut\r
+ this parameter is used to specify the timeout \r
+ value for the PioReadWriteData() function. \r
+\r
+ @retval EFI_SUCCESS\r
+ send out the ATAPI packet command successfully\r
+ and device sends data successfully.\r
+ \r
+ @retval EFI_DEVICE_ERROR\r
+ 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
+/**\r
+ This function is used to send out ATAPI commands conforms to the \r
+ Packet Command with PIO Data Out Protocol.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *Packet\r
+ pointer pointing to ATAPI_PACKET_COMMAND data structure\r
+ which contains the contents of the command.\r
+\r
+ @param[in] *Buffer\r
+ buffer contained data transferred from host to device.\r
+\r
+ @param[in] ByteCount\r
+ data size in byte unit of the buffer.\r
+\r
+ @param[in] TimeOut\r
+ this parameter is used to specify the timeout \r
+ value for the PioReadWriteData() function. \r
+\r
+ @retval EFI_SUCCESS\r
+ send out the ATAPI packet command successfully\r
+ and device received data successfully.\r
+ \r
+ @retval EFI_DEVICE_ERROR\r
+ 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
+/**\r
+ This function is called by either AtapiPacketCommandIn() or \r
+ AtapiPacketCommandOut(). It is used to transfer data between\r
+ host and device. The data direction is specified by the fourth\r
+ parameter.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *Buffer\r
+ buffer contained data transferred between host and device.\r
+\r
+ @param[in] ByteCount\r
+ data size in byte unit of the buffer.\r
+\r
+ @param[in] Read\r
+ 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
+\r
+ @param[in] TimeOut\r
+ timeout value for wait DRQ ready before each data \r
+ stream's transfer.\r
+\r
+ @retval EFI_SUCCESS\r
+ data is transferred successfully.\r
+ \r
+ @retval EFI_DEVICE_ERROR\r
+ the device failed to transfer data.\r
+\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
+ Sends out ATAPI Test Unit Ready Packet Command to the specified device\r
+ to find out whether device is accessible.\r
+\r
+ @param[in] *IdeDev Pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+ @param[in] *SenseCount Sense count 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 UINTN *SenseCount\r
+ )\r
+{\r
+ ATAPI_PACKET_COMMAND Packet;\r
+ EFI_STATUS Status;\r
+\r
+ *SenseCount = 0;\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
+ *SenseCount = 0;\r
+ return Status;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Sends out ATAPI Request Sense Packet Command to the specified device.\r
+ This command will return all the current Sense data in the device. \r
+ This function will pack all the Sense data in one single buffer.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[out] **SenseBuffers\r
+ 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
+ @param[out] *BufUnit\r
+ record the unit size of the sense data block in the SenseBuffers,\r
+\r
+ @param[out] *BufNumbers\r
+ record the number of units in the SenseBuffers.\r
+\r
+ @retval EFI_SUCCESS\r
+ Request Sense command completes successfully.\r
+ \r
+ @retval EFI_DEVICE_ERROR\r
+ Request Sense command failed.\r
+\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 = 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
+/**\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[in] *IdeDev Pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+ @param[in] SenseCount Sense count 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
+\r
+ @note Parameter "IdeDev" will be updated in this function.\r
+\r
+ TODO: EFI_NOT_READY - add return value to function comment\r
+**/\r
+EFI_STATUS\r
+AtapiReadCapacity (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ OUT UINTN *SenseCount\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
+\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
+ *SenseCount = 0;\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
+ *SenseCount = 0;\r
+ return Status;\r
+ }\r
+\r
+ SenseStatus = AtapiRequestSense (IdeDev, SenseCount);\r
+\r
+ if (!EFI_ERROR (SenseStatus)) {\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+\r
+ if (IdeDev->Type == IdeCdRom) {\r
+\r
+ IdeDev->BlkIo.Media->LastBlock = (Data.LastLba3 << 24) |\r
+ (Data.LastLba2 << 16) |\r
+ (Data.LastLba1 << 8) |\r
+ Data.LastLba0;\r
+\r
+ if (IdeDev->BlkIo.Media->LastBlock != 0) {\r
+\r
+ IdeDev->BlkIo.Media->BlockSize = (Data.BlockSize3 << 24) |\r
+ (Data.BlockSize2 << 16) |\r
+ (Data.BlockSize1 << 8) |\r
+ Data.BlockSize0;\r
+\r
+ IdeDev->BlkIo.Media->MediaPresent = TRUE;\r
+ } else {\r
+ IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
+ return EFI_DEVICE_ERROR;\r
+ }\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 = (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
+ *SenseCount = 0;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+}\r
+\r
+/**\r
+ Used before read/write blocks from/to ATAPI device media. \r
+ Since ATAPI device media is removable, it is necessary to detect\r
+ whether media is present and get current present media's\r
+ information, and if media has been changed, Block I/O Protocol\r
+ need to be reinstalled.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[out] *MediaChange\r
+ return value that indicates if the media of the device has been\r
+ changed.\r
+\r
+ @retval EFI_SUCCESS\r
+ media found successfully.\r
+ \r
+ @retval EFI_DEVICE_ERROR\r
+ any error encounters during media detection.\r
+ \r
+ @retval EFI_NO_MEDIA\r
+ 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
+ UINTN SenseCount;\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, &SenseCount);\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
+\r
+ ParseSenseData (IdeDev, SenseCount, &SResult);\r
+\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, &SenseCount);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ RetryTimes--;\r
+ continue;\r
+ } else {\r
+\r
+ ParseSenseData (IdeDev, SenseCount, &SResult);\r
+\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[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *Buffer\r
+ A pointer to the destination buffer for the data. \r
+\r
+ @param[in] Lba\r
+ The starting logical block address to read from \r
+ on the device media.\r
+\r
+ @param[in] NumberOfBlocks\r
+ The number of transfer data blocks.\r
+\r
+ @return status is fully dependent on the return status\r
+ 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[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *Buffer\r
+ A pointer to the source buffer for the data. \r
+\r
+ @param[in] Lba\r
+ The starting logical block address to write onto \r
+ the device media.\r
+\r
+ @param[in] NumberOfBlocks\r
+ The number of transfer data blocks.\r
+\r
+ @return status is fully dependent on the return status\r
+ 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
+/**\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[in] *IdeDev\r
+ 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\r
+ Soft reset completes successfully.\r
+ \r
+ @retval EFI_DEVICE_ERROR\r
+ 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[in] *IdeBlkIoDev\r
+ Indicates the calling context.\r
+\r
+ @param[in] MediaId\r
+ The media id that the read request is for.\r
+\r
+ @param[in] LBA\r
+ The starting logical block address to read from \r
+ on the device.\r
+\r
+ @param[in] BufferSize\r
+ The size of the Buffer in bytes. This must be a\r
+ multiple of the intrinsic block size of the device.\r
+\r
+ @param[out] *Buffer\r
+ A pointer to the destination buffer for the data. \r
+ The caller is responsible for either having implicit\r
+ or explicit ownership of the memory that data is read into.\r
+\r
+ @retval EFI_SUCCESS\r
+ Read Blocks successfully.\r
+ \r
+ @retval EFI_DEVICE_ERROR\r
+ Read Blocks failed.\r
+ \r
+ @retval EFI_NO_MEDIA\r
+ There is no media in the device.\r
+ \r
+ @retval EFI_MEDIA_CHANGED\r
+ The MediaId is not for the current media.\r
+ \r
+ @retval EFI_BAD_BUFFER_SIZE\r
+ The BufferSize parameter is not a multiple of the\r
+ intrinsic block size of the device.\r
+ \r
+ @retval EFI_INVALID_PARAMETER\r
+ The read request contains LBAs that are not valid,\r
+ or the data buffer is not valid.\r
+\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) {\r
+ IdeBlkIoDevice->Cache = AllocatePool (BlockSize);\r
+ if (IdeBlkIoDevice != NULL) {\r
+ CopyMem ((UINT8 *) IdeBlkIoDevice->Cache, (UINT8 *) Buffer, BlockSize);\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+}\r
+\r
+/**\r
+ This function is the ATAPI implementation for WriteBlocks in the\r
+ Block I/O Protocol interface.\r
+\r
+ @param[in] *This\r
+ Indicates the calling context.\r
+\r
+ @param[in] MediaId\r
+ The media id that the write request is for.\r
+\r
+ @param[in] LBA\r
+ The starting logical block address to write onto \r
+ the device.\r
+\r
+ @param[in] BufferSize\r
+ The size of the Buffer in bytes. This must be a\r
+ multiple of the intrinsic block size of the device.\r
+\r
+ @param[out] *Buffer\r
+ A pointer to the source buffer for the data. \r
+ The caller is responsible for either having implicit\r
+ or explicit ownership of the memory that data is \r
+ written from.\r
+\r
+ @retval EFI_SUCCESS\r
+ Write Blocks successfully.\r
+ \r
+ @retval EFI_DEVICE_ERROR\r
+ Write Blocks failed.\r
+ \r
+ @retval EFI_NO_MEDIA\r
+ There is no media in the device.\r
+ \r
+ @retval EFI_MEDIA_CHANGE\r
+ The MediaId is not for the current media.\r
+ \r
+ @retval EFI_BAD_BUFFER_SIZE\r
+ The BufferSize parameter is not a multiple of the\r
+ intrinsic block size of the device.\r
+ \r
+ @retval EFI_INVALID_PARAMETER\r
+ The write request contains LBAs that are not valid,\r
+ or the data buffer is not valid.\r
+\r
+ TODO: EFI_MEDIA_CHANGED - add return value to function comment\r
+ TODO: EFI_WRITE_PROTECTED - add return value to function comment\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) {\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) {\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) {\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) {\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
+ This function is used to parse sense data. Only the first\r
+ sense data is honoured.\r
+\r
+ @param[in] IdeDev Indicates the calling context.\r
+ @param[in] SenseCount Count of sense data.\r
+ @param[out] 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
+ This function reads the pending data in the device.\r
+\r
+ @param[in] 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
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param WriteProtected TODO: add argument description\r
+\r
+ @retval EFI_DEVICE_ERROR TODO: Add description for return value\r
+ @retval EFI_DEVICE_ERROR TODO: Add description for return value\r
+ @retval EFI_SUCCESS TODO: Add description for return value\r
+\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
+++ /dev/null
-/** @file\r
- Copyright (c) 2006 - 2007, Intel Corporation \r
- All rights reserved. This program and the accompanying materials \r
- are licensed and made available under the terms and conditions of the BSD License \r
- which accompanies this distribution. The full text of the license may be found at \r
- http://opensource.org/licenses/bsd-license.php \r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \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[in] *IdeDev\r
- 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\r
- The media status is achieved successfully and the media\r
- can be read/written.\r
- \r
- @retval EFI_DEVICE_ERROR\r
- Get Media Status Command is failed.\r
- \r
- @retval EFI_NO_MEDIA\r
- There is no media in the drive.\r
- \r
- @retval EFI_WRITE_PROTECTED\r
- The media is writing protected.\r
-\r
- @note\r
- 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
-**/\r
-STATIC\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) {\r
- return EFI_NO_MEDIA;\r
- }\r
-\r
- if (StatusValue & BIT6) {\r
- return EFI_WRITE_PROTECTED;\r
- } else {\r
- return EFI_SUCCESS;\r
- }\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[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @param[in] Enable\r
- a flag that indicates whether enable or disable media\r
- status notification.\r
-\r
- @retval EFI_SUCCESS\r
- If command completes successfully.\r
- \r
- @retval EFI_DEVICE_ERROR\r
- If command failed.\r
-\r
-**/\r
-STATIC\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
-/**\r
- This function is called by DiscoverIdeDevice() during its device\r
- identification.\r
-\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
-\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
-\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
-\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[in] *IdeDev\r
- 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\r
- Identify ATAPI device successfully.\r
- \r
- @retval EFI_DEVICE_ERROR\r
- ATAPI Identify Device Command failed or device type\r
- is not supported by this IDE driver.\r
-\r
- @note\r
- Parameter "IdeDev" will be updated in this function.\r
-\r
- TODO: EFI_OUT_OF_RESOURCES - add return value to function comment\r
- TODO: EFI_OUT_OF_RESOURCES - add return value to function comment\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->pIdData = 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->pIdData);\r
- //\r
- // Make sure the pIdData will not be freed again.\r
- //\r
- IdeDev->pIdData = NULL;\r
- return EFI_DEVICE_ERROR;\r
- }\r
- //\r
- // Get media removable info from INQUIRY data.\r
- //\r
- IdeDev->BlkIo.Media->RemovableMedia = (UINT8) ((IdeDev->pInquiryData->RMB & 0x80) == 0x80);\r
-\r
- //\r
- // Identify device type via INQUIRY data.\r
- //\r
- switch (IdeDev->pInquiryData->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->pIdData);\r
- gBS->FreePool (IdeDev->pInquiryData);\r
- //\r
- // Make sure the pIdData and pInquiryData will not be freed again.\r
- //\r
- IdeDev->pIdData = NULL;\r
- IdeDev->pInquiryData = 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->pIdData);\r
- gBS->FreePool (IdeDev->pInquiryData);\r
- //\r
- // Make sure the pIdData and pInquiryData will not be freed again.\r
- //\r
- IdeDev->pIdData = NULL;\r
- IdeDev->pInquiryData = NULL;\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Sends out ATAPI Inquiry Packet Command to the specified device.\r
- This command will return INQUIRY data of the device.\r
-\r
- @param[in] *IdeDev\r
- 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\r
- Inquiry command completes successfully.\r
- \r
- @retval EFI_DEVICE_ERROR\r
- Inquiry command failed.\r
-\r
- @note\r
- 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 = 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->pInquiryData = InquiryData;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- This function is used to send out ATAPI commands conforms to the \r
- Packet Command with PIO Data In Protocol.\r
-\r
- @param[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @param[in] *Packet\r
- pointer pointing to ATAPI_PACKET_COMMAND data structure\r
- which contains the contents of the command. \r
-\r
- @param[in] *Buffer\r
- buffer contained data transferred from device to host.\r
-\r
- @param[in] ByteCount\r
- data size in byte unit of the buffer.\r
-\r
- @param[in] TimeOut\r
- this parameter is used to specify the timeout \r
- value for the PioReadWriteData() function. \r
-\r
- @retval EFI_SUCCESS\r
- send out the ATAPI packet command successfully\r
- and device sends data successfully.\r
- \r
- @retval EFI_DEVICE_ERROR\r
- 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
-/**\r
- This function is used to send out ATAPI commands conforms to the \r
- Packet Command with PIO Data Out Protocol.\r
-\r
- @param[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @param[in] *Packet\r
- pointer pointing to ATAPI_PACKET_COMMAND data structure\r
- which contains the contents of the command.\r
-\r
- @param[in] *Buffer\r
- buffer contained data transferred from host to device.\r
-\r
- @param[in] ByteCount\r
- data size in byte unit of the buffer.\r
-\r
- @param[in] TimeOut\r
- this parameter is used to specify the timeout \r
- value for the PioReadWriteData() function. \r
-\r
- @retval EFI_SUCCESS\r
- send out the ATAPI packet command successfully\r
- and device received data successfully.\r
- \r
- @retval EFI_DEVICE_ERROR\r
- 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
-/**\r
- This function is called by either AtapiPacketCommandIn() or \r
- AtapiPacketCommandOut(). It is used to transfer data between\r
- host and device. The data direction is specified by the fourth\r
- parameter.\r
-\r
- @param[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @param[in] *Buffer\r
- buffer contained data transferred between host and device.\r
-\r
- @param[in] ByteCount\r
- data size in byte unit of the buffer.\r
-\r
- @param[in] Read\r
- 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
-\r
- @param[in] TimeOut\r
- timeout value for wait DRQ ready before each data \r
- stream's transfer.\r
-\r
- @retval EFI_SUCCESS\r
- data is transferred successfully.\r
- \r
- @retval EFI_DEVICE_ERROR\r
- the device failed to transfer data.\r
-\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
- Sends out ATAPI Test Unit Ready Packet Command to the specified device\r
- to find out whether device is accessible.\r
-\r
- @param[in] *IdeDev Pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
- @param[in] *SenseCount Sense count 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 UINTN *SenseCount\r
- )\r
-{\r
- ATAPI_PACKET_COMMAND Packet;\r
- EFI_STATUS Status;\r
-\r
- *SenseCount = 0;\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
- *SenseCount = 0;\r
- return Status;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Sends out ATAPI Request Sense Packet Command to the specified device.\r
- This command will return all the current Sense data in the device. \r
- This function will pack all the Sense data in one single buffer.\r
-\r
- @param[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @param[out] **SenseBuffers\r
- 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
- @param[out] *BufUnit\r
- record the unit size of the sense data block in the SenseBuffers,\r
-\r
- @param[out] *BufNumbers\r
- record the number of units in the SenseBuffers.\r
-\r
- @retval EFI_SUCCESS\r
- Request Sense command completes successfully.\r
- \r
- @retval EFI_DEVICE_ERROR\r
- Request Sense command failed.\r
-\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 = 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
-/**\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[in] *IdeDev Pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
- @param[in] SenseCount Sense count 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
-\r
- @note Parameter "IdeDev" will be updated in this function.\r
-\r
- TODO: EFI_NOT_READY - add return value to function comment\r
-**/\r
-EFI_STATUS\r
-AtapiReadCapacity (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- OUT UINTN *SenseCount\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
-\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
- *SenseCount = 0;\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
- *SenseCount = 0;\r
- return Status;\r
- }\r
-\r
- SenseStatus = AtapiRequestSense (IdeDev, SenseCount);\r
-\r
- if (!EFI_ERROR (SenseStatus)) {\r
-\r
- if (!EFI_ERROR (Status)) {\r
-\r
- if (IdeDev->Type == IdeCdRom) {\r
-\r
- IdeDev->BlkIo.Media->LastBlock = (Data.LastLba3 << 24) |\r
- (Data.LastLba2 << 16) |\r
- (Data.LastLba1 << 8) |\r
- Data.LastLba0;\r
-\r
- if (IdeDev->BlkIo.Media->LastBlock != 0) {\r
-\r
- IdeDev->BlkIo.Media->BlockSize = (Data.BlockSize3 << 24) |\r
- (Data.BlockSize2 << 16) |\r
- (Data.BlockSize1 << 8) |\r
- Data.BlockSize0;\r
-\r
- IdeDev->BlkIo.Media->MediaPresent = TRUE;\r
- } else {\r
- IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
- return EFI_DEVICE_ERROR;\r
- }\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 = (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
- *SenseCount = 0;\r
- return EFI_DEVICE_ERROR;\r
- }\r
-}\r
-\r
-/**\r
- Used before read/write blocks from/to ATAPI device media. \r
- Since ATAPI device media is removable, it is necessary to detect\r
- whether media is present and get current present media's\r
- information, and if media has been changed, Block I/O Protocol\r
- need to be reinstalled.\r
-\r
- @param[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @param[out] *MediaChange\r
- return value that indicates if the media of the device has been\r
- changed.\r
-\r
- @retval EFI_SUCCESS\r
- media found successfully.\r
- \r
- @retval EFI_DEVICE_ERROR\r
- any error encounters during media detection.\r
- \r
- @retval EFI_NO_MEDIA\r
- 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
- UINTN SenseCount;\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, &SenseCount);\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
-\r
- ParseSenseData (IdeDev, SenseCount, &SResult);\r
-\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, &SenseCount);\r
-\r
- if (EFI_ERROR (Status)) {\r
- RetryTimes--;\r
- continue;\r
- } else {\r
-\r
- ParseSenseData (IdeDev, SenseCount, &SResult);\r
-\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[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @param[in] *Buffer\r
- A pointer to the destination buffer for the data. \r
-\r
- @param[in] Lba\r
- The starting logical block address to read from \r
- on the device media.\r
-\r
- @param[in] NumberOfBlocks\r
- The number of transfer data blocks.\r
-\r
- @return status is fully dependent on the return status\r
- 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[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @param[in] *Buffer\r
- A pointer to the source buffer for the data. \r
-\r
- @param[in] Lba\r
- The starting logical block address to write onto \r
- the device media.\r
-\r
- @param[in] NumberOfBlocks\r
- The number of transfer data blocks.\r
-\r
- @return status is fully dependent on the return status\r
- 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
-/**\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[in] *IdeDev\r
- 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\r
- Soft reset completes successfully.\r
- \r
- @retval EFI_DEVICE_ERROR\r
- 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[in] *IdeBlkIoDev\r
- Indicates the calling context.\r
-\r
- @param[in] MediaId\r
- The media id that the read request is for.\r
-\r
- @param[in] LBA\r
- The starting logical block address to read from \r
- on the device.\r
-\r
- @param[in] BufferSize\r
- The size of the Buffer in bytes. This must be a\r
- multiple of the intrinsic block size of the device.\r
-\r
- @param[out] *Buffer\r
- A pointer to the destination buffer for the data. \r
- The caller is responsible for either having implicit\r
- or explicit ownership of the memory that data is read into.\r
-\r
- @retval EFI_SUCCESS\r
- Read Blocks successfully.\r
- \r
- @retval EFI_DEVICE_ERROR\r
- Read Blocks failed.\r
- \r
- @retval EFI_NO_MEDIA\r
- There is no media in the device.\r
- \r
- @retval EFI_MEDIA_CHANGED\r
- The MediaId is not for the current media.\r
- \r
- @retval EFI_BAD_BUFFER_SIZE\r
- The BufferSize parameter is not a multiple of the\r
- intrinsic block size of the device.\r
- \r
- @retval EFI_INVALID_PARAMETER\r
- The read request contains LBAs that are not valid,\r
- or the data buffer is not valid.\r
-\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) {\r
- IdeBlkIoDevice->Cache = AllocatePool (BlockSize);\r
- if (IdeBlkIoDevice != NULL) {\r
- CopyMem ((UINT8 *) IdeBlkIoDevice->Cache, (UINT8 *) Buffer, BlockSize);\r
- }\r
- }\r
-\r
- return EFI_SUCCESS;\r
-\r
-}\r
-\r
-/**\r
- This function is the ATAPI implementation for WriteBlocks in the\r
- Block I/O Protocol interface.\r
-\r
- @param[in] *This\r
- Indicates the calling context.\r
-\r
- @param[in] MediaId\r
- The media id that the write request is for.\r
-\r
- @param[in] LBA\r
- The starting logical block address to write onto \r
- the device.\r
-\r
- @param[in] BufferSize\r
- The size of the Buffer in bytes. This must be a\r
- multiple of the intrinsic block size of the device.\r
-\r
- @param[out] *Buffer\r
- A pointer to the source buffer for the data. \r
- The caller is responsible for either having implicit\r
- or explicit ownership of the memory that data is \r
- written from.\r
-\r
- @retval EFI_SUCCESS\r
- Write Blocks successfully.\r
- \r
- @retval EFI_DEVICE_ERROR\r
- Write Blocks failed.\r
- \r
- @retval EFI_NO_MEDIA\r
- There is no media in the device.\r
- \r
- @retval EFI_MEDIA_CHANGE\r
- The MediaId is not for the current media.\r
- \r
- @retval EFI_BAD_BUFFER_SIZE\r
- The BufferSize parameter is not a multiple of the\r
- intrinsic block size of the device.\r
- \r
- @retval EFI_INVALID_PARAMETER\r
- The write request contains LBAs that are not valid,\r
- or the data buffer is not valid.\r
-\r
- TODO: EFI_MEDIA_CHANGED - add return value to function comment\r
- TODO: EFI_WRITE_PROTECTED - add return value to function comment\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) {\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) {\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) {\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) {\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
- This function is used to parse sense data. Only the first\r
- sense data is honoured.\r
-\r
- @param[in] IdeDev Indicates the calling context.\r
- @param[in] SenseCount Count of sense data.\r
- @param[out] 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
- This function reads the pending data in the device.\r
-\r
- @param[in] 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
- TODO: Add function description\r
-\r
- @param IdeDev TODO: add argument description\r
- @param WriteProtected TODO: add argument description\r
-\r
- @retval EFI_DEVICE_ERROR TODO: Add description for return value\r
- @retval EFI_DEVICE_ERROR TODO: Add description for return value\r
- @retval EFI_SUCCESS TODO: Add description for return value\r
-\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