1 /** @file
2   Implementation of UEFI driver Dialnostics protocol which to perform diagnostic on the IDE
3   Bus controller.
4 
5   Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
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 
17 #include "IdeBus.h"
18 
19 #define IDE_BUS_DIAGNOSTIC_ERROR  L"PCI IDE/ATAPI Driver Diagnostics Failed"
20 
21 //
22 // EFI Driver Diagnostics Protocol
23 //
24 GLOBAL_REMOVE_IF_UNREFERENCED EFI_DRIVER_DIAGNOSTICS_PROTOCOL gIDEBusDriverDiagnostics = {
25   IDEBusDriverDiagnosticsRunDiagnostics,
26   "eng"
27 };
28 
29 //
30 // EFI Driver Diagnostics 2 Protocol
31 //
32 GLOBAL_REMOVE_IF_UNREFERENCED EFI_DRIVER_DIAGNOSTICS2_PROTOCOL gIDEBusDriverDiagnostics2 = {
33   (EFI_DRIVER_DIAGNOSTICS2_RUN_DIAGNOSTICS) IDEBusDriverDiagnosticsRunDiagnostics,
34   "en"
35 };
36 
37 /**
38   Runs diagnostics on a controller.
39 
40   @param  This             A pointer to the EFI_DRIVER_DIAGNOSTICS_PROTOCOLinstance.
41   @param  ControllerHandle The handle of the controller to run diagnostics on.
42   @param  ChildHandle      The handle of the child controller to run diagnostics on
43                            This is an optional parameter that may be NULL.  It will
44                            be NULL for device drivers.  It will also be NULL for a
45                            bus drivers that wish to run diagnostics on the bus controller.
46                            It will not be NULL for a bus driver that wishes to run
47                            diagnostics on one of its child controllers.
48   @param  DiagnosticType   Indicates type of diagnostics to perform on the controller
49                            specified by ControllerHandle and ChildHandle.
50   @param  Language         A pointer to a three character ISO 639-2 language identifier.
51                            This is the language in which the optional error message should
52                            be returned in Buffer, and it must match one of the languages
53                            specified in SupportedLanguages. The number of languages supported by
54                            a driver is up to the driver writer.
55   @param  ErrorType        A GUID that defines the format of the data returned in Buffer.
56   @param  BufferSize       The size, in bytes, of the data returned in Buffer.
57   @param  Buffer           A buffer that contains a Null-terminated Unicode string
58                            plus some additional data whose format is defined by ErrorType.
59                            Buffer is allocated by this function with AllocatePool(), and
60                            it is the caller's responsibility to free it with a call to FreePool().
61 
62   @retval  EFI_SUCCESS           The controller specified by ControllerHandle and ChildHandle passed
63                                  the diagnostic.
64   @retval  EFI_INVALID_PARAMETER ControllerHandle is NULL.
65   @retval  EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
66   @retval  EFI_INVALID_PARAMETER Language is NULL.
67   @retval  EFI_INVALID_PARAMETER ErrorType is NULL.
68   @retval  EFI_INVALID_PARAMETER BufferType is NULL.
69   @retval  EFI_INVALID_PARAMETER Buffer is NULL.
70   @retval  EFI_UNSUPPORTED       The driver specified by This does not support running
71                                  diagnostics for the controller specified by ControllerHandle
72                                  and ChildHandle.
73   @retval  EFI_UNSUPPORTED       The driver specified by This does not support the
74                                  type of diagnostic specified by DiagnosticType.
75   @retval  EFI_UNSUPPORTED       The driver specified by This does not support the language
76                                  specified by Language.
77   @retval  EFI_OUT_OF_RESOURCES  There are not enough resources available to complete the
78                                  diagnostics.
79   @retval  EFI_OUT_OF_RESOURCES  There are not enough resources available to return the
80                                  status information in ErrorType, BufferSize,and Buffer.
81   @retval  EFI_DEVICE_ERROR      The controller specified by ControllerHandle and ChildHandle
82                                  did not pass the diagnostic.
83 **/
84 EFI_STATUS
85 EFIAPI
IDEBusDriverDiagnosticsRunDiagnostics(IN EFI_DRIVER_DIAGNOSTICS_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_HANDLE ChildHandle OPTIONAL,IN EFI_DRIVER_DIAGNOSTIC_TYPE DiagnosticType,IN CHAR8 * Language,OUT EFI_GUID ** ErrorType,OUT UINTN * BufferSize,OUT CHAR16 ** Buffer)86 IDEBusDriverDiagnosticsRunDiagnostics (
87   IN  EFI_DRIVER_DIAGNOSTICS_PROTOCOL               *This,
88   IN  EFI_HANDLE                                    ControllerHandle,
89   IN  EFI_HANDLE                                    ChildHandle  OPTIONAL,
90   IN  EFI_DRIVER_DIAGNOSTIC_TYPE                    DiagnosticType,
91   IN  CHAR8                                         *Language,
92   OUT EFI_GUID                                      **ErrorType,
93   OUT UINTN                                         *BufferSize,
94   OUT CHAR16                                        **Buffer
95   )
96 {
97   EFI_STATUS            Status;
98   EFI_PCI_IO_PROTOCOL   *PciIo;
99   EFI_BLOCK_IO_PROTOCOL *BlkIo;
100   IDE_BLK_IO_DEV        *IdeBlkIoDevice;
101   UINT32                VendorDeviceId;
102   VOID                  *BlockBuffer;
103   CHAR8                 *SupportedLanguages;
104   BOOLEAN               Iso639Language;
105   BOOLEAN               Found;
106   UINTN                 Index;
107 
108   if (Language         == NULL ||
109       ErrorType        == NULL ||
110       Buffer           == NULL ||
111       ControllerHandle == NULL ||
112       BufferSize       == NULL) {
113 
114     return EFI_INVALID_PARAMETER;
115   }
116 
117   SupportedLanguages = This->SupportedLanguages;
118   Iso639Language = (BOOLEAN)(This == &gIDEBusDriverDiagnostics);
119   //
120   // Make sure Language is in the set of Supported Languages
121   //
122   Found = FALSE;
123   while (*SupportedLanguages != 0) {
124     if (Iso639Language) {
125       if (CompareMem (Language, SupportedLanguages, 3) == 0) {
126         Found = TRUE;
127         break;
128       }
129       SupportedLanguages += 3;
130     } else {
131       for (Index = 0; SupportedLanguages[Index] != 0 && SupportedLanguages[Index] != ';'; Index++);
132       if ((AsciiStrnCmp(SupportedLanguages, Language, Index) == 0) && (Language[Index] == 0)) {
133         Found = TRUE;
134         break;
135       }
136       SupportedLanguages += Index;
137       for (; *SupportedLanguages != 0 && *SupportedLanguages == ';'; SupportedLanguages++);
138     }
139   }
140   //
141   // If Language is not a member of SupportedLanguages, then return EFI_UNSUPPORTED
142   //
143   if (!Found) {
144     return EFI_UNSUPPORTED;
145   }
146 
147   *ErrorType  = NULL;
148   *BufferSize = 0;
149 
150   if (ChildHandle == NULL) {
151     Status = gBS->OpenProtocol (
152                     ControllerHandle,
153                     &gEfiCallerIdGuid,
154                     NULL,
155                     gIDEBusDriverBinding.DriverBindingHandle,
156                     ControllerHandle,
157                     EFI_OPEN_PROTOCOL_TEST_PROTOCOL
158                     );
159     if (EFI_ERROR (Status)) {
160       return Status;
161     }
162 
163     Status = gBS->OpenProtocol (
164                     ControllerHandle,
165                     &gEfiPciIoProtocolGuid,
166                     (VOID **) &PciIo,
167                     gIDEBusDriverBinding.DriverBindingHandle,
168                     ControllerHandle,
169                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
170                     );
171     if (EFI_ERROR (Status)) {
172       return EFI_DEVICE_ERROR;
173     }
174 
175     //
176     // Use services of PCI I/O Protocol to test the PCI IDE/ATAPI Controller
177     // The following test simply reads the Device ID and Vendor ID.
178     // It should never fail.  A real test would perform more advanced
179     // diagnostics.
180     //
181 
182     Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0, 1, &VendorDeviceId);
183     if (EFI_ERROR (Status) || VendorDeviceId == 0xffffffff) {
184       return EFI_DEVICE_ERROR;
185     }
186 
187     return EFI_SUCCESS;
188   }
189 
190   Status = gBS->OpenProtocol (
191                   ChildHandle,
192                   &gEfiBlockIoProtocolGuid,
193                   (VOID **) &BlkIo,
194                   gIDEBusDriverBinding.DriverBindingHandle,
195                   ChildHandle,
196                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
197                   );
198   if (EFI_ERROR (Status)) {
199     return Status;
200   }
201 
202   IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (BlkIo);
203 
204   //
205   // Use services available from IdeBlkIoDevice to test the IDE/ATAPI device
206   //
207   Status = gBS->AllocatePool (
208                   EfiBootServicesData,
209                   IdeBlkIoDevice->BlkMedia.BlockSize,
210                   (VOID **) &BlockBuffer
211                   );
212   if (EFI_ERROR (Status)) {
213     return Status;
214   }
215 
216   Status = IdeBlkIoDevice->BlkIo.ReadBlocks (
217                                   &IdeBlkIoDevice->BlkIo,
218                                   IdeBlkIoDevice->BlkMedia.MediaId,
219                                   0,
220                                   IdeBlkIoDevice->BlkMedia.BlockSize,
221                                   BlockBuffer
222                                   );
223 
224   if (EFI_ERROR (Status)) {
225     *ErrorType  = &gEfiCallerIdGuid;
226     *BufferSize = sizeof (IDE_BUS_DIAGNOSTIC_ERROR);
227 
228     Status = gBS->AllocatePool (
229                     EfiBootServicesData,
230                     (UINTN) (*BufferSize),
231                     (VOID **) Buffer
232                     );
233     if (EFI_ERROR (Status)) {
234       return Status;
235     }
236 
237     CopyMem (*Buffer, IDE_BUS_DIAGNOSTIC_ERROR, *BufferSize);
238 
239     Status = EFI_DEVICE_ERROR;
240   }
241 
242   gBS->FreePool (BlockBuffer);
243 
244   return Status;
245 }
246