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