/** @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
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
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
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
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
@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
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
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
}\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
Status = ScsiDiskAsyncRead10 (\r
ScsiDiskDevice,\r
Timeout,\r
+ 0,\r
PtrBuffer,\r
ByteCount,\r
(UINT32) Lba,\r
Status = ScsiDiskAsyncRead16 (\r
ScsiDiskDevice,\r
Timeout,\r
+ 0,\r
PtrBuffer,\r
ByteCount,\r
Lba,\r
}\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
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
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
}\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
Status = ScsiDiskAsyncWrite10 (\r
ScsiDiskDevice,\r
Timeout,\r
+ 0,\r
PtrBuffer,\r
ByteCount,\r
(UINT32) Lba,\r
Status = ScsiDiskAsyncWrite16 (\r
ScsiDiskDevice,\r
Timeout,\r
+ 0,\r
PtrBuffer,\r
ByteCount,\r
Lba,\r
}\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
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
Status = ScsiDiskAsyncRead10 (\r
ScsiDiskDevice,\r
Request->Timeout,\r
+ Request->TimesRetry,\r
Request->InBuffer,\r
Request->DataLength,\r
(UINT32) Request->StartLba,\r
Status = ScsiDiskAsyncRead16 (\r
ScsiDiskDevice,\r
Request->Timeout,\r
+ Request->TimesRetry,\r
Request->InBuffer,\r
Request->DataLength,\r
Request->StartLba,\r
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
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
Status = ScsiDiskAsyncWrite10 (\r
ScsiDiskDevice,\r
Request->Timeout,\r
+ Request->TimesRetry,\r
Request->OutBuffer,\r
Request->DataLength,\r
(UINT32) Request->StartLba,\r
Status = ScsiDiskAsyncWrite16 (\r
ScsiDiskDevice,\r
Request->Timeout,\r
+ Request->TimesRetry,\r
Request->OutBuffer,\r
Request->DataLength,\r
Request->StartLba,\r
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
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
\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
\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
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
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
\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
//\r
Status = gBS->CreateEvent (\r
EVT_NOTIFY_SIGNAL,\r
- TPL_CALLBACK,\r
+ TPL_NOTIFY,\r
ScsiDiskNotify,\r
Request,\r
&AsyncIoEvent\r
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
\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
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
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
\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
//\r
Status = gBS->CreateEvent (\r
EVT_NOTIFY_SIGNAL,\r
- TPL_CALLBACK,\r
+ TPL_NOTIFY,\r
ScsiDiskNotify,\r
Request,\r
&AsyncIoEvent\r
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
\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
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
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
\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
//\r
Status = gBS->CreateEvent (\r
EVT_NOTIFY_SIGNAL,\r
- TPL_CALLBACK,\r
+ TPL_NOTIFY,\r
ScsiDiskNotify,\r
Request,\r
&AsyncIoEvent\r
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
\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
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
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
\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
//\r
Status = gBS->CreateEvent (\r
EVT_NOTIFY_SIGNAL,\r
- TPL_CALLBACK,\r
+ TPL_NOTIFY,\r
ScsiDiskNotify,\r
Request,\r
&AsyncIoEvent\r
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