git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@461 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			2344 lines
		
	
	
		
			59 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2344 lines
		
	
	
		
			59 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Copyright (c) 2006, Intel Corporation                                                         
 | 
						|
  All rights reserved. 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 "idebus.h"
 | 
						|
 | 
						|
/**
 | 
						|
  This function is used to get the current status of the media residing
 | 
						|
  in the LS-120 drive or ZIP drive. The media status is returned in the 
 | 
						|
  Error Status.
 | 
						|
 | 
						|
  @param[in] *IdeDev
 | 
						|
  pointer pointing to IDE_BLK_IO_DEV data structure, used
 | 
						|
  to record all the information of the IDE device.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS
 | 
						|
  The media status is achieved successfully and the media
 | 
						|
  can be read/written.
 | 
						|
  
 | 
						|
  @retval EFI_DEVICE_ERROR
 | 
						|
  Get Media Status Command is failed.
 | 
						|
  
 | 
						|
  @retval EFI_NO_MEDIA
 | 
						|
  There is no media in the drive.
 | 
						|
  
 | 
						|
  @retval EFI_WRITE_PROTECTED
 | 
						|
  The media is writing protected.
 | 
						|
 | 
						|
  @note
 | 
						|
  This function must be called after the LS120EnableMediaStatus() 
 | 
						|
  with second parameter set to TRUE 
 | 
						|
  (means enable media status notification) is called.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
LS120GetMediaStatus (
 | 
						|
  IN  IDE_BLK_IO_DEV  *IdeDev
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8       DeviceSelect;
 | 
						|
  UINT8       StatusValue;
 | 
						|
  EFI_STATUS  EfiStatus;
 | 
						|
  //
 | 
						|
  // Poll Alternate Register for BSY clear within timeout.
 | 
						|
  //
 | 
						|
  EfiStatus = WaitForBSYClear2 (IdeDev, ATATIMEOUT);
 | 
						|
  if (EFI_ERROR (EfiStatus)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Select device via Device/Head Register.
 | 
						|
  //
 | 
						|
  DeviceSelect = (UINT8) ((IdeDev->Device) << 4 | 0xe0);
 | 
						|
  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);
 | 
						|
 | 
						|
  //
 | 
						|
  // Poll Alternate Register for DRDY set within timeout.
 | 
						|
  // After device is selected, DRDY set indicates the device is ready to
 | 
						|
  // accept command.
 | 
						|
  //
 | 
						|
  EfiStatus = DRDYReady2 (IdeDev, ATATIMEOUT);
 | 
						|
  if (EFI_ERROR (EfiStatus)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get Media Status Command is sent
 | 
						|
  //
 | 
						|
  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0xDA);
 | 
						|
 | 
						|
  //
 | 
						|
  // BSY bit will clear after command is complete.
 | 
						|
  //
 | 
						|
  EfiStatus = WaitForBSYClear2 (IdeDev, ATATIMEOUT);
 | 
						|
  if (EFI_ERROR (EfiStatus)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // the media status is returned by the command in the ERROR register
 | 
						|
  //
 | 
						|
  StatusValue = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
 | 
						|
 | 
						|
  if (StatusValue & bit1) {
 | 
						|
    return EFI_NO_MEDIA;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StatusValue & bit6) {
 | 
						|
    return EFI_WRITE_PROTECTED;
 | 
						|
  } else {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function is used to send Enable Media Status Notification Command
 | 
						|
  or Disable Media Status Notification Command.
 | 
						|
 | 
						|
  @param[in] *IdeDev
 | 
						|
  pointer pointing to IDE_BLK_IO_DEV data structure, used
 | 
						|
  to record all the information of the IDE device.
 | 
						|
 | 
						|
  @param[in] Enable
 | 
						|
  a flag that indicates whether enable or disable media
 | 
						|
  status notification.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS
 | 
						|
  If command completes successfully.
 | 
						|
  
 | 
						|
  @retval EFI_DEVICE_ERROR
 | 
						|
  If command failed.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
LS120EnableMediaStatus (
 | 
						|
  IN  IDE_BLK_IO_DEV  *IdeDev,
 | 
						|
  IN  BOOLEAN         Enable
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8       DeviceSelect;
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // Poll Alternate Register for BSY clear within timeout.
 | 
						|
  //
 | 
						|
  Status = WaitForBSYClear2 (IdeDev, ATATIMEOUT);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Select device via Device/Head Register.
 | 
						|
  //
 | 
						|
  DeviceSelect = (UINT8) ((IdeDev->Device) << 4 | 0xe0);
 | 
						|
  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);
 | 
						|
 | 
						|
  //
 | 
						|
  // Poll Alternate Register for DRDY set within timeout.
 | 
						|
  // After device is selected, DRDY set indicates the device is ready to
 | 
						|
  // accept command.
 | 
						|
  //
 | 
						|
  Status = DRDYReady2 (IdeDev, ATATIMEOUT);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Enable) {
 | 
						|
    //
 | 
						|
    // 0x95: Enable media status notification
 | 
						|
    //
 | 
						|
    IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x95);
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // 0x31: Disable media status notification
 | 
						|
    //
 | 
						|
    IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x31);
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Set Feature Command is sent
 | 
						|
  //
 | 
						|
  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0xEF);
 | 
						|
 | 
						|
  //
 | 
						|
  // BSY bit will clear after command is complete.
 | 
						|
  //
 | 
						|
  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function is called by DiscoverIdeDevice() during its device
 | 
						|
  identification.
 | 
						|
 | 
						|
  Its main purpose is to get enough information for the device media
 | 
						|
  to fill in the Media data structure of the Block I/O Protocol interface.
 | 
						|
 | 
						|
  There are 5 steps to reach such objective:
 | 
						|
 | 
						|
  1. Sends out the ATAPI Identify Command to the specified device. 
 | 
						|
  Only ATAPI device responses to this command. If the command succeeds,
 | 
						|
  it returns the Identify data structure which filled with information 
 | 
						|
  about the device. Since the ATAPI device contains removable media, 
 | 
						|
  the only meaningful information is the device module name.
 | 
						|
 | 
						|
  2. Sends out ATAPI Inquiry Packet Command to the specified device.
 | 
						|
  This command will return inquiry data of the device, which contains
 | 
						|
  the device type information.
 | 
						|
 | 
						|
  3. Allocate sense data space for future use. We don't detect the media
 | 
						|
  presence here to improvement boot performance, especially when CD 
 | 
						|
  media is present. The media detection will be performed just before
 | 
						|
  each BLK_IO read/write
 | 
						|
 | 
						|
  @param[in] *IdeDev
 | 
						|
  pointer pointing to IDE_BLK_IO_DEV data structure, used
 | 
						|
  to record all the information of the IDE device.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS
 | 
						|
  Identify ATAPI device successfully.
 | 
						|
  
 | 
						|
  @retval EFI_DEVICE_ERROR
 | 
						|
  ATAPI Identify Device Command failed or device type
 | 
						|
  is not supported by this IDE driver.
 | 
						|
 | 
						|
  @note
 | 
						|
  Parameter "IdeDev" will be updated in this function.
 | 
						|
 | 
						|
  TODO:    EFI_OUT_OF_RESOURCES - add return value to function comment
 | 
						|
  TODO:    EFI_OUT_OF_RESOURCES - add return value to function comment
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ATAPIIdentify (
 | 
						|
  IN  IDE_BLK_IO_DEV  *IdeDev
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_IDENTIFY_DATA *AtapiIdentifyPointer;
 | 
						|
  UINT8             DeviceSelect;
 | 
						|
  EFI_STATUS        Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // device select bit
 | 
						|
  //
 | 
						|
  DeviceSelect          = 0;
 | 
						|
  DeviceSelect          = (UINT8) ((IdeDev->Device) << 4);
 | 
						|
 | 
						|
  AtapiIdentifyPointer  = AllocatePool (sizeof (EFI_IDENTIFY_DATA));
 | 
						|
  if (AtapiIdentifyPointer == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Send ATAPI Identify Command to get IDENTIFY data.
 | 
						|
  //
 | 
						|
  Status = AtaPioDataIn (
 | 
						|
            IdeDev,
 | 
						|
            (VOID *) AtapiIdentifyPointer,
 | 
						|
            sizeof (EFI_IDENTIFY_DATA),
 | 
						|
            ATAPI_IDENTIFY_DEVICE_CMD,
 | 
						|
            DeviceSelect,
 | 
						|
            0,
 | 
						|
            0,
 | 
						|
            0,
 | 
						|
            0
 | 
						|
            );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    gBS->FreePool (AtapiIdentifyPointer);
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  IdeDev->pIdData = AtapiIdentifyPointer;
 | 
						|
  PrintAtaModuleName (IdeDev);
 | 
						|
 | 
						|
  //
 | 
						|
  // Send ATAPI Inquiry Packet Command to get INQUIRY data.
 | 
						|
  //
 | 
						|
  Status = AtapiInquiry (IdeDev);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    gBS->FreePool (IdeDev->pIdData);
 | 
						|
    //
 | 
						|
    // Make sure the pIdData will not be freed again.
 | 
						|
    //
 | 
						|
    IdeDev->pIdData = NULL;
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Get media removable info from INQUIRY data.
 | 
						|
  //
 | 
						|
  IdeDev->BlkIo.Media->RemovableMedia = (UINT8) ((IdeDev->pInquiryData->RMB & 0x80) == 0x80);
 | 
						|
 | 
						|
  //
 | 
						|
  // Identify device type via INQUIRY data.
 | 
						|
  //
 | 
						|
  switch (IdeDev->pInquiryData->peripheral_type & 0x1f) {
 | 
						|
 | 
						|
  //
 | 
						|
  // Magnetic Disk
 | 
						|
  //
 | 
						|
  case 0x00:
 | 
						|
 | 
						|
    //
 | 
						|
    // device is LS120 or ZIP drive.
 | 
						|
    //
 | 
						|
    IdeDev->Type = IdeMagnetic;
 | 
						|
 | 
						|
    IdeDev->BlkIo.Media->MediaId      = 0;
 | 
						|
    //
 | 
						|
    // Give initial value
 | 
						|
    //
 | 
						|
    IdeDev->BlkIo.Media->MediaPresent = FALSE;
 | 
						|
 | 
						|
    IdeDev->BlkIo.Media->LastBlock  = 0;
 | 
						|
    IdeDev->BlkIo.Media->BlockSize  = 0x200;
 | 
						|
    break;
 | 
						|
 | 
						|
  //
 | 
						|
  // CD-ROM
 | 
						|
  //
 | 
						|
  case 0x05:
 | 
						|
 | 
						|
    IdeDev->Type                      = IdeCdRom;
 | 
						|
    IdeDev->BlkIo.Media->MediaId      = 0;
 | 
						|
    //
 | 
						|
    // Give initial value
 | 
						|
    //
 | 
						|
    IdeDev->BlkIo.Media->MediaPresent = FALSE;
 | 
						|
 | 
						|
    IdeDev->BlkIo.Media->LastBlock  = 0;
 | 
						|
    IdeDev->BlkIo.Media->BlockSize  = 0x800;
 | 
						|
    IdeDev->BlkIo.Media->ReadOnly   = TRUE;
 | 
						|
    break;
 | 
						|
 | 
						|
  //
 | 
						|
  // Tape
 | 
						|
  //
 | 
						|
  case 0x01:
 | 
						|
 | 
						|
  //
 | 
						|
  // WORM
 | 
						|
  //
 | 
						|
  case 0x04:
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Optical
 | 
						|
  //
 | 
						|
  case 0x07:
 | 
						|
 | 
						|
  default:
 | 
						|
    IdeDev->Type = IdeUnknown;
 | 
						|
    gBS->FreePool (IdeDev->pIdData);
 | 
						|
    gBS->FreePool (IdeDev->pInquiryData);
 | 
						|
    //
 | 
						|
    // Make sure the pIdData and pInquiryData will not be freed again.
 | 
						|
    //
 | 
						|
    IdeDev->pIdData       = NULL;
 | 
						|
    IdeDev->pInquiryData  = NULL;
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // original sense data numbers
 | 
						|
  //
 | 
						|
  IdeDev->SenseDataNumber = 20;
 | 
						|
 | 
						|
  IdeDev->SenseData = AllocatePool (IdeDev->SenseDataNumber * sizeof (REQUEST_SENSE_DATA));
 | 
						|
  if (IdeDev->SenseData == NULL) {
 | 
						|
    gBS->FreePool (IdeDev->pIdData);
 | 
						|
    gBS->FreePool (IdeDev->pInquiryData);
 | 
						|
    //
 | 
						|
    // Make sure the pIdData and pInquiryData will not be freed again.
 | 
						|
    //
 | 
						|
    IdeDev->pIdData       = NULL;
 | 
						|
    IdeDev->pInquiryData  = NULL;
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Sends out ATAPI Inquiry Packet Command to the specified device.
 | 
						|
  This command will return INQUIRY data of the device.
 | 
						|
 | 
						|
  @param[in] *IdeDev
 | 
						|
  pointer pointing to IDE_BLK_IO_DEV data structure, used
 | 
						|
  to record all the information of the IDE device.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS
 | 
						|
  Inquiry command completes successfully.
 | 
						|
  
 | 
						|
  @retval EFI_DEVICE_ERROR
 | 
						|
  Inquiry command failed.
 | 
						|
 | 
						|
  @note
 | 
						|
  Parameter "IdeDev" will be updated in this function.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AtapiInquiry (
 | 
						|
  IN  IDE_BLK_IO_DEV  *IdeDev
 | 
						|
  )
 | 
						|
{
 | 
						|
  ATAPI_PACKET_COMMAND  Packet;
 | 
						|
  EFI_STATUS            Status;
 | 
						|
  INQUIRY_DATA          *InquiryData;
 | 
						|
 | 
						|
  //
 | 
						|
  // prepare command packet for the ATAPI Inquiry Packet Command.
 | 
						|
  //
 | 
						|
  ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
 | 
						|
  Packet.Inquiry.opcode             = INQUIRY;
 | 
						|
  Packet.Inquiry.page_code          = 0;
 | 
						|
  Packet.Inquiry.allocation_length  = sizeof (INQUIRY_DATA);
 | 
						|
 | 
						|
  InquiryData                       = AllocatePool (sizeof (INQUIRY_DATA));
 | 
						|
  if (InquiryData == NULL) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Send command packet and get requested Inquiry data.
 | 
						|
  //
 | 
						|
  Status = AtapiPacketCommandIn (
 | 
						|
            IdeDev,
 | 
						|
            &Packet,
 | 
						|
            (UINT16 *) InquiryData,
 | 
						|
            sizeof (INQUIRY_DATA),
 | 
						|
            ATAPITIMEOUT
 | 
						|
            );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    gBS->FreePool (InquiryData);
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  IdeDev->pInquiryData = InquiryData;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function is used to send out ATAPI commands conforms to the 
 | 
						|
  Packet Command with PIO Data In Protocol.
 | 
						|
 | 
						|
  @param[in] *IdeDev
 | 
						|
  pointer pointing to IDE_BLK_IO_DEV data structure, used
 | 
						|
  to record all the information of the IDE device.
 | 
						|
 | 
						|
  @param[in] *Packet
 | 
						|
  pointer pointing to ATAPI_PACKET_COMMAND data structure
 | 
						|
  which contains the contents of the command.     
 | 
						|
 | 
						|
  @param[in] *Buffer
 | 
						|
  buffer contained data transferred from device to host.
 | 
						|
 | 
						|
  @param[in] ByteCount
 | 
						|
  data size in byte unit of the buffer.
 | 
						|
 | 
						|
  @param[in] TimeOut
 | 
						|
  this parameter is used to specify the timeout 
 | 
						|
  value for the PioReadWriteData() function. 
 | 
						|
 | 
						|
  @retval EFI_SUCCESS
 | 
						|
  send out the ATAPI packet command successfully
 | 
						|
  and device sends data successfully.
 | 
						|
  
 | 
						|
  @retval EFI_DEVICE_ERROR
 | 
						|
  the device failed to send data.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AtapiPacketCommandIn (
 | 
						|
  IN  IDE_BLK_IO_DEV        *IdeDev,
 | 
						|
  IN  ATAPI_PACKET_COMMAND  *Packet,
 | 
						|
  IN  UINT16                *Buffer,
 | 
						|
  IN  UINT32                ByteCount,
 | 
						|
  IN  UINTN                 TimeOut
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT16      *CommandIndex;
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINT32      Count;
 | 
						|
 | 
						|
  //
 | 
						|
  // Set all the command parameters by fill related registers.
 | 
						|
  // Before write to all the following registers, BSY and DRQ must be 0.
 | 
						|
  //
 | 
						|
  Status = DRQClear2 (IdeDev, ATAPITIMEOUT);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Select device via Device/Head Register.
 | 
						|
  //
 | 
						|
  IDEWritePortB (
 | 
						|
    IdeDev->PciIo,
 | 
						|
    IdeDev->IoPort->Head,
 | 
						|
    (UINT8) ((IdeDev->Device << 4) | DEFAULT_CMD)  // DEFAULT_CMD: 0xa0 (1010,0000)
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // No OVL; No DMA
 | 
						|
  //
 | 
						|
  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00);
 | 
						|
 | 
						|
  //
 | 
						|
  // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device
 | 
						|
  // determine how many data should be transferred.
 | 
						|
  //
 | 
						|
  IDEWritePortB (
 | 
						|
    IdeDev->PciIo,
 | 
						|
    IdeDev->IoPort->CylinderLsb,
 | 
						|
    (UINT8) (MAX_ATAPI_BYTE_COUNT & 0x00ff)
 | 
						|
    );
 | 
						|
  IDEWritePortB (
 | 
						|
    IdeDev->PciIo,
 | 
						|
    IdeDev->IoPort->CylinderMsb,
 | 
						|
    (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8)
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  //  DEFAULT_CTL:0x0a (0000,1010)
 | 
						|
  //  Disable interrupt
 | 
						|
  //
 | 
						|
  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DEFAULT_CTL);
 | 
						|
 | 
						|
  //
 | 
						|
  // Send Packet command to inform device
 | 
						|
  // that the following data bytes are command packet.
 | 
						|
  //
 | 
						|
  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, PACKET_CMD);
 | 
						|
 | 
						|
  Status = DRQReady (IdeDev, ATAPITIMEOUT);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Send out command packet
 | 
						|
  //
 | 
						|
  CommandIndex = Packet->Data16;
 | 
						|
  for (Count = 0; Count < 6; Count++, CommandIndex++) {
 | 
						|
 | 
						|
    IDEWritePortW (IdeDev->PciIo, IdeDev->IoPort->Data, *CommandIndex);
 | 
						|
    gBS->Stall (10);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // call PioReadWriteData() function to get
 | 
						|
  // requested transfer data form device.
 | 
						|
  //
 | 
						|
  return PioReadWriteData (IdeDev, Buffer, ByteCount, 1, TimeOut);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function is used to send out ATAPI commands conforms to the 
 | 
						|
  Packet Command with PIO Data Out Protocol.
 | 
						|
 | 
						|
  @param[in] *IdeDev
 | 
						|
  pointer pointing to IDE_BLK_IO_DEV data structure, used
 | 
						|
  to record all the information of the IDE device.
 | 
						|
 | 
						|
  @param[in] *Packet
 | 
						|
  pointer pointing to ATAPI_PACKET_COMMAND data structure
 | 
						|
  which contains the contents of the command.
 | 
						|
 | 
						|
  @param[in] *Buffer
 | 
						|
  buffer contained data transferred from host to device.
 | 
						|
 | 
						|
  @param[in] ByteCount
 | 
						|
  data size in byte unit of the buffer.
 | 
						|
 | 
						|
  @param[in] TimeOut
 | 
						|
  this parameter is used to specify the timeout 
 | 
						|
  value for the PioReadWriteData() function. 
 | 
						|
 | 
						|
  @retval EFI_SUCCESS
 | 
						|
  send out the ATAPI packet command successfully
 | 
						|
  and device received data successfully.
 | 
						|
  
 | 
						|
  @retval EFI_DEVICE_ERROR
 | 
						|
  the device failed to send data.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AtapiPacketCommandOut (
 | 
						|
  IN  IDE_BLK_IO_DEV        *IdeDev,
 | 
						|
  IN  ATAPI_PACKET_COMMAND  *Packet,
 | 
						|
  IN  UINT16                *Buffer,
 | 
						|
  IN  UINT32                ByteCount,
 | 
						|
  IN  UINTN                 TimeOut
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT16      *CommandIndex;
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINT32      Count;
 | 
						|
 | 
						|
  //
 | 
						|
  // set all the command parameters
 | 
						|
  // Before write to all the following registers, BSY and DRQ must be 0.
 | 
						|
  //
 | 
						|
  Status = DRQClear2 (IdeDev, ATAPITIMEOUT);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Select device via Device/Head Register.
 | 
						|
  //
 | 
						|
  IDEWritePortB (
 | 
						|
    IdeDev->PciIo,
 | 
						|
    IdeDev->IoPort->Head,
 | 
						|
    (UINT8) ((IdeDev->Device << 4) | DEFAULT_CMD)   // DEFAULT_CMD: 0xa0 (1010,0000)
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // No OVL; No DMA
 | 
						|
  //
 | 
						|
  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00);
 | 
						|
 | 
						|
  //
 | 
						|
  // set the transfersize to MAX_ATAPI_BYTE_COUNT to
 | 
						|
  // let the device determine how many data should be transferred.
 | 
						|
  //
 | 
						|
  IDEWritePortB (
 | 
						|
    IdeDev->PciIo,
 | 
						|
    IdeDev->IoPort->CylinderLsb,
 | 
						|
    (UINT8) (MAX_ATAPI_BYTE_COUNT & 0x00ff)
 | 
						|
    );
 | 
						|
  IDEWritePortB (
 | 
						|
    IdeDev->PciIo,
 | 
						|
    IdeDev->IoPort->CylinderMsb,
 | 
						|
    (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8)
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  //  DEFAULT_CTL:0x0a (0000,1010)
 | 
						|
  //  Disable interrupt
 | 
						|
  //
 | 
						|
  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DEFAULT_CTL);
 | 
						|
 | 
						|
  //
 | 
						|
  // Send Packet command to inform device
 | 
						|
  // that the following data bytes are command packet.
 | 
						|
  //
 | 
						|
  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, PACKET_CMD);
 | 
						|
 | 
						|
  Status = DRQReady2 (IdeDev, ATAPITIMEOUT);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Send out command packet
 | 
						|
  //
 | 
						|
  CommandIndex = Packet->Data16;
 | 
						|
  for (Count = 0; Count < 6; Count++, CommandIndex++) {
 | 
						|
    IDEWritePortW (IdeDev->PciIo, IdeDev->IoPort->Data, *CommandIndex);
 | 
						|
    gBS->Stall (10);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // call PioReadWriteData() function to send requested transfer data to device.
 | 
						|
  //
 | 
						|
  return PioReadWriteData (IdeDev, Buffer, ByteCount, 0, TimeOut);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function is called by either AtapiPacketCommandIn() or 
 | 
						|
  AtapiPacketCommandOut(). It is used to transfer data between
 | 
						|
  host and device. The data direction is specified by the fourth
 | 
						|
  parameter.
 | 
						|
 | 
						|
  @param[in] *IdeDev
 | 
						|
  pointer pointing to IDE_BLK_IO_DEV data structure, used
 | 
						|
  to record all the information of the IDE device.
 | 
						|
 | 
						|
  @param[in] *Buffer
 | 
						|
  buffer contained data transferred between host and device.
 | 
						|
 | 
						|
  @param[in] ByteCount
 | 
						|
  data size in byte unit of the buffer.
 | 
						|
 | 
						|
  @param[in] Read
 | 
						|
  flag used to determine the data transfer direction.
 | 
						|
  Read equals 1, means data transferred from device to host;
 | 
						|
  Read equals 0, means data transferred from host to device.
 | 
						|
 | 
						|
  @param[in] TimeOut
 | 
						|
  timeout value for wait DRQ ready before each data 
 | 
						|
  stream's transfer.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS
 | 
						|
  data is transferred successfully.
 | 
						|
  
 | 
						|
  @retval EFI_DEVICE_ERROR
 | 
						|
  the device failed to transfer data.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
PioReadWriteData (
 | 
						|
  IN  IDE_BLK_IO_DEV  *IdeDev,
 | 
						|
  IN  UINT16          *Buffer,
 | 
						|
  IN  UINT32          ByteCount,
 | 
						|
  IN  BOOLEAN         Read,
 | 
						|
  IN  UINTN           TimeOut
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // required transfer data in word unit.
 | 
						|
  //
 | 
						|
  UINT32      RequiredWordCount;
 | 
						|
 | 
						|
  //
 | 
						|
  // actual transfer data in word unit.
 | 
						|
  //
 | 
						|
  UINT32      ActualWordCount;
 | 
						|
  UINT32      WordCount;
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINT16      *PtrBuffer;
 | 
						|
 | 
						|
  //
 | 
						|
  // containing status byte read from Status Register.
 | 
						|
  //
 | 
						|
  UINT8       StatusRegister;
 | 
						|
 | 
						|
  //
 | 
						|
  // No data transfer is premitted.
 | 
						|
  //
 | 
						|
  if (ByteCount == 0) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // for performance, we assert the ByteCount is an even number
 | 
						|
  // which is actually a resonable assumption  
 | 
						|
  ASSERT((ByteCount%2) == 0);
 | 
						|
  
 | 
						|
  PtrBuffer         = Buffer;
 | 
						|
  RequiredWordCount = ByteCount / 2;
 | 
						|
  //
 | 
						|
  // ActuralWordCount means the word count of data really transferred.
 | 
						|
  //
 | 
						|
  ActualWordCount = 0;
 | 
						|
 | 
						|
  while (ActualWordCount < RequiredWordCount) {
 | 
						|
    
 | 
						|
    //
 | 
						|
    // before each data transfer stream, the host should poll DRQ bit ready,
 | 
						|
    // to see whether indicates device is ready to transfer data.
 | 
						|
    //
 | 
						|
    Status = DRQReady2 (IdeDev, TimeOut);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return CheckErrorStatus (IdeDev);
 | 
						|
    }
 | 
						|
    
 | 
						|
    //
 | 
						|
    // read Status Register will clear interrupt
 | 
						|
    //
 | 
						|
    StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
 | 
						|
 | 
						|
    //
 | 
						|
    // get current data transfer size from Cylinder Registers.
 | 
						|
    //
 | 
						|
    WordCount =
 | 
						|
      (
 | 
						|
        (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb) << 8) |
 | 
						|
        IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb)
 | 
						|
      ) & 0xffff;
 | 
						|
    WordCount /= 2;
 | 
						|
 | 
						|
    WordCount = EFI_MIN (WordCount, (RequiredWordCount - ActualWordCount));
 | 
						|
 | 
						|
    if (Read) {
 | 
						|
      IDEReadPortWMultiple (
 | 
						|
        IdeDev->PciIo,
 | 
						|
        IdeDev->IoPort->Data,
 | 
						|
        WordCount,
 | 
						|
        PtrBuffer
 | 
						|
        );
 | 
						|
    } else {
 | 
						|
      IDEWritePortWMultiple (
 | 
						|
        IdeDev->PciIo,
 | 
						|
        IdeDev->IoPort->Data,
 | 
						|
        WordCount,
 | 
						|
        PtrBuffer
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    PtrBuffer += WordCount;
 | 
						|
    ActualWordCount += WordCount;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // After data transfer is completed, normally, DRQ bit should clear.
 | 
						|
  //
 | 
						|
  Status = DRQClear2 (IdeDev, ATAPITIMEOUT);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // read status register to check whether error happens.
 | 
						|
  //
 | 
						|
  return CheckErrorStatus (IdeDev);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Sends out ATAPI Test Unit Ready Packet Command to the specified device
 | 
						|
  to find out whether device is accessible.
 | 
						|
 | 
						|
  @param[in] *IdeDev
 | 
						|
  pointer pointing to IDE_BLK_IO_DEV data structure, used
 | 
						|
  to record all the information of the IDE device.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS
 | 
						|
  device is accessible.
 | 
						|
  
 | 
						|
  @retval EFI_DEVICE_ERROR
 | 
						|
  device is not accessible.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AtapiTestUnitReady (
 | 
						|
  IN  IDE_BLK_IO_DEV  *IdeDev
 | 
						|
  )
 | 
						|
{
 | 
						|
  ATAPI_PACKET_COMMAND  Packet;
 | 
						|
  EFI_STATUS            Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // fill command packet
 | 
						|
  //
 | 
						|
  ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
 | 
						|
  Packet.TestUnitReady.opcode = TEST_UNIT_READY;
 | 
						|
 | 
						|
  //
 | 
						|
  // send command packet
 | 
						|
  //
 | 
						|
  Status = AtapiPacketCommandIn (IdeDev, &Packet, NULL, 0, ATAPITIMEOUT);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Sends out ATAPI Request Sense Packet Command to the specified device.
 | 
						|
  This command will return all the current Sense data in the device. 
 | 
						|
  This function will pack all the Sense data in one single buffer.
 | 
						|
 | 
						|
  @param[in] *IdeDev
 | 
						|
  pointer pointing to IDE_BLK_IO_DEV data structure, used
 | 
						|
  to record all the information of the IDE device.
 | 
						|
 | 
						|
  @param[out] **SenseBuffers
 | 
						|
  allocated in this function, and freed by the calling function.
 | 
						|
  This buffer is used to accommodate all the sense data returned 
 | 
						|
  by the device.
 | 
						|
 | 
						|
  @param[out] *BufUnit
 | 
						|
  record the unit size of the sense data block in the SenseBuffers,
 | 
						|
 | 
						|
  @param[out] *BufNumbers
 | 
						|
  record the number of units in the SenseBuffers.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS
 | 
						|
  Request Sense command completes successfully.
 | 
						|
  
 | 
						|
  @retval EFI_DEVICE_ERROR
 | 
						|
  Request Sense command failed.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AtapiRequestSense (
 | 
						|
  IN  IDE_BLK_IO_DEV  *IdeDev,
 | 
						|
  OUT UINTN           *SenseCounts
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS            Status;
 | 
						|
  REQUEST_SENSE_DATA    *Sense;
 | 
						|
  UINT16                *Ptr;
 | 
						|
  BOOLEAN               FetchSenseData;
 | 
						|
  ATAPI_PACKET_COMMAND  Packet;
 | 
						|
 | 
						|
  *SenseCounts = 0;
 | 
						|
 | 
						|
  ZeroMem (IdeDev->SenseData, sizeof (REQUEST_SENSE_DATA) * (IdeDev->SenseDataNumber));
 | 
						|
  //
 | 
						|
  // 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);
 | 
						|
 | 
						|
  //
 | 
						|
  // initialize pointer
 | 
						|
  //
 | 
						|
  Ptr = (UINT16 *) IdeDev->SenseData;
 | 
						|
  //
 | 
						|
  //  request sense data from device continuously until no sense data
 | 
						|
  //  exists in the device.
 | 
						|
  //
 | 
						|
  for (FetchSenseData = TRUE; FetchSenseData;) {
 | 
						|
 | 
						|
    Sense = (REQUEST_SENSE_DATA *) Ptr;
 | 
						|
 | 
						|
    //
 | 
						|
    // send out Request Sense Packet Command and get one Sense data form device
 | 
						|
    //
 | 
						|
    Status = AtapiPacketCommandIn (
 | 
						|
              IdeDev,
 | 
						|
              &Packet,
 | 
						|
              Ptr,
 | 
						|
              sizeof (REQUEST_SENSE_DATA),
 | 
						|
              ATAPITIMEOUT
 | 
						|
              );
 | 
						|
    //
 | 
						|
    // failed to get Sense data
 | 
						|
    //
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      if (*SenseCounts == 0) {
 | 
						|
        return EFI_DEVICE_ERROR;
 | 
						|
      } else {
 | 
						|
        return EFI_SUCCESS;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    (*SenseCounts)++;
 | 
						|
    //
 | 
						|
    // We limit MAX sense data count to 20 in order to avoid dead loop. Some
 | 
						|
    // incompatible ATAPI devices don't retrive NO_SENSE when there is no media.
 | 
						|
    // In this case, dead loop occurs if we don't have a gatekeeper. 20 is
 | 
						|
    // supposed to be large enough for any ATAPI device.
 | 
						|
    //
 | 
						|
    if ((Sense->sense_key != SK_NO_SENSE) && ((*SenseCounts) < 20)) {
 | 
						|
      //
 | 
						|
      // Ptr is word-based pointer
 | 
						|
      //
 | 
						|
      Ptr += sizeof (REQUEST_SENSE_DATA) / 2;
 | 
						|
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // when no sense key, skip out the loop
 | 
						|
      //
 | 
						|
      FetchSenseData = 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.
 | 
						|
 | 
						|
  Current device status will impact device's response to the Read Capacity
 | 
						|
  Command. For example, if the device once reset, the Read Capacity
 | 
						|
  Command will fail. The Sense data record the current device status, so 
 | 
						|
  if the Read Capacity Command failed, the Sense data must be requested
 | 
						|
  and be analyzed to determine if the Read Capacity Command should retry.
 | 
						|
 | 
						|
  @param[in] *IdeDev
 | 
						|
  pointer pointing to IDE_BLK_IO_DEV data structure, used
 | 
						|
  to record all the information of the IDE device.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS
 | 
						|
  Read Capacity Command finally completes successfully.
 | 
						|
  
 | 
						|
  @retval EFI_DEVICE_ERROR
 | 
						|
  Read Capacity Command failed because of device error.
 | 
						|
 | 
						|
  @note
 | 
						|
  parameter "IdeDev" will be updated in this function.
 | 
						|
 | 
						|
  TODO:    EFI_NOT_READY - add return value to function comment
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AtapiReadCapacity (
 | 
						|
  IN  IDE_BLK_IO_DEV  *IdeDev
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // status returned by Read Capacity Packet Command
 | 
						|
  //
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  ATAPI_PACKET_COMMAND      Packet;
 | 
						|
 | 
						|
  //
 | 
						|
  // used for capacity data returned from ATAPI device
 | 
						|
  //
 | 
						|
  READ_CAPACITY_DATA        Data;
 | 
						|
  READ_FORMAT_CAPACITY_DATA FormatData;
 | 
						|
 | 
						|
  ZeroMem (&Data, sizeof (Data));
 | 
						|
  ZeroMem (&FormatData, sizeof (FormatData));
 | 
						|
 | 
						|
  if (IdeDev->Type == IdeCdRom) {
 | 
						|
 | 
						|
    ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
 | 
						|
    Packet.Inquiry.opcode = READ_CAPACITY;
 | 
						|
    Status = AtapiPacketCommandIn (
 | 
						|
              IdeDev,
 | 
						|
              &Packet,
 | 
						|
              (UINT16 *) &Data,
 | 
						|
              sizeof (READ_CAPACITY_DATA),
 | 
						|
              ATAPITIMEOUT
 | 
						|
              );
 | 
						|
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // Type == IdeMagnetic
 | 
						|
    //
 | 
						|
    ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
 | 
						|
    Packet.ReadFormatCapacity.opcode                = READ_FORMAT_CAPACITY;
 | 
						|
    Packet.ReadFormatCapacity.allocation_length_lo  = 12;
 | 
						|
    Status = AtapiPacketCommandIn (
 | 
						|
              IdeDev,
 | 
						|
              &Packet,
 | 
						|
              (UINT16 *) &FormatData,
 | 
						|
              sizeof (READ_FORMAT_CAPACITY_DATA),
 | 
						|
              ATAPITIMEOUT
 | 
						|
              );
 | 
						|
  }
 | 
						|
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
 | 
						|
    if (IdeDev->Type == IdeCdRom) {
 | 
						|
 | 
						|
      IdeDev->BlkIo.Media->LastBlock = (Data.LastLba3 << 24) |
 | 
						|
        (Data.LastLba2 << 16) |
 | 
						|
        (Data.LastLba1 << 8) |
 | 
						|
        Data.LastLba0;
 | 
						|
 | 
						|
      if (IdeDev->BlkIo.Media->LastBlock != 0) {
 | 
						|
 | 
						|
        IdeDev->BlkIo.Media->BlockSize = (Data.BlockSize3 << 24) |
 | 
						|
          (Data.BlockSize2 << 16) |
 | 
						|
          (Data.BlockSize1 << 8) |
 | 
						|
          Data.BlockSize0;
 | 
						|
 | 
						|
        IdeDev->BlkIo.Media->MediaPresent = TRUE;
 | 
						|
      } else {
 | 
						|
        IdeDev->BlkIo.Media->MediaPresent = FALSE;
 | 
						|
        return EFI_DEVICE_ERROR;
 | 
						|
      }
 | 
						|
 | 
						|
      IdeDev->BlkIo.Media->ReadOnly = TRUE;
 | 
						|
 | 
						|
      //
 | 
						|
      // Because the user data portion in the sector of the Data CD supported
 | 
						|
      // is always 0x800
 | 
						|
      //
 | 
						|
      IdeDev->BlkIo.Media->BlockSize = 0x800;
 | 
						|
    }
 | 
						|
 | 
						|
    if (IdeDev->Type == IdeMagnetic) {
 | 
						|
 | 
						|
      if (FormatData.DesCode == 3) {
 | 
						|
        IdeDev->BlkIo.Media->MediaPresent = FALSE;
 | 
						|
        IdeDev->BlkIo.Media->LastBlock    = 0;
 | 
						|
      } else {
 | 
						|
 | 
						|
        IdeDev->BlkIo.Media->LastBlock =  (FormatData.LastLba3 << 24) |
 | 
						|
                                          (FormatData.LastLba2 << 16) | 
 | 
						|
                                          (FormatData.LastLba1 << 8)  |
 | 
						|
                                           FormatData.LastLba0;
 | 
						|
        if (IdeDev->BlkIo.Media->LastBlock != 0) {
 | 
						|
          IdeDev->BlkIo.Media->LastBlock--;
 | 
						|
 | 
						|
          IdeDev->BlkIo.Media->BlockSize = (FormatData.BlockSize2 << 16) |
 | 
						|
            (FormatData.BlockSize1 << 8) |
 | 
						|
            FormatData.BlockSize0;
 | 
						|
 | 
						|
          IdeDev->BlkIo.Media->MediaPresent = TRUE;
 | 
						|
        } else {
 | 
						|
          IdeDev->BlkIo.Media->MediaPresent = FALSE;
 | 
						|
          //
 | 
						|
          // Return EFI_NOT_READY operation succeeds but returned capacity is 0
 | 
						|
          //
 | 
						|
          return EFI_NOT_READY;
 | 
						|
        }
 | 
						|
 | 
						|
        IdeDev->BlkIo.Media->BlockSize = 0x200;
 | 
						|
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    return EFI_SUCCESS;
 | 
						|
 | 
						|
  } else {
 | 
						|
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Used before read/write blocks from/to ATAPI device media. 
 | 
						|
  Since ATAPI device media is removable, it is necessary to detect
 | 
						|
  whether media is present and get current present media's
 | 
						|
  information, and if media has been changed, Block I/O Protocol
 | 
						|
  need to be reinstalled.
 | 
						|
 | 
						|
  @param[in] *IdeDev
 | 
						|
  pointer pointing to IDE_BLK_IO_DEV data structure, used
 | 
						|
  to record all the information of the IDE device.
 | 
						|
 | 
						|
  @param[out] *MediaChange
 | 
						|
  return value that indicates if the media of the device has been
 | 
						|
  changed.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS
 | 
						|
  media found successfully.
 | 
						|
  
 | 
						|
  @retval EFI_DEVICE_ERROR
 | 
						|
  any error encounters during media detection.
 | 
						|
  
 | 
						|
  @retval EFI_NO_MEDIA
 | 
						|
  media not found.
 | 
						|
 | 
						|
  @note
 | 
						|
  parameter IdeDev may be updated in this function.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AtapiDetectMedia (
 | 
						|
  IN  IDE_BLK_IO_DEV  *IdeDev,
 | 
						|
  OUT BOOLEAN         *MediaChange
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS          Status;
 | 
						|
  EFI_STATUS          ReadCapacityStatus;
 | 
						|
  EFI_BLOCK_IO_MEDIA  OldMediaInfo;
 | 
						|
  UINTN               SenseCounts;
 | 
						|
  UINTN               RetryIndex;
 | 
						|
  UINTN               RetryTimes;
 | 
						|
  UINTN               MaximumRetryTimes;
 | 
						|
  UINTN               ReadyWaitFactor;
 | 
						|
  BOOLEAN             NeedRetry;
 | 
						|
  //
 | 
						|
  // a flag used to determine whether need to perform Read Capacity command.
 | 
						|
  //
 | 
						|
  BOOLEAN             NeedReadCapacity;
 | 
						|
  BOOLEAN             WriteProtected;
 | 
						|
 | 
						|
  //
 | 
						|
  // init
 | 
						|
  //
 | 
						|
  CopyMem (&OldMediaInfo, IdeDev->BlkIo.Media, sizeof (OldMediaInfo));
 | 
						|
  // OldMediaInfo        = *(IdeDev->BlkIo.Media);
 | 
						|
  *MediaChange        = FALSE;
 | 
						|
  ReadCapacityStatus  = EFI_DEVICE_ERROR;
 | 
						|
 | 
						|
  //
 | 
						|
  // if there is no media, or media is not changed,
 | 
						|
  // the request sense command will detect faster than read capacity command.
 | 
						|
  // read capacity command can be bypassed, thus improve performance.
 | 
						|
  //
 | 
						|
 | 
						|
  //
 | 
						|
  // Test Unit Ready command is used to detect whether device is accessible,
 | 
						|
  // the device will produce corresponding Sense data.
 | 
						|
  //
 | 
						|
  for (RetryIndex = 0; RetryIndex < 2; RetryIndex++) {
 | 
						|
 | 
						|
    Status = AtapiTestUnitReady (IdeDev);
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      //
 | 
						|
      // skip the loop if test unit command succeeds.
 | 
						|
      //
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = AtapiSoftReset (IdeDev);
 | 
						|
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      AtaSoftReset (IdeDev);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  SenseCounts       = 0;
 | 
						|
  NeedReadCapacity  = TRUE;
 | 
						|
 | 
						|
  //
 | 
						|
  // at most retry 5 times
 | 
						|
  //
 | 
						|
  MaximumRetryTimes = 5;
 | 
						|
  RetryTimes        = 1;
 | 
						|
 | 
						|
  for (RetryIndex = 0; 
 | 
						|
       (RetryIndex < RetryTimes) && (RetryIndex < MaximumRetryTimes);
 | 
						|
       RetryIndex++) {
 | 
						|
 | 
						|
    Status = AtapiRequestSense (IdeDev, &SenseCounts);
 | 
						|
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      //
 | 
						|
      // if first time there is no Sense Key, no need to read capacity any more
 | 
						|
      //
 | 
						|
      if (!HaveSenseKey (IdeDev->SenseData, SenseCounts) &&
 | 
						|
          (IdeDev->BlkIo.Media->MediaPresent)) {
 | 
						|
 | 
						|
        if (RetryIndex == 0) {
 | 
						|
          NeedReadCapacity = FALSE;
 | 
						|
        }
 | 
						|
 | 
						|
      } else {
 | 
						|
        //
 | 
						|
        // No Media
 | 
						|
        //
 | 
						|
        if (IsNoMedia (IdeDev->SenseData, SenseCounts)) {
 | 
						|
          NeedReadCapacity                  = FALSE;
 | 
						|
          IdeDev->BlkIo.Media->MediaPresent = FALSE;
 | 
						|
          IdeDev->BlkIo.Media->LastBlock    = 0;
 | 
						|
        } else {
 | 
						|
          //
 | 
						|
          // Media Changed
 | 
						|
          //
 | 
						|
          if (IsMediaChange (IdeDev->SenseData, SenseCounts)) {
 | 
						|
            NeedReadCapacity = TRUE;
 | 
						|
            IdeDev->BlkIo.Media->MediaId++;
 | 
						|
          }
 | 
						|
          //
 | 
						|
          // Media Error
 | 
						|
          //
 | 
						|
          if (IsMediaError (IdeDev->SenseData, SenseCounts)) {
 | 
						|
            return EFI_DEVICE_ERROR;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // retry once more, if request sense command met errors.
 | 
						|
      //
 | 
						|
      RetryTimes++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (NeedReadCapacity) {
 | 
						|
    //
 | 
						|
    // at most retry 5 times
 | 
						|
    //
 | 
						|
    MaximumRetryTimes = 5;
 | 
						|
    //
 | 
						|
    // initial retry twice
 | 
						|
    //
 | 
						|
    RetryTimes        = 2;
 | 
						|
    ReadyWaitFactor = 2;
 | 
						|
 | 
						|
    for (RetryIndex = 0;
 | 
						|
         (RetryIndex < RetryTimes) && (RetryIndex < MaximumRetryTimes);
 | 
						|
         RetryIndex++) {
 | 
						|
 | 
						|
      ReadCapacityStatus  = AtapiReadCapacity (IdeDev);
 | 
						|
 | 
						|
      SenseCounts         = 0;
 | 
						|
 | 
						|
      if (!EFI_ERROR (ReadCapacityStatus)) {
 | 
						|
        //
 | 
						|
        // Read Capacity succeeded
 | 
						|
        //
 | 
						|
        break;
 | 
						|
 | 
						|
      } else {
 | 
						|
 | 
						|
        if (ReadCapacityStatus == EFI_NOT_READY) {
 | 
						|
          //
 | 
						|
          // If device not ready, wait here... waiting time increases by retry
 | 
						|
          // times.
 | 
						|
          //
 | 
						|
          gBS->Stall (ReadyWaitFactor * 2000 * STALL_1_MILLI_SECOND);
 | 
						|
          ReadyWaitFactor++;
 | 
						|
          //
 | 
						|
          // retry once more
 | 
						|
          //
 | 
						|
          RetryTimes++;
 | 
						|
          continue;
 | 
						|
        }
 | 
						|
        
 | 
						|
        //
 | 
						|
        // Other errors returned, requery sense data
 | 
						|
        //
 | 
						|
        Status = AtapiRequestSense (IdeDev, &SenseCounts);
 | 
						|
 | 
						|
        //
 | 
						|
        // If Request Sense data failed, reset the device and retry.
 | 
						|
        //
 | 
						|
        if (EFI_ERROR (Status)) {
 | 
						|
 | 
						|
          Status = AtapiSoftReset (IdeDev);
 | 
						|
 | 
						|
          //
 | 
						|
          // if ATAPI soft reset fail,
 | 
						|
          // use stronger reset mechanism -- ATA soft reset.
 | 
						|
          //
 | 
						|
          if (EFI_ERROR (Status)) {
 | 
						|
            AtaSoftReset (IdeDev);
 | 
						|
          }
 | 
						|
          //
 | 
						|
          // retry once more
 | 
						|
          //
 | 
						|
          RetryTimes++;
 | 
						|
          continue;
 | 
						|
        }
 | 
						|
        
 | 
						|
        //
 | 
						|
        // No Media
 | 
						|
        //
 | 
						|
        if (IsNoMedia (IdeDev->SenseData, SenseCounts)) {
 | 
						|
 | 
						|
          IdeDev->BlkIo.Media->MediaPresent = FALSE;
 | 
						|
          IdeDev->BlkIo.Media->LastBlock    = 0;
 | 
						|
          return EFI_NO_MEDIA;
 | 
						|
        }
 | 
						|
 | 
						|
        if (IsMediaError (IdeDev->SenseData, SenseCounts)) {
 | 
						|
          return EFI_DEVICE_ERROR;
 | 
						|
        }
 | 
						|
        
 | 
						|
        //
 | 
						|
        // Media Changed
 | 
						|
        //
 | 
						|
        if (IsMediaChange (IdeDev->SenseData, SenseCounts)) {
 | 
						|
          IdeDev->BlkIo.Media->MediaId++;
 | 
						|
        }
 | 
						|
 | 
						|
        if (!IsDriveReady (IdeDev->SenseData, SenseCounts, &NeedRetry)) {
 | 
						|
          
 | 
						|
          //
 | 
						|
          // Drive not ready: if NeedRetry, then retry once more;
 | 
						|
          // else return error
 | 
						|
          //
 | 
						|
          if (NeedRetry) {
 | 
						|
            //
 | 
						|
            // Stall 1 second to wait for drive becoming ready
 | 
						|
            //
 | 
						|
            gBS->Stall (1000 * STALL_1_MILLI_SECOND);
 | 
						|
            //
 | 
						|
            // reset retry variable to zero,
 | 
						|
            // to make it retry for "drive in progress of becoming ready".
 | 
						|
            //
 | 
						|
            RetryIndex = 0;
 | 
						|
            continue;
 | 
						|
          } else {
 | 
						|
            AtapiSoftReset (IdeDev);
 | 
						|
            return EFI_DEVICE_ERROR;
 | 
						|
          }
 | 
						|
        }
 | 
						|
        //
 | 
						|
        // if read capacity fail not for above reasons, retry once more
 | 
						|
        //
 | 
						|
        RetryTimes++;
 | 
						|
      }
 | 
						|
 | 
						|
    }
 | 
						|
  
 | 
						|
    //
 | 
						|
    // tell whether the readcapacity process is successful or not in the end
 | 
						|
    //
 | 
						|
    if (EFI_ERROR (ReadCapacityStatus)) {
 | 
						|
      return EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // the following code is to check the write-protected for LS120 media
 | 
						|
  //
 | 
						|
  if ((IdeDev->BlkIo.Media->MediaPresent) && (IdeDev->Type == IdeMagnetic)) {
 | 
						|
 | 
						|
    Status = IsLS120orZipWriteProtected (IdeDev, &WriteProtected);
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
 | 
						|
      if (WriteProtected) {
 | 
						|
 | 
						|
        IdeDev->BlkIo.Media->ReadOnly = TRUE;
 | 
						|
      } else {
 | 
						|
 | 
						|
        IdeDev->BlkIo.Media->ReadOnly = FALSE;
 | 
						|
      }
 | 
						|
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (IdeDev->BlkIo.Media->MediaId != OldMediaInfo.MediaId) {
 | 
						|
    //
 | 
						|
    // Media change information got from the device
 | 
						|
    //
 | 
						|
    *MediaChange = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (IdeDev->BlkIo.Media->ReadOnly != OldMediaInfo.ReadOnly) {
 | 
						|
    *MediaChange = TRUE;
 | 
						|
    IdeDev->BlkIo.Media->MediaId += 1;
 | 
						|
  }
 | 
						|
 | 
						|
  if (IdeDev->BlkIo.Media->BlockSize != OldMediaInfo.BlockSize) {
 | 
						|
    *MediaChange = TRUE;
 | 
						|
    IdeDev->BlkIo.Media->MediaId += 1;
 | 
						|
  }
 | 
						|
 | 
						|
  if (IdeDev->BlkIo.Media->LastBlock != OldMediaInfo.LastBlock) {
 | 
						|
    *MediaChange = TRUE;
 | 
						|
    IdeDev->BlkIo.Media->MediaId += 1;
 | 
						|
  }
 | 
						|
 | 
						|
  if (IdeDev->BlkIo.Media->MediaPresent != OldMediaInfo.MediaPresent) {
 | 
						|
    if (IdeDev->BlkIo.Media->MediaPresent) {
 | 
						|
      //
 | 
						|
      // when change from no media to media present, reset the MediaId to 1.
 | 
						|
      //
 | 
						|
      IdeDev->BlkIo.Media->MediaId = 1;
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // when no media, reset the MediaId to zero.
 | 
						|
      //
 | 
						|
      IdeDev->BlkIo.Media->MediaId = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    *MediaChange = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // if any change on current existing media,
 | 
						|
  // the Block I/O protocol need to be reinstalled.
 | 
						|
  //
 | 
						|
  if (*MediaChange) {
 | 
						|
    gBS->ReinstallProtocolInterface (
 | 
						|
          IdeDev->Handle,
 | 
						|
          &gEfiBlockIoProtocolGuid,
 | 
						|
          &IdeDev->BlkIo,
 | 
						|
          &IdeDev->BlkIo
 | 
						|
          );
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function is called by the AtapiBlkIoReadBlocks() to perform
 | 
						|
  read from media in block unit.
 | 
						|
 | 
						|
  The main command used to access media here is READ(10) Command. 
 | 
						|
  READ(10) Command requests that the ATAPI device media transfer 
 | 
						|
  specified data to the host. Data is transferred in block(sector) 
 | 
						|
  unit. The maximum number of blocks that can be transferred once is
 | 
						|
  65536. This is the main difference between READ(10) and READ(12) 
 | 
						|
  Command. The maximum number of blocks in READ(12) is 2 power 32.
 | 
						|
 | 
						|
  @param[in] *IdeDev
 | 
						|
  pointer pointing to IDE_BLK_IO_DEV data structure, used
 | 
						|
  to record all the information of the IDE device.
 | 
						|
 | 
						|
  @param[in] *Buffer
 | 
						|
  A pointer to the destination buffer for the data. 
 | 
						|
 | 
						|
  @param[in] Lba
 | 
						|
  The starting logical block address to read from 
 | 
						|
  on the device media.
 | 
						|
 | 
						|
  @param[in] NumberOfBlocks
 | 
						|
  The number of transfer data blocks.
 | 
						|
 | 
						|
  @return status is fully dependent on the return status
 | 
						|
  of AtapiPacketCommandIn() function.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AtapiReadSectors (
 | 
						|
  IN  IDE_BLK_IO_DEV  *IdeDev,
 | 
						|
  IN  VOID            *Buffer,
 | 
						|
  IN  EFI_LBA         Lba,
 | 
						|
  IN  UINTN           NumberOfBlocks
 | 
						|
  )
 | 
						|
{
 | 
						|
 | 
						|
  ATAPI_PACKET_COMMAND  Packet;
 | 
						|
  READ10_CMD            *Read10Packet;
 | 
						|
  EFI_STATUS            Status;
 | 
						|
  UINTN                 BlocksRemaining;
 | 
						|
  UINT32                Lba32;
 | 
						|
  UINT32                BlockSize;
 | 
						|
  UINT32                ByteCount;
 | 
						|
  UINT16                SectorCount;
 | 
						|
  VOID                  *PtrBuffer;
 | 
						|
  UINT16                MaxBlock;
 | 
						|
  UINTN                 TimeOut;
 | 
						|
 | 
						|
  //
 | 
						|
  // fill command packet for Read(10) command
 | 
						|
  //
 | 
						|
  ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
 | 
						|
  Read10Packet  = &Packet.Read10;
 | 
						|
  Lba32         = (UINT32) Lba;
 | 
						|
  PtrBuffer     = Buffer;
 | 
						|
 | 
						|
  BlockSize     = IdeDev->BlkIo.Media->BlockSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // limit the data bytes that can be transferred by one Read(10) Command
 | 
						|
  //
 | 
						|
  MaxBlock        = (UINT16) (65536 / BlockSize);
 | 
						|
 | 
						|
  BlocksRemaining = NumberOfBlocks;
 | 
						|
 | 
						|
  Status          = EFI_SUCCESS;
 | 
						|
  while (BlocksRemaining > 0) {
 | 
						|
 | 
						|
    if (BlocksRemaining <= MaxBlock) {
 | 
						|
 | 
						|
      SectorCount = (UINT16) 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;
 | 
						|
 | 
						|
    if (IdeDev->Type == IdeCdRom) {
 | 
						|
      TimeOut = CDROMLONGTIMEOUT;
 | 
						|
    } else {
 | 
						|
      TimeOut = ATAPILONGTIMEOUT;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = AtapiPacketCommandIn (
 | 
						|
              IdeDev,
 | 
						|
              &Packet,
 | 
						|
              (UINT16 *) PtrBuffer,
 | 
						|
              ByteCount,
 | 
						|
              TimeOut
 | 
						|
              );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    Lba32 += SectorCount;
 | 
						|
    PtrBuffer = (UINT8 *) PtrBuffer + SectorCount * BlockSize;
 | 
						|
    BlocksRemaining -= SectorCount;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function is called by the AtapiBlkIoWriteBlocks() to perform
 | 
						|
  write onto media in block unit.
 | 
						|
  The main command used to access media here is Write(10) Command. 
 | 
						|
  Write(10) Command requests that the ATAPI device media transfer 
 | 
						|
  specified data to the host. Data is transferred in block (sector) 
 | 
						|
  unit. The maximum number of blocks that can be transferred once is
 | 
						|
  65536. 
 | 
						|
 | 
						|
  @param[in] *IdeDev
 | 
						|
  pointer pointing to IDE_BLK_IO_DEV data structure, used
 | 
						|
  to record all the information of the IDE device.
 | 
						|
 | 
						|
  @param[in] *Buffer
 | 
						|
  A pointer to the source buffer for the data. 
 | 
						|
 | 
						|
  @param[in] Lba
 | 
						|
  The starting logical block address to write onto 
 | 
						|
  the device media.
 | 
						|
 | 
						|
  @param[in] NumberOfBlocks
 | 
						|
  The number of transfer data blocks.
 | 
						|
 | 
						|
  @return status is fully dependent on the return status
 | 
						|
  of AtapiPacketCommandOut() function.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AtapiWriteSectors (
 | 
						|
  IN  IDE_BLK_IO_DEV  *IdeDev,
 | 
						|
  IN  VOID            *Buffer,
 | 
						|
  IN  EFI_LBA         Lba,
 | 
						|
  IN  UINTN           NumberOfBlocks
 | 
						|
  )
 | 
						|
{
 | 
						|
 | 
						|
  ATAPI_PACKET_COMMAND  Packet;
 | 
						|
  READ10_CMD            *Read10Packet;
 | 
						|
 | 
						|
  EFI_STATUS            Status;
 | 
						|
  UINTN                 BlocksRemaining;
 | 
						|
  UINT32                Lba32;
 | 
						|
  UINT32                BlockSize;
 | 
						|
  UINT32                ByteCount;
 | 
						|
  UINT16                SectorCount;
 | 
						|
  VOID                  *PtrBuffer;
 | 
						|
  UINT16                MaxBlock;
 | 
						|
 | 
						|
  //
 | 
						|
  // fill command packet for Write(10) command
 | 
						|
  // Write(10) command packet has the same data structure as
 | 
						|
  // Read(10) command packet,
 | 
						|
  // so here use the Read10Packet data structure
 | 
						|
  // for the Write(10) command packet.
 | 
						|
  //
 | 
						|
  ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
 | 
						|
  Read10Packet  = &Packet.Read10;
 | 
						|
 | 
						|
  Lba32         = (UINT32) Lba;
 | 
						|
  PtrBuffer     = Buffer;
 | 
						|
 | 
						|
  BlockSize     = IdeDev->BlkIo.Media->BlockSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // limit the data bytes that can be transferred by one Read(10) Command
 | 
						|
  //
 | 
						|
  MaxBlock        = (UINT16) (65536 / BlockSize);
 | 
						|
 | 
						|
  BlocksRemaining = NumberOfBlocks;
 | 
						|
 | 
						|
  Status          = EFI_SUCCESS;
 | 
						|
  while (BlocksRemaining > 0) {
 | 
						|
 | 
						|
    if (BlocksRemaining >= MaxBlock) {
 | 
						|
      SectorCount = MaxBlock;
 | 
						|
    } else {
 | 
						|
      SectorCount = (UINT16) BlocksRemaining;
 | 
						|
    }
 | 
						|
  
 | 
						|
    //
 | 
						|
    // Command code is WRITE_10.
 | 
						|
    //
 | 
						|
    Read10Packet->opcode = WRITE_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;
 | 
						|
 | 
						|
    Status = AtapiPacketCommandOut (
 | 
						|
              IdeDev,
 | 
						|
              &Packet,
 | 
						|
              (UINT16 *) PtrBuffer,
 | 
						|
              ByteCount,
 | 
						|
              ATAPILONGTIMEOUT
 | 
						|
              );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    Lba32 += SectorCount;
 | 
						|
    PtrBuffer = ((UINT8 *) PtrBuffer + SectorCount * BlockSize);
 | 
						|
    BlocksRemaining -= SectorCount;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function is used to implement the Soft Reset on the specified
 | 
						|
  ATAPI device. Different from the AtaSoftReset(), here reset is a ATA
 | 
						|
  Soft Reset Command special for ATAPI device, and it only take effects
 | 
						|
  on the specified ATAPI device, not on the whole IDE bus.
 | 
						|
  Since the ATAPI soft reset is needed when device is in exceptional
 | 
						|
  condition (such as BSY bit is always set ), I think the Soft Reset
 | 
						|
  command should be sent without waiting for the BSY clear and DRDY
 | 
						|
  set.
 | 
						|
  This function is called by IdeBlkIoReset(), 
 | 
						|
  a interface function of Block I/O protocol.
 | 
						|
 | 
						|
  @param[in] *IdeDev
 | 
						|
  pointer pointing to IDE_BLK_IO_DEV data structure, used
 | 
						|
  to record all the information of the IDE device.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS
 | 
						|
  Soft reset completes successfully.
 | 
						|
  
 | 
						|
  @retval EFI_DEVICE_ERROR
 | 
						|
  Any step during the reset process is failed.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AtapiSoftReset (
 | 
						|
  IN  IDE_BLK_IO_DEV  *IdeDev
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8       Command;
 | 
						|
  UINT8       DeviceSelect;
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // for ATAPI device, no need to wait DRDY ready after device selecting.
 | 
						|
  // (bit7 and bit5 are both set to 1 for backward compatibility)
 | 
						|
  //
 | 
						|
  DeviceSelect = (UINT8) (((bit7 | bit5) | (IdeDev->Device << 4)));
 | 
						|
  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);
 | 
						|
 | 
						|
  Command = ATAPI_SOFT_RESET_CMD;
 | 
						|
  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, Command);
 | 
						|
 | 
						|
  //
 | 
						|
  // BSY cleared is the only status return to the host by the device
 | 
						|
  // when reset is completed.
 | 
						|
  // slave device needs at most 31s to clear BSY
 | 
						|
  //
 | 
						|
  Status = WaitForBSYClear (IdeDev, 31000);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // stall 5 seconds to make the device status stable
 | 
						|
  //
 | 
						|
  gBS->Stall (5000000);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function is the ATAPI implementation for ReadBlocks in the
 | 
						|
  Block I/O Protocol interface.
 | 
						|
 | 
						|
  @param[in] *IdeBlkIoDev
 | 
						|
  Indicates the calling context.
 | 
						|
 | 
						|
  @param[in] MediaId
 | 
						|
  The media id that the read request is for.
 | 
						|
 | 
						|
  @param[in] LBA
 | 
						|
  The starting logical block address to read from 
 | 
						|
  on the device.
 | 
						|
 | 
						|
  @param[in] BufferSize
 | 
						|
  The size of the Buffer in bytes. This must be a
 | 
						|
  multiple of the intrinsic block size of the device.
 | 
						|
 | 
						|
  @param[out] *Buffer
 | 
						|
  A pointer to the destination buffer for the data. 
 | 
						|
  The caller is responsible for either having implicit
 | 
						|
  or explicit ownership of the memory that data is read into.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS
 | 
						|
  Read Blocks successfully.
 | 
						|
  
 | 
						|
  @retval EFI_DEVICE_ERROR
 | 
						|
  Read Blocks failed.
 | 
						|
  
 | 
						|
  @retval EFI_NO_MEDIA
 | 
						|
  There is no media in the device.
 | 
						|
  
 | 
						|
  @retval EFI_MEDIA_CHANGED
 | 
						|
  The MediaId is not for the current media.
 | 
						|
  
 | 
						|
  @retval EFI_BAD_BUFFER_SIZE
 | 
						|
  The BufferSize parameter is not a multiple of the
 | 
						|
  intrinsic block size of the device.
 | 
						|
  
 | 
						|
  @retval EFI_INVALID_PARAMETER
 | 
						|
  The read request contains LBAs that are not valid,
 | 
						|
  or the data buffer is not valid.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AtapiBlkIoReadBlocks (
 | 
						|
  IN IDE_BLK_IO_DEV   *IdeBlkIoDevice,
 | 
						|
  IN UINT32           MediaId,
 | 
						|
  IN EFI_LBA          LBA,
 | 
						|
  IN UINTN            BufferSize,
 | 
						|
  OUT VOID            *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_BLOCK_IO_MEDIA  *Media;
 | 
						|
  UINTN               BlockSize;
 | 
						|
  UINTN               NumberOfBlocks;
 | 
						|
  EFI_STATUS          Status;
 | 
						|
 | 
						|
  BOOLEAN             MediaChange;
 | 
						|
 | 
						|
  if (Buffer == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (BufferSize == 0) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // ATAPI device media is removable, so it is a must
 | 
						|
  // to detect media first before read operation
 | 
						|
  //
 | 
						|
  MediaChange = FALSE;
 | 
						|
  Status      = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
 | 
						|
    if (IdeBlkIoDevice->Cache != NULL) {
 | 
						|
      gBS->FreePool (IdeBlkIoDevice->Cache);
 | 
						|
      IdeBlkIoDevice->Cache = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Get the intrinsic block size
 | 
						|
  //
 | 
						|
  Media           = IdeBlkIoDevice->BlkIo.Media;
 | 
						|
  BlockSize       = Media->BlockSize;
 | 
						|
 | 
						|
  NumberOfBlocks  = BufferSize / BlockSize;
 | 
						|
 | 
						|
  if (!(Media->MediaPresent)) {
 | 
						|
 | 
						|
    if (IdeBlkIoDevice->Cache != NULL) {
 | 
						|
      gBS->FreePool (IdeBlkIoDevice->Cache);
 | 
						|
      IdeBlkIoDevice->Cache = NULL;
 | 
						|
    }
 | 
						|
    return EFI_NO_MEDIA;
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  if ((MediaId != Media->MediaId) || MediaChange) {
 | 
						|
 | 
						|
    if (IdeBlkIoDevice->Cache != NULL) {
 | 
						|
      gBS->FreePool (IdeBlkIoDevice->Cache);
 | 
						|
      IdeBlkIoDevice->Cache = NULL;
 | 
						|
    }
 | 
						|
    return EFI_MEDIA_CHANGED;
 | 
						|
  }
 | 
						|
 | 
						|
  if (BufferSize % BlockSize != 0) {
 | 
						|
    return EFI_BAD_BUFFER_SIZE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (LBA > Media->LastBlock) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // if all the parameters are valid, then perform read sectors command
 | 
						|
  // to transfer data from device to host.
 | 
						|
  //
 | 
						|
  Status = AtapiReadSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Read blocks succeeded
 | 
						|
  //
 | 
						|
  
 | 
						|
  //
 | 
						|
  // save the first block to the cache for performance
 | 
						|
  //
 | 
						|
  if (LBA == 0 && !IdeBlkIoDevice->Cache) {
 | 
						|
    IdeBlkIoDevice->Cache = AllocatePool (BlockSize);
 | 
						|
    if (IdeBlkIoDevice != NULL) {
 | 
						|
      CopyMem ((UINT8 *) IdeBlkIoDevice->Cache, (UINT8 *) Buffer, BlockSize);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function is the ATAPI implementation for WriteBlocks in the
 | 
						|
  Block I/O Protocol interface.
 | 
						|
 | 
						|
  @param[in] *This
 | 
						|
  Indicates the calling context.
 | 
						|
 | 
						|
  @param[in] MediaId
 | 
						|
  The media id that the write request is for.
 | 
						|
 | 
						|
  @param[in] LBA
 | 
						|
  The starting logical block address to write onto 
 | 
						|
  the device.
 | 
						|
 | 
						|
  @param[in] BufferSize
 | 
						|
  The size of the Buffer in bytes. This must be a
 | 
						|
  multiple of the intrinsic block size of the device.
 | 
						|
 | 
						|
  @param[out] *Buffer
 | 
						|
  A pointer to the source buffer for the data. 
 | 
						|
  The caller is responsible for either having implicit
 | 
						|
  or explicit ownership of the memory that data is 
 | 
						|
  written from.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS
 | 
						|
  Write Blocks successfully.
 | 
						|
  
 | 
						|
  @retval EFI_DEVICE_ERROR
 | 
						|
  Write Blocks failed.
 | 
						|
  
 | 
						|
  @retval EFI_NO_MEDIA
 | 
						|
  There is no media in the device.
 | 
						|
  
 | 
						|
  @retval EFI_MEDIA_CHANGE
 | 
						|
  The MediaId is not for the current media.
 | 
						|
  
 | 
						|
  @retval EFI_BAD_BUFFER_SIZE
 | 
						|
  The BufferSize parameter is not a multiple of the
 | 
						|
  intrinsic block size of the device.
 | 
						|
  
 | 
						|
  @retval EFI_INVALID_PARAMETER
 | 
						|
  The write request contains LBAs that are not valid,
 | 
						|
  or the data buffer is not valid.
 | 
						|
 | 
						|
  TODO:    EFI_MEDIA_CHANGED - add return value to function comment
 | 
						|
  TODO:    EFI_WRITE_PROTECTED - add return value to function comment
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AtapiBlkIoWriteBlocks (
 | 
						|
  IN IDE_BLK_IO_DEV   *IdeBlkIoDevice,
 | 
						|
  IN UINT32           MediaId,
 | 
						|
  IN EFI_LBA          LBA,
 | 
						|
  IN UINTN            BufferSize,
 | 
						|
  OUT VOID            *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
 | 
						|
  EFI_BLOCK_IO_MEDIA  *Media;
 | 
						|
  UINTN               BlockSize;
 | 
						|
  UINTN               NumberOfBlocks;
 | 
						|
  EFI_STATUS          Status;
 | 
						|
  BOOLEAN             MediaChange;
 | 
						|
 | 
						|
  if (LBA == 0 && IdeBlkIoDevice->Cache) {
 | 
						|
    gBS->FreePool (IdeBlkIoDevice->Cache);
 | 
						|
    IdeBlkIoDevice->Cache = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Buffer == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (BufferSize == 0) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // ATAPI device media is removable,
 | 
						|
  // so it is a must to detect media first before write operation
 | 
						|
  //
 | 
						|
  MediaChange = FALSE;
 | 
						|
  Status      = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
 | 
						|
    if (LBA == 0 && IdeBlkIoDevice->Cache) {
 | 
						|
      gBS->FreePool (IdeBlkIoDevice->Cache);
 | 
						|
      IdeBlkIoDevice->Cache = NULL;
 | 
						|
    }
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Get the intrinsic block size
 | 
						|
  //
 | 
						|
  Media           = IdeBlkIoDevice->BlkIo.Media;
 | 
						|
  BlockSize       = Media->BlockSize;
 | 
						|
  NumberOfBlocks  = BufferSize / BlockSize;
 | 
						|
 | 
						|
  if (!(Media->MediaPresent)) {
 | 
						|
 | 
						|
    if (LBA == 0 && IdeBlkIoDevice->Cache) {
 | 
						|
      gBS->FreePool (IdeBlkIoDevice->Cache);
 | 
						|
      IdeBlkIoDevice->Cache = NULL;
 | 
						|
    }
 | 
						|
    return EFI_NO_MEDIA;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((MediaId != Media->MediaId) || MediaChange) {
 | 
						|
 | 
						|
    if (LBA == 0 && IdeBlkIoDevice->Cache) {
 | 
						|
      gBS->FreePool (IdeBlkIoDevice->Cache);
 | 
						|
      IdeBlkIoDevice->Cache = NULL;
 | 
						|
    }
 | 
						|
    return EFI_MEDIA_CHANGED;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Media->ReadOnly) {
 | 
						|
    return EFI_WRITE_PROTECTED;
 | 
						|
  }
 | 
						|
 | 
						|
  if (BufferSize % BlockSize != 0) {
 | 
						|
    return EFI_BAD_BUFFER_SIZE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (LBA > Media->LastBlock) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // if all the parameters are valid,
 | 
						|
  // then perform write sectors command to transfer data from host to device.
 | 
						|
  //
 | 
						|
  Status = AtapiWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// The following functions are a set of helper functions,
 | 
						|
// which are used to parse sense key returned by the device.
 | 
						|
//
 | 
						|
 | 
						|
/**
 | 
						|
  TODO: Add function description
 | 
						|
 | 
						|
  @param  SenseData TODO: add argument description
 | 
						|
  @param  SenseCounts TODO: add argument description
 | 
						|
 | 
						|
  TODO: add return values
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsNoMedia (
 | 
						|
  IN  REQUEST_SENSE_DATA    *SenseData,
 | 
						|
  IN  UINTN                 SenseCounts
 | 
						|
  )
 | 
						|
{
 | 
						|
  REQUEST_SENSE_DATA  *SensePointer;
 | 
						|
  UINTN               Index;
 | 
						|
  BOOLEAN             NoMedia;
 | 
						|
 | 
						|
  NoMedia       = FALSE;
 | 
						|
  SensePointer  = SenseData;
 | 
						|
 | 
						|
  for (Index = 0; Index < SenseCounts; Index++) {
 | 
						|
    //
 | 
						|
    // Sense Key is SK_NOT_READY (0x2),
 | 
						|
    // Additional Sense Code is ASC_NO_MEDIA (0x3A)
 | 
						|
    //
 | 
						|
    if ((SensePointer->sense_key == SK_NOT_READY) &&
 | 
						|
        (SensePointer->addnl_sense_code == ASC_NO_MEDIA)) {
 | 
						|
 | 
						|
      NoMedia = TRUE;
 | 
						|
    }
 | 
						|
 | 
						|
    SensePointer++;
 | 
						|
  }
 | 
						|
 | 
						|
  return NoMedia;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Test if the device meets a media error after media changed
 | 
						|
 | 
						|
  @param[in] *SenseData
 | 
						|
  pointer pointing to ATAPI device sense data list.
 | 
						|
  @param[in] SenseCounts
 | 
						|
  sense data number of the list          
 | 
						|
 | 
						|
  @retval TRUE Device meets a media error
 | 
						|
  @retval FALSE No media error
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsMediaError (
 | 
						|
  IN  REQUEST_SENSE_DATA    *SenseData,
 | 
						|
  IN  UINTN                 SenseCounts
 | 
						|
  )
 | 
						|
{
 | 
						|
  REQUEST_SENSE_DATA  *SensePointer;
 | 
						|
  UINTN               Index;
 | 
						|
  BOOLEAN             IsError;
 | 
						|
 | 
						|
  IsError       = FALSE;
 | 
						|
  SensePointer  = SenseData;
 | 
						|
 | 
						|
  for (Index = 0; Index < SenseCounts; Index++) {
 | 
						|
 | 
						|
    switch (SensePointer->sense_key) {
 | 
						|
 | 
						|
    case SK_MEDIUM_ERROR:
 | 
						|
      //
 | 
						|
      // Sense Key is SK_MEDIUM_ERROR (0x3)
 | 
						|
      //
 | 
						|
      switch (SensePointer->addnl_sense_code) {
 | 
						|
      case ASC_MEDIA_ERR1:
 | 
						|
      case ASC_MEDIA_ERR2:
 | 
						|
      case ASC_MEDIA_ERR3:
 | 
						|
      case ASC_MEDIA_ERR4:
 | 
						|
        IsError = TRUE;
 | 
						|
        break;
 | 
						|
 | 
						|
      default:
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      break;
 | 
						|
 | 
						|
    case SK_NOT_READY:
 | 
						|
      //
 | 
						|
      // Sense Key is SK_NOT_READY (0x2)
 | 
						|
      //
 | 
						|
      switch (SensePointer->addnl_sense_code) {
 | 
						|
      //
 | 
						|
      // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
 | 
						|
      //
 | 
						|
      case ASC_MEDIA_UPSIDE_DOWN:
 | 
						|
        IsError = TRUE;
 | 
						|
        break;
 | 
						|
 | 
						|
      default:
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    SensePointer++;
 | 
						|
  }
 | 
						|
 | 
						|
  return IsError;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  TODO: Add function description
 | 
						|
 | 
						|
  @param  SenseData TODO: add argument description
 | 
						|
  @param  SenseCounts TODO: add argument description
 | 
						|
 | 
						|
  TODO: add return values
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsMediaChange (
 | 
						|
  IN  REQUEST_SENSE_DATA    *SenseData,
 | 
						|
  IN  UINTN                 SenseCounts
 | 
						|
  )
 | 
						|
{
 | 
						|
  REQUEST_SENSE_DATA  *SensePointer;
 | 
						|
  UINTN               Index;
 | 
						|
  BOOLEAN             IsMediaChange;
 | 
						|
 | 
						|
  IsMediaChange = FALSE;
 | 
						|
  SensePointer  = SenseData;
 | 
						|
 | 
						|
  for (Index = 0; Index < SenseCounts; Index++) {
 | 
						|
    //
 | 
						|
    // Sense Key is SK_UNIT_ATTENTION (0x6)
 | 
						|
    //
 | 
						|
    if ((SensePointer->sense_key == SK_UNIT_ATTENTION) &&
 | 
						|
        (SensePointer->addnl_sense_code == ASC_MEDIA_CHANGE)) {
 | 
						|
 | 
						|
      IsMediaChange = TRUE;
 | 
						|
    }
 | 
						|
 | 
						|
    SensePointer++;
 | 
						|
  }
 | 
						|
 | 
						|
  return IsMediaChange;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  TODO: Add function description
 | 
						|
 | 
						|
  @param  SenseData TODO: add argument description
 | 
						|
  @param  SenseCounts TODO: add argument description
 | 
						|
  @param  NeedRetry TODO: add argument description
 | 
						|
 | 
						|
  TODO: add return values
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsDriveReady (
 | 
						|
  IN  REQUEST_SENSE_DATA    *SenseData,
 | 
						|
  IN  UINTN                 SenseCounts,
 | 
						|
  OUT BOOLEAN               *NeedRetry
 | 
						|
  )
 | 
						|
{
 | 
						|
  REQUEST_SENSE_DATA  *SensePointer;
 | 
						|
  UINTN               Index;
 | 
						|
  BOOLEAN             IsReady;
 | 
						|
 | 
						|
  IsReady       = TRUE;
 | 
						|
  *NeedRetry    = FALSE;
 | 
						|
  SensePointer  = SenseData;
 | 
						|
 | 
						|
  for (Index = 0; Index < SenseCounts; Index++) {
 | 
						|
 | 
						|
    switch (SensePointer->sense_key) {
 | 
						|
 | 
						|
    case SK_NOT_READY:
 | 
						|
      //
 | 
						|
      // Sense Key is SK_NOT_READY (0x2)
 | 
						|
      //
 | 
						|
      switch (SensePointer->addnl_sense_code) {
 | 
						|
      case ASC_NOT_READY:
 | 
						|
        //
 | 
						|
        // Additional Sense Code is ASC_NOT_READY (0x4)
 | 
						|
        //
 | 
						|
        switch (SensePointer->addnl_sense_code_qualifier) {
 | 
						|
        case ASCQ_IN_PROGRESS:
 | 
						|
          //
 | 
						|
          // Additional Sense Code Qualifier is ASCQ_IN_PROGRESS (0x1)
 | 
						|
          //
 | 
						|
          IsReady     = FALSE;
 | 
						|
          *NeedRetry  = TRUE;
 | 
						|
          break;
 | 
						|
 | 
						|
        default:
 | 
						|
          IsReady     = FALSE;
 | 
						|
          *NeedRetry  = FALSE;
 | 
						|
          break;
 | 
						|
        }
 | 
						|
        break;
 | 
						|
 | 
						|
      default:
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    SensePointer++;
 | 
						|
  }
 | 
						|
 | 
						|
  return IsReady;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  TODO: Add function description
 | 
						|
 | 
						|
  @param  SenseData TODO: add argument description
 | 
						|
  @param  SenseCounts TODO: add argument description
 | 
						|
 | 
						|
  TODO: add return values
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
HaveSenseKey (
 | 
						|
  IN  REQUEST_SENSE_DATA    *SenseData,
 | 
						|
  IN  UINTN                 SenseCounts
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN Have;
 | 
						|
 | 
						|
  Have = TRUE;
 | 
						|
 | 
						|
  //
 | 
						|
  // if first sense key in the Sense Data Array is SK_NO_SENSE,
 | 
						|
  // it indicates there is no more sense key in the Sense Data Array.
 | 
						|
  //
 | 
						|
  if (SenseData->sense_key == SK_NO_SENSE) {
 | 
						|
    Have = FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  return Have;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  TODO: Add function description
 | 
						|
 | 
						|
  @param  IdeDev TODO: add argument description
 | 
						|
  @param  WriteProtected TODO: add argument description
 | 
						|
 | 
						|
  @retval  EFI_DEVICE_ERROR TODO: Add description for return value
 | 
						|
  @retval  EFI_DEVICE_ERROR TODO: Add description for return value
 | 
						|
  @retval  EFI_SUCCESS TODO: Add description for return value
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
IsLS120orZipWriteProtected (
 | 
						|
  IN  IDE_BLK_IO_DEV    *IdeDev,
 | 
						|
  OUT BOOLEAN           *WriteProtected
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  *WriteProtected = FALSE;
 | 
						|
 | 
						|
  Status          = LS120EnableMediaStatus (IdeDev, TRUE);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // the Get Media Status Command is only valid
 | 
						|
  // if a Set Features/Enable Media Status Command has been priviously issued.
 | 
						|
  //
 | 
						|
  if (LS120GetMediaStatus (IdeDev) == EFI_WRITE_PROTECTED) {
 | 
						|
 | 
						|
    *WriteProtected = TRUE;
 | 
						|
  } else {
 | 
						|
 | 
						|
    *WriteProtected = FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // After Get Media Status Command completes,
 | 
						|
  // Set Features/Disable Media Command should be sent.
 | 
						|
  //
 | 
						|
  Status = LS120EnableMediaStatus (IdeDev, FALSE);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 |