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 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 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