mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-11-04 03:52:45 +00:00 
			
		
		
		
	Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Feng Tian <feng.tian@intel.com> Reviewed-by: Star Zeng <star.zeng@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17482 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1194 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1194 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
 | 
						|
  Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
 | 
						|
  This program and the accompanying materials
 | 
						|
  are licensed and made available under the terms and conditions of the BSD License
 | 
						|
  which accompanies this distribution.  The full text of the license may be found at
 | 
						|
  http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "UfsBlockIoPei.h"
 | 
						|
 | 
						|
//
 | 
						|
// Template for UFS HC Peim Private Data.
 | 
						|
//
 | 
						|
UFS_PEIM_HC_PRIVATE_DATA   gUfsHcPeimTemplate = {
 | 
						|
  UFS_PEIM_HC_SIG,                // Signature
 | 
						|
  NULL,                           // Controller
 | 
						|
  NULL,                           // Pool
 | 
						|
  {                               // BlkIoPpi
 | 
						|
    UfsBlockIoPeimGetDeviceNo,
 | 
						|
    UfsBlockIoPeimGetMediaInfo,
 | 
						|
    UfsBlockIoPeimReadBlocks
 | 
						|
  },
 | 
						|
  {                               // BlkIo2Ppi
 | 
						|
    EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION,
 | 
						|
    UfsBlockIoPeimGetDeviceNo2,
 | 
						|
    UfsBlockIoPeimGetMediaInfo2,
 | 
						|
    UfsBlockIoPeimReadBlocks2
 | 
						|
  },
 | 
						|
  {                               // BlkIoPpiList
 | 
						|
    EFI_PEI_PPI_DESCRIPTOR_PPI,
 | 
						|
    &gEfiPeiVirtualBlockIoPpiGuid,
 | 
						|
    NULL
 | 
						|
  },
 | 
						|
  {                               // BlkIo2PpiList
 | 
						|
    EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
 | 
						|
    &gEfiPeiVirtualBlockIo2PpiGuid,
 | 
						|
    NULL
 | 
						|
  },
 | 
						|
  {                               // Media
 | 
						|
    {
 | 
						|
      MSG_UFS_DP,
 | 
						|
      FALSE,
 | 
						|
      TRUE,
 | 
						|
      FALSE,
 | 
						|
      0x1000,
 | 
						|
      0
 | 
						|
    },
 | 
						|
    {
 | 
						|
      MSG_UFS_DP,
 | 
						|
      FALSE,
 | 
						|
      TRUE,
 | 
						|
      FALSE,
 | 
						|
      0x1000,
 | 
						|
      0
 | 
						|
    },
 | 
						|
    {
 | 
						|
      MSG_UFS_DP,
 | 
						|
      FALSE,
 | 
						|
      TRUE,
 | 
						|
      FALSE,
 | 
						|
      0x1000,
 | 
						|
      0
 | 
						|
    },
 | 
						|
    {
 | 
						|
      MSG_UFS_DP,
 | 
						|
      FALSE,
 | 
						|
      TRUE,
 | 
						|
      FALSE,
 | 
						|
      0x1000,
 | 
						|
      0
 | 
						|
    },
 | 
						|
    {
 | 
						|
      MSG_UFS_DP,
 | 
						|
      FALSE,
 | 
						|
      TRUE,
 | 
						|
      FALSE,
 | 
						|
      0x1000,
 | 
						|
      0
 | 
						|
    },
 | 
						|
    {
 | 
						|
      MSG_UFS_DP,
 | 
						|
      FALSE,
 | 
						|
      TRUE,
 | 
						|
      FALSE,
 | 
						|
      0x1000,
 | 
						|
      0
 | 
						|
    },
 | 
						|
    {
 | 
						|
      MSG_UFS_DP,
 | 
						|
      FALSE,
 | 
						|
      TRUE,
 | 
						|
      FALSE,
 | 
						|
      0x1000,
 | 
						|
      0
 | 
						|
    },
 | 
						|
    {
 | 
						|
      MSG_UFS_DP,
 | 
						|
      FALSE,
 | 
						|
      TRUE,
 | 
						|
      FALSE,
 | 
						|
      0x1000,
 | 
						|
      0
 | 
						|
    }
 | 
						|
  },
 | 
						|
  0,                              // UfsHcBase
 | 
						|
  0,                              // Capabilities
 | 
						|
  0,                              // TaskTag
 | 
						|
  0,                              // UtpTrlBase
 | 
						|
  0,                              // Nutrs
 | 
						|
  0,                              // UtpTmrlBase
 | 
						|
  0,                              // Nutmrs
 | 
						|
  {                               // Luns
 | 
						|
    {
 | 
						|
      UFS_LUN_0,                      // Ufs Common Lun 0
 | 
						|
      UFS_LUN_1,                      // Ufs Common Lun 1
 | 
						|
      UFS_LUN_2,                      // Ufs Common Lun 2
 | 
						|
      UFS_LUN_3,                      // Ufs Common Lun 3
 | 
						|
      UFS_LUN_4,                      // Ufs Common Lun 4
 | 
						|
      UFS_LUN_5,                      // Ufs Common Lun 5
 | 
						|
      UFS_LUN_6,                      // Ufs Common Lun 6
 | 
						|
      UFS_LUN_7,                      // Ufs Common Lun 7
 | 
						|
    },
 | 
						|
    0x0000,                           // By default exposing all Luns.
 | 
						|
    0x0
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
  Execute Request Sense SCSI command on a specific UFS device.
 | 
						|
 | 
						|
  @param[in]  Private              A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
  @param[in]  Lun                  The lun on which the SCSI cmd executed.
 | 
						|
  @param[out] DataBuffer           A pointer to output sense data.
 | 
						|
  @param[out] DataBufferLength     The length of output sense data.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS              The command executed successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR         A device error occurred while attempting to send SCSI Request Packet.
 | 
						|
  @retval EFI_TIMEOUT              A timeout occurred while waiting for the SCSI Request Packet to execute.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsPeimRequestSense (
 | 
						|
  IN     UFS_PEIM_HC_PRIVATE_DATA        *Private,
 | 
						|
  IN     UINTN                           Lun,  
 | 
						|
     OUT VOID                            *DataBuffer,
 | 
						|
     OUT UINT32                          *DataBufferLength
 | 
						|
  )  
 | 
						|
{
 | 
						|
  UFS_SCSI_REQUEST_PACKET                Packet;
 | 
						|
  UINT8                                  Cdb[UFS_SCSI_OP_LENGTH_SIX];
 | 
						|
  EFI_STATUS                             Status;
 | 
						|
 | 
						|
  ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
 | 
						|
  ZeroMem (Cdb, sizeof (Cdb));
 | 
						|
 | 
						|
  Cdb[0]  = EFI_SCSI_OP_REQUEST_SENSE;
 | 
						|
 | 
						|
  Packet.Timeout          = UFS_TIMEOUT;
 | 
						|
  Packet.Cdb              = Cdb;
 | 
						|
  Packet.CdbLength        = sizeof (Cdb);
 | 
						|
  Packet.DataDirection    = UfsDataIn;
 | 
						|
  Packet.InDataBuffer     = DataBuffer;
 | 
						|
  Packet.InTransferLength = *DataBufferLength;
 | 
						|
  Packet.SenseData        = NULL;
 | 
						|
  Packet.SenseDataLength  = 0;
 | 
						|
 | 
						|
  Status = UfsExecScsiCmds (Private,(UINT8)Lun, &Packet);
 | 
						|
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    *DataBufferLength = Packet.InTransferLength;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Execute TEST UNITY READY SCSI command on a specific UFS device.
 | 
						|
 | 
						|
  @param[in]  Private              A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
  @param[in]  Lun                  The lun on which the SCSI cmd executed.
 | 
						|
  @param[out] SenseData            A pointer to output sense data.
 | 
						|
  @param[out] SenseDataLength      The length of output sense data.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS              The command executed successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR         A device error occurred while attempting to send SCSI Request Packet.
 | 
						|
  @retval EFI_TIMEOUT              A timeout occurred while waiting for the SCSI Request Packet to execute.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsPeimTestUnitReady (
 | 
						|
  IN     UFS_PEIM_HC_PRIVATE_DATA        *Private,
 | 
						|
  IN     UINTN                           Lun,  
 | 
						|
     OUT VOID                            *SenseData,  OPTIONAL
 | 
						|
     OUT UINT8                           *SenseDataLength
 | 
						|
  )  
 | 
						|
{
 | 
						|
  UFS_SCSI_REQUEST_PACKET                Packet;
 | 
						|
  UINT8                                  Cdb[UFS_SCSI_OP_LENGTH_SIX];
 | 
						|
  EFI_STATUS                             Status;
 | 
						|
 | 
						|
  ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
 | 
						|
  ZeroMem (Cdb, sizeof (Cdb));
 | 
						|
 | 
						|
  Cdb[0]  = EFI_SCSI_OP_TEST_UNIT_READY;
 | 
						|
 | 
						|
  Packet.Timeout         = UFS_TIMEOUT;
 | 
						|
  Packet.Cdb             = Cdb;
 | 
						|
  Packet.CdbLength       = sizeof (Cdb);
 | 
						|
  Packet.DataDirection   = UfsNoData;
 | 
						|
  Packet.SenseData       = SenseData;
 | 
						|
  Packet.SenseDataLength = *SenseDataLength;
 | 
						|
 | 
						|
  Status = UfsExecScsiCmds (Private,(UINT8)Lun, &Packet);
 | 
						|
 | 
						|
  if (*SenseDataLength != 0) {
 | 
						|
    *SenseDataLength = Packet.SenseDataLength;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Execute INQUIRY SCSI command on a specific UFS device.
 | 
						|
 | 
						|
  @param[in]  Private              A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
  @param[in]  Lun                  The lun on which the SCSI cmd executed.
 | 
						|
  @param[out] Inquiry              A pointer to Inquiry data buffer.
 | 
						|
  @param[out] InquiryLengths       The length of output Inquiry data.
 | 
						|
  @param[out] SenseData            A pointer to output sense data.
 | 
						|
  @param[out] SenseDataLength      The length of output sense data.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS              The command executed successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR         A device error occurred while attempting to send SCSI Request Packet.
 | 
						|
  @retval EFI_TIMEOUT              A timeout occurred while waiting for the SCSI Request Packet to execute.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsPeimInquiry (
 | 
						|
  IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
 | 
						|
  IN     UINTN                        Lun,
 | 
						|
     OUT VOID                         *Inquiry,
 | 
						|
     OUT UINT32                       *InquiryLength,
 | 
						|
     OUT VOID                         *SenseData,  OPTIONAL
 | 
						|
     OUT UINT8                        *SenseDataLength
 | 
						|
  )  
 | 
						|
{
 | 
						|
  UFS_SCSI_REQUEST_PACKET             Packet;
 | 
						|
  UINT8                               Cdb[UFS_SCSI_OP_LENGTH_SIX];
 | 
						|
  EFI_STATUS                          Status;
 | 
						|
 | 
						|
  ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
 | 
						|
  ZeroMem (Cdb, sizeof (Cdb));
 | 
						|
 | 
						|
  Cdb[0]  = EFI_SCSI_OP_INQUIRY;
 | 
						|
  Cdb[4]  = sizeof (EFI_SCSI_INQUIRY_DATA);
 | 
						|
 | 
						|
  Packet.Timeout          = UFS_TIMEOUT;
 | 
						|
  Packet.Cdb              = Cdb;
 | 
						|
  Packet.CdbLength        = sizeof (Cdb);
 | 
						|
  Packet.InDataBuffer     = Inquiry;
 | 
						|
  Packet.InTransferLength = *InquiryLength;
 | 
						|
  Packet.DataDirection    = UfsDataIn;
 | 
						|
  Packet.SenseData        = SenseData;
 | 
						|
  Packet.SenseDataLength  = *SenseDataLength;
 | 
						|
 | 
						|
  Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);
 | 
						|
 | 
						|
  if (*SenseDataLength != 0) {
 | 
						|
    *SenseDataLength = Packet.SenseDataLength;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    *InquiryLength = Packet.InTransferLength;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Execute READ CAPACITY(10) SCSI command on a specific UFS device.
 | 
						|
 | 
						|
  @param[in]  Private              A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
  @param[in]  Lun                  The lun on which the SCSI cmd executed.
 | 
						|
  @param[out] DataBuffer           A pointer to READ_CAPACITY data buffer.
 | 
						|
  @param[out] DataLength           The length of output READ_CAPACITY data.
 | 
						|
  @param[out] SenseData            A pointer to output sense data.
 | 
						|
  @param[out] SenseDataLength      The length of output sense data.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS              The command executed successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR         A device error occurred while attempting to send SCSI Request Packet.
 | 
						|
  @retval EFI_TIMEOUT              A timeout occurred while waiting for the SCSI Request Packet to execute.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsPeimReadCapacity (
 | 
						|
  IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
 | 
						|
  IN     UINTN                        Lun,
 | 
						|
     OUT VOID                         *DataBuffer,
 | 
						|
     OUT UINT32                       *DataLength,
 | 
						|
     OUT VOID                         *SenseData,  OPTIONAL
 | 
						|
     OUT UINT8                        *SenseDataLength
 | 
						|
  )  
 | 
						|
{
 | 
						|
  UFS_SCSI_REQUEST_PACKET             Packet;
 | 
						|
  UINT8                               Cdb[UFS_SCSI_OP_LENGTH_TEN];
 | 
						|
  EFI_STATUS                          Status;
 | 
						|
 | 
						|
  ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
 | 
						|
  ZeroMem (Cdb, sizeof (Cdb));
 | 
						|
 | 
						|
  Cdb[0] = EFI_SCSI_OP_READ_CAPACITY;
 | 
						|
 | 
						|
  Packet.Timeout          = UFS_TIMEOUT;
 | 
						|
  Packet.Cdb              = Cdb;
 | 
						|
  Packet.CdbLength        = sizeof (Cdb);
 | 
						|
  Packet.InDataBuffer     = DataBuffer;
 | 
						|
  Packet.InTransferLength = *DataLength;
 | 
						|
  Packet.DataDirection    = UfsDataIn;
 | 
						|
  Packet.SenseData        = SenseData;
 | 
						|
  Packet.SenseDataLength  = *SenseDataLength;
 | 
						|
 | 
						|
  Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);
 | 
						|
 | 
						|
  if (*SenseDataLength != 0) {
 | 
						|
    *SenseDataLength = Packet.SenseDataLength;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    *DataLength = Packet.InTransferLength;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Execute READ CAPACITY(16) SCSI command on a specific UFS device.
 | 
						|
 | 
						|
  @param[in]  Private              A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
  @param[in]  Lun                  The lun on which the SCSI cmd executed.
 | 
						|
  @param[out] DataBuffer           A pointer to READ_CAPACITY data buffer.
 | 
						|
  @param[out] DataLength           The length of output READ_CAPACITY data.
 | 
						|
  @param[out] SenseData            A pointer to output sense data.
 | 
						|
  @param[out] SenseDataLength      The length of output sense data.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS              The command executed successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR         A device error occurred while attempting to send SCSI Request Packet.
 | 
						|
  @retval EFI_TIMEOUT              A timeout occurred while waiting for the SCSI Request Packet to execute.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsPeimReadCapacity16 (
 | 
						|
  IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
 | 
						|
  IN     UINTN                        Lun,
 | 
						|
     OUT VOID                         *DataBuffer,
 | 
						|
     OUT UINT32                       *DataLength,
 | 
						|
     OUT VOID                         *SenseData,  OPTIONAL
 | 
						|
     OUT UINT8                        *SenseDataLength
 | 
						|
  )  
 | 
						|
{
 | 
						|
  UFS_SCSI_REQUEST_PACKET             Packet;
 | 
						|
  UINT8                               Cdb[UFS_SCSI_OP_LENGTH_SIXTEEN];
 | 
						|
  EFI_STATUS                          Status;
 | 
						|
 | 
						|
  ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
 | 
						|
  ZeroMem (Cdb, sizeof (Cdb));
 | 
						|
 | 
						|
  Cdb[0]  = EFI_SCSI_OP_READ_CAPACITY16;
 | 
						|
  Cdb[1]  = 0x10;          // Service Action should be 0x10 for UFS device.
 | 
						|
  Cdb[13] = 0x20;          // The maximum number of bytes for returned data.
 | 
						|
 | 
						|
  Packet.Timeout          = UFS_TIMEOUT;
 | 
						|
  Packet.Cdb              = Cdb;
 | 
						|
  Packet.CdbLength        = sizeof (Cdb);
 | 
						|
  Packet.InDataBuffer     = DataBuffer;
 | 
						|
  Packet.InTransferLength = *DataLength;
 | 
						|
  Packet.DataDirection    = UfsDataIn;
 | 
						|
  Packet.SenseData        = SenseData;
 | 
						|
  Packet.SenseDataLength  = *SenseDataLength;
 | 
						|
 | 
						|
  Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);
 | 
						|
 | 
						|
  if (*SenseDataLength != 0) {
 | 
						|
    *SenseDataLength = Packet.SenseDataLength;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    *DataLength = Packet.InTransferLength;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Execute READ (10) SCSI command on a specific UFS device.
 | 
						|
 | 
						|
  @param[in]  Private              A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
  @param[in]  Lun                  The lun on which the SCSI cmd executed.
 | 
						|
  @param[in]  StartLba             The start LBA.
 | 
						|
  @param[in]  SectorNum            The sector number to be read.
 | 
						|
  @param[out] DataBuffer           A pointer to data buffer.
 | 
						|
  @param[out] DataLength           The length of output data.
 | 
						|
  @param[out] SenseData            A pointer to output sense data.
 | 
						|
  @param[out] SenseDataLength      The length of output sense data.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS              The command executed successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR         A device error occurred while attempting to send SCSI Request Packet.
 | 
						|
  @retval EFI_TIMEOUT              A timeout occurred while waiting for the SCSI Request Packet to execute.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsPeimRead10 (
 | 
						|
  IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
 | 
						|
  IN     UINTN                        Lun,
 | 
						|
  IN     UINTN                        StartLba,
 | 
						|
  IN     UINT32                       SectorNum,
 | 
						|
     OUT VOID                         *DataBuffer,
 | 
						|
     OUT UINT32                       *DataLength,
 | 
						|
     OUT VOID                         *SenseData,  OPTIONAL
 | 
						|
     OUT UINT8                        *SenseDataLength
 | 
						|
  )  
 | 
						|
{
 | 
						|
  UFS_SCSI_REQUEST_PACKET             Packet;
 | 
						|
  UINT8                               Cdb[UFS_SCSI_OP_LENGTH_TEN];
 | 
						|
  EFI_STATUS                          Status;
 | 
						|
 | 
						|
  ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
 | 
						|
  ZeroMem (Cdb, sizeof (Cdb));
 | 
						|
 | 
						|
  Cdb[0] = EFI_SCSI_OP_READ10;
 | 
						|
  WriteUnaligned32 ((UINT32 *)&Cdb[2], SwapBytes32 ((UINT32) StartLba));
 | 
						|
  WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 ((UINT16) SectorNum));
 | 
						|
 | 
						|
  Packet.Timeout          = UFS_TIMEOUT;
 | 
						|
  Packet.Cdb              = Cdb;
 | 
						|
  Packet.CdbLength        = sizeof (Cdb);
 | 
						|
  Packet.InDataBuffer     = DataBuffer;
 | 
						|
  Packet.InTransferLength = *DataLength;
 | 
						|
  Packet.DataDirection    = UfsDataIn;
 | 
						|
  Packet.SenseData        = SenseData;
 | 
						|
  Packet.SenseDataLength  = *SenseDataLength;
 | 
						|
 | 
						|
  Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);
 | 
						|
 | 
						|
  if (*SenseDataLength != 0) {
 | 
						|
    *SenseDataLength = Packet.SenseDataLength;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    *DataLength = Packet.InTransferLength;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Execute READ (16) SCSI command on a specific UFS device.
 | 
						|
 | 
						|
  @param[in]  Private              A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
 | 
						|
  @param[in]  Lun                  The lun on which the SCSI cmd executed.
 | 
						|
  @param[in]  StartLba             The start LBA.
 | 
						|
  @param[in]  SectorNum            The sector number to be read.
 | 
						|
  @param[out] DataBuffer           A pointer to data buffer.
 | 
						|
  @param[out] DataLength           The length of output data.
 | 
						|
  @param[out] SenseData            A pointer to output sense data.
 | 
						|
  @param[out] SenseDataLength      The length of output sense data.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS              The command executed successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR         A device error occurred while attempting to send SCSI Request Packet.
 | 
						|
  @retval EFI_TIMEOUT              A timeout occurred while waiting for the SCSI Request Packet to execute.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsPeimRead16 (
 | 
						|
  IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
 | 
						|
  IN     UINTN                        Lun,
 | 
						|
  IN     UINTN                        StartLba,
 | 
						|
  IN     UINT32                       SectorNum,
 | 
						|
     OUT VOID                         *DataBuffer,
 | 
						|
     OUT UINT32                       *DataLength,
 | 
						|
     OUT VOID                         *SenseData,  OPTIONAL
 | 
						|
     OUT UINT8                        *SenseDataLength
 | 
						|
  )  
 | 
						|
{
 | 
						|
  UFS_SCSI_REQUEST_PACKET             Packet;
 | 
						|
  UINT8                               Cdb[UFS_SCSI_OP_LENGTH_SIXTEEN];
 | 
						|
  EFI_STATUS                          Status;
 | 
						|
 | 
						|
  ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
 | 
						|
  ZeroMem (Cdb, sizeof (Cdb));
 | 
						|
 | 
						|
  Cdb[0] = EFI_SCSI_OP_READ16;
 | 
						|
  WriteUnaligned64 ((UINT64 *)&Cdb[2], SwapBytes64 (StartLba));
 | 
						|
  WriteUnaligned32 ((UINT32 *)&Cdb[10], SwapBytes32 (SectorNum));
 | 
						|
 | 
						|
  Packet.Timeout          = UFS_TIMEOUT;
 | 
						|
  Packet.Cdb              = Cdb;
 | 
						|
  Packet.CdbLength        = sizeof (Cdb);
 | 
						|
  Packet.InDataBuffer     = DataBuffer;
 | 
						|
  Packet.InTransferLength = *DataLength;
 | 
						|
  Packet.DataDirection    = UfsDataIn;
 | 
						|
  Packet.SenseData        = SenseData;
 | 
						|
  Packet.SenseDataLength  = *SenseDataLength;
 | 
						|
 | 
						|
  Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);
 | 
						|
 | 
						|
  if (*SenseDataLength != 0) {
 | 
						|
    *SenseDataLength = Packet.SenseDataLength;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    *DataLength = Packet.InTransferLength;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Parsing Sense Keys from sense data.
 | 
						|
 | 
						|
  @param  Media              The pointer of EFI_PEI_BLOCK_IO_MEDIA
 | 
						|
  @param  SenseData          The pointer of EFI_SCSI_SENSE_DATA
 | 
						|
  @param  NeedRetry          The pointer of action which indicates what is need to retry
 | 
						|
 | 
						|
  @retval EFI_DEVICE_ERROR   Indicates that error occurs
 | 
						|
  @retval EFI_SUCCESS        Successfully to complete the parsing
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UfsPeimParsingSenseKeys (
 | 
						|
  IN     EFI_PEI_BLOCK_IO2_MEDIA   *Media,
 | 
						|
  IN     EFI_SCSI_SENSE_DATA       *SenseData,
 | 
						|
     OUT BOOLEAN                   *NeedRetry
 | 
						|
  )
 | 
						|
{
 | 
						|
  if ((SenseData->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
 | 
						|
      (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA)) {
 | 
						|
    Media->MediaPresent = FALSE;
 | 
						|
    *NeedRetry = FALSE;
 | 
						|
    DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Is No Media\n"));
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((SenseData->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
 | 
						|
      (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE)) {
 | 
						|
    *NeedRetry = TRUE;
 | 
						|
    DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Is Media Change\n"));
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((SenseData->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
 | 
						|
      (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_RESET)) {
 | 
						|
    *NeedRetry = TRUE;
 | 
						|
    DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Was Reset Before\n"));
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((SenseData->Sense_Key == EFI_SCSI_SK_MEDIUM_ERROR) ||
 | 
						|
      ((SenseData->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
 | 
						|
      (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN))) {
 | 
						|
    *NeedRetry = FALSE;
 | 
						|
    DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Media Error\n"));
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (SenseData->Sense_Key == EFI_SCSI_SK_HARDWARE_ERROR) {
 | 
						|
    *NeedRetry = FALSE;
 | 
						|
    DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Hardware Error\n"));
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((SenseData->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
 | 
						|
      (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_NOT_READY) &&
 | 
						|
      (SenseData->Addnl_Sense_Code_Qualifier == EFI_SCSI_ASCQ_IN_PROGRESS)) {
 | 
						|
    *NeedRetry = TRUE;
 | 
						|
    DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Was Reset Before\n"));
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  *NeedRetry = FALSE;
 | 
						|
  DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Sense Key = 0x%x ASC = 0x%x!\n", SenseData->Sense_Key, SenseData->Addnl_Sense_Code));
 | 
						|
  return EFI_DEVICE_ERROR;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Gets the count of block I/O devices that one specific block driver detects.
 | 
						|
 | 
						|
  This function is used for getting the count of block I/O devices that one 
 | 
						|
  specific block driver detects.  To the PEI ATAPI driver, it returns the number
 | 
						|
  of all the detected ATAPI devices it detects during the enumeration process. 
 | 
						|
  To the PEI legacy floppy driver, it returns the number of all the legacy 
 | 
						|
  devices it finds during its enumeration process. If no device is detected, 
 | 
						|
  then the function will return zero.  
 | 
						|
  
 | 
						|
  @param[in]  PeiServices          General-purpose services that are available 
 | 
						|
                                   to every PEIM.
 | 
						|
  @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI 
 | 
						|
                                   instance.
 | 
						|
  @param[out] NumberBlockDevices   The number of block I/O devices discovered.
 | 
						|
 | 
						|
  @retval     EFI_SUCCESS          The operation performed successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UfsBlockIoPeimGetDeviceNo (
 | 
						|
  IN  EFI_PEI_SERVICES               **PeiServices,
 | 
						|
  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,
 | 
						|
  OUT UINTN                          *NumberBlockDevices
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // For Ufs device, it has up to 8 normal Luns plus some well-known Luns.
 | 
						|
  // At PEI phase, we will only expose normal Luns to user.
 | 
						|
  // For those disabled Lun, when user try to access it, the operation would fail.
 | 
						|
  //
 | 
						|
  *NumberBlockDevices = UFS_PEIM_MAX_LUNS;
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Gets a block device's media information.
 | 
						|
 | 
						|
  This function will provide the caller with the specified block device's media 
 | 
						|
  information. If the media changes, calling this function will update the media 
 | 
						|
  information accordingly.
 | 
						|
 | 
						|
  @param[in]  PeiServices   General-purpose services that are available to every
 | 
						|
                            PEIM
 | 
						|
  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
 | 
						|
  @param[in]  DeviceIndex   Specifies the block device to which the function wants 
 | 
						|
                            to talk. Because the driver that implements Block I/O 
 | 
						|
                            PPIs will manage multiple block devices, the PPIs that 
 | 
						|
                            want to talk to a single device must specify the 
 | 
						|
                            device index that was assigned during the enumeration
 | 
						|
                            process. This index is a number from one to 
 | 
						|
                            NumberBlockDevices.
 | 
						|
  @param[out] MediaInfo     The media information of the specified block media.  
 | 
						|
                            The caller is responsible for the ownership of this 
 | 
						|
                            data structure.
 | 
						|
 | 
						|
  @par Note: 
 | 
						|
      The MediaInfo structure describes an enumeration of possible block device 
 | 
						|
      types.  This enumeration exists because no device paths are actually passed 
 | 
						|
      across interfaces that describe the type or class of hardware that is publishing 
 | 
						|
      the block I/O interface. This enumeration will allow for policy decisions
 | 
						|
      in the Recovery PEIM, such as "Try to recover from legacy floppy first, 
 | 
						|
      LS-120 second, CD-ROM third." If there are multiple partitions abstracted 
 | 
						|
      by a given device type, they should be reported in ascending order; this 
 | 
						|
      order also applies to nested partitions, such as legacy MBR, where the 
 | 
						|
      outermost partitions would have precedence in the reporting order. The 
 | 
						|
      same logic applies to systems such as IDE that have precedence relationships 
 | 
						|
      like "Master/Slave" or "Primary/Secondary". The master device should be 
 | 
						|
      reported first, the slave second.
 | 
						|
  
 | 
						|
  @retval EFI_SUCCESS        Media information about the specified block device 
 | 
						|
                             was obtained successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR   Cannot get the media information due to a hardware 
 | 
						|
                             error.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UfsBlockIoPeimGetMediaInfo (
 | 
						|
  IN  EFI_PEI_SERVICES               **PeiServices,
 | 
						|
  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,
 | 
						|
  IN  UINTN                          DeviceIndex,
 | 
						|
  OUT EFI_PEI_BLOCK_IO_MEDIA         *MediaInfo
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                         Status;
 | 
						|
  UFS_PEIM_HC_PRIVATE_DATA           *Private;
 | 
						|
  EFI_SCSI_SENSE_DATA                SenseData;
 | 
						|
  UINT8                              SenseDataLength;
 | 
						|
  EFI_SCSI_DISK_CAPACITY_DATA        Capacity;
 | 
						|
  EFI_SCSI_DISK_CAPACITY_DATA16      Capacity16;
 | 
						|
  UINTN                              DataLength;
 | 
						|
  BOOLEAN                            NeedRetry;  
 | 
						|
 | 
						|
  Private   = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
 | 
						|
  NeedRetry = TRUE;
 | 
						|
 | 
						|
  if (DeviceIndex >= UFS_PEIM_MAX_LUNS) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Private->Luns.BitMask & (BIT0 << DeviceIndex)) == 0) {
 | 
						|
    return EFI_ACCESS_DENIED;
 | 
						|
  }
 | 
						|
 | 
						|
  ZeroMem (&SenseData, sizeof (SenseData));
 | 
						|
  ZeroMem (&Capacity, sizeof (Capacity));
 | 
						|
  ZeroMem (&Capacity16, sizeof (Capacity16));
 | 
						|
  SenseDataLength = sizeof (SenseData);
 | 
						|
  //
 | 
						|
  // First test unit ready
 | 
						|
  //
 | 
						|
  do {
 | 
						|
    Status = UfsPeimTestUnitReady (
 | 
						|
               Private,
 | 
						|
               DeviceIndex,
 | 
						|
               &SenseData,
 | 
						|
               &SenseDataLength
 | 
						|
               );
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  
 | 
						|
    if (SenseDataLength == 0) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = UfsPeimParsingSenseKeys (&(Private->Media[DeviceIndex]), &SenseData, &NeedRetry);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
  } while (NeedRetry);
 | 
						|
 | 
						|
  DataLength      = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);
 | 
						|
  SenseDataLength = 0;
 | 
						|
  Status = UfsPeimReadCapacity (Private, DeviceIndex, &Capacity, (UINT32 *)&DataLength, NULL, &SenseDataLength);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Capacity.LastLba3 == 0xff) && (Capacity.LastLba2 == 0xff) &&
 | 
						|
      (Capacity.LastLba1 == 0xff) && (Capacity.LastLba0 == 0xff)) {
 | 
						|
    DataLength      = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);
 | 
						|
    SenseDataLength = 0;
 | 
						|
    Status = UfsPeimReadCapacity16 (Private, DeviceIndex, &Capacity16, (UINT32 *)&DataLength, NULL, &SenseDataLength);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
    Private->Media[DeviceIndex].LastBlock  = (Capacity16.LastLba3 << 24) | (Capacity16.LastLba2 << 16) | (Capacity16.LastLba1 << 8) | Capacity16.LastLba0;
 | 
						|
    Private->Media[DeviceIndex].LastBlock |= ((UINT64)Capacity16.LastLba7 << 56) | ((UINT64)Capacity16.LastLba6 << 48) | ((UINT64)Capacity16.LastLba5 << 40) | ((UINT64)Capacity16.LastLba4 << 32);
 | 
						|
    Private->Media[DeviceIndex].BlockSize  = (Capacity16.BlockSize3 << 24) | (Capacity16.BlockSize2 << 16) | (Capacity16.BlockSize1 << 8) | Capacity16.BlockSize0;
 | 
						|
  } else {
 | 
						|
    Private->Media[DeviceIndex].LastBlock  = (Capacity.LastLba3 << 24) | (Capacity.LastLba2 << 16) | (Capacity.LastLba1 << 8) | Capacity.LastLba0;
 | 
						|
    Private->Media[DeviceIndex].BlockSize  = (Capacity.BlockSize3 << 24) | (Capacity.BlockSize2 << 16) | (Capacity.BlockSize1 << 8) | Capacity.BlockSize0;
 | 
						|
  }
 | 
						|
 | 
						|
  MediaInfo->DeviceType   = UfsDevice;
 | 
						|
  MediaInfo->MediaPresent = Private->Media[DeviceIndex].MediaPresent;
 | 
						|
  MediaInfo->LastBlock    = (UINTN)Private->Media[DeviceIndex].LastBlock;
 | 
						|
  MediaInfo->BlockSize    = Private->Media[DeviceIndex].BlockSize;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Reads the requested number of blocks from the specified block device.
 | 
						|
 | 
						|
  The function reads the requested number of blocks from the device. All the 
 | 
						|
  blocks are read, or an error is returned. If there is no media in the device,
 | 
						|
  the function returns EFI_NO_MEDIA.
 | 
						|
 | 
						|
  @param[in]  PeiServices   General-purpose services that are available to 
 | 
						|
                            every PEIM.
 | 
						|
  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
 | 
						|
  @param[in]  DeviceIndex   Specifies the block device to which the function wants 
 | 
						|
                            to talk. Because the driver that implements Block I/O 
 | 
						|
                            PPIs will manage multiple block devices, PPIs that 
 | 
						|
                            want to talk to a single device must specify the device 
 | 
						|
                            index that was assigned during the enumeration process. 
 | 
						|
                            This index is a number from one to NumberBlockDevices.
 | 
						|
  @param[in]  StartLBA      The starting logical block address (LBA) to read from
 | 
						|
                            on the device
 | 
						|
  @param[in]  BufferSize    The size of the Buffer in bytes. This number 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 the ownership of the 
 | 
						|
                            buffer.
 | 
						|
                         
 | 
						|
  @retval EFI_SUCCESS             The data was read correctly from the device.
 | 
						|
  @retval EFI_DEVICE_ERROR        The device reported an error while attempting 
 | 
						|
                                  to perform the read operation.
 | 
						|
  @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not 
 | 
						|
                                  valid, or the buffer is not properly aligned.
 | 
						|
  @retval EFI_NO_MEDIA            There is no media in the device.
 | 
						|
  @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of
 | 
						|
                                  the intrinsic block size of the device.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UfsBlockIoPeimReadBlocks (
 | 
						|
  IN  EFI_PEI_SERVICES               **PeiServices,
 | 
						|
  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,
 | 
						|
  IN  UINTN                          DeviceIndex,
 | 
						|
  IN  EFI_PEI_LBA                    StartLBA,
 | 
						|
  IN  UINTN                          BufferSize,
 | 
						|
  OUT VOID                           *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                         Status;
 | 
						|
  UINTN                              BlockSize;
 | 
						|
  UINTN                              NumberOfBlocks;
 | 
						|
  UFS_PEIM_HC_PRIVATE_DATA           *Private;
 | 
						|
  EFI_SCSI_SENSE_DATA                SenseData;
 | 
						|
  UINT8                              SenseDataLength;
 | 
						|
  BOOLEAN                            NeedRetry;  
 | 
						|
 | 
						|
  Status    = EFI_SUCCESS;
 | 
						|
  NeedRetry = TRUE;
 | 
						|
  Private   = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
 | 
						|
 | 
						|
  ZeroMem (&SenseData, sizeof (SenseData));
 | 
						|
  SenseDataLength = sizeof (SenseData);
 | 
						|
 | 
						|
  //
 | 
						|
  // Check parameters
 | 
						|
  //
 | 
						|
  if (Buffer == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (BufferSize == 0) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (DeviceIndex >= UFS_PEIM_MAX_LUNS) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Private->Luns.BitMask & (BIT0 << DeviceIndex)) == 0) {
 | 
						|
    return EFI_ACCESS_DENIED;
 | 
						|
  }
 | 
						|
 | 
						|
  BlockSize = Private->Media[DeviceIndex].BlockSize;
 | 
						|
 | 
						|
  if (BufferSize % BlockSize != 0) {
 | 
						|
    Status = EFI_BAD_BUFFER_SIZE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StartLBA > Private->Media[DeviceIndex].LastBlock) {
 | 
						|
    Status = EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  NumberOfBlocks = BufferSize / BlockSize;
 | 
						|
 | 
						|
  do {
 | 
						|
    Status = UfsPeimTestUnitReady (
 | 
						|
               Private,
 | 
						|
               DeviceIndex,
 | 
						|
               &SenseData,
 | 
						|
               &SenseDataLength
 | 
						|
               );
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  
 | 
						|
    if (SenseDataLength == 0) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = UfsPeimParsingSenseKeys (&(Private->Media[DeviceIndex]), &SenseData, &NeedRetry);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
  } while (NeedRetry);
 | 
						|
 | 
						|
  SenseDataLength = 0;
 | 
						|
  if (Private->Media[DeviceIndex].LastBlock < 0xfffffffful) {
 | 
						|
    Status = UfsPeimRead10 (
 | 
						|
               Private,
 | 
						|
               DeviceIndex,
 | 
						|
               (UINT32)StartLBA,
 | 
						|
               (UINT32)NumberOfBlocks,
 | 
						|
               Buffer,
 | 
						|
               (UINT32 *)&BufferSize,
 | 
						|
               NULL,
 | 
						|
               &SenseDataLength
 | 
						|
               );
 | 
						|
  } else {
 | 
						|
    Status = UfsPeimRead16 (
 | 
						|
               Private,
 | 
						|
               DeviceIndex,
 | 
						|
               (UINT32)StartLBA,
 | 
						|
               (UINT32)NumberOfBlocks,
 | 
						|
               Buffer,
 | 
						|
               (UINT32 *)&BufferSize,
 | 
						|
               NULL,
 | 
						|
               &SenseDataLength
 | 
						|
               );
 | 
						|
  }
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Gets the count of block I/O devices that one specific block driver detects.
 | 
						|
 | 
						|
  This function is used for getting the count of block I/O devices that one 
 | 
						|
  specific block driver detects.  To the PEI ATAPI driver, it returns the number
 | 
						|
  of all the detected ATAPI devices it detects during the enumeration process. 
 | 
						|
  To the PEI legacy floppy driver, it returns the number of all the legacy 
 | 
						|
  devices it finds during its enumeration process. If no device is detected, 
 | 
						|
  then the function will return zero.  
 | 
						|
  
 | 
						|
  @param[in]  PeiServices          General-purpose services that are available 
 | 
						|
                                   to every PEIM.
 | 
						|
  @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI 
 | 
						|
                                   instance.
 | 
						|
  @param[out] NumberBlockDevices   The number of block I/O devices discovered.
 | 
						|
 | 
						|
  @retval     EFI_SUCCESS          The operation performed successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UfsBlockIoPeimGetDeviceNo2 (
 | 
						|
  IN  EFI_PEI_SERVICES               **PeiServices,
 | 
						|
  IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
 | 
						|
  OUT UINTN                          *NumberBlockDevices
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // For Ufs device, it has up to 8 normal Luns plus some well-known Luns.
 | 
						|
  // At PEI phase, we will only expose normal Luns to user.
 | 
						|
  // For those disabled Lun, when user try to access it, the operation would fail.
 | 
						|
  //
 | 
						|
  *NumberBlockDevices = UFS_PEIM_MAX_LUNS;
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Gets a block device's media information.
 | 
						|
 | 
						|
  This function will provide the caller with the specified block device's media 
 | 
						|
  information. If the media changes, calling this function will update the media 
 | 
						|
  information accordingly.
 | 
						|
 | 
						|
  @param[in]  PeiServices   General-purpose services that are available to every
 | 
						|
                            PEIM
 | 
						|
  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
 | 
						|
  @param[in]  DeviceIndex   Specifies the block device to which the function wants 
 | 
						|
                            to talk. Because the driver that implements Block I/O 
 | 
						|
                            PPIs will manage multiple block devices, the PPIs that 
 | 
						|
                            want to talk to a single device must specify the 
 | 
						|
                            device index that was assigned during the enumeration
 | 
						|
                            process. This index is a number from one to 
 | 
						|
                            NumberBlockDevices.
 | 
						|
  @param[out] MediaInfo     The media information of the specified block media.  
 | 
						|
                            The caller is responsible for the ownership of this 
 | 
						|
                            data structure.
 | 
						|
 | 
						|
  @par Note: 
 | 
						|
      The MediaInfo structure describes an enumeration of possible block device 
 | 
						|
      types.  This enumeration exists because no device paths are actually passed 
 | 
						|
      across interfaces that describe the type or class of hardware that is publishing 
 | 
						|
      the block I/O interface. This enumeration will allow for policy decisions
 | 
						|
      in the Recovery PEIM, such as "Try to recover from legacy floppy first, 
 | 
						|
      LS-120 second, CD-ROM third." If there are multiple partitions abstracted 
 | 
						|
      by a given device type, they should be reported in ascending order; this 
 | 
						|
      order also applies to nested partitions, such as legacy MBR, where the 
 | 
						|
      outermost partitions would have precedence in the reporting order. The 
 | 
						|
      same logic applies to systems such as IDE that have precedence relationships 
 | 
						|
      like "Master/Slave" or "Primary/Secondary". The master device should be 
 | 
						|
      reported first, the slave second.
 | 
						|
  
 | 
						|
  @retval EFI_SUCCESS        Media information about the specified block device 
 | 
						|
                             was obtained successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR   Cannot get the media information due to a hardware 
 | 
						|
                             error.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UfsBlockIoPeimGetMediaInfo2 (
 | 
						|
  IN  EFI_PEI_SERVICES               **PeiServices,
 | 
						|
  IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
 | 
						|
  IN  UINTN                          DeviceIndex,
 | 
						|
  OUT EFI_PEI_BLOCK_IO2_MEDIA        *MediaInfo
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                         Status;
 | 
						|
  UFS_PEIM_HC_PRIVATE_DATA           *Private;
 | 
						|
  EFI_PEI_BLOCK_IO_MEDIA             Media;
 | 
						|
 | 
						|
  Private   = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
 | 
						|
  
 | 
						|
  Status    = UfsBlockIoPeimGetMediaInfo (
 | 
						|
                PeiServices,
 | 
						|
                &Private->BlkIoPpi,
 | 
						|
                DeviceIndex,
 | 
						|
                &Media
 | 
						|
                );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  CopyMem (MediaInfo, &(Private->Media[DeviceIndex]), sizeof (EFI_PEI_BLOCK_IO2_MEDIA));
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Reads the requested number of blocks from the specified block device.
 | 
						|
 | 
						|
  The function reads the requested number of blocks from the device. All the 
 | 
						|
  blocks are read, or an error is returned. If there is no media in the device,
 | 
						|
  the function returns EFI_NO_MEDIA.
 | 
						|
 | 
						|
  @param[in]  PeiServices   General-purpose services that are available to 
 | 
						|
                            every PEIM.
 | 
						|
  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
 | 
						|
  @param[in]  DeviceIndex   Specifies the block device to which the function wants 
 | 
						|
                            to talk. Because the driver that implements Block I/O 
 | 
						|
                            PPIs will manage multiple block devices, PPIs that 
 | 
						|
                            want to talk to a single device must specify the device 
 | 
						|
                            index that was assigned during the enumeration process. 
 | 
						|
                            This index is a number from one to NumberBlockDevices.
 | 
						|
  @param[in]  StartLBA      The starting logical block address (LBA) to read from
 | 
						|
                            on the device
 | 
						|
  @param[in]  BufferSize    The size of the Buffer in bytes. This number 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 the ownership of the 
 | 
						|
                            buffer.
 | 
						|
                         
 | 
						|
  @retval EFI_SUCCESS             The data was read correctly from the device.
 | 
						|
  @retval EFI_DEVICE_ERROR        The device reported an error while attempting 
 | 
						|
                                  to perform the read operation.
 | 
						|
  @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not 
 | 
						|
                                  valid, or the buffer is not properly aligned.
 | 
						|
  @retval EFI_NO_MEDIA            There is no media in the device.
 | 
						|
  @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of
 | 
						|
                                  the intrinsic block size of the device.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UfsBlockIoPeimReadBlocks2 (
 | 
						|
  IN  EFI_PEI_SERVICES               **PeiServices,
 | 
						|
  IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
 | 
						|
  IN  UINTN                          DeviceIndex,
 | 
						|
  IN  EFI_PEI_LBA                    StartLBA,
 | 
						|
  IN  UINTN                          BufferSize,
 | 
						|
  OUT VOID                           *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                         Status;
 | 
						|
  UFS_PEIM_HC_PRIVATE_DATA           *Private; 
 | 
						|
 | 
						|
  Status    = EFI_SUCCESS;
 | 
						|
  Private   = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
 | 
						|
 | 
						|
  Status  = UfsBlockIoPeimReadBlocks (
 | 
						|
              PeiServices,
 | 
						|
              &Private->BlkIoPpi,
 | 
						|
              DeviceIndex,
 | 
						|
              StartLBA,
 | 
						|
              BufferSize,
 | 
						|
              Buffer
 | 
						|
              );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  The user code starts with this function.
 | 
						|
  
 | 
						|
  @param  FileHandle             Handle of the file being invoked.
 | 
						|
  @param  PeiServices            Describes the list of possible PEI Services.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The driver is successfully initialized.
 | 
						|
  @retval Others                 Can't initialize the driver.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
InitializeUfsBlockIoPeim (
 | 
						|
  IN EFI_PEI_FILE_HANDLE        FileHandle,
 | 
						|
  IN CONST EFI_PEI_SERVICES     **PeiServices
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                    Status;
 | 
						|
  UFS_PEIM_HC_PRIVATE_DATA      *Private;
 | 
						|
  EDKII_UFS_HOST_CONTROLLER_PPI *UfsHcPpi;
 | 
						|
  UINT32                        Index;
 | 
						|
  UFS_CONFIG_DESC               Config;
 | 
						|
  UINTN                         MmioBase;
 | 
						|
  UINT8                         Controller;
 | 
						|
 | 
						|
  //
 | 
						|
  // Shadow this PEIM to run from memory
 | 
						|
  //
 | 
						|
  if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // locate ufs host controller PPI
 | 
						|
  //
 | 
						|
  Status = PeiServicesLocatePpi (
 | 
						|
             &gEdkiiPeiUfsHostControllerPpiGuid,
 | 
						|
             0,
 | 
						|
             NULL,
 | 
						|
             (VOID **) &UfsHcPpi
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  Controller = 0;
 | 
						|
  MmioBase   = 0;
 | 
						|
  while (TRUE) {
 | 
						|
    Status = UfsHcPpi->GetUfsHcMmioBar (UfsHcPpi, Controller, &MmioBase);
 | 
						|
    //
 | 
						|
    // When status is error, meant no controller is found
 | 
						|
    //
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    Private = AllocateCopyPool (sizeof (UFS_PEIM_HC_PRIVATE_DATA), &gUfsHcPeimTemplate);
 | 
						|
    if (Private == NULL) {
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    Private->BlkIoPpiList.Ppi  = &Private->BlkIoPpi;
 | 
						|
    Private->BlkIo2PpiList.Ppi = &Private->BlkIo2Ppi;
 | 
						|
    Private->UfsHcBase         = MmioBase;
 | 
						|
 | 
						|
    //
 | 
						|
    // Initialize the memory pool which will be used in all transactions.
 | 
						|
    //
 | 
						|
    Status = UfsPeimInitMemPool (Private);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Initialize UFS Host Controller H/W.
 | 
						|
    //
 | 
						|
    Status = UfsControllerInit (Private);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      DEBUG ((EFI_D_ERROR, "UfsDevicePei: Host Controller Initialization Error, Status = %r\n", Status));
 | 
						|
      Controller++;
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // UFS 2.0 spec Section 13.1.3.3:
 | 
						|
    // At the end of the UFS Interconnect Layer initialization on both host and device side, 
 | 
						|
    // the host shall send a NOP OUT UPIU to verify that the device UTP Layer is ready. 
 | 
						|
    //
 | 
						|
    Status = UfsExecNopCmds (Private);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      DEBUG ((EFI_D_ERROR, "Ufs Sending NOP IN command Error, Status = %r\n", Status));
 | 
						|
      Controller++;
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // The host enables the device initialization completion by setting fDeviceInit flag.
 | 
						|
    //
 | 
						|
    Status = UfsSetFlag (Private, UfsFlagDevInit);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      DEBUG ((EFI_D_ERROR, "Ufs Set fDeviceInit Flag Error, Status = %r\n", Status));
 | 
						|
      Controller++;
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Get Ufs Device's Lun Info by reading Configuration Descriptor.
 | 
						|
    //
 | 
						|
    Status = UfsRwDeviceDesc (Private, TRUE, UfsConfigDesc, 0, 0, &Config, sizeof (UFS_CONFIG_DESC));
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      DEBUG ((EFI_D_ERROR, "Ufs Get Configuration Descriptor Error, Status = %r\n", Status));
 | 
						|
      Controller++;
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    for (Index = 0; Index < UFS_PEIM_MAX_LUNS; Index++) {
 | 
						|
      if (Config.UnitDescConfParams[Index].LunEn != 0) {
 | 
						|
        Private->Luns.BitMask |= (BIT0 << Index);
 | 
						|
        DEBUG ((EFI_D_INFO, "Ufs %d Lun %d is enabled\n", Controller, Index));
 | 
						|
      }
 | 
						|
    }
 | 
						|
    
 | 
						|
    Status = PeiServicesInstallPpi (&Private->BlkIoPpiList);
 | 
						|
    Controller++;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 |