Home | History | Annotate | Download | only in LegacyBiosDxe
      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