]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
SecurityPkg OpalPasswordSmm: Always execute BlockSid command.
[mirror_edk2.git] / MdeModulePkg / Bus / Scsi / ScsiDiskDxe / ScsiDisk.c
index 88bce3f70c24e276a0b0097eef439e9e0668d818..dfa5fa32e6353a35ac92e7356d0b59e5532295f1 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   SCSI disk driver that layers on every SCSI IO protocol in the system.\r
 \r
-Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2016, 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
@@ -466,8 +466,12 @@ ScsiDiskReset (
   Status          = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
 \r
   if (EFI_ERROR (Status)) {\r
-    Status = EFI_DEVICE_ERROR;\r
-    goto Done;\r
+    if (Status == EFI_UNSUPPORTED) {\r
+      Status = EFI_SUCCESS;\r
+    } else {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto Done;\r
+    }\r
   }\r
 \r
   if (!ExtendedVerification) {\r
@@ -692,6 +696,11 @@ ScsiDiskWriteBlocks (
     goto Done;\r
   }\r
 \r
+  if (Media->ReadOnly) {\r
+    Status = EFI_WRITE_PROTECTED;\r
+    goto Done;\r
+  }\r
+\r
   if (BufferSize == 0) {\r
     Status = EFI_SUCCESS;\r
     goto Done;\r
@@ -785,8 +794,12 @@ ScsiDiskResetEx (
   Status          = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
 \r
   if (EFI_ERROR (Status)) {\r
-    Status = EFI_DEVICE_ERROR;\r
-    goto Done;\r
+    if (Status == EFI_UNSUPPORTED) {\r
+      Status = EFI_SUCCESS;\r
+    } else {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto Done;\r
+    }\r
   }\r
 \r
   if (!ExtendedVerification) {\r
@@ -1048,6 +1061,11 @@ ScsiDiskWriteBlocksEx (
     goto Done;\r
   }\r
 \r
+  if (Media->ReadOnly) {\r
+    Status = EFI_WRITE_PROTECTED;\r
+    goto Done;\r
+  }\r
+\r
   if (BufferSize == 0) {\r
     if ((Token != NULL) && (Token->Event != NULL)) {\r
       Token->TransactionStatus = EFI_SUCCESS;\r
@@ -1116,10 +1134,12 @@ Done:
   @param  This       Indicates a pointer to the calling context.\r
   @param  Token      A pointer to the token associated with the transaction.\r
 \r
-  @retval EFI_SUCCESS       All outstanding data was written to the device.\r
-  @retval EFI_DEVICE_ERROR  The device reported an error while writing back the\r
-                            data.\r
-  @retval EFI_NO_MEDIA      There is no media in the device.\r
+  @retval EFI_SUCCESS         All outstanding data was written to the device.\r
+  @retval EFI_DEVICE_ERROR    The device reported an error while attempting to\r
+                              write data.\r
+  @retval EFI_WRITE_PROTECTED The device cannot be written to.\r
+  @retval EFI_NO_MEDIA        There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGED   The MediaId is not for the current media.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -1129,15 +1149,72 @@ ScsiDiskFlushBlocksEx (
   IN OUT EFI_BLOCK_IO2_TOKEN     *Token\r
   )\r
 {\r
+  SCSI_DISK_DEV       *ScsiDiskDevice;\r
+  EFI_BLOCK_IO_MEDIA  *Media;\r
+  EFI_STATUS          Status;\r
+  BOOLEAN             MediaChange;\r
+  EFI_TPL             OldTpl;\r
+\r
+  MediaChange    = FALSE;\r
+  OldTpl         = gBS->RaiseTPL (TPL_CALLBACK);\r
+  ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);\r
+\r
+  if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {\r
+\r
+    Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto Done;\r
+    }\r
+\r
+    if (MediaChange) {\r
+      gBS->ReinstallProtocolInterface (\r
+            ScsiDiskDevice->Handle,\r
+            &gEfiBlockIoProtocolGuid,\r
+            &ScsiDiskDevice->BlkIo,\r
+            &ScsiDiskDevice->BlkIo\r
+            );\r
+      gBS->ReinstallProtocolInterface (\r
+             ScsiDiskDevice->Handle,\r
+             &gEfiBlockIo2ProtocolGuid,\r
+             &ScsiDiskDevice->BlkIo2,\r
+             &ScsiDiskDevice->BlkIo2\r
+             );\r
+      Status = EFI_MEDIA_CHANGED;\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+  Media = ScsiDiskDevice->BlkIo2.Media;\r
+\r
+  if (!(Media->MediaPresent)) {\r
+    Status = EFI_NO_MEDIA;\r
+    goto Done;\r
+  }\r
+\r
+  if (Media->ReadOnly) {\r
+    Status = EFI_WRITE_PROTECTED;\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Wait for the BlockIo2 requests queue to become empty\r
+  //\r
+  while (!IsListEmpty (&ScsiDiskDevice->BlkIo2Queue));\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
   //\r
-  // Signal event and return directly.\r
+  // Signal caller event\r
   //\r
   if ((Token != NULL) && (Token->Event != NULL)) {\r
     Token->TransactionStatus = EFI_SUCCESS;\r
     gBS->SignalEvent (Token->Event);\r
   }\r
 \r
-  return EFI_SUCCESS;\r
+Done:\r
+  gBS->RestoreTPL (OldTpl);\r
+  return Status;\r
 }\r
 \r
 \r
@@ -2540,6 +2617,7 @@ ScsiDiskAsyncReadSectors (
   UINT64                Timeout;\r
   SCSI_BLKIO2_REQUEST   *BlkIo2Req;\r
   EFI_STATUS            Status;\r
+  EFI_TPL               OldTpl;\r
 \r
   if ((Token == NULL) || (Token->Event == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -2551,7 +2629,11 @@ ScsiDiskAsyncReadSectors (
   }\r
 \r
   BlkIo2Req->Token  = Token;\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
   InsertTailList (&ScsiDiskDevice->BlkIo2Queue, &BlkIo2Req->Link);\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
   InitializeListHead (&BlkIo2Req->ScsiRWQueue);\r
 \r
   Status            = EFI_SUCCESS;\r
@@ -2623,6 +2705,7 @@ ScsiDiskAsyncReadSectors (
       Status = ScsiDiskAsyncRead10 (\r
                  ScsiDiskDevice,\r
                  Timeout,\r
+                 0,\r
                  PtrBuffer,\r
                  ByteCount,\r
                  (UINT32) Lba,\r
@@ -2634,6 +2717,7 @@ ScsiDiskAsyncReadSectors (
       Status = ScsiDiskAsyncRead16 (\r
                  ScsiDiskDevice,\r
                  Timeout,\r
+                 0,\r
                  PtrBuffer,\r
                  ByteCount,\r
                  Lba,\r
@@ -2644,15 +2728,47 @@ ScsiDiskAsyncReadSectors (
     }\r
     if (EFI_ERROR (Status)) {\r
       //\r
-      // Free the SCSI_BLKIO2_REQUEST structure only when the first SCSI\r
-      // command fails. Otherwise, it will be freed in the callback function\r
-      // ScsiDiskNotify().\r
+      // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data\r
+      // length of a SCSI I/O command is too large.\r
+      // In this case, we retry sending the SCSI command with a data length\r
+      // half of its previous value.\r
       //\r
+      if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {\r
+        if ((MaxBlock > 1) && (SectorCount > 1)) {\r
+          MaxBlock = MIN (MaxBlock, SectorCount) >> 1;\r
+          continue;\r
+        }\r
+      }\r
+\r
+      OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
       if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {\r
+        //\r
+        // Free the SCSI_BLKIO2_REQUEST structure only when there is no other\r
+        // SCSI sub-task running. Otherwise, it will be freed in the callback\r
+        // function ScsiDiskNotify().\r
+        //\r
         RemoveEntryList (&BlkIo2Req->Link);\r
         FreePool (BlkIo2Req);\r
+        BlkIo2Req = NULL;\r
+        gBS->RestoreTPL (OldTpl);\r
+\r
+        //\r
+        // It is safe to return error status to the caller, since there is no\r
+        // previous SCSI sub-task executing.\r
+        //\r
+        Status = EFI_DEVICE_ERROR;\r
+        goto Done;\r
+      } else {\r
+        gBS->RestoreTPL (OldTpl);\r
+\r
+        //\r
+        // There are previous SCSI commands still running, EFI_SUCCESS should\r
+        // be returned to make sure that the caller does not free resources\r
+        // still using by these SCSI commands.\r
+        //\r
+        Status = EFI_SUCCESS;\r
+        goto Done;\r
       }\r
-      return EFI_DEVICE_ERROR;\r
     }\r
 \r
     //\r
@@ -2665,7 +2781,24 @@ ScsiDiskAsyncReadSectors (
     BlocksRemaining -= SectorCount;\r
   }\r
 \r
-  return EFI_SUCCESS;\r
+  Status = EFI_SUCCESS;\r
+\r
+Done:\r
+  if (BlkIo2Req != NULL) {\r
+    BlkIo2Req->LastScsiRW = TRUE;\r
+\r
+    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+    if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {\r
+      RemoveEntryList (&BlkIo2Req->Link);\r
+      FreePool (BlkIo2Req);\r
+      BlkIo2Req = NULL;\r
+\r
+      gBS->SignalEvent (Token->Event);\r
+    }\r
+    gBS->RestoreTPL (OldTpl);\r
+  }\r
+\r
+  return Status;\r
 }\r
 \r
 /**\r
@@ -2701,6 +2834,7 @@ ScsiDiskAsyncWriteSectors (
   UINT64                Timeout;\r
   SCSI_BLKIO2_REQUEST   *BlkIo2Req;\r
   EFI_STATUS            Status;\r
+  EFI_TPL               OldTpl;\r
 \r
   if ((Token == NULL) || (Token->Event == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -2712,7 +2846,11 @@ ScsiDiskAsyncWriteSectors (
   }\r
 \r
   BlkIo2Req->Token  = Token;\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
   InsertTailList (&ScsiDiskDevice->BlkIo2Queue, &BlkIo2Req->Link);\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
   InitializeListHead (&BlkIo2Req->ScsiRWQueue);\r
 \r
   Status            = EFI_SUCCESS;\r
@@ -2784,6 +2922,7 @@ ScsiDiskAsyncWriteSectors (
       Status = ScsiDiskAsyncWrite10 (\r
                  ScsiDiskDevice,\r
                  Timeout,\r
+                 0,\r
                  PtrBuffer,\r
                  ByteCount,\r
                  (UINT32) Lba,\r
@@ -2795,6 +2934,7 @@ ScsiDiskAsyncWriteSectors (
       Status = ScsiDiskAsyncWrite16 (\r
                  ScsiDiskDevice,\r
                  Timeout,\r
+                 0,\r
                  PtrBuffer,\r
                  ByteCount,\r
                  Lba,\r
@@ -2805,15 +2945,47 @@ ScsiDiskAsyncWriteSectors (
     }\r
     if (EFI_ERROR (Status)) {\r
       //\r
-      // Free the SCSI_BLKIO2_REQUEST structure only when the first SCSI\r
-      // command fails. Otherwise, it will be freed in the callback function\r
-      // ScsiDiskNotify().\r
+      // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data\r
+      // length of a SCSI I/O command is too large.\r
+      // In this case, we retry sending the SCSI command with a data length\r
+      // half of its previous value.\r
       //\r
+      if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {\r
+        if ((MaxBlock > 1) && (SectorCount > 1)) {\r
+          MaxBlock = MIN (MaxBlock, SectorCount) >> 1;\r
+          continue;\r
+        }\r
+      }\r
+\r
+      OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
       if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {\r
+        //\r
+        // Free the SCSI_BLKIO2_REQUEST structure only when there is no other\r
+        // SCSI sub-task running. Otherwise, it will be freed in the callback\r
+        // function ScsiDiskNotify().\r
+        //\r
         RemoveEntryList (&BlkIo2Req->Link);\r
         FreePool (BlkIo2Req);\r
+        BlkIo2Req = NULL;\r
+        gBS->RestoreTPL (OldTpl);\r
+\r
+        //\r
+        // It is safe to return error status to the caller, since there is no\r
+        // previous SCSI sub-task executing.\r
+        //\r
+        Status = EFI_DEVICE_ERROR;\r
+        goto Done;\r
+      } else {\r
+        gBS->RestoreTPL (OldTpl);\r
+\r
+        //\r
+        // There are previous SCSI commands still running, EFI_SUCCESS should\r
+        // be returned to make sure that the caller does not free resources\r
+        // still using by these SCSI commands.\r
+        //\r
+        Status = EFI_SUCCESS;\r
+        goto Done;\r
       }\r
-      return EFI_DEVICE_ERROR;\r
     }\r
 \r
     //\r
@@ -2826,7 +2998,24 @@ ScsiDiskAsyncWriteSectors (
     BlocksRemaining -= SectorCount;\r
   }\r
 \r
-  return EFI_SUCCESS;\r
+  Status = EFI_SUCCESS;\r
+\r
+Done:\r
+  if (BlkIo2Req != NULL) {\r
+    BlkIo2Req->LastScsiRW = TRUE;\r
+\r
+    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+    if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {\r
+      RemoveEntryList (&BlkIo2Req->Link);\r
+      FreePool (BlkIo2Req);\r
+      BlkIo2Req = NULL;\r
+\r
+      gBS->SignalEvent (Token->Event);\r
+    }\r
+    gBS->RestoreTPL (OldTpl);\r
+  }\r
+\r
+  return Status;\r
 }\r
 \r
 \r
@@ -3458,6 +3647,7 @@ Retry:
       Status = ScsiDiskAsyncRead10 (\r
                  ScsiDiskDevice,\r
                  Request->Timeout,\r
+                 Request->TimesRetry,\r
                  Request->InBuffer,\r
                  Request->DataLength,\r
                  (UINT32) Request->StartLba,\r
@@ -3469,6 +3659,7 @@ Retry:
       Status = ScsiDiskAsyncRead16 (\r
                  ScsiDiskDevice,\r
                  Request->Timeout,\r
+                 Request->TimesRetry,\r
                  Request->InBuffer,\r
                  Request->DataLength,\r
                  Request->StartLba,\r
@@ -3490,6 +3681,7 @@ Retry:
         Status = ScsiDiskAsyncRead10 (\r
                    ScsiDiskDevice,\r
                    Request->Timeout,\r
+                   0,\r
                    Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,\r
                    OldDataLength - Request->DataLength,\r
                    (UINT32) Request->StartLba + Request->SectorCount,\r
@@ -3501,6 +3693,7 @@ Retry:
         Status = ScsiDiskAsyncRead16 (\r
                    ScsiDiskDevice,\r
                    Request->Timeout,\r
+                   0,\r
                    Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,\r
                    OldDataLength - Request->DataLength,\r
                    Request->StartLba + Request->SectorCount,\r
@@ -3522,6 +3715,7 @@ Retry:
       Status = ScsiDiskAsyncWrite10 (\r
                  ScsiDiskDevice,\r
                  Request->Timeout,\r
+                 Request->TimesRetry,\r
                  Request->OutBuffer,\r
                  Request->DataLength,\r
                  (UINT32) Request->StartLba,\r
@@ -3533,6 +3727,7 @@ Retry:
       Status = ScsiDiskAsyncWrite16 (\r
                  ScsiDiskDevice,\r
                  Request->Timeout,\r
+                 Request->TimesRetry,\r
                  Request->OutBuffer,\r
                  Request->DataLength,\r
                  Request->StartLba,\r
@@ -3554,6 +3749,7 @@ Retry:
         Status = ScsiDiskAsyncWrite10 (\r
                    ScsiDiskDevice,\r
                    Request->Timeout,\r
+                   0,\r
                    Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,\r
                    OldDataLength - Request->DataLength,\r
                    (UINT32) Request->StartLba + Request->SectorCount,\r
@@ -3565,6 +3761,7 @@ Retry:
         Status = ScsiDiskAsyncWrite16 (\r
                    ScsiDiskDevice,\r
                    Request->Timeout,\r
+                   0,\r
                    Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,\r
                    OldDataLength - Request->DataLength,\r
                    Request->StartLba + Request->SectorCount,\r
@@ -3582,7 +3779,8 @@ Retry:
 \r
 Exit:\r
   RemoveEntryList (&Request->Link);\r
-  if (IsListEmpty (&Request->BlkIo2Req->ScsiRWQueue)) {\r
+  if ((IsListEmpty (&Request->BlkIo2Req->ScsiRWQueue)) &&\r
+      (Request->BlkIo2Req->LastScsiRW)) {\r
     //\r
     // The last SCSI R/W command of a BlockIo2 request completes\r
     //\r
@@ -3601,6 +3799,7 @@ Exit:
 \r
   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice.\r
   @param  Timeout            The time to complete the command.\r
+  @param  TimesRetry         The number of times the command has been retried.\r
   @param  DataBuffer         The buffer to fill with the read out data.\r
   @param  DataLength         The length of buffer.\r
   @param  StartLba           The start logic block address.\r
@@ -3619,6 +3818,7 @@ EFI_STATUS
 ScsiDiskAsyncRead10 (\r
   IN     SCSI_DISK_DEV         *ScsiDiskDevice,\r
   IN     UINT64                Timeout,\r
+  IN     UINT8                 TimesRetry,\r
      OUT UINT8                 *DataBuffer,\r
   IN     UINT32                DataLength,\r
   IN     UINT32                StartLba,\r
@@ -3630,12 +3830,18 @@ ScsiDiskAsyncRead10 (
   EFI_STATUS                   Status;\r
   SCSI_ASYNC_RW_REQUEST        *Request;\r
   EFI_EVENT                    AsyncIoEvent;\r
+  EFI_TPL                      OldTpl;\r
+\r
+  AsyncIoEvent = NULL;\r
 \r
   Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));\r
   if (Request == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
   InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);\r
+  gBS->RestoreTPL (OldTpl);\r
 \r
   Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));\r
   Request->SenseData       = AllocateZeroPool (Request->SenseDataLength);\r
@@ -3646,6 +3852,7 @@ ScsiDiskAsyncRead10 (
 \r
   Request->ScsiDiskDevice  = ScsiDiskDevice;\r
   Request->Timeout         = Timeout;\r
+  Request->TimesRetry      = TimesRetry;\r
   Request->InBuffer        = DataBuffer;\r
   Request->DataLength      = DataLength;\r
   Request->StartLba        = StartLba;\r
@@ -3657,7 +3864,7 @@ ScsiDiskAsyncRead10 (
   //\r
   Status = gBS->CreateEvent (\r
                   EVT_NOTIFY_SIGNAL,\r
-                  TPL_CALLBACK,\r
+                  TPL_NOTIFY,\r
                   ScsiDiskNotify,\r
                   Request,\r
                   &AsyncIoEvent\r
@@ -3686,12 +3893,19 @@ ScsiDiskAsyncRead10 (
   return EFI_SUCCESS;\r
 \r
 ErrorExit:\r
+  if (AsyncIoEvent != NULL) {\r
+    gBS->CloseEvent (AsyncIoEvent);\r
+  }\r
+\r
   if (Request != NULL) {\r
     if (Request->SenseData != NULL) {\r
       FreePool (Request->SenseData);\r
     }\r
 \r
+    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
     RemoveEntryList (&Request->Link);\r
+    gBS->RestoreTPL (OldTpl);\r
+\r
     FreePool (Request);\r
   }\r
 \r
@@ -3704,6 +3918,7 @@ ErrorExit:
 \r
   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice.\r
   @param  Timeout            The time to complete the command.\r
+  @param  TimesRetry         The number of times the command has been retried.\r
   @param  DataBuffer         The buffer contains the data to write.\r
   @param  DataLength         The length of buffer.\r
   @param  StartLba           The start logic block address.\r
@@ -3722,6 +3937,7 @@ EFI_STATUS
 ScsiDiskAsyncWrite10 (\r
   IN     SCSI_DISK_DEV         *ScsiDiskDevice,\r
   IN     UINT64                Timeout,\r
+  IN     UINT8                 TimesRetry,\r
   IN     UINT8                 *DataBuffer,\r
   IN     UINT32                DataLength,\r
   IN     UINT32                StartLba,\r
@@ -3733,12 +3949,18 @@ ScsiDiskAsyncWrite10 (
   EFI_STATUS                   Status;\r
   SCSI_ASYNC_RW_REQUEST        *Request;\r
   EFI_EVENT                    AsyncIoEvent;\r
+  EFI_TPL                      OldTpl;\r
+\r
+  AsyncIoEvent = NULL;\r
 \r
   Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));\r
   if (Request == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
   InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);\r
+  gBS->RestoreTPL (OldTpl);\r
 \r
   Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));\r
   Request->SenseData       = AllocateZeroPool (Request->SenseDataLength);\r
@@ -3749,6 +3971,7 @@ ScsiDiskAsyncWrite10 (
 \r
   Request->ScsiDiskDevice  = ScsiDiskDevice;\r
   Request->Timeout         = Timeout;\r
+  Request->TimesRetry      = TimesRetry;\r
   Request->OutBuffer       = DataBuffer;\r
   Request->DataLength      = DataLength;\r
   Request->StartLba        = StartLba;\r
@@ -3760,7 +3983,7 @@ ScsiDiskAsyncWrite10 (
   //\r
   Status = gBS->CreateEvent (\r
                   EVT_NOTIFY_SIGNAL,\r
-                  TPL_CALLBACK,\r
+                  TPL_NOTIFY,\r
                   ScsiDiskNotify,\r
                   Request,\r
                   &AsyncIoEvent\r
@@ -3789,12 +4012,19 @@ ScsiDiskAsyncWrite10 (
   return EFI_SUCCESS;\r
 \r
 ErrorExit:\r
+  if (AsyncIoEvent != NULL) {\r
+    gBS->CloseEvent (AsyncIoEvent);\r
+  }\r
+\r
   if (Request != NULL) {\r
     if (Request->SenseData != NULL) {\r
       FreePool (Request->SenseData);\r
     }\r
 \r
+    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
     RemoveEntryList (&Request->Link);\r
+    gBS->RestoreTPL (OldTpl);\r
+\r
     FreePool (Request);\r
   }\r
 \r
@@ -3807,6 +4037,7 @@ ErrorExit:
 \r
   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice.\r
   @param  Timeout            The time to complete the command.\r
+  @param  TimesRetry         The number of times the command has been retried.\r
   @param  DataBuffer         The buffer to fill with the read out data.\r
   @param  DataLength         The length of buffer.\r
   @param  StartLba           The start logic block address.\r
@@ -3825,6 +4056,7 @@ EFI_STATUS
 ScsiDiskAsyncRead16 (\r
   IN     SCSI_DISK_DEV         *ScsiDiskDevice,\r
   IN     UINT64                Timeout,\r
+  IN     UINT8                 TimesRetry,\r
      OUT UINT8                 *DataBuffer,\r
   IN     UINT32                DataLength,\r
   IN     UINT64                StartLba,\r
@@ -3836,12 +4068,18 @@ ScsiDiskAsyncRead16 (
   EFI_STATUS                   Status;\r
   SCSI_ASYNC_RW_REQUEST        *Request;\r
   EFI_EVENT                    AsyncIoEvent;\r
+  EFI_TPL                      OldTpl;\r
+\r
+  AsyncIoEvent = NULL;\r
 \r
   Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));\r
   if (Request == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
   InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);\r
+  gBS->RestoreTPL (OldTpl);\r
 \r
   Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));\r
   Request->SenseData       = AllocateZeroPool (Request->SenseDataLength);\r
@@ -3852,6 +4090,7 @@ ScsiDiskAsyncRead16 (
 \r
   Request->ScsiDiskDevice  = ScsiDiskDevice;\r
   Request->Timeout         = Timeout;\r
+  Request->TimesRetry      = TimesRetry;\r
   Request->InBuffer        = DataBuffer;\r
   Request->DataLength      = DataLength;\r
   Request->StartLba        = StartLba;\r
@@ -3863,7 +4102,7 @@ ScsiDiskAsyncRead16 (
   //\r
   Status = gBS->CreateEvent (\r
                   EVT_NOTIFY_SIGNAL,\r
-                  TPL_CALLBACK,\r
+                  TPL_NOTIFY,\r
                   ScsiDiskNotify,\r
                   Request,\r
                   &AsyncIoEvent\r
@@ -3892,12 +4131,19 @@ ScsiDiskAsyncRead16 (
   return EFI_SUCCESS;\r
 \r
 ErrorExit:\r
+  if (AsyncIoEvent != NULL) {\r
+    gBS->CloseEvent (AsyncIoEvent);\r
+  }\r
+\r
   if (Request != NULL) {\r
     if (Request->SenseData != NULL) {\r
       FreePool (Request->SenseData);\r
     }\r
 \r
+    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
     RemoveEntryList (&Request->Link);\r
+    gBS->RestoreTPL (OldTpl);\r
+\r
     FreePool (Request);\r
   }\r
 \r
@@ -3910,6 +4156,7 @@ ErrorExit:
 \r
   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice.\r
   @param  Timeout            The time to complete the command.\r
+  @param  TimesRetry         The number of times the command has been retried.\r
   @param  DataBuffer         The buffer contains the data to write.\r
   @param  DataLength         The length of buffer.\r
   @param  StartLba           The start logic block address.\r
@@ -3928,6 +4175,7 @@ EFI_STATUS
 ScsiDiskAsyncWrite16 (\r
   IN     SCSI_DISK_DEV         *ScsiDiskDevice,\r
   IN     UINT64                Timeout,\r
+  IN     UINT8                 TimesRetry,\r
   IN     UINT8                 *DataBuffer,\r
   IN     UINT32                DataLength,\r
   IN     UINT64                StartLba,\r
@@ -3939,12 +4187,18 @@ ScsiDiskAsyncWrite16 (
   EFI_STATUS                   Status;\r
   SCSI_ASYNC_RW_REQUEST        *Request;\r
   EFI_EVENT                    AsyncIoEvent;\r
+  EFI_TPL                      OldTpl;\r
+\r
+  AsyncIoEvent = NULL;\r
 \r
   Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));\r
   if (Request == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
   InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);\r
+  gBS->RestoreTPL (OldTpl);\r
 \r
   Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));\r
   Request->SenseData       = AllocateZeroPool (Request->SenseDataLength);\r
@@ -3955,6 +4209,7 @@ ScsiDiskAsyncWrite16 (
 \r
   Request->ScsiDiskDevice  = ScsiDiskDevice;\r
   Request->Timeout         = Timeout;\r
+  Request->TimesRetry      = TimesRetry;\r
   Request->OutBuffer       = DataBuffer;\r
   Request->DataLength      = DataLength;\r
   Request->StartLba        = StartLba;\r
@@ -3966,7 +4221,7 @@ ScsiDiskAsyncWrite16 (
   //\r
   Status = gBS->CreateEvent (\r
                   EVT_NOTIFY_SIGNAL,\r
-                  TPL_CALLBACK,\r
+                  TPL_NOTIFY,\r
                   ScsiDiskNotify,\r
                   Request,\r
                   &AsyncIoEvent\r
@@ -3995,12 +4250,19 @@ ScsiDiskAsyncWrite16 (
   return EFI_SUCCESS;\r
 \r
 ErrorExit:\r
+  if (AsyncIoEvent != NULL) {\r
+    gBS->CloseEvent (AsyncIoEvent);\r
+  }\r
+\r
   if (Request != NULL) {\r
     if (Request->SenseData != NULL) {\r
       FreePool (Request->SenseData);\r
     }\r
 \r
+    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
     RemoveEntryList (&Request->Link);\r
+    gBS->RestoreTPL (OldTpl);\r
+\r
     FreePool (Request);\r
   }\r
 \r