Changes to allow reading blocks that greater than 65535 sectors. Signed-off-by: Jiangang He <jiangang.he@amd.com> Cc: Hao A Wu <hao.a.wu@intel.com> Cc: Ray Ni <ray.ni@intel.com> Cc: Garrett Kirkendall <garrett.kirkendall@amd.com> Cc: Abner Chang <abner.chang@amd.com> Cc: Kuei-Hung Lin <Kuei-Hung.Lin@amd.com> Reviewed-by: Hao A Wu <hao.a.wu@intel.com>
		
			
				
	
	
		
			642 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			642 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
| Pei USB ATAPI command implementations.
 | |
| 
 | |
| Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>
 | |
| Copyright (C) 2022 Advanced Micro Devices, Inc. All rights reserved.<BR>
 | |
| 
 | |
| SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #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;
 | |
|     PeiBotDevice->Media2.ReadOnly       = TRUE;
 | |
|     PeiBotDevice->Media2.RemovableMedia = TRUE;
 | |
|     PeiBotDevice->Media2.BlockSize      = 0x800;
 | |
|   } else {
 | |
|     PeiBotDevice->DeviceType            = USBFLOPPY;
 | |
|     PeiBotDevice->Media.BlockSize       = 0x200;
 | |
|     PeiBotDevice->Media2.ReadOnly       = FALSE;
 | |
|     PeiBotDevice->Media2.RemovableMedia = TRUE;
 | |
|     PeiBotDevice->Media2.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;
 | |
|   UINT32                    LastBlock;
 | |
| 
 | |
|   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;
 | |
|   }
 | |
| 
 | |
|   LastBlock = ((UINT32)Data.LastLba3 << 24) | (Data.LastLba2 << 16) | (Data.LastLba1 << 8) | Data.LastLba0;
 | |
| 
 | |
|   if (LastBlock == 0xFFFFFFFF) {
 | |
|     DEBUG ((DEBUG_INFO, "The usb device LBA count is larger than 0xFFFFFFFF!\n"));
 | |
|   }
 | |
| 
 | |
|   PeiBotDevice->Media.LastBlock    = LastBlock;
 | |
|   PeiBotDevice->Media.MediaPresent = TRUE;
 | |
| 
 | |
|   PeiBotDevice->Media2.LastBlock    = LastBlock;
 | |
|   PeiBotDevice->Media2.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;
 | |
|   UINT32                           LastBlock;
 | |
| 
 | |
|   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;
 | |
|     PeiBotDevice->Media2.MediaPresent = FALSE;
 | |
|     PeiBotDevice->Media2.LastBlock    = 0;
 | |
|   } else {
 | |
|     LastBlock = ((UINT32)FormatData.LastLba3 << 24) | (FormatData.LastLba2 << 16) | (FormatData.LastLba1 << 8) | FormatData.LastLba0;
 | |
|     if (LastBlock == 0xFFFFFFFF) {
 | |
|       DEBUG ((DEBUG_INFO, "The usb device LBA count is larger than 0xFFFFFFFF!\n"));
 | |
|     }
 | |
| 
 | |
|     PeiBotDevice->Media.LastBlock = LastBlock;
 | |
| 
 | |
|     PeiBotDevice->Media.LastBlock--;
 | |
| 
 | |
|     PeiBotDevice->Media.MediaPresent = TRUE;
 | |
| 
 | |
|     PeiBotDevice->Media2.MediaPresent = TRUE;
 | |
|     PeiBotDevice->Media2.LastBlock    = PeiBotDevice->Media.LastBlock;
 | |
|   }
 | |
| 
 | |
|   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;
 | |
|   UINT32                BlocksRemaining;
 | |
|   UINT32                SectorCount;
 | |
|   UINT32                Lba32;
 | |
|   UINT32                BlockSize;
 | |
|   UINT32                ByteCount;
 | |
|   VOID                  *PtrBuffer;
 | |
|   EFI_STATUS            Status;
 | |
|   UINT32                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)(MAX_UINT16 / BlockSize);
 | |
|   ASSERT (NumberOfBlocks < MAX_UINT32);
 | |
|   BlocksRemaining = (UINT32)NumberOfBlocks;
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
|   while (BlocksRemaining > 0) {
 | |
|     SectorCount = MIN (BlocksRemaining, 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 = SectorCount * 2000;
 | |
| 
 | |
|     //
 | |
|     // send command packet
 | |
|     //
 | |
|     Status = PeiAtapiCommand (
 | |
|                PeiServices,
 | |
|                PeiBotDevice,
 | |
|                &Packet,
 | |
|                (UINT8)sizeof (ATAPI_PACKET_COMMAND),
 | |
|                (VOID *)PtrBuffer,
 | |
|                ByteCount,
 | |
|                EfiUsbDataIn,
 | |
|                (UINT16)MIN (TimeOut, MAX_UINT16)
 | |
|                );
 | |
| 
 | |
|     if (Status != EFI_SUCCESS) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     ASSERT (Lba32 <= (MAX_UINT32-SectorCount));
 | |
|     Lba32          += SectorCount;
 | |
|     PtrBuffer       = (UINT8 *)PtrBuffer + SectorCount * BlockSize;
 | |
|     BlocksRemaining = 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;
 | |
| }
 |