• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
BiosBlockIoDriverEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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
BiosBlockIoDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)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
BiosBlockIoDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)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
BiosBlockIoDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)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
SetBiosInitBlockIoDevicePath(IN EFI_DEVICE_PATH_PROTOCOL * BaseDevicePath,IN BIOS_LEGACY_DRIVE * Drive,OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath)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
BuildEdd30DevicePath(IN EFI_DEVICE_PATH_PROTOCOL * BaseDevicePath,IN BIOS_LEGACY_DRIVE * Drive,IN EFI_DEVICE_PATH_PROTOCOL ** DevicePath)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