#include <Library/DebugLib.h>\r
#include <Library/UefiScsiLib.h>\r
#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
\r
#include <IndustryStandard/Scsi.h>\r
\r
#define EFI_SCSI_OP_LENGTH_TEN 0xa\r
#define EFI_SCSI_OP_LENGTH_SIXTEEN 0x10\r
\r
+//\r
+// The context structure used when non-blocking SCSI read/write operation\r
+// completes.\r
+//\r
+typedef struct {\r
+ ///\r
+ /// The SCSI request packet to send to the SCSI controller specified by\r
+ /// the device handle.\r
+ ///\r
+ EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;\r
+ ///\r
+ /// The length of the output sense data.\r
+ ///\r
+ UINT8 *SenseDataLength;\r
+ ///\r
+ /// The status of the SCSI host adapter.\r
+ ///\r
+ UINT8 *HostAdapterStatus;\r
+ ///\r
+ /// The status of the target SCSI device.\r
+ ///\r
+ UINT8 *TargetStatus;\r
+ ///\r
+ /// The length of the data buffer for the SCSI read/write command.\r
+ ///\r
+ UINT32 *DataLength;\r
+ ///\r
+ /// The caller event to be signaled when the SCSI read/write command\r
+ /// completes.\r
+ ///\r
+ EFI_EVENT CallerEvent;\r
+} EFI_SCSI_LIB_ASYNC_CONTEXT;\r
+\r
\r
\r
/**\r
\r
return Status;\r
}\r
+\r
+\r
+/**\r
+ Internal helper notify function in which update the result of the\r
+ non-blocking SCSI Read/Write commands and signal caller event.\r
+\r
+ @param Event The instance of EFI_EVENT.\r
+ @param Context The parameter passed in.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+ScsiLibNotify (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_SCSI_LIB_ASYNC_CONTEXT *LibContext;\r
+ EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket;\r
+ EFI_EVENT CallerEvent;\r
+\r
+ LibContext = (EFI_SCSI_LIB_ASYNC_CONTEXT *) Context;\r
+ CommandPacket = &LibContext->CommandPacket;\r
+ CallerEvent = LibContext->CallerEvent;\r
+\r
+ //\r
+ // Update SCSI Read/Write operation results\r
+ //\r
+ *LibContext->SenseDataLength = CommandPacket->SenseDataLength;\r
+ *LibContext->HostAdapterStatus = CommandPacket->HostAdapterStatus;\r
+ *LibContext->TargetStatus = CommandPacket->TargetStatus;\r
+ if (CommandPacket->InDataBuffer != NULL) {\r
+ *LibContext->DataLength = CommandPacket->InTransferLength;\r
+ } else {\r
+ *LibContext->DataLength = CommandPacket->OutTransferLength;\r
+ }\r
+\r
+ if (CommandPacket->Cdb != NULL) {\r
+ FreePool (CommandPacket->Cdb);\r
+ }\r
+ FreePool (Context);\r
+\r
+ gBS->CloseEvent (Event);\r
+ gBS->SignalEvent (CallerEvent);\r
+}\r
+\r
+\r
+/**\r
+ Execute blocking/non-blocking Read(10) SCSI command on a specific SCSI\r
+ target.\r
+\r
+ Executes the SCSI Read(10) command on the SCSI target specified by ScsiIo.\r
+ When Event is NULL, blocking command will be executed. Otherwise non-blocking\r
+ command will be executed.\r
+ For blocking I/O, if Timeout is zero, this function will wait indefinitely\r
+ for the command to complete. If Timeout is greater than zero, then the\r
+ command is executed and will timeout after Timeout 100 ns units.\r
+ For non-blocking I/O, if Timeout is zero, Event will be signaled only after\r
+ the command to completes. If Timeout is greater than zero, Event will also be\r
+ signaled after Timeout 100 ns units.\r
+ The StartLba and SectorSize parameters are used to construct the CDB for this\r
+ SCSI command.\r
+\r
+ If ScsiIo is NULL, then ASSERT().\r
+ If SenseDataLength is NULL, then ASSERT().\r
+ If HostAdapterStatus is NULL, then ASSERT().\r
+ If TargetStatus is NULL, then ASSERT().\r
+ If DataLength is NULL, then ASSERT().\r
+\r
+ If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet\r
+ buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise\r
+ EFI_INVALID_PARAMETER gets returned.\r
+\r
+ If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet\r
+ buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise\r
+ EFI_INVALID_PARAMETER gets returned.\r
+\r
+ @param[in] ScsiIo A pointer to SCSI IO protocol.\r
+ @param[in] Timeout The length of timeout period.\r
+ @param[in, out] SenseData A pointer to output sense data.\r
+ @param[in, out] SenseDataLength The length of output sense data.\r
+ @param[out] HostAdapterStatus The status of Host Adapter.\r
+ @param[out] TargetStatus The status of the target.\r
+ @param[in, out] DataBuffer Read 16 command data.\r
+ @param[in, out] DataLength The length of data buffer.\r
+ @param[in] StartLba The start address of LBA.\r
+ @param[in] SectorSize The number of contiguous logical blocks\r
+ of data that shall be transferred.\r
+ @param[in] Event If the SCSI target does not support\r
+ non-blocking I/O, then Event is ignored,\r
+ and blocking I/O is performed. If Event\r
+ is NULL, then blocking I/O is performed.\r
+ If Event is not NULL and non-blocking\r
+ I/O is supported, then non-blocking I/O\r
+ is performed, and Event will be signaled\r
+ when the SCSI Read(10) command\r
+ completes.\r
+\r
+ @retval EFI_SUCCESS Command is executed successfully.\r
+ @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,\r
+ but the entire DataBuffer could not be\r
+ transferred. The actual number of bytes\r
+ transferred is returned in DataLength.\r
+ @retval EFI_NOT_READY The SCSI Request Packet could not be\r
+ sent because there are too many SCSI\r
+ Command Packets already queued.\r
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting\r
+ to send SCSI Request Packet.\r
+ @retval EFI_UNSUPPORTED The command described by the SCSI\r
+ Request Packet is not supported by the\r
+ SCSI initiator(i.e., SCSI Host\r
+ Controller)\r
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the\r
+ SCSI Request Packet to execute.\r
+ @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet\r
+ are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due\r
+ to a lack of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ScsiRead10CommandEx (\r
+ IN EFI_SCSI_IO_PROTOCOL *ScsiIo,\r
+ IN UINT64 Timeout,\r
+ IN OUT VOID *SenseData, OPTIONAL\r
+ IN OUT UINT8 *SenseDataLength,\r
+ OUT UINT8 *HostAdapterStatus,\r
+ OUT UINT8 *TargetStatus,\r
+ IN OUT VOID *DataBuffer, OPTIONAL\r
+ IN OUT UINT32 *DataLength,\r
+ IN UINT32 StartLba,\r
+ IN UINT32 SectorSize,\r
+ IN EFI_EVENT Event OPTIONAL\r
+ )\r
+{\r
+ EFI_SCSI_LIB_ASYNC_CONTEXT *Context;\r
+ EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket;\r
+ EFI_STATUS Status;\r
+ UINT8 *Cdb;\r
+ EFI_EVENT SelfEvent;\r
+\r
+ if (Event == NULL) {\r
+ return ScsiRead10Command (\r
+ ScsiIo,\r
+ Timeout,\r
+ SenseData,\r
+ SenseDataLength,\r
+ HostAdapterStatus,\r
+ TargetStatus,\r
+ DataBuffer,\r
+ DataLength,\r
+ StartLba,\r
+ SectorSize\r
+ );\r
+ }\r
+\r
+ ASSERT (SenseDataLength != NULL);\r
+ ASSERT (HostAdapterStatus != NULL);\r
+ ASSERT (TargetStatus != NULL);\r
+ ASSERT (DataLength != NULL);\r
+ ASSERT (ScsiIo != NULL);\r
+\r
+ Context = AllocateZeroPool (sizeof (EFI_SCSI_LIB_ASYNC_CONTEXT));\r
+ if (Context == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Cdb = AllocateZeroPool (EFI_SCSI_OP_LENGTH_TEN);\r
+ if (Cdb == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ErrorExit;\r
+ }\r
+\r
+ Context->SenseDataLength = SenseDataLength;\r
+ Context->HostAdapterStatus = HostAdapterStatus;\r
+ Context->TargetStatus = TargetStatus;\r
+ Context->CallerEvent = Event;\r
+\r
+ CommandPacket = &Context->CommandPacket;\r
+ CommandPacket->Timeout = Timeout;\r
+ CommandPacket->InDataBuffer = DataBuffer;\r
+ CommandPacket->SenseData = SenseData;\r
+ CommandPacket->InTransferLength = *DataLength;\r
+ CommandPacket->Cdb = Cdb;\r
+ //\r
+ // Fill Cdb for Read (10) Command\r
+ //\r
+ Cdb[0] = EFI_SCSI_OP_READ10;\r
+ WriteUnaligned32 ((UINT32 *)&Cdb[2], SwapBytes32 (StartLba));\r
+ WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 ((UINT16) SectorSize));\r
+\r
+ CommandPacket->CdbLength = EFI_SCSI_OP_LENGTH_TEN;\r
+ CommandPacket->DataDirection = EFI_SCSI_DATA_IN;\r
+ CommandPacket->SenseDataLength = *SenseDataLength;\r
+\r
+ //\r
+ // Create Event\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ ScsiLibNotify,\r
+ Context,\r
+ &SelfEvent\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ goto ErrorExit;\r
+ }\r
+\r
+ return ScsiIo->ExecuteScsiCommand (ScsiIo, CommandPacket, SelfEvent);\r
+\r
+ErrorExit:\r
+ if (Context != NULL) {\r
+ FreePool (Context);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Execute blocking/non-blocking Write(10) SCSI command on a specific SCSI\r
+ target.\r
+\r
+ Executes the SCSI Write(10) command on the SCSI target specified by ScsiIo.\r
+ When Event is NULL, blocking command will be executed. Otherwise non-blocking\r
+ command will be executed.\r
+ For blocking I/O, if Timeout is zero, this function will wait indefinitely\r
+ for the command to complete. If Timeout is greater than zero, then the\r
+ command is executed and will timeout after Timeout 100 ns units.\r
+ For non-blocking I/O, if Timeout is zero, Event will be signaled only after\r
+ the command to completes. If Timeout is greater than zero, Event will also be\r
+ signaled after Timeout 100 ns units.\r
+ The StartLba and SectorSize parameters are used to construct the CDB for this\r
+ SCSI command.\r
+\r
+ If ScsiIo is NULL, then ASSERT().\r
+ If SenseDataLength is NULL, then ASSERT().\r
+ If HostAdapterStatus is NULL, then ASSERT().\r
+ If TargetStatus is NULL, then ASSERT().\r
+ If DataLength is NULL, then ASSERT().\r
+\r
+ If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet\r
+ buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise\r
+ EFI_INVALID_PARAMETER gets returned.\r
+\r
+ If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet\r
+ buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise\r
+ EFI_INVALID_PARAMETER gets returned.\r
+\r
+ @param[in] ScsiIo SCSI IO Protocol to use\r
+ @param[in] Timeout The length of timeout period.\r
+ @param[in, out] SenseData A pointer to output sense data.\r
+ @param[in, out] SenseDataLength The length of output sense data.\r
+ @param[out] HostAdapterStatus The status of Host Adapter.\r
+ @param[out] TargetStatus The status of the target.\r
+ @param[in, out] DataBuffer A pointer to a data buffer.\r
+ @param[in, out] DataLength The length of data buffer.\r
+ @param[in] StartLba The start address of LBA.\r
+ @param[in] SectorSize The number of contiguous logical blocks\r
+ of data that shall be transferred.\r
+ @param[in] Event If the SCSI target does not support\r
+ non-blocking I/O, then Event is ignored,\r
+ and blocking I/O is performed. If Event\r
+ is NULL, then blocking I/O is performed.\r
+ If Event is not NULL and non-blocking\r
+ I/O is supported, then non-blocking I/O\r
+ is performed, and Event will be signaled\r
+ when the SCSI Write(10) command\r
+ completes.\r
+\r
+ @retval EFI_SUCCESS Command is executed successfully.\r
+ @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,\r
+ but the entire DataBuffer could not be\r
+ transferred. The actual number of bytes\r
+ transferred is returned in DataLength.\r
+ @retval EFI_NOT_READY The SCSI Request Packet could not be\r
+ sent because there are too many SCSI\r
+ Command Packets already queued.\r
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting\r
+ to send SCSI Request Packet.\r
+ @retval EFI_UNSUPPORTED The command described by the SCSI\r
+ Request Packet is not supported by the\r
+ SCSI initiator(i.e., SCSI Host\r
+ Controller)\r
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the\r
+ SCSI Request Packet to execute.\r
+ @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet\r
+ are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due\r
+ to a lack of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ScsiWrite10CommandEx (\r
+ IN EFI_SCSI_IO_PROTOCOL *ScsiIo,\r
+ IN UINT64 Timeout,\r
+ IN OUT VOID *SenseData, OPTIONAL\r
+ IN OUT UINT8 *SenseDataLength,\r
+ OUT UINT8 *HostAdapterStatus,\r
+ OUT UINT8 *TargetStatus,\r
+ IN OUT VOID *DataBuffer, OPTIONAL\r
+ IN OUT UINT32 *DataLength,\r
+ IN UINT32 StartLba,\r
+ IN UINT32 SectorSize,\r
+ IN EFI_EVENT Event OPTIONAL\r
+ )\r
+{\r
+ EFI_SCSI_LIB_ASYNC_CONTEXT *Context;\r
+ EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket;\r
+ EFI_STATUS Status;\r
+ UINT8 *Cdb;\r
+ EFI_EVENT SelfEvent;\r
+\r
+ if (Event == NULL) {\r
+ return ScsiWrite10Command (\r
+ ScsiIo,\r
+ Timeout,\r
+ SenseData,\r
+ SenseDataLength,\r
+ HostAdapterStatus,\r
+ TargetStatus,\r
+ DataBuffer,\r
+ DataLength,\r
+ StartLba,\r
+ SectorSize\r
+ );\r
+ }\r
+\r
+ ASSERT (SenseDataLength != NULL);\r
+ ASSERT (HostAdapterStatus != NULL);\r
+ ASSERT (TargetStatus != NULL);\r
+ ASSERT (DataLength != NULL);\r
+ ASSERT (ScsiIo != NULL);\r
+\r
+ Context = AllocateZeroPool (sizeof (EFI_SCSI_LIB_ASYNC_CONTEXT));\r
+ if (Context == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Cdb = AllocateZeroPool (EFI_SCSI_OP_LENGTH_TEN);\r
+ if (Cdb == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ErrorExit;\r
+ }\r
+\r
+ Context->SenseDataLength = SenseDataLength;\r
+ Context->HostAdapterStatus = HostAdapterStatus;\r
+ Context->TargetStatus = TargetStatus;\r
+ Context->CallerEvent = Event;\r
+\r
+ CommandPacket = &Context->CommandPacket;\r
+ CommandPacket->Timeout = Timeout;\r
+ CommandPacket->OutDataBuffer = DataBuffer;\r
+ CommandPacket->SenseData = SenseData;\r
+ CommandPacket->OutTransferLength = *DataLength;\r
+ CommandPacket->Cdb = Cdb;\r
+ //\r
+ // Fill Cdb for Write (10) Command\r
+ //\r
+ Cdb[0] = EFI_SCSI_OP_WRITE10;\r
+ WriteUnaligned32 ((UINT32 *)&Cdb[2], SwapBytes32 (StartLba));\r
+ WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 ((UINT16) SectorSize));\r
+\r
+ CommandPacket->CdbLength = EFI_SCSI_OP_LENGTH_TEN;\r
+ CommandPacket->DataDirection = EFI_SCSI_DATA_OUT;\r
+ CommandPacket->SenseDataLength = *SenseDataLength;\r
+\r
+ //\r
+ // Create Event\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ ScsiLibNotify,\r
+ Context,\r
+ &SelfEvent\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ goto ErrorExit;\r
+ }\r
+\r
+ return ScsiIo->ExecuteScsiCommand (ScsiIo, CommandPacket, Event);\r
+\r
+ErrorExit:\r
+ if (Context != NULL) {\r
+ FreePool (Context);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Execute blocking/non-blocking Read(16) SCSI command on a specific SCSI\r
+ target.\r
+\r
+ Executes the SCSI Read(16) command on the SCSI target specified by ScsiIo.\r
+ When Event is NULL, blocking command will be executed. Otherwise non-blocking\r
+ command will be executed.\r
+ For blocking I/O, if Timeout is zero, this function will wait indefinitely\r
+ for the command to complete. If Timeout is greater than zero, then the\r
+ command is executed and will timeout after Timeout 100 ns units.\r
+ For non-blocking I/O, if Timeout is zero, Event will be signaled only after\r
+ the command to completes. If Timeout is greater than zero, Event will also be\r
+ signaled after Timeout 100 ns units.\r
+ The StartLba and SectorSize parameters are used to construct the CDB for this\r
+ SCSI command.\r
+\r
+ If ScsiIo is NULL, then ASSERT().\r
+ If SenseDataLength is NULL, then ASSERT().\r
+ If HostAdapterStatus is NULL, then ASSERT().\r
+ If TargetStatus is NULL, then ASSERT().\r
+ If DataLength is NULL, then ASSERT().\r
+\r
+ If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet\r
+ buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise\r
+ EFI_INVALID_PARAMETER gets returned.\r
+\r
+ If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet\r
+ buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise\r
+ EFI_INVALID_PARAMETER gets returned.\r
+\r
+ @param[in] ScsiIo A pointer to SCSI IO protocol.\r
+ @param[in] Timeout The length of timeout period.\r
+ @param[in, out] SenseData A pointer to output sense data.\r
+ @param[in, out] SenseDataLength The length of output sense data.\r
+ @param[out] HostAdapterStatus The status of Host Adapter.\r
+ @param[out] TargetStatus The status of the target.\r
+ @param[in, out] DataBuffer Read 16 command data.\r
+ @param[in, out] DataLength The length of data buffer.\r
+ @param[in] StartLba The start address of LBA.\r
+ @param[in] SectorSize The number of contiguous logical blocks\r
+ of data that shall be transferred.\r
+ @param[in] Event If the SCSI target does not support\r
+ non-blocking I/O, then Event is ignored,\r
+ and blocking I/O is performed. If Event\r
+ is NULL, then blocking I/O is performed.\r
+ If Event is not NULL and non-blocking\r
+ I/O is supported, then non-blocking I/O\r
+ is performed, and Event will be signaled\r
+ when the SCSI Read(16) command\r
+ completes.\r
+\r
+ @retval EFI_SUCCESS Command is executed successfully.\r
+ @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,\r
+ but the entire DataBuffer could not be\r
+ transferred. The actual number of bytes\r
+ transferred is returned in DataLength.\r
+ @retval EFI_NOT_READY The SCSI Request Packet could not be\r
+ sent because there are too many SCSI\r
+ Command Packets already queued.\r
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting\r
+ to send SCSI Request Packet.\r
+ @retval EFI_UNSUPPORTED The command described by the SCSI\r
+ Request Packet is not supported by the\r
+ SCSI initiator(i.e., SCSI Host\r
+ Controller)\r
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the\r
+ SCSI Request Packet to execute.\r
+ @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet\r
+ are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due\r
+ to a lack of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ScsiRead16CommandEx (\r
+ IN EFI_SCSI_IO_PROTOCOL *ScsiIo,\r
+ IN UINT64 Timeout,\r
+ IN OUT VOID *SenseData, OPTIONAL\r
+ IN OUT UINT8 *SenseDataLength,\r
+ OUT UINT8 *HostAdapterStatus,\r
+ OUT UINT8 *TargetStatus,\r
+ IN OUT VOID *DataBuffer, OPTIONAL\r
+ IN OUT UINT32 *DataLength,\r
+ IN UINT64 StartLba,\r
+ IN UINT32 SectorSize,\r
+ IN EFI_EVENT Event OPTIONAL\r
+ )\r
+{\r
+ EFI_SCSI_LIB_ASYNC_CONTEXT *Context;\r
+ EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket;\r
+ EFI_STATUS Status;\r
+ UINT8 *Cdb;\r
+ EFI_EVENT SelfEvent;\r
+\r
+ if (Event == NULL) {\r
+ return ScsiRead16Command (\r
+ ScsiIo,\r
+ Timeout,\r
+ SenseData,\r
+ SenseDataLength,\r
+ HostAdapterStatus,\r
+ TargetStatus,\r
+ DataBuffer,\r
+ DataLength,\r
+ StartLba,\r
+ SectorSize\r
+ );\r
+ }\r
+\r
+ ASSERT (SenseDataLength != NULL);\r
+ ASSERT (HostAdapterStatus != NULL);\r
+ ASSERT (TargetStatus != NULL);\r
+ ASSERT (DataLength != NULL);\r
+ ASSERT (ScsiIo != NULL);\r
+\r
+ Context = AllocateZeroPool (sizeof (EFI_SCSI_LIB_ASYNC_CONTEXT));\r
+ if (Context == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Cdb = AllocateZeroPool (EFI_SCSI_OP_LENGTH_SIXTEEN);\r
+ if (Cdb == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ErrorExit;\r
+ }\r
+\r
+ Context->SenseDataLength = SenseDataLength;\r
+ Context->HostAdapterStatus = HostAdapterStatus;\r
+ Context->TargetStatus = TargetStatus;\r
+ Context->CallerEvent = Event;\r
+\r
+ CommandPacket = &Context->CommandPacket;\r
+ CommandPacket->Timeout = Timeout;\r
+ CommandPacket->InDataBuffer = DataBuffer;\r
+ CommandPacket->SenseData = SenseData;\r
+ CommandPacket->InTransferLength = *DataLength;\r
+ CommandPacket->Cdb = Cdb;\r
+ //\r
+ // Fill Cdb for Read (16) Command\r
+ //\r
+ Cdb[0] = EFI_SCSI_OP_READ16;\r
+ WriteUnaligned64 ((UINT64 *)&Cdb[2], SwapBytes64 (StartLba));\r
+ WriteUnaligned32 ((UINT32 *)&Cdb[10], SwapBytes32 (SectorSize));\r
+\r
+ CommandPacket->CdbLength = EFI_SCSI_OP_LENGTH_SIXTEEN;\r
+ CommandPacket->DataDirection = EFI_SCSI_DATA_IN;\r
+ CommandPacket->SenseDataLength = *SenseDataLength;\r
+\r
+ //\r
+ // Create Event\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ ScsiLibNotify,\r
+ Context,\r
+ &SelfEvent\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ goto ErrorExit;\r
+ }\r
+\r
+ return ScsiIo->ExecuteScsiCommand (ScsiIo, CommandPacket, Event);\r
+\r
+ErrorExit:\r
+ if (Context != NULL) {\r
+ FreePool (Context);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Execute blocking/non-blocking Write(16) SCSI command on a specific SCSI\r
+ target.\r
+\r
+ Executes the SCSI Write(16) command on the SCSI target specified by ScsiIo.\r
+ When Event is NULL, blocking command will be executed. Otherwise non-blocking\r
+ command will be executed.\r
+ For blocking I/O, if Timeout is zero, this function will wait indefinitely\r
+ for the command to complete. If Timeout is greater than zero, then the\r
+ command is executed and will timeout after Timeout 100 ns units.\r
+ For non-blocking I/O, if Timeout is zero, Event will be signaled only after\r
+ the command to completes. If Timeout is greater than zero, Event will also be\r
+ signaled after Timeout 100 ns units.\r
+ The StartLba and SectorSize parameters are used to construct the CDB for this\r
+ SCSI command.\r
+\r
+ If ScsiIo is NULL, then ASSERT().\r
+ If SenseDataLength is NULL, then ASSERT().\r
+ If HostAdapterStatus is NULL, then ASSERT().\r
+ If TargetStatus is NULL, then ASSERT().\r
+ If DataLength is NULL, then ASSERT().\r
+\r
+ If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet\r
+ buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise\r
+ EFI_INVALID_PARAMETER gets returned.\r
+\r
+ If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet\r
+ buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise\r
+ EFI_INVALID_PARAMETER gets returned.\r
+\r
+ @param[in] ScsiIo SCSI IO Protocol to use\r
+ @param[in] Timeout The length of timeout period.\r
+ @param[in, out] SenseData A pointer to output sense data.\r
+ @param[in, out] SenseDataLength The length of output sense data.\r
+ @param[out] HostAdapterStatus The status of Host Adapter.\r
+ @param[out] TargetStatus The status of the target.\r
+ @param[in, out] DataBuffer A pointer to a data buffer.\r
+ @param[in, out] DataLength The length of data buffer.\r
+ @param[in] StartLba The start address of LBA.\r
+ @param[in] SectorSize The number of contiguous logical blocks\r
+ of data that shall be transferred.\r
+ @param[in] Event If the SCSI target does not support\r
+ non-blocking I/O, then Event is ignored,\r
+ and blocking I/O is performed. If Event\r
+ is NULL, then blocking I/O is performed.\r
+ If Event is not NULL and non-blocking\r
+ I/O is supported, then non-blocking I/O\r
+ is performed, and Event will be signaled\r
+ when the SCSI Write(16) command\r
+ completes.\r
+\r
+ @retval EFI_SUCCESS Command is executed successfully.\r
+ @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,\r
+ but the entire DataBuffer could not be\r
+ transferred. The actual number of bytes\r
+ transferred is returned in DataLength.\r
+ @retval EFI_NOT_READY The SCSI Request Packet could not be\r
+ sent because there are too many SCSI\r
+ Command Packets already queued.\r
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting\r
+ to send SCSI Request Packet.\r
+ @retval EFI_UNSUPPORTED The command described by the SCSI\r
+ Request Packet is not supported by the\r
+ SCSI initiator(i.e., SCSI Host\r
+ Controller)\r
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the\r
+ SCSI Request Packet to execute.\r
+ @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet\r
+ are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due\r
+ to a lack of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ScsiWrite16CommandEx (\r
+ IN EFI_SCSI_IO_PROTOCOL *ScsiIo,\r
+ IN UINT64 Timeout,\r
+ IN OUT VOID *SenseData, OPTIONAL\r
+ IN OUT UINT8 *SenseDataLength,\r
+ OUT UINT8 *HostAdapterStatus,\r
+ OUT UINT8 *TargetStatus,\r
+ IN OUT VOID *DataBuffer, OPTIONAL\r
+ IN OUT UINT32 *DataLength,\r
+ IN UINT64 StartLba,\r
+ IN UINT32 SectorSize,\r
+ IN EFI_EVENT Event OPTIONAL\r
+ )\r
+{\r
+ EFI_SCSI_LIB_ASYNC_CONTEXT *Context;\r
+ EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket;\r
+ EFI_STATUS Status;\r
+ UINT8 *Cdb;\r
+ EFI_EVENT SelfEvent;\r
+\r
+ if (Event == NULL) {\r
+ return ScsiWrite16Command (\r
+ ScsiIo,\r
+ Timeout,\r
+ SenseData,\r
+ SenseDataLength,\r
+ HostAdapterStatus,\r
+ TargetStatus,\r
+ DataBuffer,\r
+ DataLength,\r
+ StartLba,\r
+ SectorSize\r
+ );\r
+ }\r
+\r
+ ASSERT (SenseDataLength != NULL);\r
+ ASSERT (HostAdapterStatus != NULL);\r
+ ASSERT (TargetStatus != NULL);\r
+ ASSERT (DataLength != NULL);\r
+ ASSERT (ScsiIo != NULL);\r
+\r
+ Context = AllocateZeroPool (sizeof (EFI_SCSI_LIB_ASYNC_CONTEXT));\r
+ if (Context == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Cdb = AllocateZeroPool (EFI_SCSI_OP_LENGTH_SIXTEEN);\r
+ if (Cdb == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ErrorExit;\r
+ }\r
+\r
+ Context->SenseDataLength = SenseDataLength;\r
+ Context->HostAdapterStatus = HostAdapterStatus;\r
+ Context->TargetStatus = TargetStatus;\r
+ Context->CallerEvent = Event;\r
+\r
+ CommandPacket = &Context->CommandPacket;\r
+ CommandPacket->Timeout = Timeout;\r
+ CommandPacket->OutDataBuffer = DataBuffer;\r
+ CommandPacket->SenseData = SenseData;\r
+ CommandPacket->OutTransferLength = *DataLength;\r
+ CommandPacket->Cdb = Cdb;\r
+ //\r
+ // Fill Cdb for Write (16) Command\r
+ //\r
+ Cdb[0] = EFI_SCSI_OP_WRITE16;\r
+ WriteUnaligned64 ((UINT64 *)&Cdb[2], SwapBytes64 (StartLba));\r
+ WriteUnaligned32 ((UINT32 *)&Cdb[10], SwapBytes32 (SectorSize));\r
+\r
+ CommandPacket->CdbLength = EFI_SCSI_OP_LENGTH_SIXTEEN;\r
+ CommandPacket->DataDirection = EFI_SCSI_DATA_OUT;\r
+ CommandPacket->SenseDataLength = *SenseDataLength;\r
+\r
+ //\r
+ // Create Event\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ ScsiLibNotify,\r
+ Context,\r
+ &SelfEvent\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ goto ErrorExit;\r
+ }\r
+\r
+ return ScsiIo->ExecuteScsiCommand (ScsiIo, CommandPacket, Event);\r
+\r
+ErrorExit:\r
+ if (Context != NULL) {\r
+ FreePool (Context);\r
+ }\r
+\r
+ return Status;\r
+}\r