Home | History | Annotate | Download | only in AtapiPassThruDxe
      1 /** @file
      2   Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
      3   This program and the accompanying materials
      4   are licensed and made available under the terms and conditions of the BSD License
      5   which accompanies this distribution.  The full text of the license may be found at
      6   http://opensource.org/licenses/bsd-license.php
      7 
      8   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
      9   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     10 
     11 **/
     12 
     13 #include "AtapiPassThru.h"
     14 
     15 
     16 SCSI_COMMAND_SET     gEndTable = { 0xff, (DATA_DIRECTION) 0xff };
     17 
     18 ///
     19 /// This table contains all the supported ATAPI commands.
     20 ///
     21 SCSI_COMMAND_SET     gSupportedATAPICommands[] = {
     22   { OP_INQUIRY,                     DataIn  },
     23   { OP_LOAD_UNLOAD_CD,              NoData  },
     24   { OP_MECHANISM_STATUS,            DataIn  },
     25   { OP_MODE_SELECT_10,              DataOut },
     26   { OP_MODE_SENSE_10,               DataIn  },
     27   { OP_PAUSE_RESUME,                NoData  },
     28   { OP_PLAY_AUDIO_10,               DataIn  },
     29   { OP_PLAY_AUDIO_MSF,              DataIn  },
     30   { OP_PLAY_CD,                     DataIn  },
     31   { OP_PLAY_CD_MSF,                 DataIn  },
     32   { OP_PREVENT_ALLOW_MEDIUM_REMOVAL,NoData  },
     33   { OP_READ_10,                     DataIn  },
     34   { OP_READ_12,                     DataIn  },
     35   { OP_READ_CAPACITY,               DataIn  },
     36   { OP_READ_CD,                     DataIn  },
     37   { OP_READ_CD_MSF,                 DataIn  },
     38   { OP_READ_HEADER,                 DataIn  },
     39   { OP_READ_SUB_CHANNEL,            DataIn  },
     40   { OP_READ_TOC,                    DataIn  },
     41   { OP_REQUEST_SENSE,               DataIn  },
     42   { OP_SCAN,                        NoData  },
     43   { OP_SEEK_10,                     NoData  },
     44   { OP_SET_CD_SPEED,                DataOut },
     45   { OP_STOPPLAY_SCAN,               NoData  },
     46   { OP_START_STOP_UNIT,             NoData  },
     47   { OP_TEST_UNIT_READY,             NoData  },
     48   { OP_FORMAT_UNIT,                 DataOut },
     49   { OP_READ_FORMAT_CAPACITIES,      DataIn  },
     50   { OP_VERIFY,                      DataOut },
     51   { OP_WRITE_10,                    DataOut },
     52   { OP_WRITE_12,                    DataOut },
     53   { OP_WRITE_AND_VERIFY,            DataOut },
     54   { 0xff,                           (DATA_DIRECTION) 0xff    }
     55 };
     56 
     57 GLOBAL_REMOVE_IF_UNREFERENCED EFI_SCSI_PASS_THRU_MODE gScsiPassThruMode = {
     58   L"ATAPI Controller",
     59   L"ATAPI Channel",
     60   4,
     61   EFI_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL,
     62   0
     63 };
     64 
     65 GLOBAL_REMOVE_IF_UNREFERENCED EFI_SCSI_PASS_THRU_PROTOCOL gScsiPassThruProtocolTemplate = {
     66   &gScsiPassThruMode,
     67   AtapiScsiPassThruFunction,
     68   AtapiScsiPassThruGetNextDevice,
     69   AtapiScsiPassThruBuildDevicePath,
     70   AtapiScsiPassThruGetTargetLun,
     71   AtapiScsiPassThruResetChannel,
     72   AtapiScsiPassThruResetTarget
     73 };
     74 
     75 GLOBAL_REMOVE_IF_UNREFERENCED EFI_EXT_SCSI_PASS_THRU_MODE gExtScsiPassThruMode = {
     76   4,
     77   EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL,
     78   0
     79 };
     80 
     81 GLOBAL_REMOVE_IF_UNREFERENCED EFI_EXT_SCSI_PASS_THRU_PROTOCOL gExtScsiPassThruProtocolTemplate = {
     82   &gExtScsiPassThruMode,
     83   AtapiExtScsiPassThruFunction,
     84   AtapiExtScsiPassThruGetNextTargetLun,
     85   AtapiExtScsiPassThruBuildDevicePath,
     86   AtapiExtScsiPassThruGetTargetLun,
     87   AtapiExtScsiPassThruResetChannel,
     88   AtapiExtScsiPassThruResetTarget,
     89   AtapiExtScsiPassThruGetNextTarget
     90 };
     91 
     92 EFI_DRIVER_BINDING_PROTOCOL gAtapiScsiPassThruDriverBinding = {
     93   AtapiScsiPassThruDriverBindingSupported,
     94   AtapiScsiPassThruDriverBindingStart,
     95   AtapiScsiPassThruDriverBindingStop,
     96   0x10,
     97   NULL,
     98   NULL
     99 };
    100 
    101 EFI_STATUS
    102 EFIAPI
    103 AtapiScsiPassThruDriverBindingSupported (
    104   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    105   IN EFI_HANDLE                   Controller,
    106   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
    107   )
    108 /*++
    109 
    110 Routine Description:
    111   Test to see if this driver supports ControllerHandle. Any ControllerHandle
    112   that has gEfiPciIoProtocolGuid installed and is IDE Controller it will be supported.
    113 
    114 Arguments:
    115 
    116   This                - Protocol instance pointer.
    117   Controller          - Handle of device to test
    118   RemainingDevicePath - Not used
    119 
    120 Returns:
    121     EFI_STATUS
    122 
    123 --*/
    124 {
    125   EFI_STATUS          Status;
    126   EFI_PCI_IO_PROTOCOL *PciIo;
    127   PCI_TYPE00          Pci;
    128 
    129 
    130   //
    131   // Open the IO Abstraction(s) needed to perform the supported test
    132   //
    133   Status = gBS->OpenProtocol (
    134                   Controller,
    135                   &gEfiPciIoProtocolGuid,
    136                   (VOID **) &PciIo,
    137                   This->DriverBindingHandle,
    138                   Controller,
    139                   EFI_OPEN_PROTOCOL_BY_DRIVER
    140                   );
    141   if (EFI_ERROR (Status)) {
    142     return Status;
    143   }
    144   //
    145   // Use the PCI I/O Protocol to see if Controller is a IDE Controller that
    146   // can be managed by this driver.  Read the PCI Configuration Header
    147   // for this device.
    148   //
    149   Status = PciIo->Pci.Read (
    150                         PciIo,
    151                         EfiPciIoWidthUint32,
    152                         0,
    153                         sizeof (Pci) / sizeof (UINT32),
    154                         &Pci
    155                         );
    156   if (EFI_ERROR (Status)) {
    157     gBS->CloseProtocol (
    158            Controller,
    159            &gEfiPciIoProtocolGuid,
    160            This->DriverBindingHandle,
    161            Controller
    162            );
    163     return EFI_UNSUPPORTED;
    164   }
    165 
    166   if (Pci.Hdr.ClassCode[2] != PCI_CLASS_MASS_STORAGE || Pci.Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE) {
    167 
    168     Status = EFI_UNSUPPORTED;
    169   }
    170 
    171   gBS->CloseProtocol (
    172          Controller,
    173          &gEfiPciIoProtocolGuid,
    174          This->DriverBindingHandle,
    175          Controller
    176          );
    177 
    178   return Status;
    179 }
    180 
    181 EFI_STATUS
    182 EFIAPI
    183 AtapiScsiPassThruDriverBindingStart (
    184   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    185   IN EFI_HANDLE                   Controller,
    186   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
    187   )
    188 /*++
    189 
    190 Routine Description:
    191   Create handles for IDE channels specified by RemainingDevicePath.
    192   Install SCSI Pass Thru Protocol onto each created handle.
    193 
    194 Arguments:
    195 
    196   This                - Protocol instance pointer.
    197   Controller          - Handle of device to test
    198   RemainingDevicePath - Not used
    199 
    200 Returns:
    201     EFI_STATUS
    202 
    203 --*/
    204 {
    205   EFI_STATUS          Status;
    206   EFI_PCI_IO_PROTOCOL *PciIo;
    207   UINT64              Supports;
    208   UINT64              OriginalPciAttributes;
    209   BOOLEAN             PciAttributesSaved;
    210 
    211   PciIo = NULL;
    212   Status = gBS->OpenProtocol (
    213                   Controller,
    214                   &gEfiPciIoProtocolGuid,
    215                   (VOID **) &PciIo,
    216                   This->DriverBindingHandle,
    217                   Controller,
    218                   EFI_OPEN_PROTOCOL_BY_DRIVER
    219                   );
    220   if (EFI_ERROR (Status)) {
    221     return Status;
    222   }
    223 
    224   PciAttributesSaved = FALSE;
    225   //
    226   // Save original PCI attributes
    227   //
    228   Status = PciIo->Attributes (
    229                     PciIo,
    230                     EfiPciIoAttributeOperationGet,
    231                     0,
    232                     &OriginalPciAttributes
    233                     );
    234 
    235   if (EFI_ERROR (Status)) {
    236     goto Done;
    237   }
    238   PciAttributesSaved = TRUE;
    239 
    240   Status = PciIo->Attributes (
    241                     PciIo,
    242                     EfiPciIoAttributeOperationSupported,
    243                     0,
    244                     &Supports
    245                     );
    246   if (!EFI_ERROR (Status)) {
    247     Supports &= (EFI_PCI_DEVICE_ENABLE               |
    248                  EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO |
    249                  EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO);
    250     Status = PciIo->Attributes (
    251                       PciIo,
    252                       EfiPciIoAttributeOperationEnable,
    253                       Supports,
    254                       NULL
    255                       );
    256   }
    257   if (EFI_ERROR (Status)) {
    258     goto Done;
    259   }
    260 
    261   //
    262   // Create SCSI Pass Thru instance for the IDE channel.
    263   //
    264   Status = RegisterAtapiScsiPassThru (This, Controller, PciIo, OriginalPciAttributes);
    265 
    266 Done:
    267   if (EFI_ERROR (Status)) {
    268     if (PciAttributesSaved == TRUE) {
    269       //
    270       // Restore original PCI attributes
    271       //
    272       PciIo->Attributes (
    273                       PciIo,
    274                       EfiPciIoAttributeOperationSet,
    275                       OriginalPciAttributes,
    276                       NULL
    277                       );
    278     }
    279 
    280     gBS->CloseProtocol (
    281            Controller,
    282            &gEfiPciIoProtocolGuid,
    283            This->DriverBindingHandle,
    284            Controller
    285            );
    286   }
    287 
    288   return Status;
    289 }
    290 
    291 EFI_STATUS
    292 EFIAPI
    293 AtapiScsiPassThruDriverBindingStop (
    294   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
    295   IN  EFI_HANDLE                      Controller,
    296   IN  UINTN                           NumberOfChildren,
    297   IN  EFI_HANDLE                      *ChildHandleBuffer
    298   )
    299 /*++
    300 
    301 Routine Description:
    302 
    303   Stop this driver on ControllerHandle. Support stopping any child handles
    304   created by this driver.
    305 
    306 Arguments:
    307 
    308   This              - Protocol instance pointer.
    309   Controller        - Handle of device to stop driver on
    310   NumberOfChildren  - Number of Children in the ChildHandleBuffer
    311   ChildHandleBuffer - List of handles for the children we need to stop.
    312 
    313 Returns:
    314 
    315     EFI_STATUS
    316 
    317 --*/
    318 {
    319   EFI_STATUS                      Status;
    320   EFI_SCSI_PASS_THRU_PROTOCOL     *ScsiPassThru;
    321   EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;
    322   ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate;
    323 
    324   if (FeaturePcdGet (PcdSupportScsiPassThru)) {
    325     Status = gBS->OpenProtocol (
    326                     Controller,
    327                     &gEfiScsiPassThruProtocolGuid,
    328                     (VOID **) &ScsiPassThru,
    329                     This->DriverBindingHandle,
    330                     Controller,
    331                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
    332                     );
    333     if (EFI_ERROR (Status)) {
    334       return Status;
    335     }
    336     AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (ScsiPassThru);
    337     if (FeaturePcdGet (PcdSupportExtScsiPassThru)) {
    338       Status = gBS->UninstallMultipleProtocolInterfaces (
    339                       Controller,
    340                       &gEfiScsiPassThruProtocolGuid,
    341                       &AtapiScsiPrivate->ScsiPassThru,
    342                       &gEfiExtScsiPassThruProtocolGuid,
    343                       &AtapiScsiPrivate->ExtScsiPassThru,
    344                       NULL
    345                       );
    346     } else {
    347       Status = gBS->UninstallMultipleProtocolInterfaces (
    348                       Controller,
    349                       &gEfiScsiPassThruProtocolGuid,
    350                       &AtapiScsiPrivate->ScsiPassThru,
    351                       NULL
    352                       );
    353     }
    354   } else {
    355     Status = gBS->OpenProtocol (
    356                     Controller,
    357                     &gEfiExtScsiPassThruProtocolGuid,
    358                     (VOID **) &ExtScsiPassThru,
    359                     This->DriverBindingHandle,
    360                     Controller,
    361                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
    362                     );
    363     if (EFI_ERROR (Status)) {
    364       return Status;
    365     }
    366     AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (ExtScsiPassThru);
    367     Status = gBS->UninstallMultipleProtocolInterfaces (
    368                     Controller,
    369                     &gEfiExtScsiPassThruProtocolGuid,
    370                     &AtapiScsiPrivate->ExtScsiPassThru,
    371                     NULL
    372                     );
    373   }
    374   if (EFI_ERROR (Status)) {
    375     return Status;
    376   }
    377 
    378   //
    379   // Restore original PCI attributes
    380   //
    381   AtapiScsiPrivate->PciIo->Attributes (
    382                   AtapiScsiPrivate->PciIo,
    383                   EfiPciIoAttributeOperationSet,
    384                   AtapiScsiPrivate->OriginalPciAttributes,
    385                   NULL
    386                   );
    387 
    388   gBS->CloseProtocol (
    389          Controller,
    390          &gEfiPciIoProtocolGuid,
    391          This->DriverBindingHandle,
    392          Controller
    393          );
    394 
    395   gBS->FreePool (AtapiScsiPrivate);
    396 
    397   return EFI_SUCCESS;
    398 }
    399 
    400 EFI_STATUS
    401 RegisterAtapiScsiPassThru (
    402   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    403   IN  EFI_HANDLE                  Controller,
    404   IN  EFI_PCI_IO_PROTOCOL         *PciIo,
    405   IN  UINT64                      OriginalPciAttributes
    406   )
    407 /*++
    408 
    409 Routine Description:
    410   Attaches SCSI Pass Thru Protocol for specified IDE channel.
    411 
    412 Arguments:
    413   This              - Protocol instance pointer.
    414   Controller        - Parent device handle to the IDE channel.
    415   PciIo             - PCI I/O protocol attached on the "Controller".
    416 
    417 Returns:
    418   Always return EFI_SUCCESS unless installing SCSI Pass Thru Protocol failed.
    419 
    420 --*/
    421 {
    422   EFI_STATUS                Status;
    423   ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate;
    424   IDE_REGISTERS_BASE_ADDR   IdeRegsBaseAddr[ATAPI_MAX_CHANNEL];
    425 
    426   AtapiScsiPrivate = AllocateZeroPool (sizeof (ATAPI_SCSI_PASS_THRU_DEV));
    427   if (AtapiScsiPrivate == NULL) {
    428     return EFI_OUT_OF_RESOURCES;
    429   }
    430 
    431   AtapiScsiPrivate->Signature = ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE;
    432   AtapiScsiPrivate->Handle    = Controller;
    433 
    434   //
    435   // will reset the IoPort inside each API function.
    436   //
    437   AtapiScsiPrivate->IoPort                = NULL;
    438   AtapiScsiPrivate->PciIo                 = PciIo;
    439   AtapiScsiPrivate->OriginalPciAttributes = OriginalPciAttributes;
    440 
    441   //
    442   // Obtain IDE IO port registers' base addresses
    443   //
    444   Status = GetIdeRegistersBaseAddr (PciIo, IdeRegsBaseAddr);
    445   if (EFI_ERROR (Status)) {
    446     return Status;
    447   }
    448 
    449   InitAtapiIoPortRegisters(AtapiScsiPrivate, IdeRegsBaseAddr);
    450 
    451   //
    452   // Initialize the LatestTargetId to MAX_TARGET_ID.
    453   //
    454   AtapiScsiPrivate->LatestTargetId  = MAX_TARGET_ID;
    455   AtapiScsiPrivate->LatestLun       = 0;
    456 
    457   Status = InstallScsiPassThruProtocols (&Controller, AtapiScsiPrivate);
    458 
    459   return Status;
    460 }
    461 
    462 EFI_STATUS
    463 EFIAPI
    464 AtapiScsiPassThruFunction (
    465   IN EFI_SCSI_PASS_THRU_PROTOCOL                        *This,
    466   IN UINT32                                             Target,
    467   IN UINT64                                             Lun,
    468   IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET         *Packet,
    469   IN EFI_EVENT                                          Event OPTIONAL
    470   )
    471 /*++
    472 
    473 Routine Description:
    474 
    475   Implements EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() function.
    476 
    477 Arguments:
    478 
    479   This:     The EFI_SCSI_PASS_THRU_PROTOCOL instance.
    480   Target:   The Target ID of the ATAPI device to send the SCSI
    481             Request Packet. To ATAPI devices attached on an IDE
    482             Channel, Target ID 0 indicates Master device;Target
    483             ID 1 indicates Slave device.
    484   Lun:      The LUN of the ATAPI device to send the SCSI Request
    485             Packet. To the ATAPI device, Lun is always 0.
    486   Packet:   The SCSI Request Packet to send to the ATAPI device
    487             specified by Target and Lun.
    488   Event:    If non-blocking I/O is not supported then Event is ignored,
    489             and blocking I/O is performed.
    490             If Event is NULL, then blocking I/O is performed.
    491             If Event is not NULL and non blocking I/O is supported,
    492             then non-blocking I/O is performed, and Event will be signaled
    493             when the SCSI Request Packet completes.
    494 
    495 Returns:
    496 
    497    EFI_STATUS
    498 
    499 --*/
    500 {
    501   ATAPI_SCSI_PASS_THRU_DEV               *AtapiScsiPrivate;
    502   EFI_STATUS                             Status;
    503 
    504   AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);
    505 
    506   //
    507   // Target is not allowed beyond MAX_TARGET_ID
    508   //
    509   if ((Target > MAX_TARGET_ID) || (Lun != 0)) {
    510     return EFI_INVALID_PARAMETER;
    511   }
    512 
    513   //
    514   // check the data fields in Packet parameter.
    515   //
    516   Status = CheckSCSIRequestPacket (Packet);
    517   if (EFI_ERROR (Status)) {
    518     return Status;
    519   }
    520 
    521   //
    522   // If Request Packet targets at the IDE channel itself,
    523   // do nothing.
    524   //
    525   if (Target == This->Mode->AdapterId) {
    526     Packet->TransferLength = 0;
    527     return EFI_SUCCESS;
    528   }
    529 
    530   //
    531   // According to Target ID, reset the Atapi I/O Register mapping
    532   // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
    533   //  Target Id in [2,3] area, using AtapiIoPortRegisters[1]
    534   //
    535   if ((Target / 2) == 0) {
    536     Target = Target % 2;
    537     AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];
    538   } else {
    539     Target = Target % 2;
    540     AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];
    541   }
    542 
    543   //
    544   // the ATAPI SCSI interface does not support non-blocking I/O
    545   // ignore the Event parameter
    546   //
    547   // Performs blocking I/O.
    548   //
    549   Status = SubmitBlockingIoCommand (AtapiScsiPrivate, Target, Packet);
    550   return Status;
    551 }
    552 
    553 EFI_STATUS
    554 EFIAPI
    555 AtapiScsiPassThruGetNextDevice (
    556   IN  EFI_SCSI_PASS_THRU_PROTOCOL    *This,
    557   IN OUT UINT32                      *Target,
    558   IN OUT UINT64                      *Lun
    559   )
    560 /*++
    561 
    562 Routine Description:
    563 
    564   Used to retrieve the list of legal Target IDs for SCSI devices
    565   on a SCSI channel.
    566 
    567 Arguments:
    568 
    569   This                  - Protocol instance pointer.
    570   Target                - On input, a pointer to the Target ID of a SCSI
    571                           device present on the SCSI channel.  On output,
    572                           a pointer to the Target ID of the next SCSI device
    573                           present on a SCSI channel.  An input value of
    574                           0xFFFFFFFF retrieves the Target ID of the first
    575                           SCSI device present on a SCSI channel.
    576   Lun                   - On input, a pointer to the LUN of a SCSI device
    577                           present on the SCSI channel. On output, a pointer
    578                           to the LUN of the next SCSI device present on
    579                           a SCSI channel.
    580 Returns:
    581 
    582   EFI_SUCCESS           - The Target ID and Lun of the next SCSI device
    583                           on the SCSI channel was returned in Target and Lun.
    584   EFI_NOT_FOUND         - There are no more SCSI devices on this SCSI channel.
    585   EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not
    586                            returned on a previous call to GetNextDevice().
    587 --*/
    588 {
    589   ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate;
    590 
    591   //
    592   // Retrieve Device Private Data Structure.
    593   //
    594   AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);
    595 
    596   //
    597   // Check whether Target is valid.
    598   //
    599   if (Target == NULL || Lun == NULL) {
    600     return EFI_INVALID_PARAMETER;
    601   }
    602 
    603   if ((*Target != 0xFFFFFFFF) &&
    604       ((*Target != AtapiScsiPrivate->LatestTargetId) ||
    605       (*Lun != AtapiScsiPrivate->LatestLun))) {
    606     return EFI_INVALID_PARAMETER;
    607   }
    608 
    609   if (*Target == MAX_TARGET_ID) {
    610     return EFI_NOT_FOUND;
    611   }
    612 
    613   if (*Target == 0xFFFFFFFF) {
    614     *Target = 0;
    615   } else {
    616     *Target = AtapiScsiPrivate->LatestTargetId + 1;
    617   }
    618 
    619   *Lun = 0;
    620 
    621   //
    622   // Update the LatestTargetId.
    623   //
    624   AtapiScsiPrivate->LatestTargetId  = *Target;
    625   AtapiScsiPrivate->LatestLun       = *Lun;
    626 
    627   return EFI_SUCCESS;
    628 
    629 }
    630 
    631 EFI_STATUS
    632 EFIAPI
    633 AtapiScsiPassThruBuildDevicePath (
    634   IN     EFI_SCSI_PASS_THRU_PROTOCOL    *This,
    635   IN     UINT32                         Target,
    636   IN     UINT64                         Lun,
    637   IN OUT EFI_DEVICE_PATH_PROTOCOL       **DevicePath
    638   )
    639 /*++
    640 
    641 Routine Description:
    642 
    643   Used to allocate and build a device path node for a SCSI device
    644   on a SCSI channel. Would not build device path for a SCSI Host Controller.
    645 
    646 Arguments:
    647 
    648   This                  - Protocol instance pointer.
    649   Target                - The Target ID of the SCSI device for which
    650                           a device path node is to be allocated and built.
    651   Lun                   - The LUN of the SCSI device for which a device
    652                           path node is to be allocated and built.
    653   DevicePath            - A pointer to a single device path node that
    654                           describes the SCSI device specified by
    655                           Target and Lun. This function is responsible
    656                           for allocating the buffer DevicePath with the boot
    657                           service AllocatePool().  It is the caller's
    658                           responsibility to free DevicePath when the caller
    659                           is finished with DevicePath.
    660   Returns:
    661   EFI_SUCCESS           - The device path node that describes the SCSI device
    662                           specified by Target and Lun was allocated and
    663                           returned in DevicePath.
    664   EFI_NOT_FOUND         - The SCSI devices specified by Target and Lun does
    665                           not exist on the SCSI channel.
    666   EFI_INVALID_PARAMETER - DevicePath is NULL.
    667   EFI_OUT_OF_RESOURCES  - There are not enough resources to allocate
    668                           DevicePath.
    669 --*/
    670 {
    671   EFI_DEV_PATH              *Node;
    672 
    673 
    674   //
    675   // Validate parameters passed in.
    676   //
    677 
    678   if (DevicePath == NULL) {
    679     return EFI_INVALID_PARAMETER;
    680   }
    681 
    682   //
    683   // can not build device path for the SCSI Host Controller.
    684   //
    685   if ((Target > (MAX_TARGET_ID - 1)) || (Lun != 0)) {
    686     return EFI_NOT_FOUND;
    687   }
    688 
    689   Node = AllocateZeroPool (sizeof (EFI_DEV_PATH));
    690   if (Node == NULL) {
    691     return EFI_OUT_OF_RESOURCES;
    692   }
    693 
    694   Node->DevPath.Type    = MESSAGING_DEVICE_PATH;
    695   Node->DevPath.SubType = MSG_ATAPI_DP;
    696   SetDevicePathNodeLength (&Node->DevPath, sizeof (ATAPI_DEVICE_PATH));
    697 
    698   Node->Atapi.PrimarySecondary  = (UINT8) (Target / 2);
    699   Node->Atapi.SlaveMaster       = (UINT8) (Target % 2);
    700   Node->Atapi.Lun               = (UINT16) Lun;
    701 
    702   *DevicePath                   = (EFI_DEVICE_PATH_PROTOCOL *) Node;
    703 
    704   return EFI_SUCCESS;
    705 }
    706 
    707 EFI_STATUS
    708 EFIAPI
    709 AtapiScsiPassThruGetTargetLun (
    710   IN  EFI_SCSI_PASS_THRU_PROTOCOL    *This,
    711   IN  EFI_DEVICE_PATH_PROTOCOL       *DevicePath,
    712   OUT UINT32                         *Target,
    713   OUT UINT64                         *Lun
    714   )
    715 /*++
    716 
    717 Routine Description:
    718 
    719   Used to translate a device path node to a Target ID and LUN.
    720 
    721 Arguments:
    722 
    723   This                  - Protocol instance pointer.
    724   DevicePath            - A pointer to the device path node that
    725                           describes a SCSI device on the SCSI channel.
    726   Target                - A pointer to the Target ID of a SCSI device
    727                           on the SCSI channel.
    728   Lun                   - A pointer to the LUN of a SCSI device on
    729                           the SCSI channel.
    730 Returns:
    731 
    732   EFI_SUCCESS           - DevicePath was successfully translated to a
    733                           Target ID and LUN, and they were returned
    734                           in Target and Lun.
    735   EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.
    736   EFI_UNSUPPORTED       - This driver does not support the device path
    737                           node type in DevicePath.
    738   EFI_NOT_FOUND         - A valid translation from DevicePath to a
    739                           Target ID and LUN does not exist.
    740 --*/
    741 {
    742   EFI_DEV_PATH  *Node;
    743 
    744   //
    745   // Validate parameters passed in.
    746   //
    747   if (DevicePath == NULL || Target == NULL || Lun == NULL) {
    748     return EFI_INVALID_PARAMETER;
    749   }
    750 
    751   //
    752   // Check whether the DevicePath belongs to SCSI_DEVICE_PATH
    753   //
    754   if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
    755       (DevicePath->SubType != MSG_ATAPI_DP) ||
    756       (DevicePathNodeLength(DevicePath) != sizeof(ATAPI_DEVICE_PATH))) {
    757     return EFI_UNSUPPORTED;
    758   }
    759 
    760   Node    = (EFI_DEV_PATH *) DevicePath;
    761 
    762   *Target = Node->Atapi.PrimarySecondary * 2 + Node->Atapi.SlaveMaster;
    763   *Lun    = Node->Atapi.Lun;
    764 
    765   if (*Target > (MAX_TARGET_ID - 1) || *Lun != 0) {
    766     return EFI_NOT_FOUND;
    767   }
    768 
    769   return EFI_SUCCESS;
    770 }
    771 
    772 EFI_STATUS
    773 EFIAPI
    774 AtapiScsiPassThruResetChannel (
    775   IN  EFI_SCSI_PASS_THRU_PROTOCOL   *This
    776   )
    777 /*++
    778 
    779 Routine Description:
    780 
    781   Resets a SCSI channel.This operation resets all the
    782   SCSI devices connected to the SCSI channel.
    783 
    784 Arguments:
    785 
    786   This                  - Protocol instance pointer.
    787 
    788 Returns:
    789 
    790   EFI_SUCCESS           - The SCSI channel was reset.
    791   EFI_UNSUPPORTED       - The SCSI channel does not support
    792                           a channel reset operation.
    793   EFI_DEVICE_ERROR      - A device error occurred while
    794                           attempting to reset the SCSI channel.
    795   EFI_TIMEOUT           - A timeout occurred while attempting
    796                           to reset the SCSI channel.
    797 --*/
    798 {
    799   UINT8                     DeviceControlValue;
    800   ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate;
    801   UINT8                     Index;
    802   BOOLEAN                   ResetFlag;
    803 
    804   AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);
    805   ResetFlag = FALSE;
    806 
    807   //
    808   // Reset both Primary channel and Secondary channel.
    809   // so, the IoPort pointer must point to the right I/O Register group
    810   //
    811   for (Index = 0; Index < 2; Index++) {
    812     //
    813     // Reset
    814     //
    815     AtapiScsiPrivate->IoPort  = &AtapiScsiPrivate->AtapiIoPortRegisters[Index];
    816 
    817     DeviceControlValue        = 0;
    818     //
    819     // set SRST bit to initiate soft reset
    820     //
    821     DeviceControlValue |= SRST;
    822     //
    823     // disable Interrupt
    824     //
    825     DeviceControlValue |= BIT1;
    826     WritePortB (
    827       AtapiScsiPrivate->PciIo,
    828       AtapiScsiPrivate->IoPort->Alt.DeviceControl,
    829       DeviceControlValue
    830       );
    831 
    832     //
    833     // Wait 10us
    834     //
    835     gBS->Stall (10);
    836 
    837     //
    838     // Clear SRST bit
    839     // 0xfb:1111,1011
    840     //
    841     DeviceControlValue &= 0xfb;
    842 
    843     WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Alt.DeviceControl, DeviceControlValue);
    844 
    845     //
    846     // slave device needs at most 31s to clear BSY
    847     //
    848     if (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000) != EFI_TIMEOUT) {
    849       ResetFlag = TRUE;
    850     }
    851   }
    852 
    853   if (ResetFlag) {
    854     return EFI_SUCCESS;
    855   }
    856 
    857   return EFI_TIMEOUT;
    858 }
    859 
    860 EFI_STATUS
    861 EFIAPI
    862 AtapiScsiPassThruResetTarget (
    863   IN EFI_SCSI_PASS_THRU_PROTOCOL    *This,
    864   IN UINT32                         Target,
    865   IN UINT64                         Lun
    866   )
    867 /*++
    868 
    869 Routine Description:
    870 
    871   Resets a SCSI device that is connected to a SCSI channel.
    872 
    873 Arguments:
    874 
    875   This                  - Protocol instance pointer.
    876   Target                - The Target ID of the SCSI device to reset.
    877   Lun                   - The LUN of the SCSI device to reset.
    878 
    879 Returns:
    880 
    881   EFI_SUCCESS           - The SCSI device specified by Target and
    882                           Lun was reset.
    883   EFI_UNSUPPORTED       - The SCSI channel does not support a target
    884                           reset operation.
    885   EFI_INVALID_PARAMETER - Target or Lun are invalid.
    886   EFI_DEVICE_ERROR      - A device error occurred while attempting
    887                           to reset the SCSI device specified by Target
    888                           and Lun.
    889   EFI_TIMEOUT           - A timeout occurred while attempting to reset
    890                           the SCSI device specified by Target and Lun.
    891 --*/
    892 {
    893   ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate;
    894   UINT8                     Command;
    895   UINT8                     DeviceSelect;
    896 
    897   AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);
    898 
    899   if ((Target > MAX_TARGET_ID) || (Lun != 0)) {
    900     return EFI_INVALID_PARAMETER;
    901   }
    902   //
    903   // Directly return EFI_SUCCESS if want to reset the host controller
    904   //
    905   if (Target == This->Mode->AdapterId) {
    906     return EFI_SUCCESS;
    907   }
    908 
    909   //
    910   // According to Target ID, reset the Atapi I/O Register mapping
    911   // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
    912   //  Target Id in [2,3] area, using AtapiIoPortRegisters[1]
    913   //
    914   if ((Target / 2) == 0) {
    915     AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];
    916   } else {
    917     AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];
    918   }
    919 
    920   //
    921   // for ATAPI device, no need to wait DRDY ready after device selecting.
    922   //
    923   // bit7 and bit5 are both set to 1 for backward compatibility
    924   //
    925   DeviceSelect = (UINT8) (((BIT7 | BIT5) | (Target << 4)));
    926   WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Head, DeviceSelect);
    927 
    928   Command = ATAPI_SOFT_RESET_CMD;
    929   WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg.Command, Command);
    930 
    931   //
    932   // BSY clear is the only status return to the host by the device
    933   // when reset is complete.
    934   // slave device needs at most 31s to clear BSY
    935   //
    936   if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000))) {
    937     return EFI_TIMEOUT;
    938   }
    939 
    940   //
    941   // stall 5 seconds to make the device status stable
    942   //
    943   gBS->Stall (5000000);
    944 
    945   return EFI_SUCCESS;
    946 }
    947 
    948 EFI_STATUS
    949 EFIAPI
    950 AtapiExtScsiPassThruFunction (
    951   IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                    *This,
    952   IN UINT8                                              *Target,
    953   IN UINT64                                             Lun,
    954   IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET     *Packet,
    955   IN EFI_EVENT                                          Event OPTIONAL
    956   )
    957 /*++
    958 
    959 Routine Description:
    960 
    961   Implements EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru() function.
    962 
    963 Arguments:
    964 
    965   This:     The EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
    966   Target:   The Target ID of the ATAPI device to send the SCSI
    967             Request Packet. To ATAPI devices attached on an IDE
    968             Channel, Target ID 0 indicates Master device;Target
    969             ID 1 indicates Slave device.
    970   Lun:      The LUN of the ATAPI device to send the SCSI Request
    971             Packet. To the ATAPI device, Lun is always 0.
    972   Packet:   The SCSI Request Packet to send to the ATAPI device
    973             specified by Target and Lun.
    974   Event:    If non-blocking I/O is not supported then Event is ignored,
    975             and blocking I/O is performed.
    976             If Event is NULL, then blocking I/O is performed.
    977             If Event is not NULL and non blocking I/O is supported,
    978             then non-blocking I/O is performed, and Event will be signaled
    979             when the SCSI Request Packet completes.
    980 
    981 Returns:
    982 
    983    EFI_STATUS
    984 
    985 --*/
    986 {
    987   EFI_STATUS                          Status;
    988   ATAPI_SCSI_PASS_THRU_DEV            *AtapiScsiPrivate;
    989   UINT8                                TargetId;
    990 
    991   AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);
    992 
    993   //
    994   // For ATAPI device, UINT8 is enough to represent the SCSI ID on channel.
    995   //
    996   TargetId = Target[0];
    997 
    998   //
    999   // Target is not allowed beyond MAX_TARGET_ID
   1000   //
   1001   if ((TargetId > MAX_TARGET_ID) || (Lun != 0)) {
   1002     return EFI_INVALID_PARAMETER;
   1003   }
   1004 
   1005   //
   1006   // check the data fields in Packet parameter.
   1007   //
   1008   Status = CheckExtSCSIRequestPacket (Packet);
   1009   if (EFI_ERROR (Status)) {
   1010     return Status;
   1011   }
   1012 
   1013   //
   1014   // If Request Packet targets at the IDE channel itself,
   1015   // do nothing.
   1016   //
   1017   if (TargetId == (UINT8)This->Mode->AdapterId) {
   1018     Packet->InTransferLength = Packet->OutTransferLength = 0;
   1019     return EFI_SUCCESS;
   1020   }
   1021 
   1022   //
   1023   // According to Target ID, reset the Atapi I/O Register mapping
   1024   // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
   1025   //  Target Id in [2,3] area, using AtapiIoPortRegisters[1]
   1026   //
   1027   if ((TargetId / 2) == 0) {
   1028     TargetId = (UINT8) (TargetId % 2);
   1029     AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];
   1030   } else {
   1031     TargetId = (UINT8) (TargetId % 2);
   1032     AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];
   1033   }
   1034 
   1035   //
   1036   // the ATAPI SCSI interface does not support non-blocking I/O
   1037   // ignore the Event parameter
   1038   //
   1039   // Performs blocking I/O.
   1040   //
   1041   Status = SubmitExtBlockingIoCommand (AtapiScsiPrivate, TargetId, Packet);
   1042   return Status;
   1043 }
   1044 
   1045 EFI_STATUS
   1046 EFIAPI
   1047 AtapiExtScsiPassThruGetNextTargetLun (
   1048   IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,
   1049   IN OUT UINT8                           **Target,
   1050   IN OUT UINT64                          *Lun
   1051   )
   1052 /*++
   1053 
   1054 Routine Description:
   1055 
   1056   Used to retrieve the list of legal Target IDs for SCSI devices
   1057   on a SCSI channel.
   1058 
   1059 Arguments:
   1060 
   1061   This                  - Protocol instance pointer.
   1062   Target                - On input, a pointer to the Target ID of a SCSI
   1063                           device present on the SCSI channel.  On output,
   1064                           a pointer to the Target ID of the next SCSI device
   1065                           present on a SCSI channel.  An input value of
   1066                           0xFFFFFFFF retrieves the Target ID of the first
   1067                           SCSI device present on a SCSI channel.
   1068   Lun                   - On input, a pointer to the LUN of a SCSI device
   1069                           present on the SCSI channel. On output, a pointer
   1070                           to the LUN of the next SCSI device present on
   1071                           a SCSI channel.
   1072 Returns:
   1073 
   1074   EFI_SUCCESS           - The Target ID and Lun of the next SCSI device
   1075                           on the SCSI channel was returned in Target and Lun.
   1076   EFI_NOT_FOUND         - There are no more SCSI devices on this SCSI channel.
   1077   EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not
   1078                            returned on a previous call to GetNextDevice().
   1079 --*/
   1080 {
   1081   UINT8                          ByteIndex;
   1082   UINT8                          TargetId;
   1083   UINT8                          ScsiId[TARGET_MAX_BYTES];
   1084   ATAPI_SCSI_PASS_THRU_DEV       *AtapiScsiPrivate;
   1085 
   1086   //
   1087   // Retrieve Device Private Data Structure.
   1088   //
   1089   AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);
   1090 
   1091   //
   1092   // Check whether Target is valid.
   1093   //
   1094   if (*Target == NULL || Lun == NULL) {
   1095     return EFI_INVALID_PARAMETER;
   1096   }
   1097 
   1098   SetMem (ScsiId, TARGET_MAX_BYTES, 0xFF);
   1099 
   1100   TargetId = (*Target)[0];
   1101 
   1102   //
   1103   // For ATAPI device, we use UINT8 to represent the SCSI ID on channel.
   1104   //
   1105   if (CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) {
   1106     for (ByteIndex = 1; ByteIndex < TARGET_MAX_BYTES; ByteIndex++) {
   1107       if ((*Target)[ByteIndex] != 0) {
   1108         return EFI_INVALID_PARAMETER;
   1109       }
   1110     }
   1111   }
   1112 
   1113   if ((CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) &&
   1114       ((TargetId != AtapiScsiPrivate->LatestTargetId) ||
   1115       (*Lun != AtapiScsiPrivate->LatestLun))) {
   1116     return EFI_INVALID_PARAMETER;
   1117   }
   1118 
   1119   if (TargetId == MAX_TARGET_ID) {
   1120     return EFI_NOT_FOUND;
   1121   }
   1122 
   1123   if (CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) == 0) {
   1124     SetMem (*Target, TARGET_MAX_BYTES,0);
   1125   } else {
   1126     (*Target)[0] = (UINT8) (AtapiScsiPrivate->LatestTargetId + 1);
   1127   }
   1128 
   1129   *Lun = 0;
   1130 
   1131   //
   1132   // Update the LatestTargetId.
   1133   //
   1134   AtapiScsiPrivate->LatestTargetId  = (*Target)[0];
   1135   AtapiScsiPrivate->LatestLun       = *Lun;
   1136 
   1137   return EFI_SUCCESS;
   1138 
   1139 }
   1140 
   1141 EFI_STATUS
   1142 EFIAPI
   1143 AtapiExtScsiPassThruBuildDevicePath (
   1144   IN     EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,
   1145   IN     UINT8                              *Target,
   1146   IN     UINT64                             Lun,
   1147   IN OUT EFI_DEVICE_PATH_PROTOCOL           **DevicePath
   1148   )
   1149 /*++
   1150 
   1151 Routine Description:
   1152 
   1153   Used to allocate and build a device path node for a SCSI device
   1154   on a SCSI channel. Would not build device path for a SCSI Host Controller.
   1155 
   1156 Arguments:
   1157 
   1158   This                  - Protocol instance pointer.
   1159   Target                - The Target ID of the SCSI device for which
   1160                           a device path node is to be allocated and built.
   1161   Lun                   - The LUN of the SCSI device for which a device
   1162                           path node is to be allocated and built.
   1163   DevicePath            - A pointer to a single device path node that
   1164                           describes the SCSI device specified by
   1165                           Target and Lun. This function is responsible
   1166                           for allocating the buffer DevicePath with the boot
   1167                           service AllocatePool().  It is the caller's
   1168                           responsibility to free DevicePath when the caller
   1169                           is finished with DevicePath.
   1170   Returns:
   1171   EFI_SUCCESS           - The device path node that describes the SCSI device
   1172                           specified by Target and Lun was allocated and
   1173                           returned in DevicePath.
   1174   EFI_NOT_FOUND         - The SCSI devices specified by Target and Lun does
   1175                           not exist on the SCSI channel.
   1176   EFI_INVALID_PARAMETER - DevicePath is NULL.
   1177   EFI_OUT_OF_RESOURCES  - There are not enough resources to allocate
   1178                           DevicePath.
   1179 --*/
   1180 {
   1181   EFI_DEV_PATH                   *Node;
   1182   UINT8                          TargetId;
   1183 
   1184   TargetId = Target[0];
   1185 
   1186   //
   1187   // Validate parameters passed in.
   1188   //
   1189 
   1190   if (DevicePath == NULL) {
   1191     return EFI_INVALID_PARAMETER;
   1192   }
   1193 
   1194   //
   1195   // can not build device path for the SCSI Host Controller.
   1196   //
   1197   if ((TargetId > (MAX_TARGET_ID - 1)) || (Lun != 0)) {
   1198     return EFI_NOT_FOUND;
   1199   }
   1200 
   1201   Node = AllocateZeroPool (sizeof (EFI_DEV_PATH));
   1202   if (Node == NULL) {
   1203     return EFI_OUT_OF_RESOURCES;
   1204   }
   1205 
   1206   Node->DevPath.Type    = MESSAGING_DEVICE_PATH;
   1207   Node->DevPath.SubType = MSG_ATAPI_DP;
   1208   SetDevicePathNodeLength (&Node->DevPath, sizeof (ATAPI_DEVICE_PATH));
   1209 
   1210   Node->Atapi.PrimarySecondary  = (UINT8) (TargetId / 2);
   1211   Node->Atapi.SlaveMaster       = (UINT8) (TargetId % 2);
   1212   Node->Atapi.Lun               = (UINT16) Lun;
   1213 
   1214   *DevicePath                   = (EFI_DEVICE_PATH_PROTOCOL *) Node;
   1215 
   1216   return EFI_SUCCESS;
   1217 }
   1218 
   1219 EFI_STATUS
   1220 EFIAPI
   1221 AtapiExtScsiPassThruGetTargetLun (
   1222   IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,
   1223   IN  EFI_DEVICE_PATH_PROTOCOL           *DevicePath,
   1224   OUT UINT8                              **Target,
   1225   OUT UINT64                             *Lun
   1226   )
   1227 /*++
   1228 
   1229 Routine Description:
   1230 
   1231   Used to translate a device path node to a Target ID and LUN.
   1232 
   1233 Arguments:
   1234 
   1235   This                  - Protocol instance pointer.
   1236   DevicePath            - A pointer to the device path node that
   1237                           describes a SCSI device on the SCSI channel.
   1238   Target                - A pointer to the Target ID of a SCSI device
   1239                           on the SCSI channel.
   1240   Lun                   - A pointer to the LUN of a SCSI device on
   1241                           the SCSI channel.
   1242 Returns:
   1243 
   1244   EFI_SUCCESS           - DevicePath was successfully translated to a
   1245                           Target ID and LUN, and they were returned
   1246                           in Target and Lun.
   1247   EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.
   1248   EFI_UNSUPPORTED       - This driver does not support the device path
   1249                           node type in DevicePath.
   1250   EFI_NOT_FOUND         - A valid translation from DevicePath to a
   1251                           Target ID and LUN does not exist.
   1252 --*/
   1253 {
   1254   EFI_DEV_PATH  *Node;
   1255 
   1256   //
   1257   // Validate parameters passed in.
   1258   //
   1259   if (DevicePath == NULL || Target == NULL || Lun == NULL) {
   1260     return EFI_INVALID_PARAMETER;
   1261   }
   1262 
   1263   //
   1264   // Check whether the DevicePath belongs to SCSI_DEVICE_PATH
   1265   //
   1266   if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
   1267       (DevicePath->SubType != MSG_ATAPI_DP) ||
   1268       (DevicePathNodeLength(DevicePath) != sizeof(ATAPI_DEVICE_PATH))) {
   1269     return EFI_UNSUPPORTED;
   1270   }
   1271 
   1272   ZeroMem (*Target, TARGET_MAX_BYTES);
   1273 
   1274   Node    = (EFI_DEV_PATH *) DevicePath;
   1275 
   1276   (*Target)[0] = (UINT8) (Node->Atapi.PrimarySecondary * 2 + Node->Atapi.SlaveMaster);
   1277   *Lun    = Node->Atapi.Lun;
   1278 
   1279   if ((*Target)[0] > (MAX_TARGET_ID - 1) || *Lun != 0) {
   1280     return EFI_NOT_FOUND;
   1281   }
   1282 
   1283   return EFI_SUCCESS;
   1284 }
   1285 
   1286 EFI_STATUS
   1287 EFIAPI
   1288 AtapiExtScsiPassThruResetChannel (
   1289   IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL   *This
   1290   )
   1291 /*++
   1292 
   1293 Routine Description:
   1294 
   1295   Resets a SCSI channel.This operation resets all the
   1296   SCSI devices connected to the SCSI channel.
   1297 
   1298 Arguments:
   1299 
   1300   This                  - Protocol instance pointer.
   1301 
   1302 Returns:
   1303 
   1304   EFI_SUCCESS           - The SCSI channel was reset.
   1305   EFI_UNSUPPORTED       - The SCSI channel does not support
   1306                           a channel reset operation.
   1307   EFI_DEVICE_ERROR      - A device error occurred while
   1308                           attempting to reset the SCSI channel.
   1309   EFI_TIMEOUT           - A timeout occurred while attempting
   1310                           to reset the SCSI channel.
   1311 --*/
   1312 {
   1313   UINT8                         DeviceControlValue;
   1314   UINT8                         Index;
   1315   ATAPI_SCSI_PASS_THRU_DEV      *AtapiScsiPrivate;
   1316   BOOLEAN                       ResetFlag;
   1317 
   1318   AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);
   1319   ResetFlag = FALSE;
   1320   //
   1321   // Reset both Primary channel and Secondary channel.
   1322   // so, the IoPort pointer must point to the right I/O Register group
   1323   // And if there is a channel reset successfully, return EFI_SUCCESS.
   1324   //
   1325   for (Index = 0; Index < 2; Index++) {
   1326     //
   1327     // Reset
   1328     //
   1329     AtapiScsiPrivate->IoPort  = &AtapiScsiPrivate->AtapiIoPortRegisters[Index];
   1330 
   1331     DeviceControlValue        = 0;
   1332     //
   1333     // set SRST bit to initiate soft reset
   1334     //
   1335     DeviceControlValue |= SRST;
   1336     //
   1337     // disable Interrupt
   1338     //
   1339     DeviceControlValue |= BIT1;
   1340     WritePortB (
   1341       AtapiScsiPrivate->PciIo,
   1342       AtapiScsiPrivate->IoPort->Alt.DeviceControl,
   1343       DeviceControlValue
   1344       );
   1345 
   1346     //
   1347     // Wait 10us
   1348     //
   1349     gBS->Stall (10);
   1350 
   1351     //
   1352     // Clear SRST bit
   1353     // 0xfb:1111,1011
   1354     //
   1355     DeviceControlValue &= 0xfb;
   1356 
   1357     WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Alt.DeviceControl, DeviceControlValue);
   1358 
   1359     //
   1360     // slave device needs at most 31s to clear BSY
   1361     //
   1362     if (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000) != EFI_TIMEOUT) {
   1363       ResetFlag = TRUE;
   1364     }
   1365   }
   1366 
   1367   if (ResetFlag) {
   1368     return EFI_SUCCESS;
   1369   }
   1370 
   1371   return EFI_TIMEOUT;
   1372 }
   1373 
   1374 EFI_STATUS
   1375 EFIAPI
   1376 AtapiExtScsiPassThruResetTarget (
   1377   IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,
   1378   IN UINT8                              *Target,
   1379   IN UINT64                             Lun
   1380   )
   1381 /*++
   1382 
   1383 Routine Description:
   1384 
   1385   Resets a SCSI device that is connected to a SCSI channel.
   1386 
   1387 Arguments:
   1388 
   1389   This                  - Protocol instance pointer.
   1390   Target                - The Target ID of the SCSI device to reset.
   1391   Lun                   - The LUN of the SCSI device to reset.
   1392 
   1393 Returns:
   1394 
   1395   EFI_SUCCESS           - The SCSI device specified by Target and
   1396                           Lun was reset.
   1397   EFI_UNSUPPORTED       - The SCSI channel does not support a target
   1398                           reset operation.
   1399   EFI_INVALID_PARAMETER - Target or Lun are invalid.
   1400   EFI_DEVICE_ERROR      - A device error occurred while attempting
   1401                           to reset the SCSI device specified by Target
   1402                           and Lun.
   1403   EFI_TIMEOUT           - A timeout occurred while attempting to reset
   1404                           the SCSI device specified by Target and Lun.
   1405 --*/
   1406 {
   1407   UINT8                         Command;
   1408   UINT8                         DeviceSelect;
   1409   UINT8                         TargetId;
   1410   ATAPI_SCSI_PASS_THRU_DEV      *AtapiScsiPrivate;
   1411 
   1412   AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);
   1413   TargetId = Target[0];
   1414 
   1415   if ((TargetId > MAX_TARGET_ID) || (Lun != 0)) {
   1416     return EFI_INVALID_PARAMETER;
   1417   }
   1418   //
   1419   // Directly return EFI_SUCCESS if want to reset the host controller
   1420   //
   1421   if (TargetId == This->Mode->AdapterId) {
   1422     return EFI_SUCCESS;
   1423   }
   1424 
   1425   //
   1426   // According to Target ID, reset the Atapi I/O Register mapping
   1427   // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
   1428   //  Target Id in [2,3] area, using AtapiIoPortRegisters[1]
   1429   //
   1430   if ((TargetId / 2) == 0) {
   1431     AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];
   1432   } else {
   1433     AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];
   1434   }
   1435 
   1436   //
   1437   // for ATAPI device, no need to wait DRDY ready after device selecting.
   1438   //
   1439   // bit7 and bit5 are both set to 1 for backward compatibility
   1440   //
   1441   DeviceSelect = (UINT8) ((BIT7 | BIT5) | (TargetId << 4));
   1442   WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Head, DeviceSelect);
   1443 
   1444   Command = ATAPI_SOFT_RESET_CMD;
   1445   WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg.Command, Command);
   1446 
   1447   //
   1448   // BSY clear is the only status return to the host by the device
   1449   // when reset is complete.
   1450   // slave device needs at most 31s to clear BSY
   1451   //
   1452   if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000))) {
   1453     return EFI_TIMEOUT;
   1454   }
   1455 
   1456   //
   1457   // stall 5 seconds to make the device status stable
   1458   //
   1459   gBS->Stall (5000000);
   1460 
   1461   return EFI_SUCCESS;
   1462 }
   1463 
   1464 
   1465 EFI_STATUS
   1466 EFIAPI
   1467 AtapiExtScsiPassThruGetNextTarget (
   1468   IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,
   1469   IN OUT UINT8                           **Target
   1470   )
   1471 /*++
   1472 
   1473 Routine Description:
   1474   Used to retrieve the list of legal Target IDs for SCSI devices
   1475   on a SCSI channel.
   1476 
   1477 Arguments:
   1478   This                  - Protocol instance pointer.
   1479   Target                - On input, a pointer to the Target ID of a SCSI
   1480                           device present on the SCSI channel.  On output,
   1481                           a pointer to the Target ID of the next SCSI device
   1482                            present on a SCSI channel.  An input value of
   1483                            0xFFFFFFFF retrieves the Target ID of the first
   1484                            SCSI device present on a SCSI channel.
   1485   Lun                   - On input, a pointer to the LUN of a SCSI device
   1486                           present on the SCSI channel. On output, a pointer
   1487                           to the LUN of the next SCSI device present on
   1488                           a SCSI channel.
   1489 
   1490 Returns:
   1491   EFI_SUCCESS           - The Target ID and Lun of the next SCSI device
   1492                           on the SCSI channel was returned in Target and Lun.
   1493   EFI_NOT_FOUND         - There are no more SCSI devices on this SCSI channel.
   1494   EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not
   1495                           returned on a previous call to GetNextDevice().
   1496 --*/
   1497 {
   1498   UINT8                         TargetId;
   1499   UINT8                         ScsiId[TARGET_MAX_BYTES];
   1500   ATAPI_SCSI_PASS_THRU_DEV      *AtapiScsiPrivate;
   1501   UINT8                         ByteIndex;
   1502 
   1503   //
   1504   // Retrieve Device Private Data Structure.
   1505   //
   1506   AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);
   1507 
   1508   //
   1509   // Check whether Target is valid.
   1510   //
   1511   if (*Target == NULL ) {
   1512     return EFI_INVALID_PARAMETER;
   1513   }
   1514 
   1515   TargetId = (*Target)[0];
   1516   SetMem (ScsiId, TARGET_MAX_BYTES, 0xFF);
   1517 
   1518   //
   1519   // For ATAPI device, we use UINT8 to represent the SCSI ID on channel.
   1520   //
   1521   if (CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) {
   1522     for (ByteIndex = 1; ByteIndex < TARGET_MAX_BYTES; ByteIndex++) {
   1523       if ((*Target)[ByteIndex] != 0) {
   1524         return EFI_INVALID_PARAMETER;
   1525       }
   1526     }
   1527   }
   1528 
   1529   if ((CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) &&(TargetId != AtapiScsiPrivate->LatestTargetId)) {
   1530     return EFI_INVALID_PARAMETER;
   1531   }
   1532 
   1533   if (TargetId == MAX_TARGET_ID) {
   1534     return EFI_NOT_FOUND;
   1535   }
   1536 
   1537   if ((CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) == 0)) {
   1538     SetMem (*Target, TARGET_MAX_BYTES, 0);
   1539   } else {
   1540     (*Target)[0] = (UINT8) (AtapiScsiPrivate->LatestTargetId + 1);
   1541   }
   1542 
   1543   //
   1544   // Update the LatestTargetId.
   1545   //
   1546   AtapiScsiPrivate->LatestTargetId  = (*Target)[0];
   1547   AtapiScsiPrivate->LatestLun       = 0;
   1548 
   1549   return EFI_SUCCESS;
   1550 }
   1551 
   1552 EFI_STATUS
   1553 GetIdeRegistersBaseAddr (
   1554   IN  EFI_PCI_IO_PROTOCOL         *PciIo,
   1555   OUT IDE_REGISTERS_BASE_ADDR     *IdeRegsBaseAddr
   1556   )
   1557 /*++
   1558 
   1559 Routine Description:
   1560   Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,
   1561   use fixed addresses. In Native-PCI mode, get base addresses from BARs in
   1562   the PCI IDE controller's Configuration Space.
   1563 
   1564 Arguments:
   1565   PciIo             - Pointer to the EFI_PCI_IO_PROTOCOL instance
   1566   IdeRegsBaseAddr   - Pointer to IDE_REGISTERS_BASE_ADDR to
   1567                       receive IDE IO port registers' base addresses
   1568 
   1569 Returns:
   1570 
   1571   EFI_STATUS
   1572 
   1573 --*/
   1574 {
   1575   EFI_STATUS  Status;
   1576   PCI_TYPE00  PciData;
   1577 
   1578   Status = PciIo->Pci.Read (
   1579                         PciIo,
   1580                         EfiPciIoWidthUint8,
   1581                         0,
   1582                         sizeof (PciData),
   1583                         &PciData
   1584                         );
   1585 
   1586   if (EFI_ERROR (Status)) {
   1587     return Status;
   1588   }
   1589 
   1590   if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {
   1591     IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr  = 0x1f0;
   1592     IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr  = 0x3f6;
   1593   } else {
   1594     //
   1595     // The BARs should be of IO type
   1596     //
   1597     if ((PciData.Device.Bar[0] & BIT0) == 0 ||
   1598         (PciData.Device.Bar[1] & BIT0) == 0) {
   1599       return EFI_UNSUPPORTED;
   1600     }
   1601 
   1602     IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr  =
   1603     (UINT16) (PciData.Device.Bar[0] & 0x0000fff8);
   1604     IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr  =
   1605     (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2);
   1606   }
   1607 
   1608   if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {
   1609     IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr  = 0x170;
   1610     IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr  = 0x376;
   1611   } else {
   1612     //
   1613     // The BARs should be of IO type
   1614     //
   1615     if ((PciData.Device.Bar[2] & BIT0) == 0 ||
   1616         (PciData.Device.Bar[3] & BIT0) == 0) {
   1617       return EFI_UNSUPPORTED;
   1618     }
   1619 
   1620     IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr  =
   1621     (UINT16) (PciData.Device.Bar[2] & 0x0000fff8);
   1622     IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr  =
   1623     (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2);
   1624   }
   1625 
   1626   return EFI_SUCCESS;
   1627 }
   1628 
   1629 VOID
   1630 InitAtapiIoPortRegisters (
   1631   IN  ATAPI_SCSI_PASS_THRU_DEV     *AtapiScsiPrivate,
   1632   IN  IDE_REGISTERS_BASE_ADDR      *IdeRegsBaseAddr
   1633   )
   1634 /*++
   1635 
   1636 Routine Description:
   1637 
   1638   Initialize each Channel's Base Address of CommandBlock and ControlBlock.
   1639 
   1640 Arguments:
   1641 
   1642   AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
   1643   IdeRegsBaseAddr             - The pointer of IDE_REGISTERS_BASE_ADDR
   1644 
   1645 Returns:
   1646 
   1647   None
   1648 
   1649 --*/
   1650 {
   1651 
   1652   UINT8               IdeChannel;
   1653   UINT16              CommandBlockBaseAddr;
   1654   UINT16              ControlBlockBaseAddr;
   1655   IDE_BASE_REGISTERS  *RegisterPointer;
   1656 
   1657 
   1658   for (IdeChannel = 0; IdeChannel < ATAPI_MAX_CHANNEL; IdeChannel++) {
   1659 
   1660     RegisterPointer =  &AtapiScsiPrivate->AtapiIoPortRegisters[IdeChannel];
   1661 
   1662     //
   1663     // Initialize IDE IO port addresses, including Command Block registers
   1664     // and Control Block registers
   1665     //
   1666     CommandBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].CommandBlockBaseAddr;
   1667     ControlBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].ControlBlockBaseAddr;
   1668 
   1669     RegisterPointer->Data = CommandBlockBaseAddr;
   1670     (*(UINT16 *) &RegisterPointer->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);
   1671     RegisterPointer->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);
   1672     RegisterPointer->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);
   1673     RegisterPointer->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);
   1674     RegisterPointer->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);
   1675     RegisterPointer->Head = (UINT16) (CommandBlockBaseAddr + 0x06);
   1676     (*(UINT16 *) &RegisterPointer->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07);
   1677 
   1678     (*(UINT16 *) &RegisterPointer->Alt) = ControlBlockBaseAddr;
   1679     RegisterPointer->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01);
   1680   }
   1681 
   1682 }
   1683 
   1684 
   1685 EFI_STATUS
   1686 CheckSCSIRequestPacket (
   1687   EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET      *Packet
   1688   )
   1689 /*++
   1690 
   1691 Routine Description:
   1692 
   1693   Checks the parameters in the SCSI Request Packet to make sure
   1694   they are valid for a SCSI Pass Thru request.
   1695 
   1696 Arguments:
   1697 
   1698   Packet         -  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
   1699 
   1700 Returns:
   1701 
   1702   EFI_STATUS
   1703 
   1704 --*/
   1705 {
   1706   if (Packet == NULL) {
   1707     return EFI_INVALID_PARAMETER;
   1708   }
   1709 
   1710   if (!ValidCdbLength (Packet->CdbLength)) {
   1711     return EFI_INVALID_PARAMETER;
   1712   }
   1713 
   1714   if (Packet->Cdb == NULL) {
   1715     return EFI_INVALID_PARAMETER;
   1716   }
   1717 
   1718   //
   1719   // Checks whether the request command is supported.
   1720   //
   1721   if (!IsCommandValid (Packet)) {
   1722     return EFI_UNSUPPORTED;
   1723   }
   1724 
   1725   return EFI_SUCCESS;
   1726 }
   1727 
   1728 BOOLEAN
   1729 IsCommandValid (
   1730   EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   *Packet
   1731   )
   1732 /*++
   1733 
   1734 Routine Description:
   1735 
   1736   Checks the requested SCSI command:
   1737   Is it supported by this driver?
   1738   Is the Data transfer direction reasonable?
   1739 
   1740 Arguments:
   1741 
   1742   Packet         -  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
   1743 
   1744 Returns:
   1745 
   1746   EFI_STATUS
   1747 
   1748 --*/
   1749 {
   1750   UINT8 Index;
   1751   UINT8 *OpCode;
   1752   UINT8 ArrayLen;
   1753 
   1754   OpCode = (UINT8 *) (Packet->Cdb);
   1755   ArrayLen = (UINT8) (ARRAY_SIZE (gSupportedATAPICommands));
   1756 
   1757   for (Index = 0; (Index < ArrayLen) && (CompareMem (&gSupportedATAPICommands[Index], &gEndTable, sizeof (SCSI_COMMAND_SET)) != 0); Index++) {
   1758 
   1759     if (*OpCode == gSupportedATAPICommands[Index].OpCode) {
   1760       //
   1761       // Check whether the requested Command is supported by this driver
   1762       //
   1763       if (Packet->DataDirection == DataIn) {
   1764         //
   1765         // Check whether the requested data direction conforms to
   1766         // what it should be.
   1767         //
   1768         if (gSupportedATAPICommands[Index].Direction == DataOut) {
   1769           return FALSE;
   1770         }
   1771       }
   1772 
   1773       if (Packet->DataDirection == DataOut) {
   1774         //
   1775         // Check whether the requested data direction conforms to
   1776         // what it should be.
   1777         //
   1778         if (gSupportedATAPICommands[Index].Direction == DataIn) {
   1779           return FALSE;
   1780         }
   1781       }
   1782 
   1783       return TRUE;
   1784     }
   1785   }
   1786 
   1787   return FALSE;
   1788 }
   1789 
   1790 EFI_STATUS
   1791 SubmitBlockingIoCommand (
   1792   ATAPI_SCSI_PASS_THRU_DEV                  *AtapiScsiPrivate,
   1793   UINT32                                    Target,
   1794   EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet
   1795   )
   1796 /*++
   1797 
   1798 Routine Description:
   1799 
   1800   Performs blocking I/O request.
   1801 
   1802 Arguments:
   1803 
   1804   AtapiScsiPrivate:   Private data structure for the specified channel.
   1805   Target:             The Target ID of the ATAPI device to send the SCSI
   1806                       Request Packet. To ATAPI devices attached on an IDE
   1807                       Channel, Target ID 0 indicates Master device;Target
   1808                       ID 1 indicates Slave device.
   1809   Packet:             The SCSI Request Packet to send to the ATAPI device
   1810                       specified by Target.
   1811 
   1812   Returns:            EFI_STATUS
   1813 
   1814 --*/
   1815 {
   1816   UINT8       PacketCommand[12];
   1817   UINT64      TimeoutInMicroSeconds;
   1818   EFI_STATUS  PacketCommandStatus;
   1819 
   1820   //
   1821   // Fill ATAPI Command Packet according to CDB
   1822   //
   1823   ZeroMem (&PacketCommand, 12);
   1824   CopyMem (&PacketCommand, Packet->Cdb, Packet->CdbLength);
   1825 
   1826   //
   1827   // Timeout is 100ns unit, convert it to 1000ns (1us) unit.
   1828   //
   1829   TimeoutInMicroSeconds = DivU64x32 (Packet->Timeout, (UINT32) 10);
   1830 
   1831   //
   1832   // Submit ATAPI Command Packet
   1833   //
   1834   PacketCommandStatus = AtapiPacketCommand (
   1835                           AtapiScsiPrivate,
   1836                           Target,
   1837                           PacketCommand,
   1838                           Packet->DataBuffer,
   1839                           &(Packet->TransferLength),
   1840                           (DATA_DIRECTION) Packet->DataDirection,
   1841                           TimeoutInMicroSeconds
   1842                           );
   1843   if (!EFI_ERROR (PacketCommandStatus) || (Packet->SenseData == NULL)) {
   1844     Packet->SenseDataLength = 0;
   1845     return PacketCommandStatus;
   1846   }
   1847 
   1848   //
   1849   // Return SenseData if PacketCommandStatus matches
   1850   // the following return codes.
   1851   //
   1852   if ((PacketCommandStatus ==  EFI_BAD_BUFFER_SIZE) ||
   1853       (PacketCommandStatus == EFI_DEVICE_ERROR) ||
   1854       (PacketCommandStatus == EFI_TIMEOUT)) {
   1855 
   1856     //
   1857     // avoid submit request sense command continuously.
   1858     //
   1859     if (PacketCommand[0] == OP_REQUEST_SENSE) {
   1860       Packet->SenseDataLength = 0;
   1861       return PacketCommandStatus;
   1862     }
   1863 
   1864     RequestSenseCommand (
   1865       AtapiScsiPrivate,
   1866       Target,
   1867       Packet->Timeout,
   1868       Packet->SenseData,
   1869       &Packet->SenseDataLength
   1870       );
   1871   }
   1872 
   1873   return PacketCommandStatus;
   1874 }
   1875 
   1876 EFI_STATUS
   1877 RequestSenseCommand (
   1878   ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,
   1879   UINT32                      Target,
   1880   UINT64                      Timeout,
   1881   VOID                        *SenseData,
   1882   UINT8                       *SenseDataLength
   1883   )
   1884 /*++
   1885 
   1886 Routine Description:
   1887 
   1888   Submit request sense command
   1889 
   1890 Arguments:
   1891 
   1892   AtapiScsiPrivate  - The pointer of ATAPI_SCSI_PASS_THRU_DEV
   1893   Target            - The target ID
   1894   Timeout           - The time to complete the command
   1895   SenseData         - The buffer to fill in sense data
   1896   SenseDataLength   - The length of buffer
   1897 
   1898 Returns:
   1899 
   1900   EFI_STATUS
   1901 
   1902 --*/
   1903 {
   1904   EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  Packet;
   1905   UINT8                                   Cdb[12];
   1906   EFI_STATUS                              Status;
   1907 
   1908   ZeroMem (&Packet, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));
   1909   ZeroMem (Cdb, 12);
   1910 
   1911   Cdb[0]                = OP_REQUEST_SENSE;
   1912   Cdb[4]                = (UINT8) (*SenseDataLength);
   1913 
   1914   Packet.Timeout        = Timeout;
   1915   Packet.DataBuffer     = SenseData;
   1916   Packet.SenseData      = NULL;
   1917   Packet.Cdb            = Cdb;
   1918   Packet.TransferLength = *SenseDataLength;
   1919   Packet.CdbLength      = 12;
   1920   Packet.DataDirection  = DataIn;
   1921 
   1922   Status                = SubmitBlockingIoCommand (AtapiScsiPrivate, Target, &Packet);
   1923   *SenseDataLength      = (UINT8) (Packet.TransferLength);
   1924   return Status;
   1925 }
   1926 
   1927 EFI_STATUS
   1928 CheckExtSCSIRequestPacket (
   1929   EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET      *Packet
   1930   )
   1931 /*++
   1932 
   1933 Routine Description:
   1934 
   1935   Checks the parameters in the SCSI Request Packet to make sure
   1936   they are valid for a SCSI Pass Thru request.
   1937 
   1938 Arguments:
   1939 
   1940   Packet       - The pointer of EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
   1941 
   1942 Returns:
   1943 
   1944   EFI_STATUS
   1945 
   1946 --*/
   1947 {
   1948   if (Packet == NULL) {
   1949     return EFI_INVALID_PARAMETER;
   1950   }
   1951 
   1952   if (!ValidCdbLength (Packet->CdbLength)) {
   1953     return EFI_INVALID_PARAMETER;
   1954   }
   1955 
   1956   if (Packet->Cdb == NULL) {
   1957     return EFI_INVALID_PARAMETER;
   1958   }
   1959 
   1960   //
   1961   // Checks whether the request command is supported.
   1962   //
   1963   if (!IsExtCommandValid (Packet)) {
   1964     return EFI_UNSUPPORTED;
   1965   }
   1966 
   1967   return EFI_SUCCESS;
   1968 }
   1969 
   1970 
   1971 BOOLEAN
   1972 IsExtCommandValid (
   1973   EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   *Packet
   1974   )
   1975 /*++
   1976 
   1977 Routine Description:
   1978 
   1979   Checks the requested SCSI command:
   1980   Is it supported by this driver?
   1981   Is the Data transfer direction reasonable?
   1982 
   1983 Arguments:
   1984 
   1985   Packet         -  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
   1986 
   1987 Returns:
   1988 
   1989   EFI_STATUS
   1990 
   1991 --*/
   1992 {
   1993   UINT8 Index;
   1994   UINT8 *OpCode;
   1995   UINT8 ArrayLen;
   1996 
   1997   OpCode = (UINT8 *) (Packet->Cdb);
   1998   ArrayLen = (UINT8) (ARRAY_SIZE (gSupportedATAPICommands));
   1999 
   2000   for (Index = 0; (Index < ArrayLen) && (CompareMem (&gSupportedATAPICommands[Index], &gEndTable, sizeof (SCSI_COMMAND_SET)) != 0); Index++) {
   2001 
   2002     if (*OpCode == gSupportedATAPICommands[Index].OpCode) {
   2003       //
   2004       // Check whether the requested Command is supported by this driver
   2005       //
   2006       if (Packet->DataDirection == DataIn) {
   2007         //
   2008         // Check whether the requested data direction conforms to
   2009         // what it should be.
   2010         //
   2011         if (gSupportedATAPICommands[Index].Direction == DataOut) {
   2012           return FALSE;
   2013         }
   2014       }
   2015 
   2016       if (Packet->DataDirection == DataOut) {
   2017         //
   2018         // Check whether the requested data direction conforms to
   2019         // what it should be.
   2020         //
   2021         if (gSupportedATAPICommands[Index].Direction == DataIn) {
   2022           return FALSE;
   2023         }
   2024       }
   2025 
   2026       return TRUE;
   2027     }
   2028   }
   2029 
   2030   return FALSE;
   2031 }
   2032 
   2033 EFI_STATUS
   2034 SubmitExtBlockingIoCommand (
   2035   ATAPI_SCSI_PASS_THRU_DEV                      *AtapiScsiPrivate,
   2036   UINT8                                         Target,
   2037   EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet
   2038   )
   2039 /*++
   2040 
   2041 Routine Description:
   2042 
   2043   Performs blocking I/O request.
   2044 
   2045 Arguments:
   2046 
   2047   AtapiScsiPrivate:   Private data structure for the specified channel.
   2048   Target:             The Target ID of the ATAPI device to send the SCSI
   2049                       Request Packet. To ATAPI devices attached on an IDE
   2050                       Channel, Target ID 0 indicates Master device;Target
   2051                       ID 1 indicates Slave device.
   2052   Packet:             The SCSI Request Packet to send to the ATAPI device
   2053                       specified by Target.
   2054 
   2055   Returns:            EFI_STATUS
   2056 
   2057 --*/
   2058 {
   2059   UINT8       PacketCommand[12];
   2060   UINT64      TimeoutInMicroSeconds;
   2061   EFI_STATUS  PacketCommandStatus;
   2062 
   2063   //
   2064   // Fill ATAPI Command Packet according to CDB
   2065   //
   2066   ZeroMem (&PacketCommand, 12);
   2067   CopyMem (&PacketCommand, Packet->Cdb, Packet->CdbLength);
   2068 
   2069   //
   2070   // Timeout is 100ns unit, convert it to 1000ns (1us) unit.
   2071   //
   2072   TimeoutInMicroSeconds = DivU64x32 (Packet->Timeout, (UINT32) 10);
   2073 
   2074   //
   2075   // Submit ATAPI Command Packet
   2076   //
   2077   if (Packet->DataDirection == DataIn) {
   2078     PacketCommandStatus = AtapiPacketCommand (
   2079                               AtapiScsiPrivate,
   2080                               Target,
   2081                               PacketCommand,
   2082                               Packet->InDataBuffer,
   2083                               &(Packet->InTransferLength),
   2084                               DataIn,
   2085                               TimeoutInMicroSeconds
   2086                               );
   2087   } else {
   2088 
   2089     PacketCommandStatus = AtapiPacketCommand (
   2090                             AtapiScsiPrivate,
   2091                             Target,
   2092                             PacketCommand,
   2093                             Packet->OutDataBuffer,
   2094                             &(Packet->OutTransferLength),
   2095                             DataOut,
   2096                             TimeoutInMicroSeconds
   2097                             );
   2098   }
   2099 
   2100   if (!EFI_ERROR (PacketCommandStatus) || (Packet->SenseData == NULL)) {
   2101     Packet->SenseDataLength = 0;
   2102     return PacketCommandStatus;
   2103   }
   2104 
   2105   //
   2106   // Return SenseData if PacketCommandStatus matches
   2107   // the following return codes.
   2108   //
   2109   if ((PacketCommandStatus == EFI_BAD_BUFFER_SIZE) ||
   2110       (PacketCommandStatus == EFI_DEVICE_ERROR) ||
   2111       (PacketCommandStatus == EFI_TIMEOUT)) {
   2112 
   2113     //
   2114     // avoid submit request sense command continuously.
   2115     //
   2116     if (PacketCommand[0] == OP_REQUEST_SENSE) {
   2117       Packet->SenseDataLength = 0;
   2118       return PacketCommandStatus;
   2119     }
   2120 
   2121     RequestSenseCommand (
   2122       AtapiScsiPrivate,
   2123       Target,
   2124       Packet->Timeout,
   2125       Packet->SenseData,
   2126       &Packet->SenseDataLength
   2127       );
   2128   }
   2129 
   2130   return PacketCommandStatus;
   2131 }
   2132 
   2133 
   2134 EFI_STATUS
   2135 AtapiPacketCommand (
   2136   ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,
   2137   UINT32                      Target,
   2138   UINT8                       *PacketCommand,
   2139   VOID                        *Buffer,
   2140   UINT32                      *ByteCount,
   2141   DATA_DIRECTION              Direction,
   2142   UINT64                      TimeoutInMicroSeconds
   2143   )
   2144 /*++
   2145 
   2146 Routine Description:
   2147 
   2148   Submits ATAPI command packet to the specified ATAPI device.
   2149 
   2150 Arguments:
   2151 
   2152   AtapiScsiPrivate:   Private data structure for the specified channel.
   2153   Target:             The Target ID of the ATAPI device to send the SCSI
   2154                       Request Packet. To ATAPI devices attached on an IDE
   2155                       Channel, Target ID 0 indicates Master device;Target
   2156                       ID 1 indicates Slave device.
   2157   PacketCommand:      Points to the ATAPI command packet.
   2158   Buffer:             Points to the transferred data.
   2159   ByteCount:          When input,indicates the buffer size; when output,
   2160                       indicates the actually transferred data size.
   2161   Direction:          Indicates the data transfer direction.
   2162   TimeoutInMicroSeconds:
   2163                       The timeout, in micro second units, to use for the
   2164                       execution of this ATAPI command.
   2165                       A TimeoutInMicroSeconds value of 0 means that
   2166                       this function will wait indefinitely for the ATAPI
   2167                       command to execute.
   2168                       If TimeoutInMicroSeconds is greater than zero, then
   2169                       this function will return EFI_TIMEOUT if the time
   2170                       required to execute the ATAPI command is greater
   2171                       than TimeoutInMicroSeconds.
   2172 
   2173 Returns:
   2174 
   2175   EFI_STATUS
   2176 
   2177 --*/
   2178 {
   2179 
   2180   UINT16      *CommandIndex;
   2181   UINT8       Count;
   2182   EFI_STATUS  Status;
   2183 
   2184   //
   2185   // Set all the command parameters by fill related registers.
   2186   // Before write to all the following registers, BSY must be 0.
   2187   //
   2188   Status = StatusWaitForBSYClear (AtapiScsiPrivate, TimeoutInMicroSeconds);
   2189   if (EFI_ERROR (Status)) {
   2190     return EFI_DEVICE_ERROR;
   2191   }
   2192 
   2193 
   2194   //
   2195   // Select device via Device/Head Register.
   2196   // "Target = 0" indicates device 0; "Target = 1" indicates device 1
   2197   //
   2198   WritePortB (
   2199     AtapiScsiPrivate->PciIo,
   2200     AtapiScsiPrivate->IoPort->Head,
   2201     (UINT8) ((Target << 4) | DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000)
   2202     );
   2203 
   2204   //
   2205   // Set all the command parameters by fill related registers.
   2206   // Before write to all the following registers, BSY DRQ must be 0.
   2207   //
   2208   Status =  StatusDRQClear(AtapiScsiPrivate,  TimeoutInMicroSeconds);
   2209 
   2210   if (EFI_ERROR (Status)) {
   2211     if (Status == EFI_ABORTED) {
   2212       Status = EFI_DEVICE_ERROR;
   2213     }
   2214     *ByteCount = 0;
   2215     return Status;
   2216   }
   2217 
   2218   //
   2219   // No OVL; No DMA (by setting feature register)
   2220   //
   2221   WritePortB (
   2222     AtapiScsiPrivate->PciIo,
   2223     AtapiScsiPrivate->IoPort->Reg1.Feature,
   2224     0x00
   2225     );
   2226 
   2227   //
   2228   // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device
   2229   // determine how much data should be transfered.
   2230   //
   2231   WritePortB (
   2232     AtapiScsiPrivate->PciIo,
   2233     AtapiScsiPrivate->IoPort->CylinderLsb,
   2234     (UINT8) (MAX_ATAPI_BYTE_COUNT & 0x00ff)
   2235     );
   2236   WritePortB (
   2237     AtapiScsiPrivate->PciIo,
   2238     AtapiScsiPrivate->IoPort->CylinderMsb,
   2239     (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8)
   2240     );
   2241 
   2242   //
   2243   //  DEFAULT_CTL:0x0a (0000,1010)
   2244   //  Disable interrupt
   2245   //
   2246   WritePortB (
   2247     AtapiScsiPrivate->PciIo,
   2248     AtapiScsiPrivate->IoPort->Alt.DeviceControl,
   2249     DEFAULT_CTL
   2250     );
   2251 
   2252   //
   2253   // Send Packet command to inform device
   2254   // that the following data bytes are command packet.
   2255   //
   2256   WritePortB (
   2257     AtapiScsiPrivate->PciIo,
   2258     AtapiScsiPrivate->IoPort->Reg.Command,
   2259     PACKET_CMD
   2260     );
   2261 
   2262   //
   2263   // Before data transfer, BSY should be 0 and DRQ should be 1.
   2264   // if they are not in specified time frame,
   2265   // retrieve Sense Key from Error Register before return.
   2266   //
   2267   Status = StatusDRQReady (AtapiScsiPrivate, TimeoutInMicroSeconds);
   2268   if (EFI_ERROR (Status)) {
   2269     if (Status == EFI_ABORTED) {
   2270       Status = EFI_DEVICE_ERROR;
   2271     }
   2272 
   2273     *ByteCount = 0;
   2274     return Status;
   2275   }
   2276 
   2277   //
   2278   // Send out command packet
   2279   //
   2280   CommandIndex = (UINT16 *) PacketCommand;
   2281   for (Count = 0; Count < 6; Count++, CommandIndex++) {
   2282     WritePortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data, *CommandIndex);
   2283   }
   2284 
   2285   //
   2286   // call AtapiPassThruPioReadWriteData() function to get
   2287   // requested transfer data form device.
   2288   //
   2289   return AtapiPassThruPioReadWriteData (
   2290           AtapiScsiPrivate,
   2291           Buffer,
   2292           ByteCount,
   2293           Direction,
   2294           TimeoutInMicroSeconds
   2295           );
   2296 }
   2297 
   2298 EFI_STATUS
   2299 AtapiPassThruPioReadWriteData (
   2300   ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate,
   2301   UINT16                    *Buffer,
   2302   UINT32                    *ByteCount,
   2303   DATA_DIRECTION            Direction,
   2304   UINT64                    TimeoutInMicroSeconds
   2305   )
   2306 /*++
   2307 
   2308 Routine Description:
   2309 
   2310   Performs data transfer between ATAPI device and host after the
   2311   ATAPI command packet is sent.
   2312 
   2313 Arguments:
   2314 
   2315   AtapiScsiPrivate:   Private data structure for the specified channel.
   2316   Buffer:             Points to the transferred data.
   2317   ByteCount:          When input,indicates the buffer size; when output,
   2318                       indicates the actually transferred data size.
   2319   Direction:          Indicates the data transfer direction.
   2320   TimeoutInMicroSeconds:
   2321                       The timeout, in micro second units, to use for the
   2322                       execution of this ATAPI command.
   2323                       A TimeoutInMicroSeconds value of 0 means that
   2324                       this function will wait indefinitely for the ATAPI
   2325                       command to execute.
   2326                       If TimeoutInMicroSeconds is greater than zero, then
   2327                       this function will return EFI_TIMEOUT if the time
   2328                       required to execute the ATAPI command is greater
   2329                       than TimeoutInMicroSeconds.
   2330  Returns:
   2331 
   2332   EFI_STATUS
   2333 
   2334 --*/
   2335 {
   2336   UINT32      Index;
   2337   UINT32      RequiredWordCount;
   2338   UINT32      ActualWordCount;
   2339   UINT32      WordCount;
   2340   EFI_STATUS  Status;
   2341   UINT16      *ptrBuffer;
   2342 
   2343   Status = EFI_SUCCESS;
   2344 
   2345   //
   2346   // Non Data transfer request is also supported.
   2347   //
   2348   if (*ByteCount == 0 || Buffer == NULL) {
   2349     *ByteCount = 0;
   2350     if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, TimeoutInMicroSeconds))) {
   2351       return EFI_DEVICE_ERROR;
   2352     }
   2353   }
   2354 
   2355   ptrBuffer         = Buffer;
   2356   RequiredWordCount = *ByteCount / 2;
   2357 
   2358   //
   2359   // ActuralWordCount means the word count of data really transfered.
   2360   //
   2361   ActualWordCount = 0;
   2362 
   2363   while (ActualWordCount < RequiredWordCount) {
   2364     //
   2365     // before each data transfer stream, the host should poll DRQ bit ready,
   2366     // which indicates device's ready for data transfer .
   2367     //
   2368     Status = StatusDRQReady (AtapiScsiPrivate, TimeoutInMicroSeconds);
   2369     if (EFI_ERROR (Status)) {
   2370       *ByteCount = ActualWordCount * 2;
   2371 
   2372       AtapiPassThruCheckErrorStatus (AtapiScsiPrivate);
   2373 
   2374       if (ActualWordCount == 0) {
   2375         return EFI_DEVICE_ERROR;
   2376       }
   2377       //
   2378       // ActualWordCount > 0
   2379       //
   2380       if (ActualWordCount < RequiredWordCount) {
   2381         return EFI_BAD_BUFFER_SIZE;
   2382       }
   2383     }
   2384     //
   2385     // get current data transfer size from Cylinder Registers.
   2386     //
   2387     WordCount = ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->CylinderMsb) << 8;
   2388     WordCount = WordCount | ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->CylinderLsb);
   2389     WordCount = WordCount & 0xffff;
   2390     WordCount /= 2;
   2391 
   2392     //
   2393     // perform a series data In/Out.
   2394     //
   2395     for (Index = 0; (Index < WordCount) && (ActualWordCount < RequiredWordCount); Index++, ActualWordCount++) {
   2396 
   2397       if (Direction == DataIn) {
   2398 
   2399         *ptrBuffer = ReadPortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data);
   2400       } else {
   2401 
   2402         WritePortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data, *ptrBuffer);
   2403       }
   2404 
   2405       ptrBuffer++;
   2406 
   2407     }
   2408   }
   2409   //
   2410   // After data transfer is completed, normally, DRQ bit should clear.
   2411   //
   2412   StatusDRQClear (AtapiScsiPrivate, TimeoutInMicroSeconds);
   2413 
   2414   //
   2415   // read status register to check whether error happens.
   2416   //
   2417   Status      = AtapiPassThruCheckErrorStatus (AtapiScsiPrivate);
   2418 
   2419   *ByteCount  = ActualWordCount * 2;
   2420 
   2421   return Status;
   2422 }
   2423 
   2424 
   2425 UINT8
   2426 ReadPortB (
   2427   IN  EFI_PCI_IO_PROTOCOL   *PciIo,
   2428   IN  UINT16                Port
   2429   )
   2430 /*++
   2431 
   2432 Routine Description:
   2433 
   2434   Read one byte from a specified I/O port.
   2435 
   2436 Arguments:
   2437 
   2438   PciIo      - The pointer of EFI_PCI_IO_PROTOCOL
   2439   Port       - IO port
   2440 
   2441 Returns:
   2442 
   2443   A byte read out
   2444 
   2445 --*/
   2446 {
   2447   UINT8 Data;
   2448 
   2449   Data = 0;
   2450   PciIo->Io.Read (
   2451               PciIo,
   2452               EfiPciIoWidthUint8,
   2453               EFI_PCI_IO_PASS_THROUGH_BAR,
   2454               (UINT64) Port,
   2455               1,
   2456               &Data
   2457               );
   2458   return Data;
   2459 }
   2460 
   2461 
   2462 UINT16
   2463 ReadPortW (
   2464   IN  EFI_PCI_IO_PROTOCOL   *PciIo,
   2465   IN  UINT16                Port
   2466   )
   2467 /*++
   2468 
   2469 Routine Description:
   2470 
   2471   Read one word from a specified I/O port.
   2472 
   2473 Arguments:
   2474 
   2475   PciIo      - The pointer of EFI_PCI_IO_PROTOCOL
   2476   Port       - IO port
   2477 
   2478 Returns:
   2479 
   2480   A word read out
   2481 --*/
   2482 {
   2483   UINT16  Data;
   2484 
   2485   Data = 0;
   2486   PciIo->Io.Read (
   2487               PciIo,
   2488               EfiPciIoWidthUint16,
   2489               EFI_PCI_IO_PASS_THROUGH_BAR,
   2490               (UINT64) Port,
   2491               1,
   2492               &Data
   2493               );
   2494   return Data;
   2495 }
   2496 
   2497 
   2498 VOID
   2499 WritePortB (
   2500   IN  EFI_PCI_IO_PROTOCOL   *PciIo,
   2501   IN  UINT16                Port,
   2502   IN  UINT8                 Data
   2503   )
   2504 /*++
   2505 
   2506 Routine Description:
   2507 
   2508   Write one byte to a specified I/O port.
   2509 
   2510 Arguments:
   2511 
   2512   PciIo      - The pointer of EFI_PCI_IO_PROTOCOL
   2513   Port       - IO port
   2514   Data       - The data to write
   2515 
   2516 Returns:
   2517 
   2518    NONE
   2519 
   2520 --*/
   2521 {
   2522   PciIo->Io.Write (
   2523               PciIo,
   2524               EfiPciIoWidthUint8,
   2525               EFI_PCI_IO_PASS_THROUGH_BAR,
   2526               (UINT64) Port,
   2527               1,
   2528               &Data
   2529               );
   2530 }
   2531 
   2532 
   2533 VOID
   2534 WritePortW (
   2535   IN  EFI_PCI_IO_PROTOCOL   *PciIo,
   2536   IN  UINT16                Port,
   2537   IN  UINT16                Data
   2538   )
   2539 /*++
   2540 
   2541 Routine Description:
   2542 
   2543   Write one word to a specified I/O port.
   2544 
   2545 Arguments:
   2546 
   2547   PciIo      - The pointer of EFI_PCI_IO_PROTOCOL
   2548   Port       - IO port
   2549   Data       - The data to write
   2550 
   2551 Returns:
   2552 
   2553    NONE
   2554 
   2555 --*/
   2556 {
   2557   PciIo->Io.Write (
   2558               PciIo,
   2559               EfiPciIoWidthUint16,
   2560               EFI_PCI_IO_PASS_THROUGH_BAR,
   2561               (UINT64) Port,
   2562               1,
   2563               &Data
   2564               );
   2565 }
   2566 
   2567 EFI_STATUS
   2568 StatusDRQClear (
   2569   ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,
   2570   UINT64                          TimeoutInMicroSeconds
   2571   )
   2572 /*++
   2573 
   2574 Routine Description:
   2575 
   2576   Check whether DRQ is clear in the Status Register. (BSY must also be cleared)
   2577   If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
   2578   DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
   2579   elapsed.
   2580 
   2581 Arguments:
   2582 
   2583   AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
   2584   TimeoutInMicroSeconds       - The time to wait for
   2585 
   2586 Returns:
   2587 
   2588   EFI_STATUS
   2589 
   2590 --*/
   2591 {
   2592   UINT64  Delay;
   2593   UINT8   StatusRegister;
   2594   UINT8   ErrRegister;
   2595 
   2596   if (TimeoutInMicroSeconds == 0) {
   2597     Delay = 2;
   2598   } else {
   2599     Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
   2600   }
   2601 
   2602   do {
   2603 
   2604     StatusRegister = ReadPortB (
   2605                       AtapiScsiPrivate->PciIo,
   2606                       AtapiScsiPrivate->IoPort->Reg.Status
   2607                       );
   2608 
   2609     //
   2610     // wait for BSY == 0 and DRQ == 0
   2611     //
   2612     if ((StatusRegister & (DRQ | BSY)) == 0) {
   2613       break;
   2614     }
   2615     //
   2616     // check whether the command is aborted by the device
   2617     //
   2618     if ((StatusRegister & (BSY | ERR)) == ERR) {
   2619 
   2620       ErrRegister = ReadPortB (
   2621                       AtapiScsiPrivate->PciIo,
   2622                       AtapiScsiPrivate->IoPort->Reg1.Error
   2623                       );
   2624       if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
   2625 
   2626         return EFI_ABORTED;
   2627       }
   2628     }
   2629     //
   2630     //  Stall for 30 us
   2631     //
   2632     gBS->Stall (30);
   2633 
   2634     //
   2635     // Loop infinitely if not meeting expected condition
   2636     //
   2637     if (TimeoutInMicroSeconds == 0) {
   2638       Delay = 2;
   2639     }
   2640 
   2641     Delay--;
   2642   } while (Delay);
   2643 
   2644   if (Delay == 0) {
   2645     return EFI_TIMEOUT;
   2646   }
   2647 
   2648   return EFI_SUCCESS;
   2649 }
   2650 
   2651 EFI_STATUS
   2652 AltStatusDRQClear (
   2653   ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,
   2654   UINT64                          TimeoutInMicroSeconds
   2655   )
   2656 /*++
   2657 
   2658 Routine Description:
   2659 
   2660   Check whether DRQ is clear in the Alternate Status Register.
   2661   (BSY must also be cleared).If TimeoutInMicroSeconds is zero, this routine should
   2662   wait infinitely for DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
   2663   elapsed.
   2664 
   2665 Arguments:
   2666 
   2667   AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
   2668   TimeoutInMicroSeconds       - The time to wait for
   2669 
   2670 Returns:
   2671 
   2672   EFI_STATUS
   2673 
   2674 --*/
   2675 {
   2676   UINT64  Delay;
   2677   UINT8   AltStatusRegister;
   2678   UINT8   ErrRegister;
   2679 
   2680   if (TimeoutInMicroSeconds == 0) {
   2681     Delay = 2;
   2682   } else {
   2683     Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
   2684   }
   2685 
   2686   do {
   2687 
   2688     AltStatusRegister = ReadPortB (
   2689                           AtapiScsiPrivate->PciIo,
   2690                           AtapiScsiPrivate->IoPort->Alt.AltStatus
   2691                           );
   2692 
   2693     //
   2694     // wait for BSY == 0 and DRQ == 0
   2695     //
   2696     if ((AltStatusRegister & (DRQ | BSY)) == 0) {
   2697       break;
   2698     }
   2699 
   2700     if ((AltStatusRegister & (BSY | ERR)) == ERR) {
   2701 
   2702       ErrRegister = ReadPortB (
   2703                       AtapiScsiPrivate->PciIo,
   2704                       AtapiScsiPrivate->IoPort->Reg1.Error
   2705                       );
   2706       if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
   2707 
   2708         return EFI_ABORTED;
   2709       }
   2710     }
   2711     //
   2712     //  Stall for 30 us
   2713     //
   2714     gBS->Stall (30);
   2715 
   2716     //
   2717     // Loop infinitely if not meeting expected condition
   2718     //
   2719     if (TimeoutInMicroSeconds == 0) {
   2720       Delay = 2;
   2721     }
   2722 
   2723     Delay--;
   2724   } while (Delay);
   2725 
   2726   if (Delay == 0) {
   2727     return EFI_TIMEOUT;
   2728   }
   2729 
   2730   return EFI_SUCCESS;
   2731 }
   2732 
   2733 EFI_STATUS
   2734 StatusDRQReady (
   2735   ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,
   2736   UINT64                          TimeoutInMicroSeconds
   2737   )
   2738 /*++
   2739 
   2740 Routine Description:
   2741 
   2742   Check whether DRQ is ready in the Status Register. (BSY must also be cleared)
   2743   If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
   2744   DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
   2745   elapsed.
   2746 
   2747 Arguments:
   2748 
   2749   AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
   2750   TimeoutInMicroSeconds       - The time to wait for
   2751 
   2752 Returns:
   2753 
   2754   EFI_STATUS
   2755 
   2756 --*/
   2757 {
   2758   UINT64  Delay;
   2759   UINT8   StatusRegister;
   2760   UINT8   ErrRegister;
   2761 
   2762   if (TimeoutInMicroSeconds == 0) {
   2763     Delay = 2;
   2764   } else {
   2765     Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
   2766   }
   2767 
   2768   do {
   2769     //
   2770     //  read Status Register will clear interrupt
   2771     //
   2772     StatusRegister = ReadPortB (
   2773                       AtapiScsiPrivate->PciIo,
   2774                       AtapiScsiPrivate->IoPort->Reg.Status
   2775                       );
   2776 
   2777     //
   2778     //  BSY==0,DRQ==1
   2779     //
   2780     if ((StatusRegister & (BSY | DRQ)) == DRQ) {
   2781       break;
   2782     }
   2783 
   2784     if ((StatusRegister & (BSY | ERR)) == ERR) {
   2785 
   2786       ErrRegister = ReadPortB (
   2787                       AtapiScsiPrivate->PciIo,
   2788                       AtapiScsiPrivate->IoPort->Reg1.Error
   2789                       );
   2790       if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
   2791         return EFI_ABORTED;
   2792       }
   2793     }
   2794 
   2795     //
   2796     // Stall for 30 us
   2797     //
   2798     gBS->Stall (30);
   2799 
   2800     //
   2801     // Loop infinitely if not meeting expected condition
   2802     //
   2803     if (TimeoutInMicroSeconds == 0) {
   2804       Delay = 2;
   2805     }
   2806 
   2807     Delay--;
   2808   } while (Delay);
   2809 
   2810   if (Delay == 0) {
   2811     return EFI_TIMEOUT;
   2812   }
   2813 
   2814   return EFI_SUCCESS;
   2815 }
   2816 
   2817 EFI_STATUS
   2818 AltStatusDRQReady (
   2819   ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,
   2820   UINT64                          TimeoutInMicroSeconds
   2821   )
   2822 /*++
   2823 
   2824 Routine Description:
   2825 
   2826   Check whether DRQ is ready in the Alternate Status Register.
   2827   (BSY must also be cleared)
   2828   If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
   2829   DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
   2830   elapsed.
   2831 
   2832 Arguments:
   2833 
   2834   AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
   2835   TimeoutInMicroSeconds       - The time to wait for
   2836 
   2837 Returns:
   2838 
   2839   EFI_STATUS
   2840 
   2841 --*/
   2842 {
   2843   UINT64  Delay;
   2844   UINT8   AltStatusRegister;
   2845   UINT8   ErrRegister;
   2846 
   2847   if (TimeoutInMicroSeconds == 0) {
   2848     Delay = 2;
   2849   } else {
   2850     Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
   2851   }
   2852 
   2853   do {
   2854     //
   2855     //  read Status Register will clear interrupt
   2856     //
   2857     AltStatusRegister = ReadPortB (
   2858                           AtapiScsiPrivate->PciIo,
   2859                           AtapiScsiPrivate->IoPort->Alt.AltStatus
   2860                           );
   2861     //
   2862     //  BSY==0,DRQ==1
   2863     //
   2864     if ((AltStatusRegister & (BSY | DRQ)) == DRQ) {
   2865       break;
   2866     }
   2867 
   2868     if ((AltStatusRegister & (BSY | ERR)) == ERR) {
   2869 
   2870       ErrRegister = ReadPortB (
   2871                       AtapiScsiPrivate->PciIo,
   2872                       AtapiScsiPrivate->IoPort->Reg1.Error
   2873                       );
   2874       if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
   2875         return EFI_ABORTED;
   2876       }
   2877     }
   2878 
   2879     //
   2880     // Stall for 30 us
   2881     //
   2882     gBS->Stall (30);
   2883 
   2884     //
   2885     // Loop infinitely if not meeting expected condition
   2886     //
   2887     if (TimeoutInMicroSeconds == 0) {
   2888       Delay = 2;
   2889     }
   2890 
   2891     Delay--;
   2892   } while (Delay);
   2893 
   2894   if (Delay == 0) {
   2895     return EFI_TIMEOUT;
   2896   }
   2897 
   2898   return EFI_SUCCESS;
   2899 }
   2900 
   2901 EFI_STATUS
   2902 StatusWaitForBSYClear (
   2903   ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,
   2904   UINT64                      TimeoutInMicroSeconds
   2905   )
   2906 /*++
   2907 
   2908 Routine Description:
   2909 
   2910   Check whether BSY is clear in the Status Register.
   2911   If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
   2912   BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
   2913   elapsed.
   2914 
   2915 Arguments:
   2916 
   2917   AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
   2918   TimeoutInMicroSeconds       - The time to wait for
   2919 
   2920 Returns:
   2921 
   2922   EFI_STATUS
   2923 
   2924 --*/
   2925 {
   2926   UINT64  Delay;
   2927   UINT8   StatusRegister;
   2928 
   2929   if (TimeoutInMicroSeconds == 0) {
   2930     Delay = 2;
   2931   } else {
   2932     Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
   2933   }
   2934 
   2935   do {
   2936 
   2937     StatusRegister = ReadPortB (
   2938                       AtapiScsiPrivate->PciIo,
   2939                       AtapiScsiPrivate->IoPort->Reg.Status
   2940                       );
   2941     if ((StatusRegister & BSY) == 0x00) {
   2942       break;
   2943     }
   2944 
   2945     //
   2946     // Stall for 30 us
   2947     //
   2948     gBS->Stall (30);
   2949 
   2950     //
   2951     // Loop infinitely if not meeting expected condition
   2952     //
   2953     if (TimeoutInMicroSeconds == 0) {
   2954       Delay = 2;
   2955     }
   2956 
   2957     Delay--;
   2958   } while (Delay);
   2959 
   2960   if (Delay == 0) {
   2961     return EFI_TIMEOUT;
   2962   }
   2963 
   2964   return EFI_SUCCESS;
   2965 }
   2966 
   2967 EFI_STATUS
   2968 AltStatusWaitForBSYClear (
   2969   ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,
   2970   UINT64                      TimeoutInMicroSeconds
   2971   )
   2972 /*++
   2973 
   2974 Routine Description:
   2975 
   2976   Check whether BSY is clear in the Alternate Status Register.
   2977   If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
   2978   BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
   2979   elapsed.
   2980 
   2981 Arguments:
   2982 
   2983   AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
   2984   TimeoutInMicroSeconds       - The time to wait for
   2985 
   2986 Returns:
   2987 
   2988   EFI_STATUS
   2989 
   2990 --*/
   2991 {
   2992   UINT64  Delay;
   2993   UINT8   AltStatusRegister;
   2994 
   2995   if (TimeoutInMicroSeconds == 0) {
   2996     Delay = 2;
   2997   } else {
   2998     Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
   2999   }
   3000 
   3001   do {
   3002 
   3003     AltStatusRegister = ReadPortB (
   3004                           AtapiScsiPrivate->PciIo,
   3005                           AtapiScsiPrivate->IoPort->Alt.AltStatus
   3006                           );
   3007     if ((AltStatusRegister & BSY) == 0x00) {
   3008       break;
   3009     }
   3010 
   3011     //
   3012     // Stall for 30 us
   3013     //
   3014     gBS->Stall (30);
   3015     //
   3016     // Loop infinitely if not meeting expected condition
   3017     //
   3018     if (TimeoutInMicroSeconds == 0) {
   3019       Delay = 2;
   3020     }
   3021 
   3022     Delay--;
   3023   } while (Delay);
   3024 
   3025   if (Delay == 0) {
   3026     return EFI_TIMEOUT;
   3027   }
   3028 
   3029   return EFI_SUCCESS;
   3030 }
   3031 
   3032 EFI_STATUS
   3033 StatusDRDYReady (
   3034   ATAPI_SCSI_PASS_THRU_DEV     *AtapiScsiPrivate,
   3035   UINT64                       TimeoutInMicroSeconds
   3036   )
   3037 /*++
   3038 
   3039 Routine Description:
   3040 
   3041   Check whether DRDY is ready in the Status Register.
   3042   (BSY must also be cleared)
   3043   If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
   3044   DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
   3045   elapsed.
   3046 
   3047 Arguments:
   3048 
   3049   AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
   3050   TimeoutInMicroSeconds       - The time to wait for
   3051 
   3052 Returns:
   3053 
   3054   EFI_STATUS
   3055 
   3056 --*/
   3057 {
   3058   UINT64  Delay;
   3059   UINT8   StatusRegister;
   3060   UINT8   ErrRegister;
   3061 
   3062   if (TimeoutInMicroSeconds == 0) {
   3063     Delay = 2;
   3064   } else {
   3065     Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
   3066   }
   3067 
   3068   do {
   3069     StatusRegister = ReadPortB (
   3070                       AtapiScsiPrivate->PciIo,
   3071                       AtapiScsiPrivate->IoPort->Reg.Status
   3072                       );
   3073     //
   3074     //  BSY == 0 , DRDY == 1
   3075     //
   3076     if ((StatusRegister & (DRDY | BSY)) == DRDY) {
   3077       break;
   3078     }
   3079 
   3080     if ((StatusRegister & (BSY | ERR)) == ERR) {
   3081 
   3082       ErrRegister = ReadPortB (
   3083                       AtapiScsiPrivate->PciIo,
   3084                       AtapiScsiPrivate->IoPort->Reg1.Error
   3085                       );
   3086       if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
   3087         return EFI_ABORTED;
   3088       }
   3089     }
   3090 
   3091     //
   3092     // Stall for 30 us
   3093     //
   3094     gBS->Stall (30);
   3095     //
   3096     // Loop infinitely if not meeting expected condition
   3097     //
   3098     if (TimeoutInMicroSeconds == 0) {
   3099       Delay = 2;
   3100     }
   3101 
   3102     Delay--;
   3103   } while (Delay);
   3104 
   3105   if (Delay == 0) {
   3106     return EFI_TIMEOUT;
   3107   }
   3108 
   3109   return EFI_SUCCESS;
   3110 }
   3111 
   3112 EFI_STATUS
   3113 AltStatusDRDYReady (
   3114   ATAPI_SCSI_PASS_THRU_DEV     *AtapiScsiPrivate,
   3115   UINT64                       TimeoutInMicroSeconds
   3116   )
   3117 /*++
   3118 
   3119 Routine Description:
   3120 
   3121   Check whether DRDY is ready in the Alternate Status Register.
   3122   (BSY must also be cleared)
   3123   If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
   3124   DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
   3125   elapsed.
   3126 
   3127 Arguments:
   3128 
   3129   AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
   3130   TimeoutInMicroSeconds       - The time to wait for
   3131 
   3132 Returns:
   3133 
   3134   EFI_STATUS
   3135 
   3136 --*/
   3137 {
   3138   UINT64  Delay;
   3139   UINT8   AltStatusRegister;
   3140   UINT8   ErrRegister;
   3141 
   3142   if (TimeoutInMicroSeconds == 0) {
   3143     Delay = 2;
   3144   } else {
   3145     Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
   3146   }
   3147 
   3148   do {
   3149     AltStatusRegister = ReadPortB (
   3150                           AtapiScsiPrivate->PciIo,
   3151                           AtapiScsiPrivate->IoPort->Alt.AltStatus
   3152                           );
   3153     //
   3154     //  BSY == 0 , DRDY == 1
   3155     //
   3156     if ((AltStatusRegister & (DRDY | BSY)) == DRDY) {
   3157       break;
   3158     }
   3159 
   3160     if ((AltStatusRegister & (BSY | ERR)) == ERR) {
   3161 
   3162       ErrRegister = ReadPortB (
   3163                       AtapiScsiPrivate->PciIo,
   3164                       AtapiScsiPrivate->IoPort->Reg1.Error
   3165                       );
   3166       if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
   3167         return EFI_ABORTED;
   3168       }
   3169     }
   3170 
   3171     //
   3172     // Stall for 30 us
   3173     //
   3174     gBS->Stall (30);
   3175     //
   3176     // Loop infinitely if not meeting expected condition
   3177     //
   3178     if (TimeoutInMicroSeconds == 0) {
   3179       Delay = 2;
   3180     }
   3181 
   3182     Delay--;
   3183   } while (Delay);
   3184 
   3185   if (Delay == 0) {
   3186     return EFI_TIMEOUT;
   3187   }
   3188 
   3189   return EFI_SUCCESS;
   3190 }
   3191 
   3192 EFI_STATUS
   3193 AtapiPassThruCheckErrorStatus (
   3194   ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate
   3195   )
   3196 /*++
   3197 
   3198 Routine Description:
   3199 
   3200   Check Error Register for Error Information.
   3201 
   3202 Arguments:
   3203 
   3204   AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
   3205 
   3206 Returns:
   3207 
   3208   EFI_STATUS
   3209 
   3210 --*/
   3211 {
   3212   UINT8 StatusRegister;
   3213   UINT8 ErrorRegister;
   3214 
   3215   StatusRegister = ReadPortB (
   3216                     AtapiScsiPrivate->PciIo,
   3217                     AtapiScsiPrivate->IoPort->Reg.Status
   3218                     );
   3219 
   3220   DEBUG_CODE_BEGIN ();
   3221 
   3222     if (StatusRegister & DWF) {
   3223       DEBUG (
   3224         (EFI_D_BLKIO,
   3225         "AtapiPassThruCheckErrorStatus()-- %02x : Error : Write Fault\n",
   3226         StatusRegister)
   3227         );
   3228     }
   3229 
   3230     if (StatusRegister & CORR) {
   3231       DEBUG (
   3232         (EFI_D_BLKIO,
   3233         "AtapiPassThruCheckErrorStatus()-- %02x : Error : Corrected Data\n",
   3234         StatusRegister)
   3235         );
   3236     }
   3237 
   3238     if (StatusRegister & ERR) {
   3239       ErrorRegister = ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg1.Error);
   3240 
   3241 
   3242       if (ErrorRegister & BBK_ERR) {
   3243         DEBUG (
   3244           (EFI_D_BLKIO,
   3245           "AtapiPassThruCheckErrorStatus()-- %02x : Error : Bad Block Detected\n",
   3246           ErrorRegister)
   3247           );
   3248       }
   3249 
   3250       if (ErrorRegister & UNC_ERR) {
   3251         DEBUG (
   3252           (EFI_D_BLKIO,
   3253           "AtapiPassThruCheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",
   3254           ErrorRegister)
   3255           );
   3256       }
   3257 
   3258       if (ErrorRegister & MC_ERR) {
   3259         DEBUG (
   3260           (EFI_D_BLKIO,
   3261           "AtapiPassThruCheckErrorStatus()-- %02x : Error : Media Change\n",
   3262           ErrorRegister)
   3263           );
   3264       }
   3265 
   3266       if (ErrorRegister & ABRT_ERR) {
   3267         DEBUG (
   3268           (EFI_D_BLKIO,
   3269           "AtapiPassThruCheckErrorStatus()-- %02x : Error : Abort\n",
   3270           ErrorRegister)
   3271           );
   3272       }
   3273 
   3274       if (ErrorRegister & TK0NF_ERR) {
   3275         DEBUG (
   3276           (EFI_D_BLKIO,
   3277           "AtapiPassThruCheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",
   3278           ErrorRegister)
   3279           );
   3280       }
   3281 
   3282       if (ErrorRegister & AMNF_ERR) {
   3283         DEBUG (
   3284           (EFI_D_BLKIO,
   3285           "AtapiPassThruCheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",
   3286           ErrorRegister)
   3287           );
   3288        }
   3289     }
   3290 
   3291   DEBUG_CODE_END ();
   3292 
   3293   if ((StatusRegister & (ERR | DWF | CORR)) == 0) {
   3294     return EFI_SUCCESS;
   3295   }
   3296 
   3297 
   3298   return EFI_DEVICE_ERROR;
   3299 }
   3300 
   3301 
   3302 /**
   3303   Installs Scsi Pass Thru and/or Ext Scsi Pass Thru
   3304   protocols based on feature flags.
   3305 
   3306   @param Controller         The controller handle to
   3307                             install these protocols on.
   3308   @param AtapiScsiPrivate   A pointer to the protocol private
   3309                             data structure.
   3310 
   3311   @retval EFI_SUCCESS       The installation succeeds.
   3312   @retval other             The installation fails.
   3313 
   3314 **/
   3315 EFI_STATUS
   3316 InstallScsiPassThruProtocols (
   3317   IN EFI_HANDLE                     *ControllerHandle,
   3318   IN ATAPI_SCSI_PASS_THRU_DEV       *AtapiScsiPrivate
   3319   )
   3320 {
   3321   EFI_STATUS                        Status;
   3322   EFI_SCSI_PASS_THRU_PROTOCOL       *ScsiPassThru;
   3323   EFI_EXT_SCSI_PASS_THRU_PROTOCOL   *ExtScsiPassThru;
   3324 
   3325   ScsiPassThru = &AtapiScsiPrivate->ScsiPassThru;
   3326   ExtScsiPassThru = &AtapiScsiPrivate->ExtScsiPassThru;
   3327 
   3328   if (FeaturePcdGet (PcdSupportScsiPassThru)) {
   3329     ScsiPassThru = CopyMem (ScsiPassThru, &gScsiPassThruProtocolTemplate, sizeof (*ScsiPassThru));
   3330     if (FeaturePcdGet (PcdSupportExtScsiPassThru)) {
   3331       ExtScsiPassThru = CopyMem (ExtScsiPassThru, &gExtScsiPassThruProtocolTemplate, sizeof (*ExtScsiPassThru));
   3332       Status = gBS->InstallMultipleProtocolInterfaces (
   3333                       ControllerHandle,
   3334                       &gEfiScsiPassThruProtocolGuid,
   3335                       ScsiPassThru,
   3336                       &gEfiExtScsiPassThruProtocolGuid,
   3337                       ExtScsiPassThru,
   3338                       NULL
   3339                       );
   3340     } else {
   3341       Status = gBS->InstallMultipleProtocolInterfaces (
   3342                       ControllerHandle,
   3343                       &gEfiScsiPassThruProtocolGuid,
   3344                       ScsiPassThru,
   3345                       NULL
   3346                       );
   3347     }
   3348   } else {
   3349     if (FeaturePcdGet (PcdSupportExtScsiPassThru)) {
   3350       ExtScsiPassThru = CopyMem (ExtScsiPassThru, &gExtScsiPassThruProtocolTemplate, sizeof (*ExtScsiPassThru));
   3351       Status = gBS->InstallMultipleProtocolInterfaces (
   3352                       ControllerHandle,
   3353                       &gEfiExtScsiPassThruProtocolGuid,
   3354                       ExtScsiPassThru,
   3355                       NULL
   3356                       );
   3357     } else {
   3358       //
   3359       // This driver must support either ScsiPassThru or
   3360       // ExtScsiPassThru protocols
   3361       //
   3362       ASSERT (FALSE);
   3363       Status = EFI_UNSUPPORTED;
   3364     }
   3365   }
   3366 
   3367   return Status;
   3368 }
   3369 
   3370 /**
   3371   The user Entry Point for module AtapiPassThru. The user code starts with this function.
   3372 
   3373   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
   3374   @param[in] SystemTable    A pointer to the EFI System Table.
   3375 
   3376   @retval EFI_SUCCESS       The entry point is executed successfully.
   3377   @retval other             Some error occurs when executing this entry point.
   3378 
   3379 **/
   3380 EFI_STATUS
   3381 EFIAPI
   3382 InitializeAtapiPassThru(
   3383   IN EFI_HANDLE           ImageHandle,
   3384   IN EFI_SYSTEM_TABLE     *SystemTable
   3385   )
   3386 {
   3387   EFI_STATUS              Status;
   3388 
   3389   //
   3390   // Install driver model protocol(s).
   3391   //
   3392   Status = EfiLibInstallDriverBindingComponentName2 (
   3393              ImageHandle,
   3394              SystemTable,
   3395              &gAtapiScsiPassThruDriverBinding,
   3396              ImageHandle,
   3397              &gAtapiScsiPassThruComponentName,
   3398              &gAtapiScsiPassThruComponentName2
   3399              );
   3400   ASSERT_EFI_ERROR (Status);
   3401 
   3402   //
   3403   // Install EFI Driver Supported EFI Version Protocol required for
   3404   // EFI drivers that are on PCI and other plug in cards.
   3405   //
   3406   gAtapiScsiPassThruDriverSupportedEfiVersion.FirmwareVersion = PcdGet32 (PcdDriverSupportedEfiVersion);
   3407   Status = gBS->InstallMultipleProtocolInterfaces (
   3408                   &ImageHandle,
   3409                   &gEfiDriverSupportedEfiVersionProtocolGuid,
   3410                   &gAtapiScsiPassThruDriverSupportedEfiVersion,
   3411                   NULL
   3412                   );
   3413   ASSERT_EFI_ERROR (Status);
   3414 
   3415   return Status;
   3416 }
   3417