Introduce tow non-blocking task lists to AtaBus. One maintains the sub-task which is related to running Ata Task and the other is for waiting Ata Task. And it will not pass any task to AtaAtapiPassThru until the previous Ata task has been finished or met error.

Signed-off-by: qianouyang
Reviewed-by: czhang46 erictian 

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13105 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
qianouyang 2012-03-16 03:31:47 +00:00
parent be30ddf795
commit 58727f29ea
6 changed files with 580 additions and 468 deletions

View File

@ -2,7 +2,7 @@
This file implements ATA_PASSTHRU_PROCTOCOL and EXT_SCSI_PASSTHRU_PROTOCOL interfaces
for managed ATA controllers.
Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
@ -408,23 +408,24 @@ AsyncNonBlockingTransferRoutine (
);
//
// If the data transfer meet a error which is not dumped into the status block
// set the Status block related bit.
// If the data transfer meet a error, remove all tasks in the list since these tasks are
// associated with one task from Ata Bus and signal the event with error status.
//
if ((Status != EFI_NOT_READY) && (Status != EFI_SUCCESS)) {
Task->Packet->Asb->AtaStatus = 0x01;
DestroyAsynTaskList (Instance, TRUE);
break;
}
//
// For Non blocking mode, the Status of EFI_NOT_READY means the operation
// is not finished yet. Other Status indicate the operation is either
// successful or failed.
// is not finished yet. Otherwise the operation is successful.
//
if (Status != EFI_NOT_READY) {
if (Status == EFI_NOT_READY) {
break;
} else {
RemoveEntryList (&Task->Link);
gBS->SignalEvent (Task->Event);
FreePool (Task);
} else {
break;
}
}
}
@ -872,7 +873,7 @@ AtaAtapiPassThruStop (
gBS->CloseEvent (Instance->TimerEvent);
Instance->TimerEvent = NULL;
}
DestroyAsynTaskList (Instance);
DestroyAsynTaskList (Instance, FALSE);
//
// Disable this ATA host controller.
@ -1090,12 +1091,15 @@ DestroyDeviceInfoList (
Destroy all pending non blocking tasks.
@param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.
@param[in] IsSigEvent Indicate whether signal the task event when remove the
task.
**/
VOID
EFIAPI
DestroyAsynTaskList (
IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance
IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
IN BOOLEAN IsSigEvent
)
{
LIST_ENTRY *Entry;
@ -1116,6 +1120,10 @@ DestroyAsynTaskList (
Task = ATA_NON_BLOCK_TASK_FROM_ENTRY (DelEntry);
RemoveEntryList (DelEntry);
if (IsSigEvent) {
Task->Packet->Asb->AtaStatus = 0x01;
gBS->SignalEvent (Task->Event);
}
FreePool (Task);
}
}

View File

@ -1,7 +1,7 @@
/** @file
Header file for ATA/ATAPI PASS THRU driver.
Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
@ -492,12 +492,15 @@ DestroyDeviceInfoList (
Destroy all pending non blocking tasks.
@param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.
@param[in] IsSigEvent Indicate whether signal the task event when remove the
task.
**/
VOID
EFIAPI
DestroyAsynTaskList (
IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance
IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
IN BOOLEAN IsSigEvent
);
/**

View File

@ -4,7 +4,7 @@
This file implements protocol interfaces: Driver Binding protocol,
Block IO protocol and DiskInfo protocol.
Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
@ -87,7 +87,8 @@ ATA_DEVICE gAtaDeviceTemplate = {
NULL, // IdentifyData
NULL, // ControllerNameTable
{L'\0', }, // ModelName
{NULL, NULL} // AtaTaskList
{NULL, NULL}, // AtaTaskList
{NULL, NULL} // AtaSubTaskList
};
/**
@ -147,7 +148,8 @@ ReleaseAtaResources (
IN ATA_DEVICE *AtaDevice
)
{
ATA_BUS_ASYN_TASK *Task;
ATA_BUS_ASYN_SUB_TASK *SubTask;
ATA_BUS_ASYN_TASK *AtaTask;
LIST_ENTRY *Entry;
LIST_ENTRY *DelEntry;
EFI_TPL OldTpl;
@ -159,6 +161,21 @@ ReleaseAtaResources (
FreePool (AtaDevice->DevicePath);
}
OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
if (!IsListEmpty (&AtaDevice->AtaSubTaskList)) {
//
// Free the Subtask list.
//
for(Entry = AtaDevice->AtaSubTaskList.ForwardLink;
Entry != (&AtaDevice->AtaSubTaskList);
) {
DelEntry = Entry;
Entry = Entry->ForwardLink;
SubTask = ATA_AYNS_SUB_TASK_FROM_ENTRY (DelEntry);
RemoveEntryList (DelEntry);
FreeAtaSubTask (SubTask);
}
}
if (!IsListEmpty (&AtaDevice->AtaTaskList)) {
//
// Free the Subtask list.
@ -168,10 +185,10 @@ ReleaseAtaResources (
) {
DelEntry = Entry;
Entry = Entry->ForwardLink;
Task = ATA_AYNS_TASK_FROM_ENTRY (DelEntry);
AtaTask = ATA_AYNS_TASK_FROM_ENTRY (DelEntry);
RemoveEntryList (DelEntry);
FreeAtaSubTask (Task);
FreePool (AtaTask);
}
}
gBS->RestoreTPL (OldTpl);
@ -273,6 +290,7 @@ RegisterAtaDevice (
// Initial Ata Task List
//
InitializeListHead (&AtaDevice->AtaTaskList);
InitializeListHead (&AtaDevice->AtaSubTaskList);
//
// Try to identify the ATA device via the ATA pass through command.

View File

@ -4,7 +4,7 @@
This file defines common data structures, macro definitions and some module
internal function header files.
Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
@ -35,6 +35,7 @@
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DevicePathLib.h>
#include <Library/TimerLib.h>
#include <IndustryStandard/Atapi.h>
@ -78,21 +79,9 @@
#define ATA_TASK_SIGNATURE SIGNATURE_32 ('A', 'T', 'S', 'K')
#define ATA_DEVICE_SIGNATURE SIGNATURE_32 ('A', 'B', 'I', 'D')
#define ATA_SUB_TASK_SIGNATURE SIGNATURE_32 ('A', 'S', 'T', 'S')
#define IS_ALIGNED(addr, size) (((UINTN) (addr) & (size - 1)) == 0)
//
// Task for the non blocking I/O
//
typedef struct {
UINT32 Signature;
EFI_BLOCK_IO2_TOKEN *Token;
UINTN *UnsignalledEventCount;
EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;
BOOLEAN *IsError;// Indicate whether meeting error during source allocation for new task.
LIST_ENTRY TaskEntry;
} ATA_BUS_ASYN_TASK;
//
// ATA bus data structure for ATA controller
//
@ -140,12 +129,41 @@ typedef struct {
CHAR16 ModelName[MAX_MODEL_NAME_LEN + 1];
LIST_ENTRY AtaTaskList;
LIST_ENTRY AtaSubTaskList;
} ATA_DEVICE;
//
// Sub-Task for the non blocking I/O
//
typedef struct {
UINT32 Signature;
ATA_DEVICE *AtaDevice;
EFI_BLOCK_IO2_TOKEN *Token;
UINTN *UnsignalledEventCount;
EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;
BOOLEAN *IsError;// Indicate whether meeting error during source allocation for new task.
LIST_ENTRY TaskEntry;
} ATA_BUS_ASYN_SUB_TASK;
//
// Task for the non blocking I/O
//
typedef struct {
UINT32 Signature;
EFI_BLOCK_IO2_TOKEN *Token;
ATA_DEVICE *AtaDevice;
UINT8 *Buffer;
EFI_LBA StartLba;
UINTN NumberOfBlocks;
BOOLEAN IsWrite;
LIST_ENTRY TaskEntry;
} ATA_BUS_ASYN_TASK;
#define ATA_DEVICE_FROM_BLOCK_IO(a) CR (a, ATA_DEVICE, BlockIo, ATA_DEVICE_SIGNATURE)
#define ATA_DEVICE_FROM_BLOCK_IO2(a) CR (a, ATA_DEVICE, BlockIo2, ATA_DEVICE_SIGNATURE)
#define ATA_DEVICE_FROM_DISK_INFO(a) CR (a, ATA_DEVICE, DiskInfo, ATA_DEVICE_SIGNATURE)
#define ATA_DEVICE_FROM_STORAGE_SECURITY(a) CR (a, ATA_DEVICE, StorageSecurity, ATA_DEVICE_SIGNATURE)
#define ATA_AYNS_SUB_TASK_FROM_ENTRY(a) CR (a, ATA_BUS_ASYN_SUB_TASK, TaskEntry, ATA_SUB_TASK_SIGNATURE)
#define ATA_AYNS_TASK_FROM_ENTRY(a) CR (a, ATA_BUS_ASYN_TASK, TaskEntry, ATA_TASK_SIGNATURE)
//
@ -199,7 +217,7 @@ FreeAlignedBuffer (
VOID
EFIAPI
FreeAtaSubTask (
IN OUT ATA_BUS_ASYN_TASK *Task
IN OUT ATA_BUS_ASYN_SUB_TASK *Task
);
/**

View File

@ -54,7 +54,7 @@
BaseLib
UefiDriverEntryPoint
DebugLib
TimerLib
[Guids]
gEfiDiskInfoIdeInterfaceGuid # CONSUMES ## GUID

View File

@ -10,7 +10,7 @@
for Security Protocol Specific layout. This implementation uses big endian for
Cylinder register.
Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
@ -527,7 +527,7 @@ TransferAtaDevice (
VOID
EFIAPI
FreeAtaSubTask (
IN OUT ATA_BUS_ASYN_TASK *Task
IN OUT ATA_BUS_ASYN_SUB_TASK *Task
)
{
if (Task->Packet.Asb != NULL) {
@ -555,11 +555,17 @@ AtaNonBlockingCallBack (
IN VOID *Context
)
{
ATA_BUS_ASYN_TASK *Task;
ATA_BUS_ASYN_SUB_TASK *Task;
ATA_BUS_ASYN_TASK *AtaTask;
ATA_DEVICE *AtaDevice;
LIST_ENTRY *Entry;
EFI_STATUS Status;
Task = (ATA_BUS_ASYN_TASK *) Context;
Task = (ATA_BUS_ASYN_SUB_TASK *) Context;
gBS->CloseEvent (Event);
AtaDevice = Task->AtaDevice;
//
// Check the command status.
// If there is error during the sub task source allocation, the error status
@ -597,6 +603,31 @@ AtaNonBlockingCallBack (
FreePool (Task->UnsignalledEventCount);
FreePool (Task->IsError);
//
// Finish all subtasks and move to the next task in AtaTaskList.
//
if (!IsListEmpty (&AtaDevice->AtaTaskList)) {
Entry = GetFirstNode (&AtaDevice->AtaTaskList);
AtaTask = ATA_AYNS_TASK_FROM_ENTRY (Entry);
DEBUG ((EFI_D_BLKIO, "Start to embark a new Ata Task\n"));
DEBUG ((EFI_D_BLKIO, "AtaTask->NumberOfBlocks = %x; AtaTask->Token=%x\n", AtaTask->NumberOfBlocks, AtaTask->Token));
Status = AccessAtaDevice (
AtaTask->AtaDevice,
AtaTask->Buffer,
AtaTask->StartLba,
AtaTask->NumberOfBlocks,
AtaTask->IsWrite,
AtaTask->Token
);
if (EFI_ERROR (Status)) {
AtaTask->Token->TransactionStatus = Status;
gBS->SignalEvent (AtaTask->Token->Event);
}
RemoveEntryList (Entry);
FreePool (AtaTask);
}
}
DEBUG ((
@ -647,9 +678,10 @@ AccessAtaDevice(
UINTN MaxTransferBlockNumber;
UINTN TransferBlockNumber;
UINTN BlockSize;
ATA_BUS_ASYN_SUB_TASK *SubTask;
UINTN *EventCount;
UINTN TempCount;
ATA_BUS_ASYN_TASK *Task;
ATA_BUS_ASYN_TASK *AtaTask;
EFI_EVENT SubEvent;
UINTN Index;
BOOLEAN *IsError;
@ -660,8 +692,9 @@ AccessAtaDevice(
EventCount = NULL;
IsError = NULL;
Index = 0;
Task = NULL;
SubTask = NULL;
SubEvent = NULL;
AtaTask = NULL;
//
// Ensure AtaDevice->Lba48Bit is a valid boolean value
@ -674,8 +707,28 @@ AccessAtaDevice(
// Initial the return status and shared account for Non Blocking.
//
if ((Token != NULL) && (Token->Event != NULL)) {
Token->TransactionStatus = EFI_SUCCESS;
OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
if (!IsListEmpty (&AtaDevice->AtaSubTaskList)) {
AtaTask = AllocateZeroPool (sizeof (ATA_BUS_ASYN_TASK));
if (AtaTask == NULL) {
gBS->RestoreTPL (OldTpl);
return EFI_OUT_OF_RESOURCES;
}
AtaTask->AtaDevice = AtaDevice;
AtaTask->Buffer = Buffer;
AtaTask->IsWrite = IsWrite;
AtaTask->NumberOfBlocks = NumberOfBlocks;
AtaTask->Signature = ATA_TASK_SIGNATURE;
AtaTask->StartLba = StartLba;
AtaTask->Token = Token;
InsertTailList (&AtaDevice->AtaTaskList, &AtaTask->TaskEntry);
gBS->RestoreTPL (OldTpl);
return EFI_SUCCESS;
}
gBS->RestoreTPL (OldTpl);
Token->TransactionStatus = EFI_SUCCESS;
EventCount = AllocateZeroPool (sizeof (UINTN));
if (EventCount == NULL) {
return EFI_OUT_OF_RESOURCES;
@ -686,10 +739,20 @@ AccessAtaDevice(
FreePool (EventCount);
return EFI_OUT_OF_RESOURCES;
}
DEBUG ((EFI_D_BLKIO, "Allocation IsError Addr=%x\n", IsError));
*IsError = FALSE;
TempCount = (NumberOfBlocks + MaxTransferBlockNumber - 1) / MaxTransferBlockNumber;
*EventCount = TempCount;
DEBUG ((EFI_D_BLKIO, "AccessAtaDevice, NumberOfBlocks=%x\n", NumberOfBlocks));
DEBUG ((EFI_D_BLKIO, "AccessAtaDevice, MaxTransferBlockNumber=%x\n", MaxTransferBlockNumber));
DEBUG ((EFI_D_BLKIO, "AccessAtaDevice, EventCount=%x\n", TempCount));
}else {
while (!IsListEmpty (&AtaDevice->AtaTaskList) || !IsListEmpty (&AtaDevice->AtaSubTaskList)) {
//
// Stall for 100us.
//
MicroSecondDelay (100);
}
}
do {
@ -705,27 +768,29 @@ AccessAtaDevice(
// Create sub event for the sub ata task. Non-blocking mode.
//
if ((Token != NULL) && (Token->Event != NULL)) {
Task = NULL;
SubTask = NULL;
SubEvent = NULL;
Task = AllocateZeroPool (sizeof (ATA_BUS_ASYN_TASK));
if (Task == NULL) {
SubTask = AllocateZeroPool (sizeof (ATA_BUS_ASYN_SUB_TASK));
if (SubTask == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto EXIT;
}
OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
Task->UnsignalledEventCount = EventCount;
Task->Token = Token;
Task->IsError = IsError;
InsertTailList (&AtaDevice->AtaTaskList, &Task->TaskEntry);
SubTask->UnsignalledEventCount = EventCount;
SubTask->Signature = ATA_SUB_TASK_SIGNATURE;
SubTask->AtaDevice = AtaDevice;
SubTask->Token = Token;
SubTask->IsError = IsError;
InsertTailList (&AtaDevice->AtaSubTaskList, &SubTask->TaskEntry);
gBS->RestoreTPL (OldTpl);
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
AtaNonBlockingCallBack,
Task,
SubTask,
&SubEvent
);
//
@ -737,11 +802,12 @@ AccessAtaDevice(
goto EXIT;
}
Status = TransferAtaDevice (AtaDevice, &Task->Packet, Buffer, StartLba, (UINT32) TransferBlockNumber, IsWrite, SubEvent);
Status = TransferAtaDevice (AtaDevice, &SubTask->Packet, Buffer, StartLba, (UINT32) TransferBlockNumber, IsWrite, SubEvent);
} else {
//
// Blocking Mode.
//
DEBUG ((EFI_D_BLKIO, "Blocking AccessAtaDevice, TransferBlockNumber=%x; StartLba = %x\n", TransferBlockNumber, StartLba));
Status = TransferAtaDevice (AtaDevice, NULL, Buffer, StartLba, (UINT32) TransferBlockNumber, IsWrite, NULL);
}
@ -770,15 +836,14 @@ EXIT:
FreePool (IsError);
}
if (Task != NULL) {
RemoveEntryList (&Task->TaskEntry);
FreeAtaSubTask (Task);
if (SubTask != NULL) {
RemoveEntryList (&SubTask->TaskEntry);
FreeAtaSubTask (SubTask);
}
if (SubEvent != NULL) {
gBS->CloseEvent (SubEvent);
}
gBS->RestoreTPL (OldTpl);
}
}