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