Home | History | Annotate | Download | only in MmcDxe
      1 /** @file
      2   Diagnostics Protocol implementation for the MMC DXE driver
      3 
      4   Copyright (c) 2011-2014, ARM Limited. All rights reserved.
      5 
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include <Uefi.h>
     17 #include <Library/DebugLib.h>
     18 #include <Library/BaseMemoryLib.h>
     19 #include <Library/MemoryAllocationLib.h>
     20 #include <Library/BaseLib.h>
     21 
     22 #include "Mmc.h"
     23 
     24 #define DIAGNOSTIC_LOGBUFFER_MAXCHAR  1024
     25 
     26 CHAR16* mLogBuffer = NULL;
     27 UINTN   mLogRemainChar = 0;
     28 
     29 CHAR16*
     30 DiagnosticInitLog (
     31   UINTN MaxBufferChar
     32   )
     33 {
     34   mLogRemainChar = MaxBufferChar;
     35   mLogBuffer = AllocatePool ((UINTN)MaxBufferChar * sizeof (CHAR16));
     36   return mLogBuffer;
     37 }
     38 
     39 UINTN
     40 DiagnosticLog (
     41   CONST CHAR16* Str
     42   )
     43 {
     44   UINTN len = StrLen (Str);
     45   if (len < mLogRemainChar) {
     46     StrCpyS (mLogBuffer, mLogRemainChar, Str);
     47     mLogRemainChar -= len;
     48     mLogBuffer += len;
     49     return len;
     50   } else {
     51     return 0;
     52   }
     53 }
     54 
     55 VOID
     56 GenerateRandomBuffer (
     57   VOID* Buffer,
     58   UINTN BufferSize
     59   )
     60 {
     61   UINT64  i;
     62   UINT64* Buffer64 = (UINT64*)Buffer;
     63 
     64   for (i = 0; i < (BufferSize >> 3); i++) {
     65     *Buffer64 = i | (~i << 32);
     66     Buffer64++;
     67   }
     68 }
     69 
     70 BOOLEAN
     71 CompareBuffer (
     72   VOID  *BufferA,
     73   VOID  *BufferB,
     74   UINTN BufferSize
     75   )
     76 {
     77   UINTN i;
     78   UINT64* BufferA64 = (UINT64*)BufferA;
     79   UINT64* BufferB64 = (UINT64*)BufferB;
     80 
     81   for (i = 0; i < (BufferSize >> 3); i++) {
     82     if (*BufferA64 != *BufferB64) {
     83       DEBUG ((EFI_D_ERROR, "CompareBuffer: Error at %i", i));
     84       DEBUG ((EFI_D_ERROR, "(0x%lX) != (0x%lX)\n", *BufferA64, *BufferB64));
     85       return FALSE;
     86     }
     87     BufferA64++;
     88     BufferB64++;
     89   }
     90   return TRUE;
     91 }
     92 
     93 EFI_STATUS
     94 MmcReadWriteDataTest (
     95   MMC_HOST_INSTANCE *MmcHostInstance,
     96   EFI_LBA           Lba,
     97   UINTN             BufferSize
     98   )
     99 {
    100   VOID                        *BackBuffer;
    101   VOID                        *WriteBuffer;
    102   VOID                        *ReadBuffer;
    103   EFI_STATUS                  Status;
    104 
    105   // Check if a Media is Present
    106   if (!MmcHostInstance->BlockIo.Media->MediaPresent) {
    107     DiagnosticLog (L"ERROR: No Media Present\n");
    108     return EFI_NO_MEDIA;
    109   }
    110 
    111   if (MmcHostInstance->State != MmcTransferState) {
    112     DiagnosticLog (L"ERROR: Not ready for Transfer state\n");
    113     return EFI_NOT_READY;
    114   }
    115 
    116   BackBuffer = AllocatePool (BufferSize);
    117   WriteBuffer = AllocatePool (BufferSize);
    118   ReadBuffer = AllocatePool (BufferSize);
    119 
    120   // Read (and save) buffer at a specific location
    121   Status = MmcReadBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,BackBuffer);
    122   if (Status != EFI_SUCCESS) {
    123     DiagnosticLog (L"ERROR: Fail to Read Block (1)\n");
    124     return Status;
    125   }
    126 
    127   // Write buffer at the same location
    128   GenerateRandomBuffer (WriteBuffer,BufferSize);
    129   Status = MmcWriteBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,WriteBuffer);
    130   if (Status != EFI_SUCCESS) {
    131     DiagnosticLog (L"ERROR: Fail to Write Block (1)\n");
    132     return Status;
    133   }
    134 
    135   // Read the buffer at the same location
    136   Status = MmcReadBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,ReadBuffer);
    137   if (Status != EFI_SUCCESS) {
    138     DiagnosticLog (L"ERROR: Fail to Read Block (2)\n");
    139     return Status;
    140   }
    141 
    142   // Check that is conform
    143   if (!CompareBuffer (ReadBuffer,WriteBuffer,BufferSize)) {
    144     DiagnosticLog (L"ERROR: Fail to Read/Write Block (1)\n");
    145     return EFI_INVALID_PARAMETER;
    146   }
    147 
    148   // Restore content at the original location
    149   Status = MmcWriteBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,BackBuffer);
    150   if (Status != EFI_SUCCESS) {
    151     DiagnosticLog (L"ERROR: Fail to Write Block (2)\n");
    152     return Status;
    153   }
    154 
    155   // Read the restored content
    156   Status = MmcReadBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,ReadBuffer);
    157   if (Status != EFI_SUCCESS) {
    158     DiagnosticLog (L"ERROR: Fail to Read Block (3)\n");
    159     return Status;
    160   }
    161 
    162   // Check the content is correct
    163   if (!CompareBuffer (ReadBuffer,BackBuffer,BufferSize)) {
    164     DiagnosticLog (L"ERROR: Fail to Read/Write Block (2)\n");
    165     return EFI_INVALID_PARAMETER;
    166   }
    167 
    168   return EFI_SUCCESS;
    169 }
    170 
    171 EFI_STATUS
    172 EFIAPI
    173 MmcDriverDiagnosticsRunDiagnostics (
    174   IN  EFI_DRIVER_DIAGNOSTICS_PROTOCOL               *This,
    175   IN  EFI_HANDLE                                    ControllerHandle,
    176   IN  EFI_HANDLE                                    ChildHandle  OPTIONAL,
    177   IN  EFI_DRIVER_DIAGNOSTIC_TYPE                    DiagnosticType,
    178   IN  CHAR8                                         *Language,
    179   OUT EFI_GUID                                      **ErrorType,
    180   OUT UINTN                                         *BufferSize,
    181   OUT CHAR16                                        **Buffer
    182   )
    183 {
    184   LIST_ENTRY              *CurrentLink;
    185   MMC_HOST_INSTANCE       *MmcHostInstance;
    186   EFI_STATUS              Status;
    187 
    188   if ((Language         == NULL) ||
    189       (ErrorType        == NULL) ||
    190       (Buffer           == NULL) ||
    191       (ControllerHandle == NULL) ||
    192       (BufferSize       == NULL)) {
    193     return EFI_INVALID_PARAMETER;
    194   }
    195 
    196   // Check Language is supported (i.e. is "en-*" - only English is supported)
    197   if (AsciiStrnCmp (Language, "en", 2) != 0) {
    198     return EFI_UNSUPPORTED;
    199   }
    200 
    201   Status = EFI_SUCCESS;
    202   *ErrorType  = NULL;
    203   *BufferSize = DIAGNOSTIC_LOGBUFFER_MAXCHAR;
    204   *Buffer = DiagnosticInitLog (DIAGNOSTIC_LOGBUFFER_MAXCHAR);
    205 
    206   DiagnosticLog (L"MMC Driver Diagnostics\n");
    207 
    208   // Find the MMC Host instance on which we have been asked to run diagnostics
    209   MmcHostInstance = NULL;
    210   CurrentLink = mMmcHostPool.ForwardLink;
    211   while (CurrentLink != NULL && CurrentLink != &mMmcHostPool && (Status == EFI_SUCCESS)) {
    212     MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK(CurrentLink);
    213     ASSERT(MmcHostInstance != NULL);
    214     if (MmcHostInstance->MmcHandle == ControllerHandle) {
    215       break;
    216     }
    217     CurrentLink = CurrentLink->ForwardLink;
    218   }
    219 
    220   // If we didn't find the controller, return EFI_UNSUPPORTED
    221   if ((MmcHostInstance == NULL)
    222       || (MmcHostInstance->MmcHandle != ControllerHandle)) {
    223     return EFI_UNSUPPORTED;
    224   }
    225 
    226   // LBA=1 Size=BlockSize
    227   DiagnosticLog (L"MMC Driver Diagnostics - Test: First Block\n");
    228   Status = MmcReadWriteDataTest (MmcHostInstance, 1, MmcHostInstance->BlockIo.Media->BlockSize);
    229 
    230   // LBA=2 Size=BlockSize
    231   DiagnosticLog (L"MMC Driver Diagnostics - Test: Second Block\n");
    232   Status = MmcReadWriteDataTest (MmcHostInstance, 2, MmcHostInstance->BlockIo.Media->BlockSize);
    233 
    234   // LBA=10 Size=BlockSize
    235   DiagnosticLog (L"MMC Driver Diagnostics - Test: Any Block\n");
    236   Status = MmcReadWriteDataTest (MmcHostInstance, MmcHostInstance->BlockIo.Media->LastBlock >> 1, MmcHostInstance->BlockIo.Media->BlockSize);
    237 
    238   // LBA=LastBlock Size=BlockSize
    239   DiagnosticLog (L"MMC Driver Diagnostics - Test: Last Block\n");
    240   Status = MmcReadWriteDataTest (MmcHostInstance, MmcHostInstance->BlockIo.Media->LastBlock, MmcHostInstance->BlockIo.Media->BlockSize);
    241 
    242   // LBA=1 Size=2*BlockSize
    243   DiagnosticLog (L"MMC Driver Diagnostics - Test: First Block / 2 BlockSSize\n");
    244   Status = MmcReadWriteDataTest (MmcHostInstance, 1, 2 * MmcHostInstance->BlockIo.Media->BlockSize);
    245 
    246   return Status;
    247 }
    248 
    249 //
    250 // EFI Driver Diagnostics 2 Protocol
    251 //
    252 GLOBAL_REMOVE_IF_UNREFERENCED EFI_DRIVER_DIAGNOSTICS2_PROTOCOL gMmcDriverDiagnostics2 = {
    253   (EFI_DRIVER_DIAGNOSTICS2_RUN_DIAGNOSTICS) MmcDriverDiagnosticsRunDiagnostics,
    254   "en"
    255 };
    256