1 /** @file
2 Collect IDE information from Native EFI Driver
3
4 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
5
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions
8 of the BSD License which accompanies this distribution. The
9 full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "LegacyBiosInterface.h"
18
19 BOOLEAN mIdeDataBuiltFlag = FALSE;
20
21 /**
22 Collect IDE Inquiry data from the IDE disks
23
24 @param Private Legacy BIOS Instance data
25 @param HddInfo Hdd Information
26 @param Flag Reconnect IdeController or not
27
28 @retval EFI_SUCCESS It should always work.
29
30 **/
31 EFI_STATUS
LegacyBiosBuildIdeData(IN LEGACY_BIOS_INSTANCE * Private,IN HDD_INFO ** HddInfo,IN UINT16 Flag)32 LegacyBiosBuildIdeData (
33 IN LEGACY_BIOS_INSTANCE *Private,
34 IN HDD_INFO **HddInfo,
35 IN UINT16 Flag
36 )
37 {
38 EFI_STATUS Status;
39 EFI_HANDLE IdeController;
40 UINTN HandleCount;
41 EFI_HANDLE *HandleBuffer;
42 UINTN Index;
43 EFI_DISK_INFO_PROTOCOL *DiskInfo;
44 UINT32 IdeChannel;
45 UINT32 IdeDevice;
46 UINT32 Size;
47 UINT8 *InquiryData;
48 UINT32 InquiryDataSize;
49 HDD_INFO *LocalHddInfo;
50 UINT32 PciIndex;
51 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
52 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
53 EFI_DEVICE_PATH_PROTOCOL *TempDevicePathNode;
54 PCI_DEVICE_PATH *PciDevicePath;
55
56 //
57 // Only build data once
58 // We have a problem with GetBbsInfo in that it can be invoked two
59 // places. Once in BDS, when all EFI drivers are connected and once in
60 // LegacyBoot after all EFI drivers are disconnected causing this routine
61 // to hang. In LegacyBoot this function is also called before EFI drivers
62 // are disconnected.
63 // Cases covered
64 // GetBbsInfo invoked in BDS. Both invocations in LegacyBoot ignored.
65 // GetBbsInfo not invoked in BDS. First invocation of this function
66 // proceeds normally and second via GetBbsInfo ignored.
67 //
68 PciDevicePath = NULL;
69 LocalHddInfo = *HddInfo;
70 Status = Private->LegacyBiosPlatform->GetPlatformHandle (
71 Private->LegacyBiosPlatform,
72 EfiGetPlatformIdeHandle,
73 0,
74 &HandleBuffer,
75 &HandleCount,
76 (VOID *) &LocalHddInfo
77 );
78 if (!EFI_ERROR (Status)) {
79 IdeController = HandleBuffer[0];
80 //
81 // Force IDE drive spin up!
82 //
83 if (Flag != 0) {
84 gBS->DisconnectController (
85 IdeController,
86 NULL,
87 NULL
88 );
89 }
90
91 gBS->ConnectController (IdeController, NULL, NULL, FALSE);
92
93 //
94 // Do GetIdeHandle twice since disconnect/reconnect will switch to native mode
95 // And GetIdeHandle will switch to Legacy mode, if required.
96 //
97 Private->LegacyBiosPlatform->GetPlatformHandle (
98 Private->LegacyBiosPlatform,
99 EfiGetPlatformIdeHandle,
100 0,
101 &HandleBuffer,
102 &HandleCount,
103 (VOID *) &LocalHddInfo
104 );
105 }
106
107 mIdeDataBuiltFlag = TRUE;
108
109 //
110 // Get Identity command from all drives
111 //
112 gBS->LocateHandleBuffer (
113 ByProtocol,
114 &gEfiDiskInfoProtocolGuid,
115 NULL,
116 &HandleCount,
117 &HandleBuffer
118 );
119
120 Private->IdeDriveCount = (UINT8) HandleCount;
121 for (Index = 0; Index < HandleCount; Index++) {
122 Status = gBS->HandleProtocol (
123 HandleBuffer[Index],
124 &gEfiDiskInfoProtocolGuid,
125 (VOID **) &DiskInfo
126 );
127 ASSERT_EFI_ERROR (Status);
128
129 if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoIdeInterfaceGuid)) {
130 //
131 // Locate which PCI device
132 //
133 Status = gBS->HandleProtocol (
134 HandleBuffer[Index],
135 &gEfiDevicePathProtocolGuid,
136 (VOID *) &DevicePath
137 );
138 ASSERT_EFI_ERROR (Status);
139
140 DevicePathNode = DevicePath;
141 while (!IsDevicePathEnd (DevicePathNode)) {
142 TempDevicePathNode = NextDevicePathNode (DevicePathNode);
143 if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) &&
144 ( DevicePathSubType (DevicePathNode) == HW_PCI_DP) &&
145 ( DevicePathType(TempDevicePathNode) == MESSAGING_DEVICE_PATH) &&
146 ( DevicePathSubType(TempDevicePathNode) == MSG_ATAPI_DP) ) {
147 PciDevicePath = (PCI_DEVICE_PATH *) DevicePathNode;
148 break;
149 }
150 DevicePathNode = NextDevicePathNode (DevicePathNode);
151 }
152
153 if (PciDevicePath == NULL) {
154 continue;
155 }
156
157 //
158 // Find start of PCI device in HddInfo. The assumption of the data
159 // structure is 2 controllers(channels) per PCI device and each
160 // controller can have 2 drives(devices).
161 // HddInfo[PciIndex+0].[0] = Channel[0].Device[0] Primary Master
162 // HddInfo[PciIndex+0].[1] = Channel[0].Device[1] Primary Slave
163 // HddInfo[PciIndex+1].[0] = Channel[1].Device[0] Secondary Master
164 // HddInfo[PciIndex+1].[1] = Channel[1].Device[1] Secondary Slave
165 // @bug eventually need to pass in max number of entries
166 // for end of for loop
167 //
168 for (PciIndex = 0; PciIndex < 8; PciIndex++) {
169 if ((PciDevicePath->Device == LocalHddInfo[PciIndex].Device) &&
170 (PciDevicePath->Function == LocalHddInfo[PciIndex].Function)
171 ) {
172 break;
173 }
174 }
175
176 if (PciIndex == 8) {
177 continue;
178 }
179
180 Status = DiskInfo->WhichIde (DiskInfo, &IdeChannel, &IdeDevice);
181 if (!EFI_ERROR (Status)) {
182 Size = sizeof (ATAPI_IDENTIFY);
183 DiskInfo->Identify (
184 DiskInfo,
185 &LocalHddInfo[PciIndex + IdeChannel].IdentifyDrive[IdeDevice],
186 &Size
187 );
188 if (IdeChannel == 0) {
189 LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_PRIMARY;
190 } else if (IdeChannel == 1) {
191 LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SECONDARY;
192 }
193
194 InquiryData = NULL;
195 InquiryDataSize = 0;
196 Status = DiskInfo->Inquiry (
197 DiskInfo,
198 NULL,
199 &InquiryDataSize
200 );
201 if (Status == EFI_BUFFER_TOO_SMALL) {
202 InquiryData = (UINT8 *) AllocatePool (
203 InquiryDataSize
204 );
205 if (InquiryData != NULL) {
206 Status = DiskInfo->Inquiry (
207 DiskInfo,
208 InquiryData,
209 &InquiryDataSize
210 );
211 }
212 } else {
213 Status = EFI_DEVICE_ERROR;
214 }
215
216 //
217 // If ATAPI device then Inquiry will pass and ATA fail.
218 //
219 if (!EFI_ERROR (Status)) {
220 ASSERT (InquiryData != NULL);
221 //
222 // If IdeDevice = 0 then set master bit, else slave bit
223 //
224 if (IdeDevice == 0) {
225 if ((InquiryData[0] & 0x1f) == 0x05) {
226 LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_ATAPI_CDROM;
227 } else if ((InquiryData[0] & 0x1f) == 0x00) {
228 LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_ATAPI_ZIPDISK;
229 }
230 } else {
231 if ((InquiryData[0] & 0x1f) == 0x05) {
232 LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_ATAPI_CDROM;
233 } else if ((InquiryData[0] & 0x1f) == 0x00) {
234 LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_ATAPI_ZIPDISK;
235 }
236 }
237 FreePool (InquiryData);
238 } else {
239 if (IdeDevice == 0) {
240 LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_IDE;
241 } else {
242 LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_IDE;
243 }
244 }
245 }
246 }
247 }
248
249 if (HandleBuffer != NULL) {
250 FreePool (HandleBuffer);
251 }
252
253 return EFI_SUCCESS;
254 }
255
256
257 /**
258 If the IDE channel is in compatibility (legacy) mode, remove all
259 PCI I/O BAR addresses from the controller.
260
261 @param IdeController The handle of target IDE controller
262
263
264 **/
265 VOID
InitLegacyIdeController(IN EFI_HANDLE IdeController)266 InitLegacyIdeController (
267 IN EFI_HANDLE IdeController
268 )
269 {
270 EFI_PCI_IO_PROTOCOL *PciIo;
271 UINT32 IOBarClear;
272 EFI_STATUS Status;
273 PCI_TYPE00 PciData;
274
275 //
276 // If the IDE channel is in compatibility (legacy) mode, remove all
277 // PCI I/O BAR addresses from the controller. Some software gets
278 // confused if an IDE controller is in compatibility (legacy) mode
279 // and has PCI I/O resources allocated
280 //
281 Status = gBS->HandleProtocol (
282 IdeController,
283 &gEfiPciIoProtocolGuid,
284 (VOID **)&PciIo
285 );
286 if (EFI_ERROR (Status)) {
287 return ;
288 }
289
290 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0, sizeof (PciData), &PciData);
291 if (EFI_ERROR (Status)) {
292 return ;
293 }
294
295 //
296 // Check whether this is IDE
297 //
298 if ((PciData.Hdr.ClassCode[2] != PCI_CLASS_MASS_STORAGE) ||
299 (PciData.Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE)) {
300 return ;
301 }
302
303 //
304 // Clear bar for legacy IDE
305 //
306 IOBarClear = 0x00;
307 if ((PciData.Hdr.ClassCode[0] & IDE_PI_REGISTER_PNE) == 0) {
308 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x10, 1, &IOBarClear);
309 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x14, 1, &IOBarClear);
310 }
311 if ((PciData.Hdr.ClassCode[0] & IDE_PI_REGISTER_SNE) == 0) {
312 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x18, 1, &IOBarClear);
313 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1C, 1, &IOBarClear);
314 }
315
316 return ;
317 }
318