]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AtaAtapiPassThru / AtaAtapiPassThru.c
index c397a04cf702b65334138e299e7929d821f4d6db..e5b8f40d03b385624117fc9f477c5711b633731f 100644 (file)
@@ -2,14 +2,8 @@
   This file implements ATA_PASSTHRU_PROCTOCOL and EXT_SCSI_PASSTHRU_PROTOCOL interfaces\r
   for managed ATA controllers.\r
 \r
-  Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR>\r
-  This program and the accompanying materials\r
-  are licensed and made available under the terms and conditions of the BSD License\r
-  which accompanies this distribution.  The full text of the license may be found at\r
-  http://opensource.org/licenses/bsd-license.php\r
-\r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+  Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -94,6 +88,7 @@ ATA_ATAPI_PASS_THRU_INSTANCE gAtaAtapiPassThruInstanceTemplate = {
     NULL,\r
     NULL\r
   },\r
+  0,                  // EnabledPciAttributes\r
   0,                  // OriginalAttributes\r
   0,                  // PreviousPort\r
   0,                  // PreviousPortMultiplier\r
@@ -141,6 +136,15 @@ UINT8 mScsiId[TARGET_MAX_BYTES] = {
   0xFF, 0xFF, 0xFF, 0xFF\r
 };\r
 \r
+EDKII_ATA_ATAPI_POLICY_PROTOCOL *mAtaAtapiPolicy;\r
+EDKII_ATA_ATAPI_POLICY_PROTOCOL mDefaultAtaAtapiPolicy = {\r
+  EDKII_ATA_ATAPI_POLICY_VERSION,\r
+  2,  // PuisEnable\r
+  0,  // DeviceSleepEnable\r
+  0,  // AggressiveDeviceSleepEnable\r
+  0   // Reserved\r
+};\r
+\r
 /**\r
   Sends an ATA command to an ATA device that is attached to the ATA controller. This function\r
   supports both blocking I/O and non-blocking I/O. The blocking I/O functionality is required,\r
@@ -148,7 +152,7 @@ UINT8 mScsiId[TARGET_MAX_BYTES] = {
 \r
   @param[in]      Port               The port number of the ATA device to send the command.\r
   @param[in]      PortMultiplierPort The port multiplier port number of the ATA device to send the command.\r
-                                     If there is no port multiplier, then specify 0.\r
+                                     If there is no port multiplier, then specify 0xFFFF.\r
   @param[in, out] Packet             A pointer to the ATA command to send to the ATA device specified by Port\r
                                      and PortMultiplierPort.\r
   @param[in]      Instance           Pointer to the ATA_ATAPI_PASS_THRU_INSTANCE.\r
@@ -272,6 +276,14 @@ AtaPassThruPassThruExecute (
       }\r
       break;\r
     case EfiAtaAhciMode :\r
+      if (PortMultiplierPort == 0xFFFF) {\r
+        //\r
+        // If there is no port multiplier, PortMultiplierPort will be 0xFFFF\r
+        // according to UEFI spec. Here, we convert its value to 0 to follow\r
+        // AHCI spec.\r
+        //\r
+        PortMultiplierPort = 0;\r
+      }\r
       switch (Protocol) {\r
         case EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA:\r
           Status = AhciNonDataTransfer (\r
@@ -662,7 +674,7 @@ AtaAtapiPassThruStart (
   EFI_IDE_CONTROLLER_INIT_PROTOCOL  *IdeControllerInit;\r
   ATA_ATAPI_PASS_THRU_INSTANCE      *Instance;\r
   EFI_PCI_IO_PROTOCOL               *PciIo;\r
-  UINT64                            Supports;\r
+  UINT64                            EnabledPciAttributes;\r
   UINT64                            OriginalPciAttributes;\r
 \r
   Status                = EFI_SUCCESS;\r
@@ -714,14 +726,14 @@ AtaAtapiPassThruStart (
                     PciIo,\r
                     EfiPciIoAttributeOperationSupported,\r
                     0,\r
-                    &Supports\r
+                    &EnabledPciAttributes\r
                     );\r
   if (!EFI_ERROR (Status)) {\r
-    Supports &= EFI_PCI_DEVICE_ENABLE;\r
+    EnabledPciAttributes &= (UINT64)EFI_PCI_DEVICE_ENABLE;\r
     Status = PciIo->Attributes (\r
                       PciIo,\r
                       EfiPciIoAttributeOperationEnable,\r
-                      Supports,\r
+                      EnabledPciAttributes,\r
                       NULL\r
                       );\r
   }\r
@@ -730,6 +742,14 @@ AtaAtapiPassThruStart (
     goto ErrorExit;\r
   }\r
 \r
+  Status = gBS->LocateProtocol (&gEdkiiAtaAtapiPolicyProtocolGuid, NULL, (VOID **)&mAtaAtapiPolicy);\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // If there is no AtaAtapiPolicy exposed, use the default policy.\r
+    //\r
+    mAtaAtapiPolicy = &mDefaultAtaAtapiPolicy;\r
+  }\r
+\r
   //\r
   // Allocate a buffer to store the ATA_ATAPI_PASS_THRU_INSTANCE data structure\r
   //\r
@@ -741,6 +761,7 @@ AtaAtapiPassThruStart (
   Instance->ControllerHandle      = Controller;\r
   Instance->IdeControllerInit     = IdeControllerInit;\r
   Instance->PciIo                 = PciIo;\r
+  Instance->EnabledPciAttributes  = EnabledPciAttributes;\r
   Instance->OriginalPciAttributes = OriginalPciAttributes;\r
   Instance->AtaPassThru.Mode      = &Instance->AtaPassThruMode;\r
   Instance->ExtScsiPassThru.Mode  = &Instance->ExtScsiPassThruMode;\r
@@ -800,12 +821,11 @@ ErrorExit:
     gBS->CloseEvent (Instance->TimerEvent);\r
   }\r
 \r
-  //\r
-  // Remove all inserted ATA devices.\r
-  //\r
-  DestroyDeviceInfoList(Instance);\r
-\r
   if (Instance != NULL) {\r
+    //\r
+    // Remove all inserted ATA devices.\r
+    //\r
+    DestroyDeviceInfoList (Instance);\r
     FreePool (Instance);\r
   }\r
   return EFI_UNSUPPORTED;\r
@@ -851,7 +871,6 @@ AtaAtapiPassThruStop (
   EFI_ATA_PASS_THRU_PROTOCOL        *AtaPassThru;\r
   EFI_PCI_IO_PROTOCOL               *PciIo;\r
   EFI_AHCI_REGISTERS                *AhciRegisters;\r
-  UINT64                            Supports;\r
 \r
   DEBUG ((EFI_D_INFO, "==AtaAtapiPassThru Stop== Controller = %x\n", Controller));\r
 \r
@@ -904,12 +923,22 @@ AtaAtapiPassThruStop (
   //\r
   DestroyDeviceInfoList (Instance);\r
 \r
+  PciIo = Instance->PciIo;\r
+\r
+  //\r
+  // Disable this ATA host controller.\r
+  //\r
+  PciIo->Attributes (\r
+           PciIo,\r
+           EfiPciIoAttributeOperationDisable,\r
+           Instance->EnabledPciAttributes,\r
+           NULL\r
+           );\r
+\r
   //\r
   // If the current working mode is AHCI mode, then pre-allocated resource\r
   // for AHCI initialization should be released.\r
   //\r
-  PciIo = Instance->PciIo;\r
-\r
   if (Instance->Mode == EfiAtaAhciMode) {\r
     AhciRegisters = &Instance->AhciRegisters;\r
     PciIo->Unmap (\r
@@ -941,25 +970,6 @@ AtaAtapiPassThruStop (
              );\r
   }\r
 \r
-  //\r
-  // Disable this ATA host controller.\r
-  //\r
-  Status = PciIo->Attributes (\r
-                    PciIo,\r
-                    EfiPciIoAttributeOperationSupported,\r
-                    0,\r
-                    &Supports\r
-                    );\r
-  if (!EFI_ERROR (Status)) {\r
-    Supports &= EFI_PCI_DEVICE_ENABLE;\r
-    PciIo->Attributes (\r
-             PciIo,\r
-             EfiPciIoAttributeOperationDisable,\r
-             Supports,\r
-             NULL\r
-             );\r
-  }\r
-\r
   //\r
   // Restore original PCI attributes\r
   //\r
@@ -982,7 +992,7 @@ AtaAtapiPassThruStop (
   @param[in]  Instance            A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
   @param[in]  Port                The port number of the ATA device to send the command.\r
   @param[in]  PortMultiplierPort  The port multiplier port number of the ATA device to send the command.\r
-                                  If there is no port multiplier, then specify 0.\r
+                                  If there is no port multiplier, then specify 0xFFFF.\r
   @param[in]  DeviceType          The device type of the ATA device.\r
 \r
   @retval     The pointer to the data structure of the device info to access.\r
@@ -1004,6 +1014,18 @@ SearchDeviceInfoList (
   while (!IsNull (&Instance->DeviceList, Node)) {\r
     DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);\r
 \r
+    //\r
+    // For CD-ROM working in the AHCI mode, only 8 bits are used to record\r
+    // the PortMultiplier information. If the CD-ROM is directly attached\r
+    // on a SATA port, the PortMultiplier should be translated from 0xFF\r
+    // to 0xFFFF according to the UEFI spec.\r
+    //\r
+    if ((Instance->Mode == EfiAtaAhciMode) &&\r
+        (DeviceInfo->Type == EfiIdeCdrom) &&\r
+        (PortMultiplier == 0xFF)) {\r
+        PortMultiplier = 0xFFFF;\r
+    }\r
+\r
     if ((DeviceInfo->Type == DeviceType) &&\r
         (Port == DeviceInfo->Port) &&\r
         (PortMultiplier == DeviceInfo->PortMultiplier)) {\r
@@ -1023,7 +1045,7 @@ SearchDeviceInfoList (
   @param[in]  Instance            A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
   @param[in]  Port                The port number of the ATA device to send the command.\r
   @param[in]  PortMultiplierPort  The port multiplier port number of the ATA device to send the command.\r
-                                  If there is no port multiplier, then specify 0.\r
+                                  If there is no port multiplier, then specify 0xFFFF.\r
   @param[in]  DeviceType          The device type of the ATA device.\r
   @param[in]  IdentifyData        The data buffer to store the output of the IDENTIFY cmd.\r
 \r
@@ -1216,7 +1238,7 @@ Done:
   @param[in]      This               A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.\r
   @param[in]      Port               The port number of the ATA device to send the command.\r
   @param[in]      PortMultiplierPort The port multiplier port number of the ATA device to send the command.\r
-                                     If there is no port multiplier, then specify 0.\r
+                                     If there is no port multiplier, then specify 0xFFFF.\r
   @param[in, out] Packet             A pointer to the ATA command to send to the ATA device specified by Port\r
                                      and PortMultiplierPort.\r
   @param[in]      Event               If non-blocking I/O is not supported then Event is ignored, and blocking\r
@@ -1255,6 +1277,7 @@ AtaPassThruPassThru (
   UINT32                          MaxSectorCount;\r
   ATA_NONBLOCK_TASK               *Task;\r
   EFI_TPL                         OldTpl;\r
+  UINT32                          BlockSize;\r
 \r
   Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);\r
 \r
@@ -1279,22 +1302,6 @@ AtaPassThruPassThru (
     }\r
   }\r
 \r
-  //\r
-  // convert the transfer length from sector count to byte.\r
-  //\r
-  if (((Packet->Length & EFI_ATA_PASS_THRU_LENGTH_BYTES) == 0) &&\r
-       (Packet->InTransferLength != 0)) {\r
-    Packet->InTransferLength = Packet->InTransferLength * 0x200;\r
-  }\r
-\r
-  //\r
-  // convert the transfer length from sector count to byte.\r
-  //\r
-  if (((Packet->Length & EFI_ATA_PASS_THRU_LENGTH_BYTES) == 0) &&\r
-       (Packet->OutTransferLength != 0)) {\r
-    Packet->OutTransferLength = Packet->OutTransferLength * 0x200;\r
-  }\r
-\r
   //\r
   // Check whether this device needs 48-bit addressing (ATAPI-6 ata device).\r
   // Per ATA-6 spec, word83: bit15 is zero and bit14 is one.\r
@@ -1314,13 +1321,39 @@ AtaPassThruPassThru (
     }\r
   }\r
 \r
+  BlockSize = 0x200;\r
+  if ((IdentifyData->AtaData.phy_logic_sector_support & (BIT14 | BIT15)) == BIT14) {\r
+    //\r
+    // Check logical block size\r
+    //\r
+    if ((IdentifyData->AtaData.phy_logic_sector_support & BIT12) != 0) {\r
+      BlockSize = (UINT32) (((IdentifyData->AtaData.logic_sector_size_hi << 16) | IdentifyData->AtaData.logic_sector_size_lo) * sizeof (UINT16));\r
+    }\r
+  }\r
+\r
+  //\r
+  // convert the transfer length from sector count to byte.\r
+  //\r
+  if (((Packet->Length & EFI_ATA_PASS_THRU_LENGTH_BYTES) == 0) &&\r
+       (Packet->InTransferLength != 0)) {\r
+    Packet->InTransferLength = Packet->InTransferLength * BlockSize;\r
+  }\r
+\r
+  //\r
+  // convert the transfer length from sector count to byte.\r
+  //\r
+  if (((Packet->Length & EFI_ATA_PASS_THRU_LENGTH_BYTES) == 0) &&\r
+       (Packet->OutTransferLength != 0)) {\r
+    Packet->OutTransferLength = Packet->OutTransferLength * BlockSize;\r
+  }\r
+\r
   //\r
   // If the data buffer described by InDataBuffer/OutDataBuffer and InTransferLength/OutTransferLength\r
   // is too big to be transferred in a single command, then no data is transferred and EFI_BAD_BUFFER_SIZE\r
   // is returned.\r
   //\r
-  if (((Packet->InTransferLength != 0) && (Packet->InTransferLength > MaxSectorCount * 0x200)) ||\r
-      ((Packet->OutTransferLength != 0) && (Packet->OutTransferLength > MaxSectorCount * 0x200))) {\r
+  if (((Packet->InTransferLength != 0) && (Packet->InTransferLength > MaxSectorCount * BlockSize)) ||\r
+      ((Packet->OutTransferLength != 0) && (Packet->OutTransferLength > MaxSectorCount * BlockSize))) {\r
     return EFI_BAD_BUFFER_SIZE;\r
   }\r
 \r
@@ -1339,7 +1372,12 @@ AtaPassThruPassThru (
     Task->Packet         = Packet;\r
     Task->Event          = Event;\r
     Task->IsStart        = FALSE;\r
-    Task->RetryTimes     = 0;\r
+    Task->RetryTimes     = DivU64x32(Packet->Timeout, 1000) + 1;\r
+    if (Packet->Timeout == 0) {\r
+      Task->InfiniteWait = TRUE;\r
+    } else {\r
+      Task->InfiniteWait = FALSE;\r
+    }\r
 \r
     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
     InsertTailList (&Instance->NonBlockingTaskList, &Task->Link);\r
@@ -1515,17 +1553,25 @@ AtaPassThruGetNextDevice (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  if (*PortMultiplierPort == 0xFFFF) {\r
+  if (Instance->PreviousPortMultiplier == 0xFFFF) {\r
     //\r
-    // If the PortMultiplierPort is all 0xFF's, start to traverse the device list from the beginning\r
+    // If a device is directly attached on a port, previous call to this\r
+    // function will return the value 0xFFFF for PortMultiplierPort. In\r
+    // this case, there should be no more device on the port multiplier.\r
     //\r
+    Instance->PreviousPortMultiplier = 0;\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (*PortMultiplierPort == Instance->PreviousPortMultiplier) {\r
     Node = GetFirstNode (&Instance->DeviceList);\r
 \r
     while (!IsNull (&Instance->DeviceList, Node)) {\r
       DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);\r
 \r
       if ((DeviceInfo->Type == EfiIdeHarddisk) &&\r
-           (DeviceInfo->Port == Port)){\r
+           (DeviceInfo->Port == Port) &&\r
+           (DeviceInfo->PortMultiplier > *PortMultiplierPort)){\r
         *PortMultiplierPort = DeviceInfo->PortMultiplier;\r
         goto Exit;\r
       }\r
@@ -1534,15 +1580,17 @@ AtaPassThruGetNextDevice (
     }\r
 \r
     return EFI_NOT_FOUND;\r
-  } else if (*PortMultiplierPort == Instance->PreviousPortMultiplier) {\r
+  } else if (*PortMultiplierPort == 0xFFFF) {\r
+    //\r
+    // If the PortMultiplierPort is all 0xFF's, start to traverse the device list from the beginning\r
+    //\r
     Node = GetFirstNode (&Instance->DeviceList);\r
 \r
     while (!IsNull (&Instance->DeviceList, Node)) {\r
       DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);\r
 \r
       if ((DeviceInfo->Type == EfiIdeHarddisk) &&\r
-           (DeviceInfo->Port == Port) &&\r
-           (DeviceInfo->PortMultiplier > *PortMultiplierPort)){\r
+           (DeviceInfo->Port == Port)){\r
         *PortMultiplierPort = DeviceInfo->PortMultiplier;\r
         goto Exit;\r
       }\r
@@ -1585,7 +1633,7 @@ Exit:
                                      device path node is to be allocated and built.\r
   @param[in]      PortMultiplierPort The port multiplier port number of the ATA device for which a\r
                                      device path node is to be allocated and built. If there is no\r
-                                     port multiplier, then specify 0.\r
+                                     port multiplier, then specify 0xFFFF.\r
   @param[in, out] DevicePath         A pointer to a single device path node that describes the ATA\r
                                      device specified by Port and PortMultiplierPort. This function\r
                                      is responsible for allocating the buffer DevicePath with the\r
@@ -1796,7 +1844,7 @@ AtaPassThruResetPort (
   @param[in] This                A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.\r
   @param[in] Port                Port represents the port number of the ATA device to be reset.\r
   @param[in] PortMultiplierPort  The port multiplier port number of the ATA device to reset.\r
-                                 If there is no port multiplier, then specify 0.\r
+                                 If there is no port multiplier, then specify 0xFFFF.\r
   @retval EFI_SUCCESS            The ATA device specified by Port and PortMultiplierPort was reset.\r
   @retval EFI_UNSUPPORTED        The ATA controller does not support a device reset operation.\r
   @retval EFI_INVALID_PARAMETER  Port or PortMultiplierPort are invalid.\r
@@ -1831,6 +1879,57 @@ AtaPassThruResetDevice (
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Submit ATAPI request sense command.\r
+\r
+  @param[in] This            A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  @param[in] Target          The Target is an array of size TARGET_MAX_BYTES and it represents\r
+                             the id of the SCSI device to send the SCSI Request Packet. Each\r
+                             transport driver may choose to utilize a subset of this size to suit the needs\r
+                             of transport target representation. For example, a Fibre Channel driver\r
+                             may use only 8 bytes (WWN) to represent an FC target.\r
+  @param[in] Lun             The LUN of the SCSI device to send the SCSI Request Packet.\r
+  @param[in] SenseData       A pointer to store sense data.\r
+  @param[in] SenseDataLength The sense data length.\r
+  @param[in] Timeout         The timeout value to execute this cmd, uses 100ns as a unit.\r
+\r
+  @retval EFI_SUCCESS        Send out the ATAPI packet command successfully.\r
+  @retval EFI_DEVICE_ERROR   The device failed to send data.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaPacketRequestSense (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL         *This,\r
+  IN  UINT8                                   *Target,\r
+  IN  UINT64                                  Lun,\r
+  IN  VOID                                    *SenseData,\r
+  IN  UINT8                                   SenseDataLength,\r
+  IN  UINT64                                  Timeout\r
+  )\r
+{\r
+  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  Packet;\r
+  UINT8                                       Cdb[12];\r
+  EFI_STATUS                                  Status;\r
+\r
+  ZeroMem (&Packet, sizeof (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));\r
+  ZeroMem (Cdb, 12);\r
+\r
+  Cdb[0] = ATA_CMD_REQUEST_SENSE;\r
+  Cdb[4] = SenseDataLength;\r
+\r
+  Packet.Timeout          = Timeout;\r
+  Packet.Cdb              = Cdb;\r
+  Packet.CdbLength        = 12;\r
+  Packet.DataDirection    = EFI_EXT_SCSI_DATA_DIRECTION_READ;\r
+  Packet.InDataBuffer     = SenseData;\r
+  Packet.InTransferLength = SenseDataLength;\r
+\r
+  Status = ExtScsiPassThruPassThru (This, Target, Lun, &Packet, NULL);\r
+\r
+  return Status;\r
+}\r
+\r
 /**\r
   Sends a SCSI Request Packet to a SCSI device that is attached to the SCSI channel. This function\r
   supports both blocking I/O and nonblocking I/O. The blocking I/O functionality is required, and the\r
@@ -1889,8 +1988,13 @@ ExtScsiPassThruPassThru (
   EFI_ATA_HC_WORK_MODE            Mode;\r
   LIST_ENTRY                      *Node;\r
   EFI_ATA_DEVICE_INFO             *DeviceInfo;\r
+  BOOLEAN                         SenseReq;\r
+  EFI_SCSI_SENSE_DATA             *PtrSenseData;\r
+  UINTN                           SenseDataLen;\r
+  EFI_STATUS                      SenseStatus;\r
 \r
-  Instance = EXT_SCSI_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);\r
+  SenseDataLen = 0;\r
+  Instance     = EXT_SCSI_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);\r
 \r
   if ((Packet == NULL) || (Packet->Cdb == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -1904,6 +2008,10 @@ ExtScsiPassThruPassThru (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  if ((Packet->SenseDataLength != 0) && (Packet->SenseData == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
   if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->InDataBuffer, This->Mode->IoAlign)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
@@ -1951,6 +2059,10 @@ ExtScsiPassThruPassThru (
   //\r
   if (*((UINT8*)Packet->Cdb) == ATA_CMD_IDENTIFY_DEVICE) {\r
     CopyMem (Packet->InDataBuffer, DeviceInfo->IdentifyData, sizeof (EFI_IDENTIFY_DATA));\r
+    //\r
+    // For IDENTIFY DEVICE cmd, we don't need to get sense data.\r
+    //\r
+    Packet->SenseDataLength = 0;\r
     return EFI_SUCCESS;\r
   }\r
 \r
@@ -1969,6 +2081,13 @@ ExtScsiPassThruPassThru (
       Status = AtaPacketCommandExecute (Instance->PciIo, &Instance->IdeRegisters[Port], Port, PortMultiplier, Packet);\r
       break;\r
     case EfiAtaAhciMode:\r
+      if (PortMultiplier == 0xFF) {\r
+        //\r
+        // If there is no port multiplier, the PortMultiplier will be 0xFF\r
+        // Here, we convert its value to 0 to follow the AHCI spec.\r
+        //\r
+        PortMultiplier = 0;\r
+      }\r
       Status = AhciPacketCommandExecute (Instance->PciIo, &Instance->AhciRegisters, Port, PortMultiplier, Packet);\r
       break;\r
     default :\r
@@ -1976,6 +2095,46 @@ ExtScsiPassThruPassThru (
       break;\r
   }\r
 \r
+  //\r
+  // If the cmd doesn't get executed correctly, then check sense data.\r
+  //\r
+  if (EFI_ERROR (Status) && (Packet->SenseDataLength != 0) && (*((UINT8*)Packet->Cdb) != ATA_CMD_REQUEST_SENSE)) {\r
+    PtrSenseData = AllocateAlignedPages (EFI_SIZE_TO_PAGES (sizeof (EFI_SCSI_SENSE_DATA)), This->Mode->IoAlign);\r
+    if (PtrSenseData == NULL) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    for (SenseReq = TRUE; SenseReq;) {\r
+      SenseStatus = AtaPacketRequestSense (\r
+                      This,\r
+                      Target,\r
+                      Lun,\r
+                      PtrSenseData,\r
+                      sizeof (EFI_SCSI_SENSE_DATA),\r
+                      Packet->Timeout\r
+                      );\r
+      if (EFI_ERROR (SenseStatus)) {\r
+        break;\r
+      }\r
+\r
+      CopyMem ((UINT8*)Packet->SenseData + SenseDataLen, PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));\r
+      SenseDataLen += sizeof (EFI_SCSI_SENSE_DATA);\r
+\r
+      //\r
+      // no more sense key or number of sense keys exceeds predefined,\r
+      // skip the loop.\r
+      //\r
+      if ((PtrSenseData->Sense_Key == EFI_SCSI_SK_NO_SENSE) ||\r
+          (SenseDataLen + sizeof (EFI_SCSI_SENSE_DATA) > Packet->SenseDataLength)) {\r
+        SenseReq = FALSE;\r
+      }\r
+    }\r
+    FreeAlignedPages (PtrSenseData, EFI_SIZE_TO_PAGES (sizeof (EFI_SCSI_SENSE_DATA)));\r
+  }\r
+  //\r
+  // Update the SenseDataLength field to the data length received.\r
+  //\r
+  Packet->SenseDataLength = (UINT8)SenseDataLen;\r
   return Status;\r
 }\r
 \r
@@ -2066,7 +2225,7 @@ ExtScsiPassThruGetNextTargetLun (
       if ((DeviceInfo->Type == EfiIdeCdrom) &&\r
          ((Target8[0] < DeviceInfo->Port) ||\r
           ((Target8[0] == DeviceInfo->Port) &&\r
-           (Target8[1] < DeviceInfo->PortMultiplier)))) {\r
+           (Target8[1] < (UINT8)DeviceInfo->PortMultiplier)))) {\r
         Target8[0] = (UINT8)DeviceInfo->Port;\r
         Target8[1] = (UINT8)DeviceInfo->PortMultiplier;\r
         goto Exit;\r
@@ -2188,7 +2347,13 @@ ExtScsiPassThruBuildDevicePath (
     }\r
 \r
     DevicePathNode->Sata.HBAPortNumber            = Port;\r
-    DevicePathNode->Sata.PortMultiplierPortNumber = PortMultiplier;\r
+    //\r
+    // For CD-ROM working in the AHCI mode, only 8 bits are used to record\r
+    // the PortMultiplier information. If the CD-ROM is directly attached\r
+    // on a SATA port, the PortMultiplier should be translated from 0xFF\r
+    // to 0xFFFF according to the UEFI spec.\r
+    //\r
+    DevicePathNode->Sata.PortMultiplierPortNumber = PortMultiplier == 0xFF ? 0xFFFF : PortMultiplier;\r
     DevicePathNode->Sata.Lun                      = (UINT16) Lun;\r
   }\r
 \r
@@ -2442,7 +2607,7 @@ ExtScsiPassThruGetNextTarget (
       if ((DeviceInfo->Type == EfiIdeCdrom) &&\r
          ((Target8[0] < DeviceInfo->Port) ||\r
           ((Target8[0] == DeviceInfo->Port) &&\r
-           (Target8[1] < DeviceInfo->PortMultiplier)))) {\r
+           (Target8[1] < (UINT8)DeviceInfo->PortMultiplier)))) {\r
         Target8[0] = (UINT8)DeviceInfo->Port;\r
         Target8[1] = (UINT8)DeviceInfo->PortMultiplier;\r
         goto Exit;\r