When reading data from non-blockingly from a CD-ROM logic partition, the
procedure can be shown by the following call stack:
(The write process is similar)

|-------------------|
| DiskIoDxe (logic) |<---Raise Tpl to TPL_CALLBACK
|-------------------|
 |
 | Sub-task 1 (UnderRun) succeeds
 |
 |    |-----------------|     |-----------------|     |-----------------|
 +--->|  PartitionDxe   |---->| DiskIoDxe (Phy) |---->|   ScsiDiskDxe   |
 |    |-----------------|     |-----------------|     |-----------------|
 |
 | Sub-task 2 (OverRun) fails
 |
 |    |-----------------|     |-----------------|     |-----------------|
 +--->|  PartitionDxe   |---->| DiskIoDxe (Phy) |---->|   ScsiDiskDxe   |
 |    |-----------------|     |-----------------|     |-----------------|
 |                                     ^
 |                                     |
 More subtasks...              Wait indefinitely
 |
 |<---Restore Tpl
 |
 Completes

In PartitionDxe, if the 'Lba' and 'BufferSize' parameters passed to
function PartitionReadBlocksEx() are invalid, the function will issue a
blocking ReadDisk call (in function ProbeMediaStatusEx()).

In DiskIoDxe, blocking I/O request will wait for all the non-blocking I/O
requests to complete first before sending down the blocking request.

If the Tpl of the async I/O callback in ScsiDiskDxe is TPL_CALLBACK and
Sub-task 1 (UnderRun) succeeds but Sub-task 2 (OverRun) fails with an
invalid parameter, DiskIoDxe will wait indefinitely for the event created
by ScsiDiskDxe of Sub-task 1 to signal.

Hence, this commit will raise the Tpl of async IO callback in ScsiDiskDxe
to TPL_NOTIFY so that the indefinite wait in DiskIoDxe can be avoided.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Hao Wu <hao.a...@intel.com>
---
 MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c | 59 ++++++++++++++++++++++------
 MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h |  8 +++-
 2 files changed, 55 insertions(+), 12 deletions(-)

diff --git a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c 
b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
index 2d6d7e3..5967b25 100644
--- a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
+++ b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
@@ -2735,19 +2735,22 @@ ScsiDiskAsyncReadSectors (
         //
         RemoveEntryList (&BlkIo2Req->Link);
         FreePool (BlkIo2Req);
+        BlkIo2Req = NULL;
 
         //
         // It is safe to return error status to the caller, since there is no
         // previous SCSI sub-task executing.
         //
-        return EFI_DEVICE_ERROR;
+        Status = EFI_DEVICE_ERROR;
+        goto Done;
       } else {
         //
         // There are previous SCSI commands still running, EFI_SUCCESS should
         // be returned to make sure that the caller does not free resources
         // still using by these SCSI commands.
         //
-        return EFI_SUCCESS;
+        Status = EFI_SUCCESS;
+        goto Done;
       }
     }
 
@@ -2761,7 +2764,22 @@ ScsiDiskAsyncReadSectors (
     BlocksRemaining -= SectorCount;
   }
 
-  return EFI_SUCCESS;
+  Status = EFI_SUCCESS;
+
+Done:
+  if (BlkIo2Req != NULL) {
+    BlkIo2Req->LastScsiRW = TRUE;
+
+    if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
+      RemoveEntryList (&BlkIo2Req->Link);
+      FreePool (BlkIo2Req);
+      BlkIo2Req = NULL;
+
+      gBS->SignalEvent (Token->Event);
+    }
+  }
+
+  return Status;
 }
 
 /**
@@ -2923,19 +2941,22 @@ ScsiDiskAsyncWriteSectors (
         //
         RemoveEntryList (&BlkIo2Req->Link);
         FreePool (BlkIo2Req);
+        BlkIo2Req = NULL;
 
         //
         // It is safe to return error status to the caller, since there is no
         // previous SCSI sub-task executing.
         //
-        return EFI_DEVICE_ERROR;
+        Status = EFI_DEVICE_ERROR;
+        goto Done;
       } else {
         //
         // There are previous SCSI commands still running, EFI_SUCCESS should
         // be returned to make sure that the caller does not free resources
         // still using by these SCSI commands.
         //
-        return EFI_SUCCESS;
+        Status = EFI_SUCCESS;
+        goto Done;
       }
     }
 
@@ -2949,7 +2970,22 @@ ScsiDiskAsyncWriteSectors (
     BlocksRemaining -= SectorCount;
   }
 
-  return EFI_SUCCESS;
+  Status = EFI_SUCCESS;
+
+Done:
+  if (BlkIo2Req != NULL) {
+    BlkIo2Req->LastScsiRW = TRUE;
+
+    if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
+      RemoveEntryList (&BlkIo2Req->Link);
+      FreePool (BlkIo2Req);
+      BlkIo2Req = NULL;
+
+      gBS->SignalEvent (Token->Event);
+    }
+  }
+
+  return Status;
 }
 
 
@@ -3713,7 +3749,8 @@ Retry:
 
 Exit:
   RemoveEntryList (&Request->Link);
-  if (IsListEmpty (&Request->BlkIo2Req->ScsiRWQueue)) {
+  if ((IsListEmpty (&Request->BlkIo2Req->ScsiRWQueue)) &&
+      (Request->BlkIo2Req->LastScsiRW)) {
     //
     // The last SCSI R/W command of a BlockIo2 request completes
     //
@@ -3793,7 +3830,7 @@ ScsiDiskAsyncRead10 (
   //
   Status = gBS->CreateEvent (
                   EVT_NOTIFY_SIGNAL,
-                  TPL_CALLBACK,
+                  TPL_NOTIFY,
                   ScsiDiskNotify,
                   Request,
                   &AsyncIoEvent
@@ -3905,7 +3942,7 @@ ScsiDiskAsyncWrite10 (
   //
   Status = gBS->CreateEvent (
                   EVT_NOTIFY_SIGNAL,
-                  TPL_CALLBACK,
+                  TPL_NOTIFY,
                   ScsiDiskNotify,
                   Request,
                   &AsyncIoEvent
@@ -4017,7 +4054,7 @@ ScsiDiskAsyncRead16 (
   //
   Status = gBS->CreateEvent (
                   EVT_NOTIFY_SIGNAL,
-                  TPL_CALLBACK,
+                  TPL_NOTIFY,
                   ScsiDiskNotify,
                   Request,
                   &AsyncIoEvent
@@ -4129,7 +4166,7 @@ ScsiDiskAsyncWrite16 (
   //
   Status = gBS->CreateEvent (
                   EVT_NOTIFY_SIGNAL,
-                  TPL_CALLBACK,
+                  TPL_NOTIFY,
                   ScsiDiskNotify,
                   Request,
                   &AsyncIoEvent
diff --git a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h 
b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h
index 7a287d3..2406df5 100644
--- a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h
+++ b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h
@@ -98,7 +98,13 @@ typedef struct {
 typedef struct {
   EFI_BLOCK_IO2_TOKEN                  *Token;
   //
-  // The queue for Scsi Read/Write requests of a BlockIo2
+  // The flag indicates if the last Scsi Read/Write sub-task for a BlockIo2
+  // request is sent to device
+  //
+  BOOLEAN                              LastScsiRW;
+
+  //
+  // The queue for Scsi Read/Write sub-tasks of a BlockIo2 request
   //
   LIST_ENTRY                           ScsiRWQueue;
 
-- 
1.9.5.msysgit.0

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to