+/**\r
+ Execute Read(16) SCSI command on a specific SCSI target.\r
+\r
+ Executes the SCSI Read(16) command on the SCSI target specified by ScsiIo.\r
+ If Timeout is zero, then this function waits indefinitely for the command to complete.\r
+ If Timeout is greater than zero, then the command is executed and will timeout\r
+ after Timeout 100 ns units. The StartLba and SectorSize parameters are used to\r
+ construct the CDB for this SCSI command.\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 buffer\r
+ alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER\r
+ gets returned.\r
+\r
+ If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer\r
+ alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER\r
+ 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 of data that shall be transferred.\r
+\r
+ @retval EFI_SUCCESS Command is executed successfully.\r
+ @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could\r
+ not be transferred. The actual number of bytes transferred is returned in DataLength.\r
+ @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many\r
+ SCSI Command Packets already queued.\r
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.\r
+ @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by\r
+ the SCSI initiator(i.e., SCSI Host Controller)\r
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.\r
+ @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ScsiRead16Command (\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
+ )\r
+{\r
+ EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;\r
+ EFI_STATUS Status;\r
+ UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIXTEEN];\r
+\r
+ ASSERT (SenseDataLength != NULL);\r
+ ASSERT (HostAdapterStatus != NULL);\r
+ ASSERT (TargetStatus != NULL);\r
+ ASSERT (DataLength != NULL);\r
+ ASSERT (ScsiIo != NULL);\r
+\r
+ ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));\r
+ ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIXTEEN);\r
+\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
+ Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);\r
+\r
+ *HostAdapterStatus = CommandPacket.HostAdapterStatus;\r
+ *TargetStatus = CommandPacket.TargetStatus;\r
+ *SenseDataLength = CommandPacket.SenseDataLength;\r
+ *DataLength = CommandPacket.InTransferLength;\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Execute Write(16) SCSI command on a specific SCSI target.\r
+\r
+ Executes the SCSI Write(16) command on the SCSI target specified by ScsiIo.\r
+ If Timeout is zero, then this function waits indefinitely for the command to complete.\r
+ If Timeout is greater than zero, then the command is executed and will timeout after\r
+ Timeout 100 ns units. The StartLba and SectorSize parameters are used to construct\r
+ the CDB for this SCSI command.\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 buffer\r
+ alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER\r
+ gets returned.\r
+\r
+ If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer\r
+ alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER\r
+ 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 of data that shall be transferred.\r
+\r
+ @retval EFI_SUCCESS Command is executed successfully.\r
+ @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could\r
+ not be transferred. The actual number of bytes transferred is returned in DataLength.\r
+ @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many\r
+ SCSI Command Packets already queued.\r
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.\r
+ @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by\r
+ the SCSI initiator(i.e., SCSI Host Controller)\r
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.\r
+ @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ScsiWrite16Command (\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
+ )\r
+{\r
+ EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;\r
+ EFI_STATUS Status;\r
+ UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIXTEEN];\r
+\r
+ ASSERT (SenseDataLength != NULL);\r
+ ASSERT (HostAdapterStatus != NULL);\r
+ ASSERT (TargetStatus != NULL);\r
+ ASSERT (DataLength != NULL);\r
+ ASSERT (ScsiIo != NULL);\r
+\r
+ ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));\r
+ ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIXTEEN);\r
+\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
+ Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);\r
+\r
+ *HostAdapterStatus = CommandPacket.HostAdapterStatus;\r
+ *TargetStatus = CommandPacket.TargetStatus;\r
+ *SenseDataLength = CommandPacket.SenseDataLength;\r
+ *DataLength = CommandPacket.OutTransferLength;\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_NOTIFY,\r
+ ScsiLibNotify,\r
+ Context,\r
+ &SelfEvent\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ goto ErrorExit;\r
+ }\r
+\r
+ Status = ScsiIo->ExecuteScsiCommand (ScsiIo, CommandPacket, SelfEvent);\r
+ if (EFI_ERROR(Status)) {\r
+ //\r
+ // Since ScsiLibNotify() will not be signaled if ExecuteScsiCommand()\r
+ // returns with error, close the event here.\r
+ //\r
+ gBS->CloseEvent (SelfEvent);\r
+ goto ErrorExit;\r
+ } else {\r
+ return EFI_SUCCESS;\r
+ }\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_NOTIFY,\r
+ ScsiLibNotify,\r
+ Context,\r
+ &SelfEvent\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ goto ErrorExit;\r
+ }\r
+\r
+ Status = ScsiIo->ExecuteScsiCommand (ScsiIo, CommandPacket, SelfEvent);\r
+ if (EFI_ERROR(Status)) {\r
+ //\r
+ // Since ScsiLibNotify() will not be signaled if ExecuteScsiCommand()\r
+ // returns with error, close the event here.\r
+ //\r
+ gBS->CloseEvent (SelfEvent);\r
+ goto ErrorExit;\r
+ } else {\r
+ return EFI_SUCCESS;\r
+ }\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_NOTIFY,\r
+ ScsiLibNotify,\r
+ Context,\r
+ &SelfEvent\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ goto ErrorExit;\r
+ }\r
+\r
+ Status = ScsiIo->ExecuteScsiCommand (ScsiIo, CommandPacket, SelfEvent);\r
+ if (EFI_ERROR(Status)) {\r
+ //\r
+ // Since ScsiLibNotify() will not be signaled if ExecuteScsiCommand()\r
+ // returns with error, close the event here.\r
+ //\r
+ gBS->CloseEvent (SelfEvent);\r
+ goto ErrorExit;\r
+ } else {\r
+ return EFI_SUCCESS;\r
+ }\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_NOTIFY,\r
+ ScsiLibNotify,\r
+ Context,\r
+ &SelfEvent\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ goto ErrorExit;\r
+ }\r
+\r
+ Status = ScsiIo->ExecuteScsiCommand (ScsiIo, CommandPacket, SelfEvent);\r
+ if (EFI_ERROR(Status)) {\r
+ //\r
+ // Since ScsiLibNotify() will not be signaled if ExecuteScsiCommand()\r
+ // returns with error, close the event here.\r
+ //\r
+ gBS->CloseEvent (SelfEvent);\r
+ goto ErrorExit;\r
+ } else {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ErrorExit:\r
+ if (Context != NULL) {\r
+ FreePool (Context);\r
+ }\r
+\r
+ return Status;\r
+}\r