summaryrefslogtreecommitdiff
path: root/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.c
diff options
context:
space:
mode:
Diffstat (limited to 'IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.c')
-rw-r--r--IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.c782
1 files changed, 782 insertions, 0 deletions
diff --git a/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.c b/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.c
new file mode 100644
index 0000000..309cf1a
--- /dev/null
+++ b/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.c
@@ -0,0 +1,782 @@
+/** @file
+ EFI glue for BIOS INT 13h block devices.
+
+ This file is coded to EDD 3.0 as defined by T13 D1386 Revision 4
+ Availible on http://www.t13.org/#Project drafts
+ Currently at ftp://fission.dt.wdc.com/pub/standards/x3t13/project/d1386r4.pdf
+
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BiosBlkIo.h"
+
+//
+// Global data declaration
+//
+//
+// EFI Driver Binding Protocol Instance
+//
+EFI_DRIVER_BINDING_PROTOCOL gBiosBlockIoDriverBinding = {
+ BiosBlockIoDriverBindingSupported,
+ BiosBlockIoDriverBindingStart,
+ BiosBlockIoDriverBindingStop,
+ 0x3,
+ NULL,
+ NULL
+};
+
+//
+// Semaphore to control access to global variables mActiveInstances and mBufferUnder1Mb
+//
+EFI_LOCK mGlobalDataLock = EFI_INITIALIZE_LOCK_VARIABLE(TPL_APPLICATION);
+
+//
+// Number of active instances of this protocol. This is used to allocate/free
+// the shared buffer. You must acquire the semaphore to modify.
+//
+UINTN mActiveInstances = 0;
+
+//
+// Pointer to the beginning of the buffer used for real mode thunk
+// You must acquire the semaphore to modify.
+//
+EFI_PHYSICAL_ADDRESS mBufferUnder1Mb = 0;
+
+//
+// Address packet is a buffer under 1 MB for all version EDD calls
+//
+EDD_DEVICE_ADDRESS_PACKET *mEddBufferUnder1Mb;
+
+//
+// This is a buffer for INT 13h func 48 information
+//
+BIOS_LEGACY_DRIVE *mLegacyDriverUnder1Mb;
+
+//
+// Buffer of 0xFE00 bytes for EDD 1.1 transfer must be under 1 MB
+// 0xFE00 bytes is the max transfer size supported.
+//
+VOID *mEdd11Buffer;
+
+EFI_GUID mUnknownDevGuid = UNKNOWN_DEVICE_GUID;
+
+/**
+ Driver entry point.
+
+ @param ImageHandle Handle of driver image.
+ @param SystemTable Pointer to system table.
+
+ @retval EFI_SUCCESS Entrypoint successfully executed.
+ @retval Others Fail to execute entrypoint.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install protocols
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gBiosBlockIoDriverBinding,
+ ImageHandle,
+ &gBiosBlockIoComponentName,
+ &gBiosBlockIoComponentName2
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Install Legacy BIOS GUID to mark this driver as a BIOS Thunk Driver
+ //
+ return gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiLegacyBiosGuid,
+ NULL,
+ NULL
+ );
+}
+
+/**
+ Check whether the driver supports this device.
+
+ @param This The Udriver binding protocol.
+ @param Controller The controller handle to check.
+ @param RemainingDevicePath The remaining device path.
+
+ @retval EFI_SUCCESS The driver supports this controller.
+ @retval other This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ PCI_TYPE00 Pci;
+
+ //
+ // See if the Legacy BIOS Protocol is available
+ //
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // See if this is a PCI VGA Controller by looking at the Command register and
+ // Class Code Register
+ //
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0, sizeof (Pci) / sizeof (UINT32), &Pci);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ Status = EFI_UNSUPPORTED;
+ if (Pci.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE ||
+ (Pci.Hdr.ClassCode[2] == PCI_BASE_CLASS_INTELLIGENT && Pci.Hdr.ClassCode[1] == PCI_SUB_CLASS_INTELLIGENT)
+ ) {
+ Status = EFI_SUCCESS;
+ }
+
+Done:
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+/**
+ Starts the device with this driver.
+
+ @param This The driver binding instance.
+ @param Controller Handle of device to bind driver to.
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS The controller is controlled by the driver.
+ @retval Other This controller cannot be started.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 DiskStart;
+ UINT8 DiskEnd;
+ BIOS_BLOCK_IO_DEV *BiosBlockIoPrivate;
+ EFI_DEVICE_PATH_PROTOCOL *PciDevPath;
+ UINTN Index;
+ UINTN Flags;
+ UINTN TmpAddress;
+ BOOLEAN DeviceEnable;
+
+ //
+ // Initialize variables
+ //
+ PciIo = NULL;
+ PciDevPath = NULL;
+
+ DeviceEnable = FALSE;
+
+ //
+ // See if the Legacy BIOS Protocol is available
+ //
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ //
+ // Open the IO Abstraction(s) needed
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &PciDevPath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ //
+ // Enable the device and make sure VGA cycles are being forwarded to this VGA device
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_DEVICE_ENABLE,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ DeviceEnable = TRUE;
+
+ //
+ // Check to see if there is a legacy option ROM image associated with this PCI device
+ //
+ Status = LegacyBios->CheckPciRom (
+ LegacyBios,
+ Controller,
+ NULL,
+ NULL,
+ &Flags
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ //
+ // Post the legacy option ROM if it is available.
+ //
+ Status = LegacyBios->InstallPciRom (
+ LegacyBios,
+ Controller,
+ NULL,
+ &Flags,
+ &DiskStart,
+ &DiskEnd,
+ NULL,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ //
+ // All instances share a buffer under 1MB to put real mode thunk code in
+ // If it has not been allocated, then we allocate it.
+ //
+ if (mBufferUnder1Mb == 0) {
+ //
+ // Should only be here if there are no active instances
+ //
+ ASSERT (mActiveInstances == 0);
+
+ //
+ // Acquire the lock
+ //
+ EfiAcquireLock (&mGlobalDataLock);
+
+ //
+ // Allocate below 1MB
+ //
+ mBufferUnder1Mb = 0x00000000000FFFFF;
+ Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData, BLOCK_IO_BUFFER_PAGE_SIZE, &mBufferUnder1Mb);
+
+ //
+ // Release the lock
+ //
+ EfiReleaseLock (&mGlobalDataLock);
+
+ //
+ // Check memory allocation success
+ //
+ if (EFI_ERROR (Status)) {
+ //
+ // In checked builds we want to assert if the allocate failed.
+ //
+ ASSERT_EFI_ERROR (Status);
+ Status = EFI_OUT_OF_RESOURCES;
+ mBufferUnder1Mb = 0;
+ goto Error;
+ }
+
+ TmpAddress = (UINTN) mBufferUnder1Mb;
+ //
+ // Adjusting the value to be on proper boundary
+ //
+ mEdd11Buffer = (VOID *) ALIGN_VARIABLE (TmpAddress);
+
+ TmpAddress = (UINTN) mEdd11Buffer + MAX_EDD11_XFER;
+ //
+ // Adjusting the value to be on proper boundary
+ //
+ mLegacyDriverUnder1Mb = (BIOS_LEGACY_DRIVE *) ALIGN_VARIABLE (TmpAddress);
+
+ TmpAddress = (UINTN) mLegacyDriverUnder1Mb + sizeof (BIOS_LEGACY_DRIVE);
+ //
+ // Adjusting the value to be on proper boundary
+ //
+ mEddBufferUnder1Mb = (EDD_DEVICE_ADDRESS_PACKET *) ALIGN_VARIABLE (TmpAddress);
+ }
+ //
+ // Allocate the private device structure for each disk
+ //
+ for (Index = DiskStart; Index < DiskEnd; Index++) {
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (BIOS_BLOCK_IO_DEV),
+ (VOID **) &BiosBlockIoPrivate
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ //
+ // Zero the private device structure
+ //
+ ZeroMem (BiosBlockIoPrivate, sizeof (BIOS_BLOCK_IO_DEV));
+
+ //
+ // Initialize the private device structure
+ //
+ BiosBlockIoPrivate->Signature = BIOS_CONSOLE_BLOCK_IO_DEV_SIGNATURE;
+ BiosBlockIoPrivate->ControllerHandle = Controller;
+ BiosBlockIoPrivate->LegacyBios = LegacyBios;
+ BiosBlockIoPrivate->PciIo = PciIo;
+
+ BiosBlockIoPrivate->Bios.Floppy = FALSE;
+ BiosBlockIoPrivate->Bios.Number = (UINT8) Index;
+ BiosBlockIoPrivate->Bios.Letter = (UINT8) (Index - 0x80 + 'C');
+ BiosBlockIoPrivate->BlockMedia.RemovableMedia = FALSE;
+
+ if (BiosInitBlockIo (BiosBlockIoPrivate)) {
+ SetBiosInitBlockIoDevicePath (PciDevPath, &BiosBlockIoPrivate->Bios, &BiosBlockIoPrivate->DevicePath);
+
+ //
+ // Install the Block Io Protocol onto a new child handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &BiosBlockIoPrivate->Handle,
+ &gEfiBlockIoProtocolGuid,
+ &BiosBlockIoPrivate->BlockIo,
+ &gEfiDevicePathProtocolGuid,
+ BiosBlockIoPrivate->DevicePath,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (BiosBlockIoPrivate);
+ }
+ //
+ // Open For Child Device
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &BiosBlockIoPrivate->PciIo,
+ This->DriverBindingHandle,
+ BiosBlockIoPrivate->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+
+ } else {
+ gBS->FreePool (BiosBlockIoPrivate);
+ }
+ }
+
+Error:
+ if (EFI_ERROR (Status)) {
+ if (PciIo != NULL) {
+ if (DeviceEnable) {
+ PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationDisable,
+ EFI_PCI_DEVICE_ENABLE,
+ NULL
+ );
+ }
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ if (PciDevPath != NULL) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+ if (mBufferUnder1Mb != 0 && mActiveInstances == 0) {
+ gBS->FreePages (mBufferUnder1Mb, BLOCK_IO_BUFFER_PAGE_SIZE);
+
+ //
+ // Clear the buffer back to 0
+ //
+ EfiAcquireLock (&mGlobalDataLock);
+ mBufferUnder1Mb = 0;
+ EfiReleaseLock (&mGlobalDataLock);
+ }
+ }
+ } else {
+ //
+ // Successfully installed, so increment the number of active instances
+ //
+ EfiAcquireLock (&mGlobalDataLock);
+ mActiveInstances++;
+ EfiReleaseLock (&mGlobalDataLock);
+ }
+
+ return Status;
+}
+
+/**
+ Stop the device handled by this driver.
+
+ @param This The driver binding protocol.
+ @param Controller The controller to release.
+ @param NumberOfChildren The number of handles in ChildHandleBuffer.
+ @param ChildHandleBuffer The array of child handle.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+ @retval Others Fail to uninstall protocols attached on the device.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN AllChildrenStopped;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ BIOS_BLOCK_IO_DEV *BiosBlockIoPrivate;
+ UINTN Index;
+
+ //
+ // Decrement the number of active instances
+ //
+ if (mActiveInstances != 0) {
+ //
+ // Add a check since the stop function will be called 2 times for each handle
+ //
+ EfiAcquireLock (&mGlobalDataLock);
+ mActiveInstances--;
+ EfiReleaseLock (&mGlobalDataLock);
+ }
+
+ if ((mActiveInstances == 0) && (mBufferUnder1Mb != 0)) {
+ //
+ // Free our global buffer
+ //
+ Status = gBS->FreePages (mBufferUnder1Mb, BLOCK_IO_BUFFER_PAGE_SIZE);
+ ASSERT_EFI_ERROR (Status);
+
+ EfiAcquireLock (&mGlobalDataLock);
+ mBufferUnder1Mb = 0;
+ EfiReleaseLock (&mGlobalDataLock);
+ }
+
+ AllChildrenStopped = TRUE;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BiosBlockIoPrivate = BIOS_BLOCK_IO_FROM_THIS (BlockIo);
+
+ //
+ // Release PCI I/O and Block IO Protocols on the clild handle.
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiBlockIoProtocolGuid,
+ &BiosBlockIoPrivate->BlockIo,
+ &gEfiDevicePathProtocolGuid,
+ BiosBlockIoPrivate->DevicePath,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ }
+ //
+ // Shutdown the hardware
+ //
+ BiosBlockIoPrivate->PciIo->Attributes (
+ BiosBlockIoPrivate->PciIo,
+ EfiPciIoAttributeOperationDisable,
+ EFI_PCI_DEVICE_ENABLE,
+ NULL
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+
+ gBS->FreePool (BiosBlockIoPrivate);
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Build device path for device.
+
+ @param BaseDevicePath Base device path.
+ @param Drive Legacy drive.
+ @param DevicePath Device path for output.
+
+**/
+VOID
+SetBiosInitBlockIoDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *BaseDevicePath,
+ IN BIOS_LEGACY_DRIVE *Drive,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ EFI_STATUS Status;
+ UNKNOWN_DEVICE_VENDOR_DEVICE_PATH VendorNode;
+
+ Status = EFI_UNSUPPORTED;
+
+ //
+ // BugBug: Check for memory leaks!
+ //
+ if (Drive->EddVersion == EDD_VERSION_30) {
+ //
+ // EDD 3.0 case.
+ //
+ Status = BuildEdd30DevicePath (BaseDevicePath, Drive, DevicePath);
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // EDD 1.1 device case or it is unrecognized EDD 3.0 device
+ //
+ ZeroMem (&VendorNode, sizeof (VendorNode));
+ VendorNode.DevicePath.Header.Type = HARDWARE_DEVICE_PATH;
+ VendorNode.DevicePath.Header.SubType = HW_VENDOR_DP;
+ SetDevicePathNodeLength (&VendorNode.DevicePath.Header, sizeof (VendorNode));
+ CopyMem (&VendorNode.DevicePath.Guid, &mUnknownDevGuid, sizeof (EFI_GUID));
+ VendorNode.LegacyDriveLetter = Drive->Number;
+ *DevicePath = AppendDevicePathNode (BaseDevicePath, &VendorNode.DevicePath.Header);
+ }
+}
+
+/**
+ Build device path for EDD 3.0.
+
+ @param BaseDevicePath Base device path.
+ @param Drive Legacy drive.
+ @param DevicePath Device path for output.
+
+ @retval EFI_SUCCESS The device path is built successfully.
+ @retval EFI_UNSUPPORTED It is failed to built device path.
+
+**/
+EFI_STATUS
+BuildEdd30DevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *BaseDevicePath,
+ IN BIOS_LEGACY_DRIVE *Drive,
+ IN EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ //
+ // AVL UINT64 Address;
+ // AVL EFI_HANDLE Handle;
+ //
+ EFI_DEV_PATH Node;
+ UINT32 Controller;
+
+ Controller = (UINT32) Drive->Parameters.InterfacePath.Pci.Controller;
+
+ ZeroMem (&Node, sizeof (Node));
+ if ((AsciiStrnCmp ("ATAPI", Drive->Parameters.InterfaceType, 5) == 0) ||
+ (AsciiStrnCmp ("ATA", Drive->Parameters.InterfaceType, 3) == 0)
+ ) {
+ //
+ // ATA or ATAPI drive found
+ //
+ Node.Atapi.Header.Type = MESSAGING_DEVICE_PATH;
+ Node.Atapi.Header.SubType = MSG_ATAPI_DP;
+ SetDevicePathNodeLength (&Node.Atapi.Header, sizeof (ATAPI_DEVICE_PATH));
+ Node.Atapi.SlaveMaster = Drive->Parameters.DevicePath.Atapi.Master;
+ Node.Atapi.Lun = Drive->Parameters.DevicePath.Atapi.Lun;
+ Node.Atapi.PrimarySecondary = (UINT8) Controller;
+ } else {
+ //
+ // Not an ATA/ATAPI drive
+ //
+ if (Controller != 0) {
+ ZeroMem (&Node, sizeof (Node));
+ Node.Controller.Header.Type = HARDWARE_DEVICE_PATH;
+ Node.Controller.Header.SubType = HW_CONTROLLER_DP;
+ SetDevicePathNodeLength (&Node.Controller.Header, sizeof (CONTROLLER_DEVICE_PATH));
+ Node.Controller.ControllerNumber = Controller;
+ *DevicePath = AppendDevicePathNode (*DevicePath, &Node.DevPath);
+ }
+
+ ZeroMem (&Node, sizeof (Node));
+
+ if (AsciiStrnCmp ("SCSI", Drive->Parameters.InterfaceType, 4) == 0) {
+ //
+ // SCSI drive
+ //
+ Node.Scsi.Header.Type = MESSAGING_DEVICE_PATH;
+ Node.Scsi.Header.SubType = MSG_SCSI_DP;
+ SetDevicePathNodeLength (&Node.Scsi.Header, sizeof (SCSI_DEVICE_PATH));
+
+ //
+ // Lun is miss aligned in both EDD and Device Path data structures.
+ // thus we do a byte copy, to prevent alignment traps on IA-64.
+ //
+ CopyMem (&Node.Scsi.Lun, &Drive->Parameters.DevicePath.Scsi.Lun, sizeof (UINT16));
+ Node.Scsi.Pun = Drive->Parameters.DevicePath.Scsi.Pun;
+
+ } else if (AsciiStrnCmp ("USB", Drive->Parameters.InterfaceType, 3) == 0) {
+ //
+ // USB drive
+ //
+ Node.Usb.Header.Type = MESSAGING_DEVICE_PATH;
+ Node.Usb.Header.SubType = MSG_USB_DP;
+ SetDevicePathNodeLength (&Node.Usb.Header, sizeof (USB_DEVICE_PATH));
+ Node.Usb.ParentPortNumber = (UINT8) Drive->Parameters.DevicePath.Usb.Reserved;
+
+ } else if (AsciiStrnCmp ("1394", Drive->Parameters.InterfaceType, 4) == 0) {
+ //
+ // 1394 drive
+ //
+ Node.F1394.Header.Type = MESSAGING_DEVICE_PATH;
+ Node.F1394.Header.SubType = MSG_1394_DP;
+ SetDevicePathNodeLength (&Node.F1394.Header, sizeof (F1394_DEVICE_PATH));
+ Node.F1394.Guid = Drive->Parameters.DevicePath.FireWire.Guid;
+
+ } else if (AsciiStrnCmp ("FIBRE", Drive->Parameters.InterfaceType, 5) == 0) {
+ //
+ // Fibre drive
+ //
+ Node.FibreChannel.Header.Type = MESSAGING_DEVICE_PATH;
+ Node.FibreChannel.Header.SubType = MSG_FIBRECHANNEL_DP;
+ SetDevicePathNodeLength (&Node.FibreChannel.Header, sizeof (FIBRECHANNEL_DEVICE_PATH));
+ Node.FibreChannel.WWN = Drive->Parameters.DevicePath.FibreChannel.Wwn;
+ Node.FibreChannel.Lun = Drive->Parameters.DevicePath.FibreChannel.Lun;
+
+ } else {
+ DEBUG (
+ (
+ DEBUG_BLKIO, "It is unrecognized EDD 3.0 device, Drive Number = %x, InterfaceType = %s\n",
+ Drive->Number,
+ Drive->Parameters.InterfaceType
+ )
+ );
+ }
+ }
+
+ if (Node.DevPath.Type == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ *DevicePath = AppendDevicePathNode (BaseDevicePath, &Node.DevPath);
+ return EFI_SUCCESS;
+}