//********************************************************************** //********************************************************************** //** ** //** (C)Copyright 1985-2006, American Megatrends, Inc. ** //** ** //** All Rights Reserved. ** //** ** //** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** //** ** //** Phone: (770)-246-8600 ** //** ** //********************************************************************** //********************************************************************** //********************************************************************** // // $Header: /Alaska/SOURCE/Modules/USBRecovery/UsbBotPeimSrc/PeiAtapi.c 11 11/24/12 5:47a Ryanchou $ // // $Revision: 11 $ // // $Date: 11/24/12 5:47a $ // //********************************************************************** // Revision History // ---------------- // $Log: /Alaska/SOURCE/Modules/USBRecovery/UsbBotPeimSrc/PeiAtapi.c $ // // 11 11/24/12 5:47a Ryanchou // [TAG] EIP103990 // [Category] Improvement // [Description] Synchronized with USB PEI module 4.6.3_USB_08.10.24. // [Files] EhciPei.c, EhciPei.h, OhciPei.c, OhciPei.h, UhcPeim.c, // BotPeim.c, BotPeim.h, PeiAtapi.c, UsbBotPeim.c, UsbBotPeim.h, // HubPeim.c, UsbPeim.c, XhciPei.c, XhciPei.h, HubPeim.h, PeiUsbLib.c, // PeiUsbLib.h, UsbPeim.h // // 10 10/24/11 5:59a Ryanchou // [TAG] EIP69936 // [Category] Bug Fix // [Severity] Normal // [Symptom] USB ODD recovery fail // [RootCause] The device needs 4 sec to respond to Inquiry command, the // current timeout value is 2 sec // [Solution] Increase the timeout value to 4 sec. // [Files] PeiAtapi.c // // 9 8/18/10 4:19p Olegi // Klockwork related fixes; EIP37978 // // 8 4/06/10 3:27p Fasihm // EIP#31987 - Added the generic USBRecovery Fix in the module. // // 7 10/21/08 5:58p Michaela // Added EHCI-related fixes for issues // that may occur if EHCI is used before // USB Recovery is invoked: // Added SDL Tokens: // PEI_EHCI_PCI_BDFS and // PEI_EHCI_MEM_BASE_ADDRESSES. // // Removed/modified some debugging // development code: // Removed SDL Tokens: // USBR_DEBUG_SUPPORT and // USBR_SERIAL_PORT_AVAILABLE // Removed Elinks: // UsbRecoveryDebug_DIR and // $(BUILD_DIR)\UsbRecoveryDebugDxe.ffs // Modified SDL Token: // FORCE_RECOVERY to default value of 0. // // (See this module's Help documentation // for more information.) // // 6 7/29/08 5:51p Michaela // 1) Updated code to move most porting tasks to SDL // 2) Added more debug break points and improved interactive // debugging capability for when a serial port is not available. // 3) Updated help files // // 5 7/18/08 5:05p Michaela // 1 File-level debugging is now available // 2 AMI_USB_DEBUG_INTERFACE.WaitConsoleKey() now returns // the keypress so that conditional debugging can // be dynamic (alphanumeric keys only) // 3 Added more function headers. // 4 Removed code that will never be used (I.e., Bala?). // 5 Moved typedef, contants and extern declarations // into header files. // 6 Now all controller blocks are enabled for SB700 // (EHCI controllers route to companion controller // by default) // 7 Removed unused constants and typedefs n OhciPei.h // (also reorganized the file to make it more // readable.) // 8 Renamed many functions/variables according to // coding standard. // 9 Removed code initializing data structures for // periodic lists, as this is not needed. // 10 Removed the CONTROLLER_TYPE SDL token to // allow UHCI and OHCI controllers to supported // simultaneously. (modified MAKE files // accordingly) // // 4 7/10/08 6:38p Michaela // Updated to support OHCI controllers // // 3 8/17/07 4:35p Ambikas // // 2 10/02/06 7:24p Sivagarn // - Fixed the bug in identifying partition table entries // - Updated function headers and converted to AMI coding standard // // 1 9/22/06 12:17p Sivagarn // - Included Recovery code in Source // // 1 9/22/06 12:14p Sivagarn // - Initial checkin // - Included Recovery code in Source // //***************************************************************************** // //---------------------------------------------------------------------------- // // Name: PeiAtapi.C // // Description: This file belongs to "Framework". // This file is modified by AMI to include copyright message, // appropriate header and integration code. // This file contains generic routines needed for USB recovery // PEIM // //---------------------------------------------------------------------------- // /*++ This file contains a 'Sample Driver' and is licensed as such under the terms of your license agreement with Intel or your vendor. This file may be modified by the user, subject to the additional terms of the license agreement --*/ /*++ Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved This software and associated documentation (if any) is furnished under a license and may only be used or copied in accordance with the terms of the license. Except as permitted by such license, no part of this software or documentation may be reproduced, stored in a retrieval system, or transmitted in any form or by any means without the express written consent of Intel Corporation. Module Name: PeiAtapi.c Abstract: Pei USB ATATPI command implementations --*/ #include "UsbBotPeim.h" #include "BotPeim.h" #include "Atapi.h" #define MAXSENSEKEY 5 // External function declaration extern VOID ZeroMem ( IN VOID *Buffer, IN UINTN Size ); // Function prototype VOID PeiUsbValidatePartitionTable ( EFI_PEI_SERVICES **PeiServices, UINT8 *Buffer, UINTN LastBlock, UINT32 *FdEmulOffset ); // //---------------------------------------------------------------------------- // Procedure: PeiUsbInquiry // // Description: This function issues the ATA Inquiry command to the USB // mass storage device // // Input: **PeiServices Pointer to the PEI services table // *PeiBotDevice Pointer to the PEI_BOT_DEVICE structure // // Output: Return Status based on the command // //---------------------------------------------------------------------------- // EFI_STATUS PeiUsbInquiry ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_BOT_DEVICE *PeiBotDevice ) { ATAPI_PACKET_COMMAND Packet; EFI_STATUS Status; USB_INQUIRY_DATA Idata; // Fill command packet ZeroMem( &Packet, sizeof(ATAPI_PACKET_COMMAND) ); ZeroMem( &Idata, sizeof(USB_INQUIRY_DATA) ); Packet.Inquiry.opcode = INQUIRY; Packet.Inquiry.page_code = 0; Packet.Inquiry.allocation_length = sizeof(USB_INQUIRY_DATA); // Send command packet Status = PeiAtapiCommand( PeiServices, PeiBotDevice, &Packet, sizeof(ATAPI_PACKET_COMMAND), &Idata, sizeof(USB_INQUIRY_DATA), EfiUsbDataIn, 4000 ); //(EIP69936) if ( EFI_ERROR( Status ) ) { return EFI_DEVICE_ERROR; } if ( (Idata.peripheral_type & 0x1f) == 0x05 ) { PeiBotDevice->DeviceType = USBCDROM; PeiBotDevice->Media.BlockSize = 0x800; } else { PeiBotDevice->DeviceType = USBFLOPPY; PeiBotDevice->Media.BlockSize = 0x200; } return EFI_SUCCESS; } // //---------------------------------------------------------------------------- // Procedure: PeiUsbTestUnitReady // // Description: This function issues the ATA Test Unit Ready command to the USB // mass storage device // // Input: **PeiServices Pointer to the PEI services table // *PeiBotDevice Pointer to the PEI_BOT_DEVICE structure // // Output: Return Status based on the command // //---------------------------------------------------------------------------- // EFI_STATUS PeiUsbTestUnitReady ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_BOT_DEVICE *PeiBotDevice ) { EFI_STATUS Status; ATAPI_PACKET_COMMAND Packet; // Fill command packet ZeroMem( &Packet, sizeof(ATAPI_PACKET_COMMAND) ); Packet.TestUnitReady.opcode = TEST_UNIT_READY; // Send command packet Status = PeiAtapiCommand( PeiServices, PeiBotDevice, &Packet, sizeof(ATAPI_PACKET_COMMAND), NULL, 0, EfiUsbNoData, 2000 ); if ( EFI_ERROR( Status ) ) { return EFI_DEVICE_ERROR; } return EFI_SUCCESS; } // //---------------------------------------------------------------------------- // Procedure: PeiUsbRequestSense // // Description: This function issues the ATA Request Sense command to the USB // mass storage device // // Input: **PeiServices Pointer to the PEI services table // *PeiBotDevice Pointer to the PEI_BOT_DEVICE structure // *SenseCounts Buffer to return sense key data // *SenseKeyBuffer Buffer used for internal use // // Output: Return Status based on the command // //---------------------------------------------------------------------------- // EFI_STATUS PeiUsbRequestSense ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_BOT_DEVICE *PeiBotDevice, IN UINT8 *SenseKeyBuffer ) { EFI_STATUS Status; ATAPI_PACKET_COMMAND Packet; // Fill command packet for Request Sense Packet Command ZeroMem( &Packet, sizeof(ATAPI_PACKET_COMMAND) ); Packet.RequestSence.opcode = REQUEST_SENSE; Packet.RequestSence.allocation_length = sizeof(REQUEST_SENSE_DATA); // Send out Request Sense Packet Command and get one Sense // data form device. Status = PeiAtapiCommand( PeiServices, PeiBotDevice, &Packet, sizeof(ATAPI_PACKET_COMMAND), (VOID *) SenseKeyBuffer, sizeof(REQUEST_SENSE_DATA), EfiUsbDataIn, 2000 ); // Failed to get Sense data if ( EFI_ERROR( Status ) ) { return EFI_DEVICE_ERROR; } return EFI_SUCCESS; } // //---------------------------------------------------------------------------- // Procedure: PeiUsbReadCapacity // // Description: This function issues the ATA Read Capacity command to the USB // mass storage device // // Input: **PeiServices Pointer to the PEI services table // *PeiBotDevice Pointer to the PEI_BOT_DEVICE structure // // Output: Return Status based on the command // //---------------------------------------------------------------------------- // EFI_STATUS PeiUsbReadCapacity ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_BOT_DEVICE *PeiBotDevice ) { EFI_STATUS Status; ATAPI_PACKET_COMMAND Packet; READ_CAPACITY_DATA Data; UINT8 Buffer[512]; ZeroMem( &Data, sizeof(READ_CAPACITY_DATA) ); ZeroMem( &Packet, sizeof(ATAPI_PACKET_COMMAND) ); Packet.Inquiry.opcode = READ_CAPACITY; // Send command packet Status = PeiAtapiCommand( PeiServices, PeiBotDevice, &Packet, sizeof(ATAPI_PACKET_COMMAND), (VOID *) &Data, sizeof(READ_CAPACITY_DATA), EfiUsbDataIn, 2000 ); if ( EFI_ERROR( Status ) ) { return EFI_DEVICE_ERROR; } PeiBotDevice->Media.LastBlock = (Data.LastLba3 << 24) | (Data.LastLba2 << 16) | (Data.LastLba1 << 8) | Data.LastLba0; // AMI Changes ->> //This is the right place to set Medium BlockSize. PeiBotDevice->Media.BlockSize = (Data.BlockSize3 << 24) | (Data.BlockSize2 << 16) | (Data.BlockSize1 << 8) | Data.BlockSize0; // <-- AMI Changes PeiBotDevice->Media.MediaPresent = TRUE; // BIOS Forced FDD option to emulate USB Key Hard Drive as Floppy // Do Floppy emulation only for Harddrive/Direct Access Device if (PeiBotDevice->DeviceType == USBFLOPPY) { Status = PeiUsbRead10( PeiServices, PeiBotDevice, Buffer, 0, /*StartLBA*/ 1 /*NumberOfBlocks*/ ); if ( EFI_ERROR( Status ) ) { // Don't return error, as this shouldn't // messup with ReadCapacity return EFI_SUCCESS; } PeiUsbValidatePartitionTable( PeiServices, Buffer, PeiBotDevice->Media.LastBlock, &(PeiBotDevice->FdEmulOffset) ); } return EFI_SUCCESS; } // AMI Changes ->> // //---------------------------------------------------------------------------- // Procedure: PeiUsbValidatePartitionTable // // Description: This function validates the existence of the partition table // from the LBA 0 data provided and return FdEmulOffset value // (hidden sector) from the partition table // // Input: **PeiServices Pointer to the PEI services table // *Buffer Pointer to the buffer containing LBA 0 // data // LastBlock Last LBA address // // *FdEmulOffset Returned FD emulation hidden sector value // Output: Nothing // //---------------------------------------------------------------------------- // VOID PeiUsbValidatePartitionTable ( IN EFI_PEI_SERVICES **PeiServices, IN UINT8 *Buffer, IN UINTN LastBlock, OUT UINT32 *FdEmulOffset ) { UINT8 i; UINT8 *pTable = Buffer + 0x1be; // Start offset of partition // table UINT8 *active_partition_addr = NULL; UINT8 PartitionFound = 0; // Total number of valid // partitions UINT8 *PartitionTableEntries[4]; for (i = 0; i < 4; i++) { PartitionTableEntries[i] = 0; // Boot flag check added to ensure that boot sector will not be // treated as a valid partation table. if (*pTable & 0x7f) { return; // BootFlag should be 0x0 or 0x80 } // Check whether beginning LBA is reasonable if (*(UINT32 *) (pTable + 8) > LastBlock) { return; } // Check whether the size is reasonable /** This check has to be refined #if HDD_PART_SIZE_CHECK if (*(UINT32*)(pTable + 0xc) > LastBlock) return; #endif **/ PartitionFound++; PartitionTableEntries[i] = pTable; // Update active entry offset if (*pTable & 0x80) { active_partition_addr = pTable; } pTable += 0x10; //Get next Partition } if (PartitionFound == 0) { return; } // If no active partition table entry found use first entry if (active_partition_addr == NULL) { for (i = 0; (i < 4) && !PartitionTableEntries[i]; i++) { ; } if (i == 4) return; active_partition_addr = PartitionTableEntries[i]; } *FdEmulOffset = *( (UINT32 *) (active_partition_addr + 8) ); PEI_TRACE( (EFI_D_ERROR, PeiServices, "USBPEIM: PeiUsbValidatePartitionTable() FdEmulOffset %x\n", *FdEmulOffset) ); } // <-- AMI Changes // //---------------------------------------------------------------------------- // Procedure: PeiUsbReadFormattedCapacity // // Description: This function issues the ATA Read Formatted Capacity command // to the USB mass storage device // // Input: **PeiServices Pointer to the PEI services table // *PeiBotDevice Pointer to the PEI_BOT_DEVICE structure // // Output: Return Status based on the command // //---------------------------------------------------------------------------- // EFI_STATUS PeiUsbReadFormattedCapacity ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_BOT_DEVICE *PeiBotDevice ) { EFI_STATUS Status; ATAPI_PACKET_COMMAND Packet; READ_FORMAT_CAPACITY_DATA FormatData; ZeroMem( &FormatData, sizeof(READ_FORMAT_CAPACITY_DATA) ); ZeroMem( &Packet, sizeof(ATAPI_PACKET_COMMAND) ); Packet.ReadFormatCapacity.opcode = READ_FORMAT_CAPACITY; Packet.ReadFormatCapacity.allocation_length_lo = 12; // Send command packet Status = PeiAtapiCommand( PeiServices, PeiBotDevice, &Packet, sizeof(ATAPI_PACKET_COMMAND), (VOID *) &FormatData, sizeof(READ_FORMAT_CAPACITY_DATA), EfiUsbDataIn, 2000 ); if ( EFI_ERROR( Status ) ) { return EFI_DEVICE_ERROR; } if (FormatData.DesCode == 3) { // Media is not present PeiBotDevice->Media.MediaPresent = FALSE; PeiBotDevice->Media.LastBlock = 0; } else { PeiBotDevice->Media.LastBlock = (FormatData.LastLba3 << 24) | (FormatData.LastLba2 << 16) | (FormatData.LastLba1 << 8) | FormatData.LastLba0; PeiBotDevice->Media.LastBlock--; PeiBotDevice->Media.MediaPresent = TRUE; } return EFI_SUCCESS; } // //---------------------------------------------------------------------------- // Procedure: PeiUsbRead10 // // Description: This function issues the ATA Read (10) command to the USB // mass storage device // // Input: **PeiServices Pointer to the PEI services table // *PeiBotDevice Pointer to the PEI_BOT_DEVICE structure // *Buffer Buffer to read the data into // Lba Start LBA Number // NumberOfBlocks Number of blocks to read // // Output: Return Status based on the command // //---------------------------------------------------------------------------- // EFI_STATUS PeiUsbRead10 ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_BOT_DEVICE *PeiBotDevice, IN VOID *Buffer, IN EFI_PEI_LBA Lba, IN UINTN NumberOfBlocks ) { VOID *ptrBuffer; UINT16 MaxBlock; UINT16 BlocksRemaining; UINT16 SectorCount; UINT16 TimeOut; // UINT32 BufferSize; UINT32 Lba32; UINT32 BlockSize; UINT32 ByteCount; EFI_STATUS Status; READ10_CMD *Read10Packet; ATAPI_PACKET_COMMAND Packet; // Prepare command packet for the Inquiry Packet Command. ZeroMem( &Packet, sizeof(ATAPI_PACKET_COMMAND) ); Read10Packet = &Packet.Read10; Lba32 = (UINT32) Lba; ptrBuffer = Buffer; BlockSize = (UINT32) PeiBotDevice->Media.BlockSize; // AMI Changes --> MaxBlock = (UINT16) (65536 / BlockSize); // BufferSize = NumberOfBlocks * BlockSize; // MaxBlock = (UINT16)(BufferSize /BlockSize); // <-- AMI Changes BlocksRemaining = (UINT16) NumberOfBlocks; Status = EFI_SUCCESS; while (BlocksRemaining > 0) { if (BlocksRemaining <= MaxBlock) { SectorCount = BlocksRemaining; } else { SectorCount = MaxBlock; } // Fill the Packet data structure Read10Packet->opcode = READ_10; // Lba0 ~ Lba3 specify the start logical block // address of the data transfer. // Lba0 is MSB, Lba3 is LSB Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff); Read10Packet->Lba2 = (UINT8) (Lba32 >> 8); Read10Packet->Lba1 = (UINT8) (Lba32 >> 16); Read10Packet->Lba0 = (UINT8) (Lba32 >> 24); // TranLen0 ~ TranLen1 specify the transfer length in block unit. // TranLen0 is MSB, TranLen is LSB Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff); Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8); ByteCount = SectorCount * BlockSize; TimeOut = (UINT16) (SectorCount * 2000); // Send command packet Status = PeiAtapiCommand( PeiServices, PeiBotDevice, &Packet, sizeof(ATAPI_PACKET_COMMAND), (VOID *) ptrBuffer, ByteCount, EfiUsbDataIn, TimeOut ); if (Status != EFI_SUCCESS) { return Status; } Lba32 += SectorCount; ptrBuffer = (UINT8 *) ptrBuffer + SectorCount * BlockSize; BlocksRemaining = (UINT16) (BlocksRemaining - SectorCount); } return Status; } // //---------------------------------------------------------------------------- // Procedure: IsNoMedia // // Description: This function verifies whether Media is present in the drive // or not by checking the Sense Data obtained from the drive // // Input: *SenseData Sense data obtained from the drive // SenseCounts Sense count value // // Output: Returns TRUE if media is present // FALSE otherwise // //---------------------------------------------------------------------------- // BOOLEAN IsNoMedia ( IN REQUEST_SENSE_DATA *SenseData, IN UINTN SenseCounts ) { UINTN i; BOOLEAN NoMedia; REQUEST_SENSE_DATA *SensePtr; NoMedia = FALSE; SensePtr = SenseData; for (i = 0; i < SenseCounts; i++) { switch (SensePtr->sense_key) { case SK_NOT_READY: switch (SensePtr->addnl_sense_code) { // If no media, fill IdeDev parameter with specific info. case ASC_NO_MEDIA: NoMedia = TRUE; break; default: break; } break; default: break; } SensePtr++; } return NoMedia; } // //---------------------------------------------------------------------------- // Procedure: IsMediaError // // Description: This function verifies whether Media access is having problem // or not by checking the Sense Data obtained from the drive // // Input: *SenseData Sense data obtained from the drive // SenseCounts Sense count value // // Output: Returns TRUE if media has error // FALSE otherwise // //---------------------------------------------------------------------------- // BOOLEAN IsMediaError ( IN REQUEST_SENSE_DATA *SenseData, IN UINTN SenseCounts ) { UINTN i; BOOLEAN Error; REQUEST_SENSE_DATA *SensePtr; SensePtr = SenseData; Error = FALSE; for (i = 0; i < SenseCounts; i++) { switch (SensePtr->sense_key) { // Medium error case case SK_MEDIUM_ERROR: switch (SensePtr->addnl_sense_code) { case ASC_MEDIA_ERR1: // fall through case ASC_MEDIA_ERR2: // fall through case ASC_MEDIA_ERR3: // fall through case ASC_MEDIA_ERR4: Error = TRUE; break; default: break; } break; // Medium upside-down case case SK_NOT_READY: switch (SensePtr->addnl_sense_code) { case ASC_MEDIA_UPSIDE_DOWN: Error = TRUE; break; default: break; } break; default: break; } SensePtr++; } return Error; } // //---------------------------------------------------------------------------- // Procedure: IsMediaChange // // Description: This function verifies whether Media change had happened // or not by checking the Sense Data obtained from the drive // // Input: *SenseData Sense data obtained from the drive // SenseCounts Sense count value // // Output: Returns TRUE if media has changed // FALSE otherwise // //---------------------------------------------------------------------------- // BOOLEAN IsMediaChange ( IN REQUEST_SENSE_DATA *SenseData, IN UINTN SenseCounts ) { UINTN i; BOOLEAN MediaChange; REQUEST_SENSE_DATA *SensePtr; MediaChange = FALSE; SensePtr = SenseData; for (i = 0; i < SenseCounts; i++) { // Catch media change sense key and addition sense data switch (SensePtr->sense_key) { case SK_UNIT_ATTENTION: switch (SensePtr->addnl_sense_code) { case ASC_MEDIA_CHANGE: MediaChange = TRUE; break; default: break; } break; default: break; } SensePtr++; } return MediaChange; } //********************************************************************** //********************************************************************** //** ** //** (C)Copyright 1985-2006, American Megatrends, Inc. ** //** ** //** All Rights Reserved. ** //** ** //** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** //** ** //** Phone: (770)-246-8600 ** //** ** //********************************************************************** //********************************************************************** //**********************************************************************