summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Bus/Usb/UsbBotPei/PeiAtapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg/Bus/Usb/UsbBotPei/PeiAtapi.c')
-rw-r--r--MdeModulePkg/Bus/Usb/UsbBotPei/PeiAtapi.c630
1 files changed, 630 insertions, 0 deletions
diff --git a/MdeModulePkg/Bus/Usb/UsbBotPei/PeiAtapi.c b/MdeModulePkg/Bus/Usb/UsbBotPei/PeiAtapi.c
new file mode 100644
index 0000000000..28574d07e1
--- /dev/null
+++ b/MdeModulePkg/Bus/Usb/UsbBotPei/PeiAtapi.c
@@ -0,0 +1,630 @@
+/** @file
+Pei USB ATATPI command implementations.
+
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "UsbBotPeim.h"
+#include "BotPeim.h"
+
+#define MAXSENSEKEY 5
+
+/**
+ Sends out ATAPI Inquiry Packet Command to the specified device. This command will
+ return INQUIRY data of the device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
+
+ @retval EFI_SUCCESS Inquiry command completes successfully.
+ @retval EFI_DEVICE_ERROR Inquiry command failed.
+
+**/
+EFI_STATUS
+PeiUsbInquiry (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDevice
+ )
+{
+ ATAPI_PACKET_COMMAND Packet;
+ EFI_STATUS Status;
+ ATAPI_INQUIRY_DATA Idata;
+
+ //
+ // fill command packet
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ ZeroMem (&Idata, sizeof (ATAPI_INQUIRY_DATA));
+
+ Packet.Inquiry.opcode = ATA_CMD_INQUIRY;
+ Packet.Inquiry.page_code = 0;
+ Packet.Inquiry.allocation_length = 36;
+
+ //
+ // Send scsi INQUIRY command packet.
+ // According to SCSI Primary Commands-2 spec, host only needs to
+ // retrieve the first 36 bytes for standard INQUIRY data.
+ //
+ Status = PeiAtapiCommand (
+ PeiServices,
+ PeiBotDevice,
+ &Packet,
+ (UINT8) sizeof (ATAPI_PACKET_COMMAND),
+ &Idata,
+ 36,
+ EfiUsbDataIn,
+ 2000
+ );
+
+ 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;
+}
+
+/**
+ Sends out ATAPI Test Unit Ready Packet Command to the specified device
+ to find out whether device is accessible.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
+
+ @retval EFI_SUCCESS TestUnit command executed successfully.
+ @retval EFI_DEVICE_ERROR Device cannot be executed TestUnit command successfully.
+
+**/
+EFI_STATUS
+PeiUsbTestUnitReady (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDevice
+ )
+{
+ ATAPI_PACKET_COMMAND Packet;
+ EFI_STATUS Status;
+
+ //
+ // fill command packet
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Packet.TestUnitReady.opcode = ATA_CMD_TEST_UNIT_READY;
+
+ //
+ // send command packet
+ //
+ Status = PeiAtapiCommand (
+ PeiServices,
+ PeiBotDevice,
+ &Packet,
+ (UINT8) sizeof (ATAPI_PACKET_COMMAND),
+ NULL,
+ 0,
+ EfiUsbNoData,
+ 2000
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Sends out ATAPI Request Sense Packet Command to the specified device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
+ @param SenseCounts Length of sense buffer.
+ @param SenseKeyBuffer Pointer to sense buffer.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Some device errors happen.
+
+**/
+EFI_STATUS
+PeiUsbRequestSense (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDevice,
+ OUT UINTN *SenseCounts,
+ IN UINT8 *SenseKeyBuffer
+ )
+{
+ EFI_STATUS Status;
+ ATAPI_PACKET_COMMAND Packet;
+ UINT8 *Ptr;
+ BOOLEAN SenseReq;
+ ATAPI_REQUEST_SENSE_DATA *Sense;
+
+ *SenseCounts = 0;
+
+ //
+ // fill command packet for Request Sense Packet Command
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Packet.RequestSence.opcode = ATA_CMD_REQUEST_SENSE;
+ Packet.RequestSence.allocation_length = (UINT8) sizeof (ATAPI_REQUEST_SENSE_DATA);
+
+ Ptr = SenseKeyBuffer;
+
+ SenseReq = TRUE;
+
+ //
+ // request sense data from device continuously
+ // until no sense data exists in the device.
+ //
+ while (SenseReq) {
+ Sense = (ATAPI_REQUEST_SENSE_DATA *) Ptr;
+
+ //
+ // send out Request Sense Packet Command and get one Sense
+ // data form device.
+ //
+ Status = PeiAtapiCommand (
+ PeiServices,
+ PeiBotDevice,
+ &Packet,
+ (UINT8) sizeof (ATAPI_PACKET_COMMAND),
+ (VOID *) Ptr,
+ sizeof (ATAPI_REQUEST_SENSE_DATA),
+ EfiUsbDataIn,
+ 2000
+ );
+
+ //
+ // failed to get Sense data
+ //
+ if (EFI_ERROR (Status)) {
+ if (*SenseCounts == 0) {
+ return EFI_DEVICE_ERROR;
+ } else {
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (Sense->sense_key != ATA_SK_NO_SENSE) {
+
+ Ptr += sizeof (ATAPI_REQUEST_SENSE_DATA);
+ //
+ // Ptr is byte based pointer
+ //
+ (*SenseCounts)++;
+
+ if (*SenseCounts == MAXSENSEKEY) {
+ break;
+ }
+
+ } else {
+ //
+ // when no sense key, skip out the loop
+ //
+ SenseReq = FALSE;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Sends out ATAPI Read Capacity Packet Command to the specified device.
+ This command will return the information regarding the capacity of the
+ media in the device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Some device errors happen.
+
+**/
+EFI_STATUS
+PeiUsbReadCapacity (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDevice
+ )
+{
+ EFI_STATUS Status;
+ ATAPI_PACKET_COMMAND Packet;
+ ATAPI_READ_CAPACITY_DATA Data;
+
+ ZeroMem (&Data, sizeof (ATAPI_READ_CAPACITY_DATA));
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+
+ Packet.Inquiry.opcode = ATA_CMD_READ_CAPACITY;
+
+ //
+ // send command packet
+ //
+ Status = PeiAtapiCommand (
+ PeiServices,
+ PeiBotDevice,
+ &Packet,
+ (UINT8) sizeof (ATAPI_PACKET_COMMAND),
+ (VOID *) &Data,
+ sizeof (ATAPI_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;
+
+ PeiBotDevice->Media.MediaPresent = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Sends out ATAPI Read Format Capacity Data Command to the specified device.
+ This command will return the information regarding the capacity of the
+ media in the device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Some device errors happen.
+
+**/
+EFI_STATUS
+PeiUsbReadFormattedCapacity (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDevice
+ )
+{
+ EFI_STATUS Status;
+ ATAPI_PACKET_COMMAND Packet;
+ ATAPI_READ_FORMAT_CAPACITY_DATA FormatData;
+
+ ZeroMem (&FormatData, sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA));
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+
+ Packet.ReadFormatCapacity.opcode = ATA_CMD_READ_FORMAT_CAPACITY;
+ Packet.ReadFormatCapacity.allocation_length_lo = 12;
+
+ //
+ // send command packet
+ //
+ Status = PeiAtapiCommand (
+ PeiServices,
+ PeiBotDevice,
+ &Packet,
+ (UINT8) sizeof (ATAPI_PACKET_COMMAND),
+ (VOID *) &FormatData,
+ sizeof (ATAPI_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;
+}
+
+/**
+ Execute Read(10) ATAPI command on a specific SCSI target.
+
+ Executes the ATAPI Read(10) command on the ATAPI target specified by PeiBotDevice.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
+ @param Buffer The pointer to data buffer.
+ @param Lba The start logic block address of reading.
+ @param NumberOfBlocks The block number of reading.
+
+ @retval EFI_SUCCESS Command executed successfully.
+ @retval EFI_DEVICE_ERROR Some device errors happen.
+
+**/
+EFI_STATUS
+PeiUsbRead10 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDevice,
+ IN VOID *Buffer,
+ IN EFI_PEI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+{
+ ATAPI_PACKET_COMMAND Packet;
+ ATAPI_READ10_CMD *Read10Packet;
+ UINT16 MaxBlock;
+ UINT16 BlocksRemaining;
+ UINT16 SectorCount;
+ UINT32 Lba32;
+ UINT32 BlockSize;
+ UINT32 ByteCount;
+ VOID *PtrBuffer;
+ EFI_STATUS Status;
+ UINT16 TimeOut;
+
+ //
+ // 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;
+
+ MaxBlock = (UINT16) (65535 / BlockSize);
+ BlocksRemaining = (UINT16) NumberOfBlocks;
+
+ Status = EFI_SUCCESS;
+ while (BlocksRemaining > 0) {
+
+ if (BlocksRemaining <= MaxBlock) {
+
+ SectorCount = BlocksRemaining;
+
+ } else {
+
+ SectorCount = MaxBlock;
+ }
+ //
+ // fill the Packet data structure
+ //
+ Read10Packet->opcode = ATA_CMD_READ_10;
+
+ //
+ // Lba0 ~ Lba3 specify the start logical block address of the data transfer.
+ // Lba0 is MSB, Lba3 is LSB
+ //
+ Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff);
+ Read10Packet->Lba2 = (UINT8) (Lba32 >> 8);
+ Read10Packet->Lba1 = (UINT8) (Lba32 >> 16);
+ Read10Packet->Lba0 = (UINT8) (Lba32 >> 24);
+
+ //
+ // TranLen0 ~ TranLen1 specify the transfer length in block unit.
+ // TranLen0 is MSB, TranLen is LSB
+ //
+ Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff);
+ Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8);
+
+ ByteCount = SectorCount * BlockSize;
+
+ TimeOut = (UINT16) (SectorCount * 2000);
+
+ //
+ // send command packet
+ //
+ Status = PeiAtapiCommand (
+ PeiServices,
+ PeiBotDevice,
+ &Packet,
+ (UINT8) 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;
+}
+
+/**
+ Check if there is media according to sense data.
+
+ @param SenseData Pointer to sense data.
+ @param SenseCounts Count of sense data.
+
+ @retval TRUE No media
+ @retval FALSE Media exists
+
+**/
+BOOLEAN
+IsNoMedia (
+ IN ATAPI_REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ )
+{
+ ATAPI_REQUEST_SENSE_DATA *SensePtr;
+ UINTN Index;
+ BOOLEAN NoMedia;
+
+ NoMedia = FALSE;
+ SensePtr = SenseData;
+
+ for (Index = 0; Index < SenseCounts; Index++) {
+
+ switch (SensePtr->sense_key) {
+
+ case ATA_SK_NOT_READY:
+ switch (SensePtr->addnl_sense_code) {
+ //
+ // if no media, fill IdeDev parameter with specific info.
+ //
+ case ATA_ASC_NO_MEDIA:
+ NoMedia = TRUE;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ SensePtr++;
+ }
+
+ return NoMedia;
+}
+
+/**
+ Check if there is media error according to sense data.
+
+ @param SenseData Pointer to sense data.
+ @param SenseCounts Count of sense data.
+
+ @retval TRUE Media error
+ @retval FALSE No media error
+
+**/
+BOOLEAN
+IsMediaError (
+ IN ATAPI_REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ )
+{
+ ATAPI_REQUEST_SENSE_DATA *SensePtr;
+ UINTN Index;
+ BOOLEAN Error;
+
+ SensePtr = SenseData;
+ Error = FALSE;
+
+ for (Index = 0; Index < SenseCounts; Index++) {
+
+ switch (SensePtr->sense_key) {
+ //
+ // Medium error case
+ //
+ case ATA_SK_MEDIUM_ERROR:
+ switch (SensePtr->addnl_sense_code) {
+ case ATA_ASC_MEDIA_ERR1:
+ //
+ // fall through
+ //
+ case ATA_ASC_MEDIA_ERR2:
+ //
+ // fall through
+ //
+ case ATA_ASC_MEDIA_ERR3:
+ //
+ // fall through
+ //
+ case ATA_ASC_MEDIA_ERR4:
+ Error = TRUE;
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ //
+ // Medium upside-down case
+ //
+ case ATA_SK_NOT_READY:
+ switch (SensePtr->addnl_sense_code) {
+ case ATA_ASC_MEDIA_UPSIDE_DOWN:
+ Error = TRUE;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ SensePtr++;
+ }
+
+ return Error;
+}
+
+/**
+ Check if media is changed according to sense data.
+
+ @param SenseData Pointer to sense data.
+ @param SenseCounts Count of sense data.
+
+ @retval TRUE There is media change event.
+ @retval FALSE media is NOT changed.
+
+**/
+BOOLEAN
+IsMediaChange (
+ IN ATAPI_REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ )
+{
+ ATAPI_REQUEST_SENSE_DATA *SensePtr;
+ UINTN Index;
+ BOOLEAN MediaChange;
+
+ MediaChange = FALSE;
+
+ SensePtr = SenseData;
+
+ for (Index = 0; Index < SenseCounts; Index++) {
+ //
+ // catch media change sense key and addition sense data
+ //
+ switch (SensePtr->sense_key) {
+ case ATA_SK_UNIT_ATTENTION:
+ switch (SensePtr->addnl_sense_code) {
+ case ATA_ASC_MEDIA_CHANGE:
+ MediaChange = TRUE;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ SensePtr++;
+ }
+
+ return MediaChange;
+}