Home | History | Annotate | Download | only in BlockIoDxe
      1 /** @file
      2   EFI glue for BIOS INT 13h block devices.
      3 
      4   This file is coded to EDD 3.0 as defined by T13 D1386 Revision 4
      5   Availible on http://www.t13.org/#Project drafts
      6   Currently at ftp://fission.dt.wdc.com/pub/standards/x3t13/project/d1386r4.pdf
      7 
      8 Copyright (c) 1999 - 2011, Intel Corporation. All rights reserved.<BR>
      9 
     10 This program and the accompanying materials
     11 are licensed and made available under the terms and conditions
     12 of the BSD License which accompanies this distribution.  The
     13 full text of the license may be found at
     14 http://opensource.org/licenses/bsd-license.php
     15 
     16 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     17 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     18 
     19 **/
     20 
     21 #include "BiosBlkIo.h"
     22 
     23 //
     24 // Global data declaration
     25 //
     26 //
     27 // EFI Driver Binding Protocol Instance
     28 //
     29 EFI_DRIVER_BINDING_PROTOCOL gBiosBlockIoDriverBinding = {
     30   BiosBlockIoDriverBindingSupported,
     31   BiosBlockIoDriverBindingStart,
     32   BiosBlockIoDriverBindingStop,
     33   0x3,
     34   NULL,
     35   NULL
     36 };
     37 
     38 //
     39 // Semaphore to control access to global variables mActiveInstances and mBufferUnder1Mb
     40 //
     41 EFI_LOCK                    mGlobalDataLock = EFI_INITIALIZE_LOCK_VARIABLE(TPL_APPLICATION);
     42 
     43 //
     44 // Number of active instances of this protocol.  This is used to allocate/free
     45 // the shared buffer.  You must acquire the semaphore to modify.
     46 //
     47 UINTN                       mActiveInstances = 0;
     48 
     49 //
     50 // Pointer to the beginning of the buffer used for real mode thunk
     51 // You must acquire the semaphore to modify.
     52 //
     53 EFI_PHYSICAL_ADDRESS        mBufferUnder1Mb = 0;
     54 
     55 //
     56 // Address packet is a buffer under 1 MB for all version EDD calls
     57 //
     58 EDD_DEVICE_ADDRESS_PACKET   *mEddBufferUnder1Mb;
     59 
     60 //
     61 // This is a buffer for INT 13h func 48 information
     62 //
     63 BIOS_LEGACY_DRIVE           *mLegacyDriverUnder1Mb;
     64 
     65 //
     66 // Buffer of 0xFE00 bytes for EDD 1.1 transfer must be under 1 MB
     67 //  0xFE00 bytes is the max transfer size supported.
     68 //
     69 VOID                        *mEdd11Buffer;
     70 
     71 /**
     72   Driver entry point.
     73 
     74   @param  ImageHandle  Handle of driver image.
     75   @param  SystemTable  Pointer to system table.
     76 
     77   @retval EFI_SUCCESS  Entrypoint successfully executed.
     78   @retval Others       Fail to execute entrypoint.
     79 
     80 **/
     81 EFI_STATUS
     82 EFIAPI
     83 BiosBlockIoDriverEntryPoint (
     84   IN EFI_HANDLE           ImageHandle,
     85   IN EFI_SYSTEM_TABLE     *SystemTable
     86   )
     87 {
     88   EFI_STATUS  Status;
     89 
     90   //
     91   // Install protocols
     92   //
     93   Status = EfiLibInstallDriverBindingComponentName2 (
     94              ImageHandle,
     95              SystemTable,
     96              &gBiosBlockIoDriverBinding,
     97              ImageHandle,
     98              &gBiosBlockIoComponentName,
     99              &gBiosBlockIoComponentName2
    100              );
    101   if (EFI_ERROR (Status)) {
    102     return Status;
    103   }
    104   //
    105   // Install Legacy BIOS GUID to mark this driver as a BIOS Thunk Driver
    106   //
    107   return gBS->InstallMultipleProtocolInterfaces (
    108                 &ImageHandle,
    109                 &gEfiLegacyBiosGuid,
    110                 NULL,
    111                 NULL
    112                 );
    113 }
    114 
    115 /**
    116   Check whether the driver supports this device.
    117 
    118   @param  This                   The Udriver binding protocol.
    119   @param  Controller             The controller handle to check.
    120   @param  RemainingDevicePath    The remaining device path.
    121 
    122   @retval EFI_SUCCESS            The driver supports this controller.
    123   @retval other                  This device isn't supported.
    124 
    125 **/
    126 EFI_STATUS
    127 EFIAPI
    128 BiosBlockIoDriverBindingSupported (
    129   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    130   IN EFI_HANDLE                   Controller,
    131   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
    132   )
    133 {
    134   EFI_STATUS                Status;
    135   EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;
    136   EFI_PCI_IO_PROTOCOL       *PciIo;
    137   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
    138   PCI_TYPE00                Pci;
    139 
    140   //
    141   // See if the Legacy BIOS Protocol is available
    142   //
    143   Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
    144   if (EFI_ERROR (Status)) {
    145     return Status;
    146   }
    147 
    148   Status = gBS->OpenProtocol (
    149                   Controller,
    150                   &gEfiDevicePathProtocolGuid,
    151                   (VOID **) &DevicePath,
    152                   This->DriverBindingHandle,
    153                   Controller,
    154                   EFI_OPEN_PROTOCOL_BY_DRIVER
    155                   );
    156   if (EFI_ERROR (Status)) {
    157     return Status;
    158   }
    159 
    160   gBS->CloseProtocol (
    161         Controller,
    162         &gEfiDevicePathProtocolGuid,
    163         This->DriverBindingHandle,
    164         Controller
    165         );
    166 
    167   //
    168   // Open the IO Abstraction(s) needed to perform the supported test
    169   //
    170   Status = gBS->OpenProtocol (
    171                   Controller,
    172                   &gEfiPciIoProtocolGuid,
    173                   (VOID **) &PciIo,
    174                   This->DriverBindingHandle,
    175                   Controller,
    176                   EFI_OPEN_PROTOCOL_BY_DRIVER
    177                   );
    178   if (EFI_ERROR (Status)) {
    179     return Status;
    180   }
    181   //
    182   // See if this is a PCI VGA Controller by looking at the Command register and
    183   // Class Code Register
    184   //
    185   Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0, sizeof (Pci) / sizeof (UINT32), &Pci);
    186   if (EFI_ERROR (Status)) {
    187     Status = EFI_UNSUPPORTED;
    188     goto Done;
    189   }
    190 
    191   Status = EFI_UNSUPPORTED;
    192   if (Pci.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE ||
    193       (Pci.Hdr.ClassCode[2] == PCI_BASE_CLASS_INTELLIGENT && Pci.Hdr.ClassCode[1] == PCI_SUB_CLASS_INTELLIGENT)
    194       ) {
    195     Status = EFI_SUCCESS;
    196   }
    197 
    198 Done:
    199   gBS->CloseProtocol (
    200         Controller,
    201         &gEfiPciIoProtocolGuid,
    202         This->DriverBindingHandle,
    203         Controller
    204         );
    205 
    206   return Status;
    207 }
    208 
    209 /**
    210   Starts the device with this driver.
    211 
    212   @param  This                   The driver binding instance.
    213   @param  Controller             Handle of device to bind driver to.
    214   @param  RemainingDevicePath    Optional parameter use to pick a specific child
    215                                  device to start.
    216 
    217   @retval EFI_SUCCESS            The controller is controlled by the driver.
    218   @retval Other                  This controller cannot be started.
    219 
    220 **/
    221 EFI_STATUS
    222 EFIAPI
    223 BiosBlockIoDriverBindingStart (
    224   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    225   IN EFI_HANDLE                   Controller,
    226   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
    227   )
    228 {
    229   EFI_STATUS                Status;
    230   EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;
    231   EFI_PCI_IO_PROTOCOL       *PciIo;
    232   UINT8                     DiskStart;
    233   UINT8                     DiskEnd;
    234   BIOS_BLOCK_IO_DEV         *BiosBlockIoPrivate;
    235   EFI_DEVICE_PATH_PROTOCOL  *PciDevPath;
    236   UINTN                     Index;
    237   UINTN                     Flags;
    238   UINTN                     TmpAddress;
    239   BOOLEAN                   DeviceEnable;
    240 
    241   //
    242   // Initialize variables
    243   //
    244   PciIo      = NULL;
    245   PciDevPath = NULL;
    246 
    247   DeviceEnable = FALSE;
    248 
    249   //
    250   // See if the Legacy BIOS Protocol is available
    251   //
    252   Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
    253   if (EFI_ERROR (Status)) {
    254     goto Error;
    255   }
    256   //
    257   // Open the IO Abstraction(s) needed
    258   //
    259   Status = gBS->OpenProtocol (
    260                   Controller,
    261                   &gEfiPciIoProtocolGuid,
    262                   (VOID **) &PciIo,
    263                   This->DriverBindingHandle,
    264                   Controller,
    265                   EFI_OPEN_PROTOCOL_BY_DRIVER
    266                   );
    267   if (EFI_ERROR (Status)) {
    268     goto Error;
    269   }
    270 
    271   Status = gBS->OpenProtocol (
    272                   Controller,
    273                   &gEfiDevicePathProtocolGuid,
    274                   (VOID **) &PciDevPath,
    275                   This->DriverBindingHandle,
    276                   Controller,
    277                   EFI_OPEN_PROTOCOL_BY_DRIVER
    278                   );
    279 
    280   if (EFI_ERROR (Status)) {
    281     goto Error;
    282   }
    283   //
    284   // Enable the device and make sure VGA cycles are being forwarded to this VGA device
    285   //
    286   Status = PciIo->Attributes (
    287                     PciIo,
    288                     EfiPciIoAttributeOperationEnable,
    289                     EFI_PCI_DEVICE_ENABLE,
    290                     NULL
    291                     );
    292   if (EFI_ERROR (Status)) {
    293     goto Error;
    294   }
    295 
    296   DeviceEnable = TRUE;
    297 
    298   //
    299   // Check to see if there is a legacy option ROM image associated with this PCI device
    300   //
    301   Status = LegacyBios->CheckPciRom (
    302                         LegacyBios,
    303                         Controller,
    304                         NULL,
    305                         NULL,
    306                         &Flags
    307                         );
    308   if (EFI_ERROR (Status)) {
    309     goto Error;
    310   }
    311   //
    312   // Post the legacy option ROM if it is available.
    313   //
    314   Status = LegacyBios->InstallPciRom (
    315                         LegacyBios,
    316                         Controller,
    317                         NULL,
    318                         &Flags,
    319                         &DiskStart,
    320                         &DiskEnd,
    321                         NULL,
    322                         NULL
    323                         );
    324   if (EFI_ERROR (Status)) {
    325     goto Error;
    326   }
    327   //
    328   // All instances share a buffer under 1MB to put real mode thunk code in
    329   // If it has not been allocated, then we allocate it.
    330   //
    331   if (mBufferUnder1Mb == 0) {
    332     //
    333     // Should only be here if there are no active instances
    334     //
    335     ASSERT (mActiveInstances == 0);
    336 
    337     //
    338     // Acquire the lock
    339     //
    340     EfiAcquireLock (&mGlobalDataLock);
    341 
    342     //
    343     // Allocate below 1MB
    344     //
    345     mBufferUnder1Mb = 0x00000000000FFFFF;
    346     Status          = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData, BLOCK_IO_BUFFER_PAGE_SIZE, &mBufferUnder1Mb);
    347 
    348     //
    349     // Release the lock
    350     //
    351     EfiReleaseLock (&mGlobalDataLock);
    352 
    353     //
    354     // Check memory allocation success
    355     //
    356     if (EFI_ERROR (Status)) {
    357       //
    358       // In checked builds we want to assert if the allocate failed.
    359       //
    360       ASSERT_EFI_ERROR (Status);
    361       Status          = EFI_OUT_OF_RESOURCES;
    362       mBufferUnder1Mb = 0;
    363       goto Error;
    364     }
    365 
    366     TmpAddress = (UINTN) mBufferUnder1Mb;
    367     //
    368     // Adjusting the value to be on proper boundary
    369     //
    370     mEdd11Buffer = (VOID *) ALIGN_VARIABLE (TmpAddress);
    371 
    372     TmpAddress   = (UINTN) mEdd11Buffer + MAX_EDD11_XFER;
    373     //
    374     // Adjusting the value to be on proper boundary
    375     //
    376     mLegacyDriverUnder1Mb = (BIOS_LEGACY_DRIVE *) ALIGN_VARIABLE (TmpAddress);
    377 
    378     TmpAddress = (UINTN) mLegacyDriverUnder1Mb + sizeof (BIOS_LEGACY_DRIVE);
    379     //
    380     // Adjusting the value to be on proper boundary
    381     //
    382     mEddBufferUnder1Mb = (EDD_DEVICE_ADDRESS_PACKET *) ALIGN_VARIABLE (TmpAddress);
    383   }
    384   //
    385   // Allocate the private device structure for each disk
    386   //
    387   for (Index = DiskStart; Index < DiskEnd; Index++) {
    388 
    389     Status = gBS->AllocatePool (
    390                     EfiBootServicesData,
    391                     sizeof (BIOS_BLOCK_IO_DEV),
    392                     (VOID **) &BiosBlockIoPrivate
    393                     );
    394     if (EFI_ERROR (Status)) {
    395       goto Error;
    396     }
    397     //
    398     // Zero the private device structure
    399     //
    400     ZeroMem (BiosBlockIoPrivate, sizeof (BIOS_BLOCK_IO_DEV));
    401 
    402     //
    403     // Initialize the private device structure
    404     //
    405     BiosBlockIoPrivate->Signature                 = BIOS_CONSOLE_BLOCK_IO_DEV_SIGNATURE;
    406     BiosBlockIoPrivate->ControllerHandle          = Controller;
    407     BiosBlockIoPrivate->LegacyBios                = LegacyBios;
    408     BiosBlockIoPrivate->PciIo                     = PciIo;
    409 
    410     BiosBlockIoPrivate->Bios.Floppy               = FALSE;
    411     BiosBlockIoPrivate->Bios.Number               = (UINT8) Index;
    412     BiosBlockIoPrivate->Bios.Letter               = (UINT8) (Index - 0x80 + 'C');
    413     BiosBlockIoPrivate->BlockMedia.RemovableMedia = FALSE;
    414 
    415     if (BiosInitBlockIo (BiosBlockIoPrivate)) {
    416       SetBiosInitBlockIoDevicePath (PciDevPath, &BiosBlockIoPrivate->Bios, &BiosBlockIoPrivate->DevicePath);
    417 
    418       //
    419       // Install the Block Io Protocol onto a new child handle
    420       //
    421       Status = gBS->InstallMultipleProtocolInterfaces (
    422                       &BiosBlockIoPrivate->Handle,
    423                       &gEfiBlockIoProtocolGuid,
    424                       &BiosBlockIoPrivate->BlockIo,
    425                       &gEfiDevicePathProtocolGuid,
    426                       BiosBlockIoPrivate->DevicePath,
    427                       NULL
    428                       );
    429       if (EFI_ERROR (Status)) {
    430         gBS->FreePool (BiosBlockIoPrivate);
    431       }
    432       //
    433       // Open For Child Device
    434       //
    435       Status = gBS->OpenProtocol (
    436                       Controller,
    437                       &gEfiPciIoProtocolGuid,
    438                       (VOID **) &BiosBlockIoPrivate->PciIo,
    439                       This->DriverBindingHandle,
    440                       BiosBlockIoPrivate->Handle,
    441                       EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    442                       );
    443 
    444     } else {
    445       gBS->FreePool (BiosBlockIoPrivate);
    446     }
    447   }
    448 
    449 Error:
    450   if (EFI_ERROR (Status)) {
    451     if (PciIo != NULL) {
    452       if (DeviceEnable) {
    453         PciIo->Attributes (
    454                 PciIo,
    455                 EfiPciIoAttributeOperationDisable,
    456                 EFI_PCI_DEVICE_ENABLE,
    457                 NULL
    458                 );
    459       }
    460       gBS->CloseProtocol (
    461             Controller,
    462             &gEfiPciIoProtocolGuid,
    463             This->DriverBindingHandle,
    464             Controller
    465             );
    466       if (PciDevPath != NULL) {
    467         gBS->CloseProtocol (
    468               Controller,
    469               &gEfiDevicePathProtocolGuid,
    470               This->DriverBindingHandle,
    471               Controller
    472               );
    473       }
    474       if (mBufferUnder1Mb != 0 && mActiveInstances == 0) {
    475         gBS->FreePages (mBufferUnder1Mb, BLOCK_IO_BUFFER_PAGE_SIZE);
    476 
    477         //
    478         // Clear the buffer back to 0
    479         //
    480         EfiAcquireLock (&mGlobalDataLock);
    481         mBufferUnder1Mb = 0;
    482         EfiReleaseLock (&mGlobalDataLock);
    483       }
    484     }
    485   } else {
    486     //
    487     // Successfully installed, so increment the number of active instances
    488     //
    489     EfiAcquireLock (&mGlobalDataLock);
    490     mActiveInstances++;
    491     EfiReleaseLock (&mGlobalDataLock);
    492   }
    493 
    494   return Status;
    495 }
    496 
    497 /**
    498   Stop the device handled by this driver.
    499 
    500   @param  This                   The driver binding protocol.
    501   @param  Controller             The controller to release.
    502   @param  NumberOfChildren       The number of handles in ChildHandleBuffer.
    503   @param  ChildHandleBuffer      The array of child handle.
    504 
    505   @retval EFI_SUCCESS            The device was stopped.
    506   @retval EFI_DEVICE_ERROR       The device could not be stopped due to a device error.
    507   @retval Others                 Fail to uninstall protocols attached on the device.
    508 
    509 **/
    510 EFI_STATUS
    511 EFIAPI
    512 BiosBlockIoDriverBindingStop (
    513   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
    514   IN  EFI_HANDLE                      Controller,
    515   IN  UINTN                           NumberOfChildren,
    516   IN  EFI_HANDLE                      *ChildHandleBuffer
    517   )
    518 {
    519   EFI_STATUS            Status;
    520   BOOLEAN               AllChildrenStopped;
    521   EFI_BLOCK_IO_PROTOCOL *BlockIo;
    522   BIOS_BLOCK_IO_DEV     *BiosBlockIoPrivate;
    523   UINTN                 Index;
    524 
    525   //
    526   // Decrement the number of active instances
    527   //
    528   if (mActiveInstances != 0) {
    529     //
    530     // Add a check since the stop function will be called 2 times for each handle
    531     //
    532     EfiAcquireLock (&mGlobalDataLock);
    533     mActiveInstances--;
    534     EfiReleaseLock (&mGlobalDataLock);
    535   }
    536 
    537   if ((mActiveInstances == 0) && (mBufferUnder1Mb != 0)) {
    538     //
    539     // Free our global buffer
    540     //
    541     Status = gBS->FreePages (mBufferUnder1Mb, BLOCK_IO_BUFFER_PAGE_SIZE);
    542     ASSERT_EFI_ERROR (Status);
    543 
    544     EfiAcquireLock (&mGlobalDataLock);
    545     mBufferUnder1Mb = 0;
    546     EfiReleaseLock (&mGlobalDataLock);
    547   }
    548 
    549   AllChildrenStopped = TRUE;
    550 
    551   for (Index = 0; Index < NumberOfChildren; Index++) {
    552     Status = gBS->OpenProtocol (
    553                     ChildHandleBuffer[Index],
    554                     &gEfiBlockIoProtocolGuid,
    555                     (VOID **) &BlockIo,
    556                     This->DriverBindingHandle,
    557                     Controller,
    558                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
    559                     );
    560     if (EFI_ERROR (Status)) {
    561       return Status;
    562     }
    563 
    564     BiosBlockIoPrivate = BIOS_BLOCK_IO_FROM_THIS (BlockIo);
    565 
    566     //
    567     // Release PCI I/O and Block IO Protocols on the clild handle.
    568     //
    569     Status = gBS->UninstallMultipleProtocolInterfaces (
    570                     ChildHandleBuffer[Index],
    571                     &gEfiBlockIoProtocolGuid,
    572                     &BiosBlockIoPrivate->BlockIo,
    573                     &gEfiDevicePathProtocolGuid,
    574                     BiosBlockIoPrivate->DevicePath,
    575                     NULL
    576                     );
    577     if (EFI_ERROR (Status)) {
    578       AllChildrenStopped = FALSE;
    579     }
    580     //
    581     // Shutdown the hardware
    582     //
    583     BiosBlockIoPrivate->PciIo->Attributes (
    584                                 BiosBlockIoPrivate->PciIo,
    585                                 EfiPciIoAttributeOperationDisable,
    586                                 EFI_PCI_DEVICE_ENABLE,
    587                                 NULL
    588                                 );
    589 
    590     gBS->CloseProtocol (
    591           Controller,
    592           &gEfiPciIoProtocolGuid,
    593           This->DriverBindingHandle,
    594           ChildHandleBuffer[Index]
    595           );
    596 
    597     gBS->FreePool (BiosBlockIoPrivate);
    598   }
    599 
    600   if (!AllChildrenStopped) {
    601     return EFI_DEVICE_ERROR;
    602   }
    603 
    604   Status = gBS->CloseProtocol (
    605                   Controller,
    606                   &gEfiDevicePathProtocolGuid,
    607                   This->DriverBindingHandle,
    608                   Controller
    609                   );
    610 
    611   Status = gBS->CloseProtocol (
    612                   Controller,
    613                   &gEfiPciIoProtocolGuid,
    614                   This->DriverBindingHandle,
    615                   Controller
    616                   );
    617 
    618   return EFI_SUCCESS;
    619 }
    620 
    621 /**
    622   Build device path for device.
    623 
    624   @param  BaseDevicePath         Base device path.
    625   @param  Drive                  Legacy drive.
    626   @param  DevicePath             Device path for output.
    627 
    628 **/
    629 VOID
    630 SetBiosInitBlockIoDevicePath (
    631   IN  EFI_DEVICE_PATH_PROTOCOL  *BaseDevicePath,
    632   IN  BIOS_LEGACY_DRIVE         *Drive,
    633   OUT EFI_DEVICE_PATH_PROTOCOL  **DevicePath
    634   )
    635 {
    636   EFI_STATUS                  Status;
    637   BLOCKIO_VENDOR_DEVICE_PATH  VendorNode;
    638 
    639   Status = EFI_UNSUPPORTED;
    640 
    641   //
    642   // BugBug: Check for memory leaks!
    643   //
    644   if (Drive->EddVersion == EDD_VERSION_30) {
    645     //
    646     // EDD 3.0 case.
    647     //
    648     Status = BuildEdd30DevicePath (BaseDevicePath, Drive, DevicePath);
    649   }
    650 
    651   if (EFI_ERROR (Status)) {
    652     //
    653     // EDD 1.1 device case or it is unrecognized EDD 3.0 device
    654     //
    655     ZeroMem (&VendorNode, sizeof (VendorNode));
    656     VendorNode.DevicePath.Header.Type     = HARDWARE_DEVICE_PATH;
    657     VendorNode.DevicePath.Header.SubType  = HW_VENDOR_DP;
    658     SetDevicePathNodeLength (&VendorNode.DevicePath.Header, sizeof (VendorNode));
    659     CopyMem (&VendorNode.DevicePath.Guid, &gBlockIoVendorGuid, sizeof (EFI_GUID));
    660     VendorNode.LegacyDriveLetter  = Drive->Number;
    661     *DevicePath                   = AppendDevicePathNode (BaseDevicePath, &VendorNode.DevicePath.Header);
    662   }
    663 }
    664 
    665 /**
    666   Build device path for EDD 3.0.
    667 
    668   @param  BaseDevicePath         Base device path.
    669   @param  Drive                  Legacy drive.
    670   @param  DevicePath             Device path for output.
    671 
    672   @retval EFI_SUCCESS            The device path is built successfully.
    673   @retval EFI_UNSUPPORTED        It is failed to built device path.
    674 
    675 **/
    676 EFI_STATUS
    677 BuildEdd30DevicePath (
    678   IN  EFI_DEVICE_PATH_PROTOCOL  *BaseDevicePath,
    679   IN  BIOS_LEGACY_DRIVE         *Drive,
    680   IN  EFI_DEVICE_PATH_PROTOCOL  **DevicePath
    681   )
    682 {
    683   //
    684   // AVL    UINT64                  Address;
    685   // AVL    EFI_HANDLE              Handle;
    686   //
    687   EFI_DEV_PATH  Node;
    688   UINT32        Controller;
    689 
    690   Controller = (UINT32) Drive->Parameters.InterfacePath.Pci.Controller;
    691 
    692   ZeroMem (&Node, sizeof (Node));
    693   if ((AsciiStrnCmp ("ATAPI", Drive->Parameters.InterfaceType, 5) == 0) ||
    694       (AsciiStrnCmp ("ATA", Drive->Parameters.InterfaceType, 3) == 0)
    695       ) {
    696     //
    697     // ATA or ATAPI drive found
    698     //
    699     Node.Atapi.Header.Type    = MESSAGING_DEVICE_PATH;
    700     Node.Atapi.Header.SubType = MSG_ATAPI_DP;
    701     SetDevicePathNodeLength (&Node.Atapi.Header, sizeof (ATAPI_DEVICE_PATH));
    702     Node.Atapi.SlaveMaster      = Drive->Parameters.DevicePath.Atapi.Master;
    703     Node.Atapi.Lun              = Drive->Parameters.DevicePath.Atapi.Lun;
    704     Node.Atapi.PrimarySecondary = (UINT8) Controller;
    705   } else {
    706     //
    707     // Not an ATA/ATAPI drive
    708     //
    709     if (Controller != 0) {
    710       ZeroMem (&Node, sizeof (Node));
    711       Node.Controller.Header.Type      = HARDWARE_DEVICE_PATH;
    712       Node.Controller.Header.SubType   = HW_CONTROLLER_DP;
    713       SetDevicePathNodeLength (&Node.Controller.Header, sizeof (CONTROLLER_DEVICE_PATH));
    714       Node.Controller.ControllerNumber = Controller;
    715       *DevicePath                      = AppendDevicePathNode (*DevicePath, &Node.DevPath);
    716     }
    717 
    718     ZeroMem (&Node, sizeof (Node));
    719 
    720     if (AsciiStrnCmp ("SCSI", Drive->Parameters.InterfaceType, 4) == 0) {
    721       //
    722       // SCSI drive
    723       //
    724       Node.Scsi.Header.Type     = MESSAGING_DEVICE_PATH;
    725       Node.Scsi.Header.SubType  = MSG_SCSI_DP;
    726       SetDevicePathNodeLength (&Node.Scsi.Header, sizeof (SCSI_DEVICE_PATH));
    727 
    728       //
    729       // Lun is miss aligned in both EDD and Device Path data structures.
    730       //  thus we do a byte copy, to prevent alignment traps on IA-64.
    731       //
    732       CopyMem (&Node.Scsi.Lun, &Drive->Parameters.DevicePath.Scsi.Lun, sizeof (UINT16));
    733       Node.Scsi.Pun = Drive->Parameters.DevicePath.Scsi.Pun;
    734 
    735     } else if (AsciiStrnCmp ("USB", Drive->Parameters.InterfaceType, 3) == 0) {
    736       //
    737       // USB drive
    738       //
    739       Node.Usb.Header.Type    = MESSAGING_DEVICE_PATH;
    740       Node.Usb.Header.SubType = MSG_USB_DP;
    741       SetDevicePathNodeLength (&Node.Usb.Header, sizeof (USB_DEVICE_PATH));
    742       Node.Usb.ParentPortNumber = (UINT8) Drive->Parameters.DevicePath.Usb.Reserved;
    743 
    744     } else if (AsciiStrnCmp ("1394", Drive->Parameters.InterfaceType, 4) == 0) {
    745       //
    746       // 1394 drive
    747       //
    748       Node.F1394.Header.Type    = MESSAGING_DEVICE_PATH;
    749       Node.F1394.Header.SubType = MSG_1394_DP;
    750       SetDevicePathNodeLength (&Node.F1394.Header, sizeof (F1394_DEVICE_PATH));
    751       Node.F1394.Guid = Drive->Parameters.DevicePath.FireWire.Guid;
    752 
    753     } else if (AsciiStrnCmp ("FIBRE", Drive->Parameters.InterfaceType, 5) == 0) {
    754       //
    755       // Fibre drive
    756       //
    757       Node.FibreChannel.Header.Type     = MESSAGING_DEVICE_PATH;
    758       Node.FibreChannel.Header.SubType  = MSG_FIBRECHANNEL_DP;
    759       SetDevicePathNodeLength (&Node.FibreChannel.Header, sizeof (FIBRECHANNEL_DEVICE_PATH));
    760       Node.FibreChannel.WWN = Drive->Parameters.DevicePath.FibreChannel.Wwn;
    761       Node.FibreChannel.Lun = Drive->Parameters.DevicePath.FibreChannel.Lun;
    762 
    763     } else {
    764       DEBUG (
    765         (
    766         DEBUG_BLKIO, "It is unrecognized EDD 3.0 device, Drive Number = %x, InterfaceType = %s\n",
    767         Drive->Number,
    768         Drive->Parameters.InterfaceType
    769         )
    770         );
    771     }
    772   }
    773 
    774   if (Node.DevPath.Type == 0) {
    775     return EFI_UNSUPPORTED;
    776   }
    777 
    778   *DevicePath = AppendDevicePathNode (BaseDevicePath, &Node.DevPath);
    779   return EFI_SUCCESS;
    780 }
    781