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