]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Bus / Scsi / ScsiBusDxe / ScsiBus.c
index 1aa67c63867a654084bd215493687f1c602aea30..c4069aec0f1335850601f9c66f6149f23eae07d8 100644 (file)
@@ -2,14 +2,8 @@
   SCSI Bus driver that layers on every SCSI Pass Thru and\r
   Extended SCSI Pass Thru protocol in the system.\r
 \r
-Copyright (c) 2006 - 2010, 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) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -26,14 +20,6 @@ EFI_DRIVER_BINDING_PROTOCOL gSCSIBusDriverBinding = {
   NULL\r
 };\r
 \r
-\r
-//\r
-// The ScsiBusProtocol is just used to locate ScsiBusDev\r
-// structure in the SCSIBusDriverBindingStop(). Then we can\r
-// Close all opened protocols and release this structure.\r
-//\r
-EFI_GUID  mScsiBusProtocolGuid = EFI_SCSI_BUS_PROTOCOL_GUID;\r
-\r
 VOID  *mWorkingBuffer;\r
 \r
 /**\r
@@ -79,6 +65,49 @@ NotifyFunction (
   IN  VOID       *Context\r
   );\r
 \r
+/**\r
+  Allocates an aligned buffer for SCSI device.\r
+\r
+  This function allocates an aligned buffer for the SCSI device to perform\r
+  SCSI pass through operations. The alignment requirement is from SCSI pass\r
+  through interface.\r
+\r
+  @param  ScsiIoDevice      The SCSI child device involved for the operation.\r
+  @param  BufferSize        The request buffer size.\r
+\r
+  @return A pointer to the aligned buffer or NULL if the allocation fails.\r
+\r
+**/\r
+VOID *\r
+AllocateAlignedBuffer (\r
+  IN SCSI_IO_DEV              *ScsiIoDevice,\r
+  IN UINTN                    BufferSize\r
+  )\r
+{\r
+  return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), ScsiIoDevice->ScsiIo.IoAlign);\r
+}\r
+\r
+/**\r
+  Frees an aligned buffer for SCSI device.\r
+\r
+  This function frees an aligned buffer for the SCSI device to perform\r
+  SCSI pass through operations.\r
+\r
+  @param  Buffer            The aligned buffer to be freed.\r
+  @param  BufferSize        The request buffer size.\r
+\r
+**/\r
+VOID\r
+FreeAlignedBuffer (\r
+  IN VOID                     *Buffer,\r
+  IN UINTN                    BufferSize\r
+  )\r
+{\r
+  if (Buffer != NULL) {\r
+    FreeAlignedPages (Buffer, EFI_SIZE_TO_PAGES (BufferSize));\r
+  }\r
+}\r
+\r
 /**\r
   The user Entry Point for module ScsiBus. The user code starts with this function.\r
 \r
@@ -153,7 +182,7 @@ SCSIBusDriverBindingSupported (
   SetMem (TargetId, TARGET_MAX_BYTES, 0xFF);\r
 \r
   //\r
-  // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as \r
+  // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as\r
   // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly\r
   // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.\r
   //\r
@@ -182,7 +211,7 @@ SCSIBusDriverBindingSupported (
              &gEfiExtScsiPassThruProtocolGuid,\r
              This->DriverBindingHandle,\r
              Controller\r
-             );      \r
+             );\r
       return EFI_SUCCESS;\r
     } else {\r
       //\r
@@ -197,7 +226,7 @@ SCSIBusDriverBindingSupported (
              &gEfiExtScsiPassThruProtocolGuid,\r
              This->DriverBindingHandle,\r
              Controller\r
-             );      \r
+             );\r
       if (!EFI_ERROR(Status)) {\r
         return EFI_SUCCESS;\r
       }\r
@@ -205,7 +234,7 @@ SCSIBusDriverBindingSupported (
   }\r
 \r
   //\r
-  // Come here in 2 condition: \r
+  // Come here in 2 condition:\r
   // 1. ExtPassThru doesn't exist.\r
   // 2. ExtPassThru exists but RemainingDevicePath is invalid.\r
   //\r
@@ -217,22 +246,22 @@ SCSIBusDriverBindingSupported (
                   Controller,\r
                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
                   );\r
-  \r
+\r
   if (Status == EFI_ALREADY_STARTED) {\r
     return EFI_SUCCESS;\r
   }\r
-  \r
+\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
-  \r
+\r
   //\r
   // Test RemainingDevicePath is valid or not.\r
   //\r
   if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {\r
     Status = PassThru->GetTargetLun (PassThru, RemainingDevicePath, &ScsiTargetId.ScsiId.Scsi, &Lun);\r
   }\r
-  \r
+\r
   gBS->CloseProtocol (\r
          Controller,\r
          &gEfiScsiPassThruProtocolGuid,\r
@@ -290,10 +319,10 @@ SCSIBusDriverBindingStart (
   FromFirstTarget = FALSE;\r
   ExtScsiSupport  = FALSE;\r
   PassThruStatus  = EFI_SUCCESS;\r
-  \r
+\r
   TargetId = &ScsiTargetId.ScsiId.ExtScsi[0];\r
   SetMem (TargetId, TARGET_MAX_BYTES, 0xFF);\r
-  \r
+\r
   DevicePathStatus = gBS->OpenProtocol (\r
                             Controller,\r
                             &gEfiDevicePathProtocolGuid,\r
@@ -307,7 +336,16 @@ SCSIBusDriverBindingStart (
   }\r
 \r
   //\r
-  // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as \r
+  // Report Status Code to indicate SCSI bus starts\r
+  //\r
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+    EFI_PROGRESS_CODE,\r
+    (EFI_IO_BUS_SCSI | EFI_IOB_PC_INIT),\r
+    ParentDevicePath\r
+    );\r
+\r
+  //\r
+  // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as\r
   // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly\r
   // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.\r
   //\r
@@ -342,13 +380,13 @@ SCSIBusDriverBindingStart (
                This->DriverBindingHandle,\r
                Controller\r
                );\r
-      } \r
+      }\r
       return Status;\r
-    } \r
+    }\r
   } else {\r
     //\r
-    // Succeed to open ExtPassThru Protocol, and meanwhile open PassThru Protocol \r
-    // with BY_DRIVER if it is also present on the handle. The intent is to prevent \r
+    // Succeed to open ExtPassThru Protocol, and meanwhile open PassThru Protocol\r
+    // with BY_DRIVER if it is also present on the handle. The intent is to prevent\r
     // another SCSI Bus Driver to work on the same host handle.\r
     //\r
     ExtScsiSupport = TRUE;\r
@@ -361,7 +399,7 @@ SCSIBusDriverBindingStart (
                             EFI_OPEN_PROTOCOL_BY_DRIVER\r
                             );\r
   }\r
-    \r
+\r
   if (Status != EFI_ALREADY_STARTED) {\r
     //\r
     // Go through here means either ExtPassThru or PassThru Protocol is successfully opened\r
@@ -379,17 +417,17 @@ SCSIBusDriverBindingStart (
     if (ScsiBusDev->ExtScsiSupport) {\r
       ScsiBusDev->ExtScsiInterface = ExtScsiInterface;\r
     } else {\r
-      ScsiBusDev->ScsiInterface    = ScsiInterface;    \r
+      ScsiBusDev->ScsiInterface    = ScsiInterface;\r
     }\r
 \r
     //\r
     // Install EFI_SCSI_BUS_PROTOCOL to the controller handle, So ScsiBusDev could be\r
     // retrieved on this controller handle. With ScsiBusDev, we can know which PassThru\r
     // Protocol is present on the handle, UEFI ExtPassThru Protocol or EFI PassThru Protocol.\r
-    // \r
+    //\r
     Status = gBS->InstallProtocolInterface (\r
                     &Controller,\r
-                    &mScsiBusProtocolGuid,\r
+                    &gEfiCallerIdGuid,\r
                     EFI_NATIVE_INTERFACE,\r
                     &ScsiBusDev->BusIdentify\r
                     );\r
@@ -403,7 +441,7 @@ SCSIBusDriverBindingStart (
     //\r
     Status = gBS->OpenProtocol (\r
                     Controller,\r
-                    &mScsiBusProtocolGuid,\r
+                    &gEfiCallerIdGuid,\r
                     (VOID **) &BusIdentify,\r
                     This->DriverBindingHandle,\r
                     Controller,\r
@@ -416,20 +454,29 @@ SCSIBusDriverBindingStart (
     ScsiBusDev = SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (BusIdentify);\r
   }\r
 \r
+  //\r
+  // Report Status Code to indicate detecting devices on bus\r
+  //\r
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+    EFI_PROGRESS_CODE,\r
+    (EFI_IO_BUS_SCSI | EFI_IOB_PC_DETECT),\r
+    ParentDevicePath\r
+    );\r
+\r
   Lun  = 0;\r
   if (RemainingDevicePath == NULL) {\r
     //\r
-    // If RemainingDevicePath is NULL, \r
+    // If RemainingDevicePath is NULL,\r
     // must enumerate all SCSI devices anyway\r
     //\r
     FromFirstTarget = TRUE;\r
   } else if (!IsDevicePathEnd (RemainingDevicePath)) {\r
     //\r
-    // If RemainingDevicePath isn't the End of Device Path Node, \r
+    // If RemainingDevicePath isn't the End of Device Path Node,\r
     // only scan the specified device by RemainingDevicePath\r
     //\r
     if (ScsiBusDev->ExtScsiSupport) {\r
-      Status = ScsiBusDev->ExtScsiInterface->GetTargetLun (ScsiBusDev->ExtScsiInterface, RemainingDevicePath, &TargetId, &Lun);  \r
+      Status = ScsiBusDev->ExtScsiInterface->GetTargetLun (ScsiBusDev->ExtScsiInterface, RemainingDevicePath, &TargetId, &Lun);\r
     } else {\r
       Status = ScsiBusDev->ScsiInterface->GetTargetLun (ScsiBusDev->ScsiInterface, RemainingDevicePath, &ScsiTargetId.ScsiId.Scsi, &Lun);\r
     }\r
@@ -441,7 +488,7 @@ SCSIBusDriverBindingStart (
     //\r
     // If RemainingDevicePath is the End of Device Path Node,\r
     // skip enumerate any device and return EFI_SUCESSS\r
-    // \r
+    //\r
     ScanOtherPuns = FALSE;\r
   }\r
 \r
@@ -486,11 +533,11 @@ SCSIBusDriverBindingStart (
   return EFI_SUCCESS;\r
 \r
 ErrorExit:\r
-  \r
+\r
   if (ScsiBusDev != NULL) {\r
     FreePool (ScsiBusDev);\r
   }\r
-  \r
+\r
   if (ExtScsiSupport) {\r
     gBS->CloseProtocol (\r
            Controller,\r
@@ -525,7 +572,7 @@ ErrorExit:
   restrictions for this service. DisconnectController() must follow these\r
   calling restrictions. If any other agent wishes to call Stop() it must also\r
   follow these calling restrictions.\r
-  \r
+\r
   @param  This              Protocol instance pointer.\r
   @param  ControllerHandle  Handle of device to stop driver on\r
   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of\r
@@ -560,7 +607,7 @@ SCSIBusDriverBindingStop (
     //\r
     Status = gBS->OpenProtocol (\r
                     Controller,\r
-                    &mScsiBusProtocolGuid,\r
+                    &gEfiCallerIdGuid,\r
                     (VOID **) &Scsidentifier,\r
                     This->DriverBindingHandle,\r
                     Controller,\r
@@ -578,7 +625,7 @@ SCSIBusDriverBindingStop (
     //\r
     gBS->UninstallProtocolInterface (\r
            Controller,\r
-           &mScsiBusProtocolGuid,\r
+           &gEfiCallerIdGuid,\r
            &ScsiBusDev->BusIdentify\r
            );\r
 \r
@@ -597,7 +644,7 @@ SCSIBusDriverBindingStop (
              );\r
       //\r
       // When Start() succeeds to open ExtPassThru, it always tries to open PassThru BY_DRIVER.\r
-      // Its intent is to prevent another SCSI Bus Driver from woking on the same host handle. \r
+      // Its intent is to prevent another SCSI Bus Driver from woking on the same host handle.\r
       // So Stop() needs to try to close PassThru if present here.\r
       //\r
       gBS->CloseProtocol (\r
@@ -710,11 +757,11 @@ SCSIBusDriverBindingStop (
 \r
   @param  This          Protocol instance pointer.\r
   @param  DeviceType    A pointer to the device type information retrieved from\r
-                        the SCSI Controller. \r
+                        the SCSI Controller.\r
 \r
   @retval EFI_SUCCESS             Retrieves the device type information successfully.\r
   @retval EFI_INVALID_PARAMETER   The DeviceType is NULL.\r
-  \r
+\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
@@ -780,7 +827,7 @@ ScsiGetDeviceLocation (
   @retval  EFI_DEVICE_ERROR  Errors encountered when resetting the SCSI bus.\r
   @retval  EFI_UNSUPPORTED   The bus reset operation is not supported by the\r
                              SCSI Host Controller.\r
-  @retval  EFI_TIMEOUT       A timeout occurred while attempting to reset \r
+  @retval  EFI_TIMEOUT       A timeout occurred while attempting to reset\r
                              the SCSI bus.\r
 **/\r
 EFI_STATUS\r
@@ -793,6 +840,15 @@ ScsiResetBus (
 \r
   ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);\r
 \r
+  //\r
+  // Report Status Code to indicate reset happens\r
+  //\r
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+    EFI_PROGRESS_CODE,\r
+    (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_RESET),\r
+    ScsiIoDevice->ScsiBusDeviceData->DevicePath\r
+    );\r
+\r
   if (ScsiIoDevice->ExtScsiSupport){\r
     return ScsiIoDevice->ExtScsiPassThru->ResetChannel (ScsiIoDevice->ExtScsiPassThru);\r
   } else {\r
@@ -822,6 +878,16 @@ ScsiResetDevice (
   UINT8        Target[TARGET_MAX_BYTES];\r
 \r
   ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);\r
+\r
+  //\r
+  // Report Status Code to indicate reset happens\r
+  //\r
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+    EFI_PROGRESS_CODE,\r
+    (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_RESET),\r
+    ScsiIoDevice->ScsiBusDeviceData->DevicePath\r
+    );\r
+\r
   CopyMem (Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);\r
 \r
 \r
@@ -845,47 +911,47 @@ ScsiResetDevice (
   Sends a SCSI Request Packet to the SCSI Controller for execution.\r
 \r
   @param  This            Protocol instance pointer.\r
-  @param  CommandPacket   The SCSI request packet to send to the SCSI \r
+  @param  CommandPacket   The SCSI request packet to send to the SCSI\r
                           Controller specified by the device handle.\r
   @param  Event           If the SCSI bus where the SCSI device is attached\r
-                          does not support non-blocking I/O, then Event is \r
-                          ignored, and blocking I/O is performed.  \r
+                          does not support non-blocking I/O, then Event is\r
+                          ignored, and blocking I/O is performed.\r
                           If Event is NULL, then blocking I/O is performed.\r
-                          If Event is not NULL and non-blocking I/O is \r
+                          If Event is not NULL and non-blocking I/O is\r
                           supported, then non-blocking I/O is performed,\r
                           and Event will be signaled when the SCSI Request\r
                           Packet completes.\r
 \r
-  @retval EFI_SUCCESS         The SCSI Request Packet was sent by the host \r
-                              successfully, and TransferLength bytes were \r
-                              transferred to/from DataBuffer.See \r
-                              HostAdapterStatus, TargetStatus, \r
+  @retval EFI_SUCCESS         The SCSI Request Packet was sent by the host\r
+                              successfully, and TransferLength bytes were\r
+                              transferred to/from DataBuffer.See\r
+                              HostAdapterStatus, TargetStatus,\r
                               SenseDataLength, and SenseData in that order\r
                               for additional status information.\r
-  @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, \r
+  @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,\r
                               but the entire DataBuffer could not be transferred.\r
                               The actual number of bytes transferred is returned\r
-                              in TransferLength. See HostAdapterStatus, \r
-                              TargetStatus, SenseDataLength, and SenseData in \r
+                              in TransferLength. See HostAdapterStatus,\r
+                              TargetStatus, SenseDataLength, and SenseData in\r
                               that order for additional status information.\r
-  @retval EFI_NOT_READY       The SCSI Request Packet could not be sent because \r
-                              there are too many SCSI Command Packets already \r
+  @retval EFI_NOT_READY       The SCSI Request Packet could not be sent because\r
+                              there are too many SCSI Command Packets already\r
                               queued.The caller may retry again later.\r
-  @retval EFI_DEVICE_ERROR    A device error occurred while attempting to send \r
-                              the SCSI Request Packet. See HostAdapterStatus, \r
-                              TargetStatus, SenseDataLength, and SenseData in \r
+  @retval EFI_DEVICE_ERROR    A device error occurred while attempting to send\r
+                              the SCSI Request Packet. See HostAdapterStatus,\r
+                              TargetStatus, SenseDataLength, and SenseData in\r
                               that order for additional status information.\r
-  @retval EFI_INVALID_PARAMETER  The contents of CommandPacket are invalid.  \r
-                                 The SCSI Request Packet was not sent, so no \r
+  @retval EFI_INVALID_PARAMETER  The contents of CommandPacket are invalid.\r
+                                 The SCSI Request Packet was not sent, so no\r
                                  additional status information is available.\r
   @retval EFI_UNSUPPORTED     The command described by the SCSI Request Packet\r
-                              is not supported by the SCSI initiator(i.e., SCSI \r
+                              is not supported by the SCSI initiator(i.e., SCSI\r
                               Host Controller). The SCSI Request Packet was not\r
-                              sent, so no additional status information is \r
+                              sent, so no additional status information is\r
                               available.\r
-  @retval EFI_TIMEOUT         A timeout occurred while waiting for the SCSI \r
+  @retval EFI_TIMEOUT         A timeout occurred while waiting for the SCSI\r
                               Request Packet to execute. See HostAdapterStatus,\r
-                              TargetStatus, SenseDataLength, and SenseData in \r
+                              TargetStatus, SenseDataLength, and SenseData in\r
                               that order for additional status information.\r
 **/\r
 EFI_STATUS\r
@@ -901,10 +967,10 @@ ScsiExecuteSCSICommand (
   UINT8                                       Target[TARGET_MAX_BYTES];\r
   EFI_EVENT                                   PacketEvent;\r
   EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *ExtRequestPacket;\r
-  SCSI_EVENT_DATA                             EventData;                                     \r
+  SCSI_EVENT_DATA                             EventData;\r
 \r
   PacketEvent = NULL;\r
-  \r
+\r
   if (Packet == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
@@ -914,13 +980,35 @@ ScsiExecuteSCSICommand (
 \r
   if (ScsiIoDevice->ExtScsiSupport) {\r
     ExtRequestPacket = (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *) Packet;\r
-    Status = ScsiIoDevice->ExtScsiPassThru->PassThru (\r
-                                          ScsiIoDevice->ExtScsiPassThru,\r
-                                          Target,\r
-                                          ScsiIoDevice->Lun,\r
-                                          ExtRequestPacket,\r
-                                          Event\r
-                                          );\r
+\r
+    if (((ScsiIoDevice->ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO) != 0) && (Event !=  NULL)) {\r
+      Status = ScsiIoDevice->ExtScsiPassThru->PassThru (\r
+                                                ScsiIoDevice->ExtScsiPassThru,\r
+                                                Target,\r
+                                                ScsiIoDevice->Lun,\r
+                                                ExtRequestPacket,\r
+                                                Event\r
+                                                );\r
+    } else {\r
+      //\r
+      // If there's no event or the SCSI Device doesn't support NON-BLOCKING,\r
+      // let the 'Event' parameter for PassThru() be NULL.\r
+      //\r
+      Status = ScsiIoDevice->ExtScsiPassThru->PassThru (\r
+                                                ScsiIoDevice->ExtScsiPassThru,\r
+                                                Target,\r
+                                                ScsiIoDevice->Lun,\r
+                                                ExtRequestPacket,\r
+                                                NULL\r
+                                                );\r
+      if ((!EFI_ERROR(Status)) && (Event != NULL)) {\r
+        //\r
+        // Signal Event to tell caller to pick up the SCSI IO packet if the\r
+        // PassThru() succeeds.\r
+        //\r
+        gBS->SignalEvent (Event);\r
+      }\r
+    }\r
   } else {\r
 \r
     mWorkingBuffer = AllocatePool (sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));\r
@@ -946,7 +1034,7 @@ ScsiExecuteSCSICommand (
       //\r
       Status = gBS->CreateEvent (\r
                        EVT_NOTIFY_SIGNAL,\r
-                       TPL_CALLBACK,\r
+                       TPL_NOTIFY,\r
                        NotifyFunction,\r
                        &EventData,\r
                        &PacketEvent\r
@@ -980,7 +1068,7 @@ ScsiExecuteSCSICommand (
                                           ScsiIoDevice->Pun.ScsiId.Scsi,\r
                                           ScsiIoDevice->Lun,\r
                                           mWorkingBuffer,\r
-                                          Event\r
+                                          NULL\r
                                           );\r
       if (EFI_ERROR(Status)) {\r
         FreePool(mWorkingBuffer);\r
@@ -993,6 +1081,13 @@ ScsiExecuteSCSICommand (
       // free mWorkingBuffer.\r
       //\r
       FreePool(mWorkingBuffer);\r
+\r
+      //\r
+      // Signal Event to tell caller to pick up the SCSI IO Packet.\r
+      //\r
+      if (Event != NULL) {\r
+        gBS->SignalEvent (Event);\r
+      }\r
     }\r
   }\r
   return Status;\r
@@ -1026,13 +1121,67 @@ ScsiScanCreateDevice (
   EFI_STATUS                Status;\r
   SCSI_IO_DEV               *ScsiIoDevice;\r
   EFI_DEVICE_PATH_PROTOCOL  *ScsiDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *RemainingDevicePath;\r
+  EFI_HANDLE                 DeviceHandle;\r
+\r
+  DevicePath          = NULL;\r
+  RemainingDevicePath = NULL;\r
+  ScsiDevicePath      = NULL;\r
+  ScsiIoDevice        = NULL;\r
+\r
+  //\r
+  // Build Device Path\r
+  //\r
+  if (ScsiBusDev->ExtScsiSupport){\r
+    Status = ScsiBusDev->ExtScsiInterface->BuildDevicePath (\r
+                                             ScsiBusDev->ExtScsiInterface,\r
+                                             &TargetId->ScsiId.ExtScsi[0],\r
+                                             Lun,\r
+                                             &ScsiDevicePath\r
+                                             );\r
+  } else {\r
+    Status = ScsiBusDev->ScsiInterface->BuildDevicePath (\r
+                                          ScsiBusDev->ScsiInterface,\r
+                                          TargetId->ScsiId.Scsi,\r
+                                          Lun,\r
+                                          &ScsiDevicePath\r
+                                          );\r
+  }\r
+\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  DevicePath = AppendDevicePathNode (\r
+                 ScsiBusDev->DevicePath,\r
+                 ScsiDevicePath\r
+                 );\r
+\r
+  if (DevicePath == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ErrorExit;\r
+  }\r
+\r
+  DeviceHandle = NULL;\r
+  RemainingDevicePath = DevicePath;\r
+  Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);\r
+  if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {\r
+    //\r
+    // The device has been started, directly return to fast boot.\r
+    //\r
+    Status = EFI_ALREADY_STARTED;\r
+    goto ErrorExit;\r
+  }\r
 \r
   ScsiIoDevice = AllocateZeroPool (sizeof (SCSI_IO_DEV));\r
   if (ScsiIoDevice == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ErrorExit;\r
   }\r
 \r
   ScsiIoDevice->Signature                 = SCSI_IO_DEV_SIGNATURE;\r
+  ScsiIoDevice->ScsiBusDeviceData         = ScsiBusDev;\r
   CopyMem(&ScsiIoDevice->Pun, TargetId, TARGET_MAX_BYTES);\r
   ScsiIoDevice->Lun                       = Lun;\r
 \r
@@ -1053,52 +1202,21 @@ ScsiScanCreateDevice (
   ScsiIoDevice->ScsiIo.ResetDevice        = ScsiResetDevice;\r
   ScsiIoDevice->ScsiIo.ExecuteScsiCommand = ScsiExecuteSCSICommand;\r
 \r
-\r
-  if (!DiscoverScsiDevice (ScsiIoDevice)) {\r
-    FreePool (ScsiIoDevice);\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
-\r
   //\r
-  // Set Device Path\r
+  // Report Status Code here since the new SCSI device will be discovered\r
   //\r
-  ScsiDevicePath = NULL;\r
-  if (ScsiIoDevice->ExtScsiSupport){\r
-    Status = ScsiIoDevice->ExtScsiPassThru->BuildDevicePath (\r
-                                          ScsiIoDevice->ExtScsiPassThru,\r
-                                          &ScsiIoDevice->Pun.ScsiId.ExtScsi[0],\r
-                                          ScsiIoDevice->Lun,\r
-                                          &ScsiDevicePath\r
-                                          );\r
-  } else {\r
-    Status = ScsiIoDevice->ScsiPassThru->BuildDevicePath (\r
-                                          ScsiIoDevice->ScsiPassThru,\r
-                                          ScsiIoDevice->Pun.ScsiId.Scsi,\r
-                                          ScsiIoDevice->Lun,\r
-                                          &ScsiDevicePath\r
-                                          );\r
-  }\r
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+    EFI_PROGRESS_CODE,\r
+    (EFI_IO_BUS_SCSI | EFI_IOB_PC_ENABLE),\r
+    ScsiBusDev->DevicePath\r
+    );\r
 \r
-  if (EFI_ERROR(Status)) {\r
-    FreePool (ScsiIoDevice);\r
-    return Status;\r
+  if (!DiscoverScsiDevice (ScsiIoDevice)) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ErrorExit;\r
   }\r
 \r
-  ScsiIoDevice->DevicePath = AppendDevicePathNode (\r
-                              ScsiBusDev->DevicePath,\r
-                              ScsiDevicePath\r
-                              );\r
-  //\r
-  // The memory space for ScsiDevicePath is allocated in\r
-  // ScsiPassThru->BuildDevicePath() function; It is no longer used\r
-  // after EfiAppendDevicePathNode,so free the memory it occupies.\r
-  //\r
-  FreePool (ScsiDevicePath);\r
-\r
-  if (ScsiIoDevice->DevicePath == NULL) {\r
-    FreePool (ScsiIoDevice);\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
+  ScsiIoDevice->DevicePath = DevicePath;\r
 \r
   Status = gBS->InstallMultipleProtocolInterfaces (\r
                   &ScsiIoDevice->Handle,\r
@@ -1109,31 +1227,48 @@ ScsiScanCreateDevice (
                   NULL\r
                   );\r
   if (EFI_ERROR (Status)) {\r
-    FreePool (ScsiIoDevice->DevicePath);\r
-    FreePool (ScsiIoDevice);\r
-    return EFI_OUT_OF_RESOURCES;\r
+    goto ErrorExit;\r
   } else {\r
     if (ScsiBusDev->ExtScsiSupport) {\r
       gBS->OpenProtocol (\r
-            Controller,\r
-            &gEfiExtScsiPassThruProtocolGuid,\r
-            (VOID **) &(ScsiBusDev->ExtScsiInterface),\r
-            This->DriverBindingHandle,\r
-            ScsiIoDevice->Handle,\r
-            EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
-            );\r
+             Controller,\r
+             &gEfiExtScsiPassThruProtocolGuid,\r
+             (VOID **) &(ScsiBusDev->ExtScsiInterface),\r
+             This->DriverBindingHandle,\r
+             ScsiIoDevice->Handle,\r
+             EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+             );\r
      } else {\r
       gBS->OpenProtocol (\r
-            Controller,\r
-            &gEfiScsiPassThruProtocolGuid,\r
-            (VOID **) &(ScsiBusDev->ScsiInterface),\r
-            This->DriverBindingHandle,\r
-            ScsiIoDevice->Handle,\r
-            EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
-            );\r
+             Controller,\r
+             &gEfiScsiPassThruProtocolGuid,\r
+             (VOID **) &(ScsiBusDev->ScsiInterface),\r
+             This->DriverBindingHandle,\r
+             ScsiIoDevice->Handle,\r
+             EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+             );\r
      }\r
   }\r
   return EFI_SUCCESS;\r
+\r
+ErrorExit:\r
+\r
+  //\r
+  // The memory space for ScsiDevicePath is allocated in\r
+  // ScsiPassThru->BuildDevicePath() function; It is no longer used\r
+  // after AppendDevicePathNode,so free the memory it occupies.\r
+  //\r
+  FreePool (ScsiDevicePath);\r
+\r
+  if (DevicePath != NULL) {\r
+    FreePool (DevicePath);\r
+  }\r
+\r
+  if (ScsiIoDevice != NULL) {\r
+    FreePool (ScsiIoDevice);\r
+  }\r
+\r
+  return Status;\r
 }\r
 \r
 \r
@@ -1156,64 +1291,109 @@ DiscoverScsiDevice (
   UINT8                 SenseDataLength;\r
   UINT8                 HostAdapterStatus;\r
   UINT8                 TargetStatus;\r
-  EFI_SCSI_SENSE_DATA   SenseData;\r
-  EFI_SCSI_INQUIRY_DATA InquiryData;\r
+  EFI_SCSI_INQUIRY_DATA *InquiryData;\r
+  EFI_SCSI_SENSE_DATA   *SenseData;\r
+  UINT8                 MaxRetry;\r
+  UINT8                 Index;\r
+  BOOLEAN               ScsiDeviceFound;\r
 \r
   HostAdapterStatus = 0;\r
   TargetStatus      = 0;\r
+  SenseData         = NULL;\r
+\r
+  InquiryData = AllocateAlignedBuffer (ScsiIoDevice, sizeof (EFI_SCSI_INQUIRY_DATA));\r
+  if (InquiryData == NULL) {\r
+    ScsiDeviceFound = FALSE;\r
+    goto Done;\r
+  }\r
+\r
+  SenseData = AllocateAlignedBuffer (\r
+                ScsiIoDevice,\r
+                sizeof (EFI_SCSI_SENSE_DATA)\r
+                );\r
+  if (SenseData == NULL) {\r
+    ScsiDeviceFound = FALSE;\r
+    goto Done;\r
+  }\r
+\r
   //\r
   // Using Inquiry command to scan for the device\r
   //\r
   InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);\r
   SenseDataLength   = sizeof (EFI_SCSI_SENSE_DATA);\r
+  ZeroMem (InquiryData, InquiryDataLength);\r
+  ZeroMem (SenseData, SenseDataLength);\r
+\r
+  MaxRetry = 2;\r
+  for (Index = 0; Index < MaxRetry; Index++) {\r
+    Status = ScsiInquiryCommand (\r
+              &ScsiIoDevice->ScsiIo,\r
+              SCSI_BUS_TIMEOUT,\r
+              SenseData,\r
+              &SenseDataLength,\r
+              &HostAdapterStatus,\r
+              &TargetStatus,\r
+              (VOID *) InquiryData,\r
+              &InquiryDataLength,\r
+              FALSE\r
+              );\r
+    if (!EFI_ERROR (Status)) {\r
+      if ((HostAdapterStatus == EFI_SCSI_IO_STATUS_HOST_ADAPTER_OK) &&\r
+          (TargetStatus == EFI_SCSI_IO_STATUS_TARGET_CHECK_CONDITION) &&\r
+          (SenseData->Error_Code == 0x70) &&\r
+          (SenseData->Sense_Key == EFI_SCSI_SK_ILLEGAL_REQUEST)) {\r
+        ScsiDeviceFound = FALSE;\r
+        goto Done;\r
+      }\r
+      break;\r
+    }\r
+    if ((Status == EFI_BAD_BUFFER_SIZE) ||\r
+        (Status == EFI_INVALID_PARAMETER) ||\r
+        (Status == EFI_UNSUPPORTED)) {\r
+      ScsiDeviceFound = FALSE;\r
+      goto Done;\r
+    }\r
+  }\r
 \r
-  Status = ScsiInquiryCommand (\r
-            &ScsiIoDevice->ScsiIo,\r
-            EFI_TIMER_PERIOD_SECONDS (1),\r
-            (VOID *) &SenseData,\r
-            &SenseDataLength,\r
-            &HostAdapterStatus,\r
-            &TargetStatus,\r
-            (VOID *) &InquiryData,\r
-            &InquiryDataLength,\r
-            FALSE\r
-            );\r
-  if (EFI_ERROR (Status) && Status != EFI_BAD_BUFFER_SIZE) {\r
-    return FALSE;\r
+  if (Index == MaxRetry) {\r
+    ScsiDeviceFound = FALSE;\r
+    goto Done;\r
   }\r
+\r
   //\r
   // Retrieved inquiry data successfully\r
   //\r
-  if ((InquiryData.Peripheral_Qualifier != 0) &&\r
-      (InquiryData.Peripheral_Qualifier != 3)) {\r
-    return FALSE;\r
+  if (InquiryData->Peripheral_Qualifier != 0) {\r
+    ScsiDeviceFound = FALSE;\r
+    goto Done;\r
   }\r
 \r
-  if (InquiryData.Peripheral_Qualifier == 3) {\r
-    if (InquiryData.Peripheral_Type != 0x1f) {\r
-      return FALSE;\r
-    }\r
-  }\r
-\r
-  if (0x1e >= InquiryData.Peripheral_Type && InquiryData.Peripheral_Type >= 0xa) {\r
-    return FALSE;\r
+  if (0x1e >= InquiryData->Peripheral_Type && InquiryData->Peripheral_Type >= 0xa) {\r
+    ScsiDeviceFound = FALSE;\r
+    goto Done;\r
   }\r
 \r
   //\r
   // valid device type and peripheral qualifier combination.\r
   //\r
-  ScsiIoDevice->ScsiDeviceType  = InquiryData.Peripheral_Type;\r
-  ScsiIoDevice->RemovableDevice = InquiryData.Rmb;\r
-  if (InquiryData.Version == 0) {\r
+  ScsiIoDevice->ScsiDeviceType  = InquiryData->Peripheral_Type;\r
+  ScsiIoDevice->RemovableDevice = InquiryData->Rmb;\r
+  if (InquiryData->Version == 0) {\r
     ScsiIoDevice->ScsiVersion = 0;\r
   } else {\r
     //\r
     // ANSI-approved version\r
     //\r
-    ScsiIoDevice->ScsiVersion = (UINT8) (InquiryData.Version & 0x03);\r
+    ScsiIoDevice->ScsiVersion = (UINT8) (InquiryData->Version & 0x07);\r
   }\r
 \r
-  return TRUE;\r
+  ScsiDeviceFound = TRUE;\r
+\r
+Done:\r
+  FreeAlignedBuffer (SenseData, sizeof (EFI_SCSI_SENSE_DATA));\r
+  FreeAlignedBuffer (InquiryData, sizeof (EFI_SCSI_INQUIRY_DATA));\r
+\r
+  return ScsiDeviceFound;\r
 }\r
 \r
 \r