--- /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
+ ATAPI_IDENTIFY_DEVICE_CMD,\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 (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
+ 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 = INQUIRY;\r
+ Packet.Inquiry.page_code = 0;\r
+ Packet.Inquiry.allocation_length = sizeof (INQUIRY_DATA);\r
+\r
+ InquiryData = AllocatePool (sizeof (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 (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) | 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 MAX_ATAPI_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) (MAX_ATAPI_BYTE_COUNT & 0x00ff)\r
+ );\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->CylinderMsb,\r
+ (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8)\r
+ );\r
+\r
+ //\r
+ // DEFAULT_CTL:0x0a (0000,1010)\r
+ // Disable interrupt\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, 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, PACKET_CMD);\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) | 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 MAX_ATAPI_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) (MAX_ATAPI_BYTE_COUNT & 0x00ff)\r
+ );\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->CylinderMsb,\r
+ (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8)\r
+ );\r
+\r
+ //\r
+ // DEFAULT_CTL:0x0a (0000,1010)\r
+ // Disable interrupt\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, 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, PACKET_CMD);\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 = EFI_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 = 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
+ 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 (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 = REQUEST_SENSE;\r
+ Packet.RequestSence.allocation_length = sizeof (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 = (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 (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 != SK_NO_SENSE) && ((*SenseCounts) < 20)) {\r
+ //\r
+ // Ptr is word-based pointer\r
+ //\r
+ Ptr += (sizeof (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
+ READ_CAPACITY_DATA Data;\r
+ 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 = READ_CAPACITY;\r
+ Status = AtapiPacketCommandIn (\r
+ IdeDev,\r
+ &Packet,\r
+ (UINT16 *) &Data,\r
+ sizeof (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 = READ_FORMAT_CAPACITY;\r
+ Packet.ReadFormatCapacity.allocation_length_lo = 12;\r
+ Status = AtapiPacketCommandIn (\r
+ IdeDev,\r
+ &Packet,\r
+ (UINT16 *) &FormatData,\r
+ sizeof (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
+ 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 = 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
+ 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 = 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 = ATAPI_SOFT_RESET_CMD;\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
+ 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 SK_NO_SENSE:\r
+ *Result = SenseNoSenseKey;\r
+ break;\r
+ case SK_NOT_READY:\r
+ switch (SenseData->addnl_sense_code) {\r
+ case ASC_NO_MEDIA:\r
+ *Result = SenseNoMedia;\r
+ break;\r
+ case ASC_MEDIA_UPSIDE_DOWN:\r
+ *Result = SenseMediaError;\r
+ break;\r
+ case ASC_NOT_READY:\r
+ if (SenseData->addnl_sense_code_qualifier == ASCQ_IN_PROGRESS) {\r
+ *Result = SenseDeviceNotReadyNeedRetry;\r
+ } else {\r
+ *Result = SenseDeviceNotReadyNoRetry;\r
+ }\r
+ break;\r
+ }\r
+ break;\r
+ case SK_UNIT_ATTENTION:\r
+ if (SenseData->addnl_sense_code == ASC_MEDIA_CHANGE) {\r
+ *Result = SenseMediaChange;\r
+ }\r
+ break;\r
+ case SK_MEDIUM_ERROR:\r
+ switch (SenseData->addnl_sense_code) {\r
+ case ASC_MEDIA_ERR1:\r
+ case ASC_MEDIA_ERR2:\r
+ case ASC_MEDIA_ERR3:\r
+ case 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 & BSY) == BSY) {\r
+ return EFI_NOT_READY;\r
+ }\r
+ if ((AltRegister & (BSY | DRQ)) == DRQ) {\r
+ TempWordBuffer = IDEReadPortB (IdeDev->PciIo,IdeDev->IoPort->Alt.AltStatus);\r
+ while ((TempWordBuffer & (BSY | DRQ)) == 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