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