diff options
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/MdePkg/Library/UefiScsiLib/UefiScsiLib.c')
-rw-r--r-- | src/VBox/Devices/EFI/Firmware/MdePkg/Library/UefiScsiLib/UefiScsiLib.c | 2290 |
1 files changed, 2290 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/MdePkg/Library/UefiScsiLib/UefiScsiLib.c b/src/VBox/Devices/EFI/Firmware/MdePkg/Library/UefiScsiLib/UefiScsiLib.c new file mode 100644 index 00000000..03f3b9f8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdePkg/Library/UefiScsiLib/UefiScsiLib.c @@ -0,0 +1,2290 @@ +/** @file + UEFI SCSI Library implementation + + Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include <Uefi.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/UefiScsiLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h> + +#include <IndustryStandard/Scsi.h> + + + // + // Scsi Command Length + // +#define EFI_SCSI_OP_LENGTH_SIX 0x6 +#define EFI_SCSI_OP_LENGTH_TEN 0xa +#define EFI_SCSI_OP_LENGTH_TWELVE 0xc +#define EFI_SCSI_OP_LENGTH_SIXTEEN 0x10 + +// +// The context structure used when non-blocking SCSI read/write operation +// completes. +// +typedef struct { + /// + /// The SCSI request packet to send to the SCSI controller specified by + /// the device handle. + /// + EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; + /// + /// The length of the output sense data. + /// + UINT8 *SenseDataLength; + /// + /// The status of the SCSI host adapter. + /// + UINT8 *HostAdapterStatus; + /// + /// The status of the target SCSI device. + /// + UINT8 *TargetStatus; + /// + /// The length of the data buffer for the SCSI read/write command. + /// + UINT32 *DataLength; + /// + /// The caller event to be signaled when the SCSI read/write command + /// completes. + /// + EFI_EVENT CallerEvent; +} EFI_SCSI_LIB_ASYNC_CONTEXT; + + + +/** + Execute Test Unit Ready SCSI command on a specific SCSI target. + + Executes the Test Unit Ready command on the SCSI target specified by ScsiIo. + If Timeout is zero, then this function waits indefinitely for the command to complete. + If Timeout is greater than zero, then the command is executed and will timeout after Timeout 100 ns units. + If ScsiIo is NULL, then ASSERT(). + If SenseDataLength is NULL, then ASSERT(). + If HostAdapterStatus is NULL, then ASSERT(). + If TargetStatus is NULL, then ASSERT(). + + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + @param[in] ScsiIo A pointer to the SCSI I/O Protocol instance + for the specific SCSI target. + @param[in] Timeout The timeout in 100 ns units to use for the execution + of this SCSI Request Packet. A Timeout value of + zero means that this function will wait indefinitely + for the SCSI Request Packet to execute. If Timeout + is greater than zero, then this function will return + EFI_TIMEOUT if the time required to execute the SCSI + Request Packet is greater than Timeout. + @param[in, out] SenseData A pointer to sense data that was generated by + the execution of the SCSI Request Packet. This + buffer must be allocated by the caller. + If SenseDataLength is 0, then this parameter is + optional and may be NULL. + @param[in, out] SenseDataLength On input, a pointer to the length in bytes of + the SenseData buffer. On output, a pointer to + the number of bytes written to the SenseData buffer. + @param[out] HostAdapterStatus The status of the SCSI Host Controller that produces + the SCSI bus containing the SCSI target specified by + ScsiIo when the SCSI Request Packet was executed. + See the EFI SCSI I/O Protocol in the UEFI Specification + for details on the possible return values. + @param[out] TargetStatus The status returned by the SCSI target specified + by ScsiIo when the SCSI Request Packet was executed + on the SCSI Host Controller. See the EFI SCSI I/O + Protocol in the UEFI Specification for details on + the possible return values. + + @retval EFI_SUCCESS The command was executed successfully. + See HostAdapterStatus, TargetStatus, SenseDataLength, + and SenseData in that order for additional status + information. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because + there are too many SCSI Command Packets already + queued. The SCSI Request Packet was not sent, so + no additional status information is available. + The caller may retry again later. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send + SCSI Request Packet. See HostAdapterStatus, + TargetStatus, SenseDataLength, and SenseData in that + order for additional status information. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet + is not supported by the SCSI initiator(i.e., SCSI + Host Controller). The SCSI Request Packet was not + sent, so no additional status information is available. + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request + Packet to execute. See HostAdapterStatus, TargetStatus, + SenseDataLength, and SenseData in that order for + additional status information. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. + +**/ +EFI_STATUS +EFIAPI +ScsiTestUnitReadyCommand ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN OUT VOID *SenseData, OPTIONAL + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus + ) +{ + EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; + EFI_STATUS Status; + UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIX]; + + ASSERT (SenseDataLength != NULL); + ASSERT (HostAdapterStatus != NULL); + ASSERT (TargetStatus != NULL); + ASSERT (ScsiIo != NULL); + + ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET)); + ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIX); + + CommandPacket.Timeout = Timeout; + CommandPacket.InDataBuffer = NULL; + CommandPacket.InTransferLength= 0; + CommandPacket.OutDataBuffer = NULL; + CommandPacket.OutTransferLength= 0; + CommandPacket.SenseData = SenseData; + CommandPacket.Cdb = Cdb; + // + // Fill Cdb for Test Unit Ready Command + // + Cdb[0] = EFI_SCSI_OP_TEST_UNIT_READY; + CommandPacket.CdbLength = (UINT8) EFI_SCSI_OP_LENGTH_SIX; + CommandPacket.SenseDataLength = *SenseDataLength; + + Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL); + + *HostAdapterStatus = CommandPacket.HostAdapterStatus; + *TargetStatus = CommandPacket.TargetStatus; + *SenseDataLength = CommandPacket.SenseDataLength; + + return Status; +} + + +/** + Execute Inquiry SCSI command on a specific SCSI target. + + Executes the Inquiry command on the SCSI target specified by ScsiIo. + If Timeout is zero, then this function waits indefinitely for the command to complete. + If Timeout is greater than zero, then the command is executed and will timeout after Timeout 100 ns units. + If ScsiIo is NULL, then ASSERT(). + If SenseDataLength is NULL, then ASSERT(). + If HostAdapterStatus is NULL, then ASSERT(). + If TargetStatus is NULL, then ASSERT(). + If InquiryDataLength is NULL, then ASSERT(). + + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If InquiryDataLength is non-zero and InquiryDataBuffer is not NULL, InquiryDataBuffer + must meet buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + @param[in] ScsiIo A pointer to the SCSI I/O Protocol instance + for the specific SCSI target. + @param[in] Timeout The timeout in 100 ns units to use for the + execution of this SCSI Request Packet. A Timeout + value of zero means that this function will wait + indefinitely for the SCSI Request Packet to execute. + If Timeout is greater than zero, then this function + will return EFI_TIMEOUT if the time required to + execute the SCSI Request Packet is greater than Timeout. + @param[in, out] SenseData A pointer to sense data that was generated + by the execution of the SCSI Request Packet. + This buffer must be allocated by the caller. + If SenseDataLength is 0, then this parameter + is optional and may be NULL. + @param[in, out] SenseDataLength On input, the length in bytes of the SenseData buffer. + On output, the number of bytes written to the SenseData buffer. + @param[out] HostAdapterStatus The status of the SCSI Host Controller that + produces the SCSI bus containing the SCSI + target specified by ScsiIo when the SCSI + Request Packet was executed. See the EFI + SCSI I/O Protocol in the UEFI Specification + for details on the possible return values. + @param[out] TargetStatus The status returned by the SCSI target specified + by ScsiIo when the SCSI Request Packet was + executed on the SCSI Host Controller. + See the EFI SCSI I/O Protocol in the UEFI + Specification for details on the possible + return values. + @param[in, out] InquiryDataBuffer A pointer to inquiry data that was generated + by the execution of the SCSI Request Packet. + This buffer must be allocated by the caller. + If InquiryDataLength is 0, then this parameter + is optional and may be NULL. + @param[in, out] InquiryDataLength On input, a pointer to the length in bytes + of the InquiryDataBuffer buffer. + On output, a pointer to the number of bytes + written to the InquiryDataBuffer buffer. + @param[in] EnableVitalProductData If TRUE, then the supported vital product + data for the PageCode is returned in InquiryDataBuffer. + If FALSE, then the standard inquiry data is + returned in InquiryDataBuffer and PageCode is ignored. + @param[in] PageCode The page code of the vital product data. + It's ignored if EnableVitalProductData is FALSE. + + @retval EFI_SUCCESS The command executed successfully. See HostAdapterStatus, + TargetStatus, SenseDataLength, and SenseData in that order + for additional status information. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire + InquiryDataBuffer could not be transferred. The actual + number of bytes transferred is returned in InquiryDataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there + are too many SCSI Command Packets already queued. + The SCSI Request Packet was not sent, so no additional + status information is available. The caller may retry again later. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI + Request Packet. See HostAdapterStatus, TargetStatus, + SenseDataLength, and SenseData in that order for additional + status information. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not + supported by the SCSI initiator(i.e., SCSI Host Controller). + The SCSI Request Packet was not sent, so no additional + status information is available. + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request + Packet to execute. See HostAdapterStatus, TargetStatus, + SenseDataLength, and SenseData in that order for + additional status information. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. + +**/ +EFI_STATUS +EFIAPI +ScsiInquiryCommandEx ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN OUT VOID *SenseData, OPTIONAL + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN OUT VOID *InquiryDataBuffer, OPTIONAL + IN OUT UINT32 *InquiryDataLength, + IN BOOLEAN EnableVitalProductData, + IN UINT8 PageCode + ) +{ + EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; + EFI_STATUS Status; + UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIX]; + + ASSERT (SenseDataLength != NULL); + ASSERT (HostAdapterStatus != NULL); + ASSERT (TargetStatus != NULL); + ASSERT (InquiryDataLength != NULL); + ASSERT (ScsiIo != NULL); + + ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET)); + ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIX); + + CommandPacket.Timeout = Timeout; + CommandPacket.InDataBuffer = InquiryDataBuffer; + CommandPacket.InTransferLength= *InquiryDataLength; + CommandPacket.SenseData = SenseData; + CommandPacket.SenseDataLength = *SenseDataLength; + CommandPacket.Cdb = Cdb; + + Cdb[0] = EFI_SCSI_OP_INQUIRY; + if (EnableVitalProductData) { + Cdb[1] |= 0x01; + Cdb[2] = PageCode; + } + + if (*InquiryDataLength > 0xff) { + *InquiryDataLength = 0xff; + } + + Cdb[4] = (UINT8) (*InquiryDataLength); + CommandPacket.CdbLength = (UINT8) EFI_SCSI_OP_LENGTH_SIX; + CommandPacket.DataDirection = EFI_SCSI_DATA_IN; + + Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL); + + *HostAdapterStatus = CommandPacket.HostAdapterStatus; + *TargetStatus = CommandPacket.TargetStatus; + *SenseDataLength = CommandPacket.SenseDataLength; + *InquiryDataLength = CommandPacket.InTransferLength; + + return Status; +} + + +/** + Execute Inquiry SCSI command on a specific SCSI target. + + Executes the Inquiry command on the SCSI target specified by ScsiIo. + If Timeout is zero, then this function waits indefinitely for the command to complete. + If Timeout is greater than zero, then the command is executed and will timeout after Timeout 100 ns units. + If ScsiIo is NULL, then ASSERT(). + If SenseDataLength is NULL, then ASSERT(). + If HostAdapterStatus is NULL, then ASSERT(). + If TargetStatus is NULL, then ASSERT(). + If InquiryDataLength is NULL, then ASSERT(). + + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If InquiryDataLength is non-zero and InquiryDataBuffer is not NULL, InquiryDataBuffer + must meet buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + @param[in] ScsiIo A pointer to the SCSI I/O Protocol instance + for the specific SCSI target. + @param[in] Timeout The timeout in 100 ns units to use for the + execution of this SCSI Request Packet. A Timeout + value of zero means that this function will wait + indefinitely for the SCSI Request Packet to execute. + If Timeout is greater than zero, then this function + will return EFI_TIMEOUT if the time required to + execute the SCSI Request Packet is greater than Timeout. + @param[in, out] SenseData A pointer to sense data that was generated + by the execution of the SCSI Request Packet. + This buffer must be allocated by the caller. + If SenseDataLength is 0, then this parameter + is optional and may be NULL. + @param[in, out] SenseDataLength On input, the length in bytes of the SenseData buffer. + On output, the number of bytes written to the SenseData buffer. + @param[out] HostAdapterStatus The status of the SCSI Host Controller that + produces the SCSI bus containing the SCSI + target specified by ScsiIo when the SCSI + Request Packet was executed. See the EFI + SCSI I/O Protocol in the UEFI Specification + for details on the possible return values. + @param[out] TargetStatus The status returned by the SCSI target specified + by ScsiIo when the SCSI Request Packet was + executed on the SCSI Host Controller. + See the EFI SCSI I/O Protocol in the UEFI + Specification for details on the possible + return values. + @param[in, out] InquiryDataBuffer A pointer to inquiry data that was generated + by the execution of the SCSI Request Packet. + This buffer must be allocated by the caller. + If InquiryDataLength is 0, then this parameter + is optional and may be NULL. + @param[in, out] InquiryDataLength On input, a pointer to the length in bytes + of the InquiryDataBuffer buffer. + On output, a pointer to the number of bytes + written to the InquiryDataBuffer buffer. + @param[in] EnableVitalProductData If TRUE, then the supported vital product + data is returned in InquiryDataBuffer. + If FALSE, then the standard inquiry data is + returned in InquiryDataBuffer. + + @retval EFI_SUCCESS The command was executed successfully. See HostAdapterStatus, + TargetStatus, SenseDataLength, and SenseData in that order + for additional status information. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire + InquiryDataBuffer could not be transferred. The actual + number of bytes transferred is returned in InquiryDataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there + are too many SCSI Command Packets already queued. + The SCSI Request Packet was not sent, so no additional + status information is available. The caller may retry again later. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI + Request Packet. See HostAdapterStatus, TargetStatus, + SenseDataLength, and SenseData in that order for additional + status information. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not + supported by the SCSI initiator(i.e., SCSI Host Controller). + The SCSI Request Packet was not sent, so no additional + status information is available. + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request + Packet to execute. See HostAdapterStatus, TargetStatus, + SenseDataLength, and SenseData in that order for + additional status information. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. + +**/ +EFI_STATUS +EFIAPI +ScsiInquiryCommand ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN OUT VOID *SenseData, OPTIONAL + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN OUT VOID *InquiryDataBuffer, OPTIONAL + IN OUT UINT32 *InquiryDataLength, + IN BOOLEAN EnableVitalProductData + ) +{ + return ScsiInquiryCommandEx ( + ScsiIo, + Timeout, + SenseData, + SenseDataLength, + HostAdapterStatus, + TargetStatus, + InquiryDataBuffer, + InquiryDataLength, + EnableVitalProductData, + 0 + ); +} + +/** + Execute Mode Sense(10) SCSI command on a specific SCSI target. + + Executes the SCSI Mode Sense(10) command on the SCSI target specified by ScsiIo. + If Timeout is zero, then this function waits indefinitely for the command to complete. + If Timeout is greater than zero, then the command is executed and will timeout + after Timeout 100 ns units. The DBDField, PageControl, and PageCode parameters + are used to construct the CDB for this SCSI command. + If ScsiIo is NULL, then ASSERT(). + If SenseDataLength is NULL, then ASSERT(). + If HostAdapterStatus is NULL, then ASSERT(). + If TargetStatus is NULL, then ASSERT(). + If DataLength is NULL, then ASSERT(). + + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + @param[in] ScsiIo A pointer to the SCSI I/O Protocol instance + for the specific SCSI target. + @param[in] Timeout The timeout in 100 ns units to use for the + execution of this SCSI Request Packet. A Timeout + value of zero means that this function will wait + indefinitely for the SCSI Request Packet to execute. + If Timeout is greater than zero, then this function + will return EFI_TIMEOUT if the time required to + execute the SCSI Request Packet is greater than Timeout. + @param[in, out] SenseData A pointer to sense data that was generated + by the execution of the SCSI Request Packet. + This buffer must be allocated by the caller. + If SenseDataLength is 0, then this parameter + is optional and may be NULL. + @param[in, out] SenseDataLength On input, the length in bytes of the SenseData buffer. + On output, the number of bytes written to the SenseData buffer. + @param[out] HostAdapterStatus The status of the SCSI Host Controller that + produces the SCSI bus containing the SCSI target + specified by ScsiIo when the SCSI Request Packet + was executed. See the EFI SCSI I/O Protocol in the + UEFI Specification for details on the possible + return values. + @param[out] TargetStatus The status returned by the SCSI target specified + by ScsiIo when the SCSI Request Packet was executed + on the SCSI Host Controller. See the EFI SCSI + I/O Protocol in the UEFI Specification for details + on the possible return values. + @param[in, out] DataBuffer A pointer to data that was generated by the + execution of the SCSI Request Packet. This + buffer must be allocated by the caller. If + DataLength is 0, then this parameter is optional + and may be NULL. + @param[in, out] DataLength On input, a pointer to the length in bytes of + the DataBuffer buffer. On output, a pointer + to the number of bytes written to the DataBuffer + buffer. + @param[in] DBDField Specifies the DBD field of the CDB for this SCSI Command. + @param[in] PageControl Specifies the PC field of the CDB for this SCSI Command. + @param[in] PageCode Specifies the Page Control field of the CDB for this SCSI Command. + + @retval EFI_SUCCESS The command was executed successfully. + See HostAdapterStatus, TargetStatus, SenseDataLength, + and SenseData in that order for additional status information. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the + entire DataBuffer could not be transferred. + The actual number of bytes transferred is returned + in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because + there are too many SCSI Command Packets already queued. + The SCSI Request Packet was not sent, so no additional + status information is available. The caller may retry + again later. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send + SCSI Request Packet. See HostAdapterStatus, TargetStatus, + SenseDataLength, and SenseData in that order for + additional status information. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet + is not supported by the SCSI initiator(i.e., SCSI + Host Controller). The SCSI Request Packet was not + sent, so no additional status information is available. + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI + Request Packet to execute. See HostAdapterStatus, + TargetStatus, SenseDataLength, and SenseData in that + order for additional status information. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. + +**/ +EFI_STATUS +EFIAPI +ScsiModeSense10Command ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN OUT VOID *SenseData, OPTIONAL + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN OUT VOID *DataBuffer, OPTIONAL + IN OUT UINT32 *DataLength, + IN UINT8 DBDField, OPTIONAL + IN UINT8 PageControl, + IN UINT8 PageCode + ) +{ + EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; + EFI_STATUS Status; + UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN]; + + ASSERT (SenseDataLength != NULL); + ASSERT (HostAdapterStatus != NULL); + ASSERT (TargetStatus != NULL); + ASSERT (DataLength != NULL); + ASSERT (ScsiIo != NULL); + + ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET)); + ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TEN); + + CommandPacket.Timeout = Timeout; + CommandPacket.InDataBuffer = DataBuffer; + CommandPacket.SenseData = SenseData; + CommandPacket.InTransferLength= *DataLength; + CommandPacket.Cdb = Cdb; + // + // Fill Cdb for Mode Sense (10) Command + // + Cdb[0] = EFI_SCSI_OP_MODE_SEN10; + // + // DBDField is in Cdb[1] bit3 of (bit7..0) + // + Cdb[1] = (UINT8) ((DBDField << 3) & 0x08); + // + // PageControl is in Cdb[2] bit7..6, PageCode is in Cdb[2] bit5..0 + // + Cdb[2] = (UINT8) (((PageControl << 6) & 0xc0) | (PageCode & 0x3f)); + Cdb[7] = (UINT8) (*DataLength >> 8); + Cdb[8] = (UINT8) (*DataLength); + + CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TEN; + CommandPacket.DataDirection = EFI_SCSI_DATA_IN; + CommandPacket.SenseDataLength = *SenseDataLength; + + Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL); + + *HostAdapterStatus = CommandPacket.HostAdapterStatus; + *TargetStatus = CommandPacket.TargetStatus; + *SenseDataLength = CommandPacket.SenseDataLength; + *DataLength = CommandPacket.InTransferLength; + + return Status; +} + + +/** + Execute Request Sense SCSI command on a specific SCSI target. + + Executes the Request Sense command on the SCSI target specified by ScsiIo. + If Timeout is zero, then this function waits indefinitely for the command to complete. + If Timeout is greater than zero, then the command is executed and will timeout after Timeout 100 ns units. + If ScsiIo is NULL, then ASSERT(). + If SenseDataLength is NULL, then ASSERT(). + If HostAdapterStatus is NULL, then ASSERT(). + If TargetStatus is NULL, then ASSERT(). + + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + @param[in] ScsiIo A pointer to SCSI IO protocol. + @param[in] Timeout The length of timeout period. + @param[in, out] SenseData A pointer to output sense data. + @param[in, out] SenseDataLength The length of output sense data. + @param[out] HostAdapterStatus The status of Host Adapter. + @param[out] TargetStatus The status of the target. + + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are + too many SCSI Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by + the SCSI initiator(i.e., SCSI Host Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. + +**/ +EFI_STATUS +EFIAPI +ScsiRequestSenseCommand ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN OUT VOID *SenseData, OPTIONAL + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus + ) +{ + EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; + EFI_STATUS Status; + UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIX]; + + ASSERT (SenseDataLength != NULL); + ASSERT (HostAdapterStatus != NULL); + ASSERT (TargetStatus != NULL); + ASSERT (ScsiIo != NULL); + + ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET)); + ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIX); + + CommandPacket.Timeout = Timeout; + CommandPacket.InDataBuffer = SenseData; + CommandPacket.SenseData = NULL; + CommandPacket.InTransferLength= *SenseDataLength; + CommandPacket.Cdb = Cdb; + // + // Fill Cdb for Request Sense Command + // + Cdb[0] = EFI_SCSI_OP_REQUEST_SENSE; + Cdb[4] = (UINT8) (*SenseDataLength); + + CommandPacket.CdbLength = (UINT8) EFI_SCSI_OP_LENGTH_SIX; + CommandPacket.DataDirection = EFI_SCSI_DATA_IN; + CommandPacket.SenseDataLength = 0; + + Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL); + + *HostAdapterStatus = CommandPacket.HostAdapterStatus; + *TargetStatus = CommandPacket.TargetStatus; + *SenseDataLength = (UINT8) CommandPacket.InTransferLength; + + return Status; +} + + +/** + Execute Read Capacity SCSI command on a specific SCSI target. + + Executes the SCSI Read Capacity command on the SCSI target specified by ScsiIo. + If Timeout is zero, then this function waits indefinitely for the command to complete. + If Timeout is greater than zero, then the command is executed and will timeout after + Timeout 100 ns units. The Pmi parameter is used to construct the CDB for this SCSI command. + If ScsiIo is NULL, then ASSERT(). + If SenseDataLength is NULL, then ASSERT(). + If HostAdapterStatus is NULL, then ASSERT(). + If TargetStatus is NULL, then ASSERT(). + If DataLength is NULL, then ASSERT(). + + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + @param[in] ScsiIo A pointer to SCSI IO protocol. + @param[in] Timeout The length of timeout period. + @param[in, out] SenseData A pointer to output sense data. + @param[in, out] SenseDataLength The length of output sense data. + @param[out] HostAdapterStatus The status of Host Adapter. + @param[out] TargetStatus The status of the target. + @param[in, out] DataBuffer A pointer to a data buffer. + @param[in, out] DataLength The length of data buffer. + @param[in] Pmi Partial medium indicator. + + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire + DataBuffer could not be transferred. The actual + number of bytes transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because + there are too many SCSI Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet + is not supported by the SCSI initiator(i.e., SCSI Host Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. + +**/ +EFI_STATUS +EFIAPI +ScsiReadCapacityCommand ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN OUT VOID *SenseData, OPTIONAL + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN OUT VOID *DataBuffer, OPTIONAL + IN OUT UINT32 *DataLength, + IN BOOLEAN Pmi + ) +{ + EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; + EFI_STATUS Status; + UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN]; + + ASSERT (SenseDataLength != NULL); + ASSERT (HostAdapterStatus != NULL); + ASSERT (TargetStatus != NULL); + ASSERT (DataLength != NULL); + ASSERT (ScsiIo != NULL); + + ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET)); + ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TEN); + + CommandPacket.Timeout = Timeout; + CommandPacket.InDataBuffer = DataBuffer; + CommandPacket.SenseData = SenseData; + CommandPacket.InTransferLength= *DataLength; + CommandPacket.Cdb = Cdb; + // + // Fill Cdb for Read Capacity Command + // + Cdb[0] = EFI_SCSI_OP_READ_CAPACITY; + if (!Pmi) { + // + // Partial medium indicator,if Pmi is FALSE, the Cdb.2 ~ Cdb.5 MUST BE ZERO. + // + ZeroMem ((Cdb + 2), 4); + } else { + Cdb[8] |= 0x01; + } + + CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TEN; + CommandPacket.DataDirection = EFI_SCSI_DATA_IN; + CommandPacket.SenseDataLength = *SenseDataLength; + + Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL); + + *HostAdapterStatus = CommandPacket.HostAdapterStatus; + *TargetStatus = CommandPacket.TargetStatus; + *SenseDataLength = CommandPacket.SenseDataLength; + *DataLength = CommandPacket.InTransferLength; + + return Status; +} + + +/** + Execute Read Capacity SCSI 16 command on a specific SCSI target. + + Executes the SCSI Read Capacity 16 command on the SCSI target specified by ScsiIo. + If Timeout is zero, then this function waits indefinitely for the command to complete. + If Timeout is greater than zero, then the command is executed and will timeout after + Timeout 100 ns units. The Pmi parameter is used to construct the CDB for this SCSI command. + If ScsiIo is NULL, then ASSERT(). + If SenseDataLength is NULL, then ASSERT(). + If HostAdapterStatus is NULL, then ASSERT(). + If TargetStatus is NULL, then ASSERT(). + If DataLength is NULL, then ASSERT(). + + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + @param[in] ScsiIo A pointer to SCSI IO protocol. + @param[in] Timeout The length of timeout period. + @param[in, out] SenseData A pointer to output sense data. + @param[in, out] SenseDataLength The length of output sense data. + @param[out] HostAdapterStatus The status of Host Adapter. + @param[out] TargetStatus The status of the target. + @param[in, out] DataBuffer A pointer to a data buffer. + @param[in, out] DataLength The length of data buffer. + @param[in] Pmi Partial medium indicator. + + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire + DataBuffer could not be transferred. The actual + number of bytes transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because + there are too many SCSI Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet + is not supported by the SCSI initiator(i.e., SCSI Host Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. + +**/ +EFI_STATUS +EFIAPI +ScsiReadCapacity16Command ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN OUT VOID *SenseData, OPTIONAL + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN OUT VOID *DataBuffer, OPTIONAL + IN OUT UINT32 *DataLength, + IN BOOLEAN Pmi + ) +{ + EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; + EFI_STATUS Status; + UINT8 Cdb[16]; + + ASSERT (SenseDataLength != NULL); + ASSERT (HostAdapterStatus != NULL); + ASSERT (TargetStatus != NULL); + ASSERT (DataLength != NULL); + ASSERT (ScsiIo != NULL); + + ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET)); + ZeroMem (Cdb, 16); + + CommandPacket.Timeout = Timeout; + CommandPacket.InDataBuffer = DataBuffer; + CommandPacket.SenseData = SenseData; + CommandPacket.InTransferLength= *DataLength; + CommandPacket.Cdb = Cdb; + // + // Fill Cdb for Read Capacity Command + // + Cdb[0] = EFI_SCSI_OP_READ_CAPACITY16; + Cdb[1] = 0x10; + if (!Pmi) { + // + // Partial medium indicator,if Pmi is FALSE, the Cdb.2 ~ Cdb.9 MUST BE ZERO. + // + ZeroMem ((Cdb + 2), 8); + } else { + Cdb[14] |= 0x01; + } + + Cdb[13] = 0x20; + CommandPacket.CdbLength = 16; + CommandPacket.DataDirection = EFI_SCSI_DATA_IN; + CommandPacket.SenseDataLength = *SenseDataLength; + + Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL); + + *HostAdapterStatus = CommandPacket.HostAdapterStatus; + *TargetStatus = CommandPacket.TargetStatus; + *SenseDataLength = CommandPacket.SenseDataLength; + *DataLength = CommandPacket.InTransferLength; + + return Status; +} + + +/** + Execute Read(10) SCSI command on a specific SCSI target. + + Executes the SCSI Read(10) command on the SCSI target specified by ScsiIo. + If Timeout is zero, then this function waits indefinitely for the command to complete. + If Timeout is greater than zero, then the command is executed and will timeout + after Timeout 100 ns units. The StartLba and SectorSize parameters are used to + construct the CDB for this SCSI command. + If ScsiIo is NULL, then ASSERT(). + If SenseDataLength is NULL, then ASSERT(). + If HostAdapterStatus is NULL, then ASSERT(). + If TargetStatus is NULL, then ASSERT(). + If DataLength is NULL, then ASSERT(). + + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + @param[in] ScsiIo A pointer to SCSI IO protocol. + @param[in] Timeout The length of timeout period. + @param[in, out] SenseData A pointer to output sense data. + @param[in, out] SenseDataLength The length of output sense data. + @param[out] HostAdapterStatus The status of Host Adapter. + @param[out] TargetStatus The status of the target. + @param[in, out] DataBuffer Read 10 command data. + @param[in, out] DataLength The length of data buffer. + @param[in] StartLba The start address of LBA. + @param[in] SectorSize The number of contiguous logical blocks of data that shall be transferred. + + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could + not be transferred. The actual number of bytes transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many + SCSI Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by + the SCSI initiator(i.e., SCSI Host Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. + +**/ +EFI_STATUS +EFIAPI +ScsiRead10Command ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN OUT VOID *SenseData, OPTIONAL + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN OUT VOID *DataBuffer, OPTIONAL + IN OUT UINT32 *DataLength, + IN UINT32 StartLba, + IN UINT32 SectorSize + ) +{ + EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; + EFI_STATUS Status; + UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN]; + + ASSERT (SenseDataLength != NULL); + ASSERT (HostAdapterStatus != NULL); + ASSERT (TargetStatus != NULL); + ASSERT (DataLength != NULL); + ASSERT (ScsiIo != NULL); + + ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET)); + ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TEN); + + CommandPacket.Timeout = Timeout; + CommandPacket.InDataBuffer = DataBuffer; + CommandPacket.SenseData = SenseData; + CommandPacket.InTransferLength= *DataLength; + CommandPacket.Cdb = Cdb; + // + // Fill Cdb for Read (10) Command + // + Cdb[0] = EFI_SCSI_OP_READ10; + WriteUnaligned32 ((UINT32 *)&Cdb[2], SwapBytes32 (StartLba)); + WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 ((UINT16) SectorSize)); + + CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TEN; + CommandPacket.DataDirection = EFI_SCSI_DATA_IN; + CommandPacket.SenseDataLength = *SenseDataLength; + + Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL); + + *HostAdapterStatus = CommandPacket.HostAdapterStatus; + *TargetStatus = CommandPacket.TargetStatus; + *SenseDataLength = CommandPacket.SenseDataLength; + *DataLength = CommandPacket.InTransferLength; + + return Status; +} + + +/** + Execute Write(10) SCSI command on a specific SCSI target. + + Executes the SCSI Write(10) command on the SCSI target specified by ScsiIo. + If Timeout is zero, then this function waits indefinitely for the command to complete. + If Timeout is greater than zero, then the command is executed and will timeout after + Timeout 100 ns units. The StartLba and SectorSize parameters are used to construct + the CDB for this SCSI command. + If ScsiIo is NULL, then ASSERT(). + If SenseDataLength is NULL, then ASSERT(). + If HostAdapterStatus is NULL, then ASSERT(). + If TargetStatus is NULL, then ASSERT(). + If DataLength is NULL, then ASSERT(). + + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + @param[in] ScsiIo SCSI IO Protocol to use + @param[in] Timeout The length of timeout period. + @param[in, out] SenseData A pointer to output sense data. + @param[in, out] SenseDataLength The length of output sense data. + @param[out] HostAdapterStatus The status of Host Adapter. + @param[out] TargetStatus The status of the target. + @param[in, out] DataBuffer A pointer to a data buffer. + @param[in, out] DataLength The length of data buffer. + @param[in] StartLba The start address of LBA. + @param[in] SectorSize The number of contiguous logical blocks of data that shall be transferred. + + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could + not be transferred. The actual number of bytes transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many + SCSI Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by + the SCSI initiator(i.e., SCSI Host Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. + +**/ +EFI_STATUS +EFIAPI +ScsiWrite10Command ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN OUT VOID *SenseData, OPTIONAL + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN OUT VOID *DataBuffer, OPTIONAL + IN OUT UINT32 *DataLength, + IN UINT32 StartLba, + IN UINT32 SectorSize + ) +{ + EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; + EFI_STATUS Status; + UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN]; + + ASSERT (SenseDataLength != NULL); + ASSERT (HostAdapterStatus != NULL); + ASSERT (TargetStatus != NULL); + ASSERT (DataLength != NULL); + ASSERT (ScsiIo != NULL); + + ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET)); + ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TEN); + + CommandPacket.Timeout = Timeout; + CommandPacket.OutDataBuffer = DataBuffer; + CommandPacket.SenseData = SenseData; + CommandPacket.OutTransferLength = *DataLength; + CommandPacket.Cdb = Cdb; + // + // Fill Cdb for Write (10) Command + // + Cdb[0] = EFI_SCSI_OP_WRITE10; + Cdb[1] = EFI_SCSI_BLOCK_FUA; + WriteUnaligned32 ((UINT32 *)&Cdb[2], SwapBytes32 (StartLba)); + WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 ((UINT16) SectorSize)); + + CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TEN; + CommandPacket.DataDirection = EFI_SCSI_DATA_OUT; + CommandPacket.SenseDataLength = *SenseDataLength; + + Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL); + + *HostAdapterStatus = CommandPacket.HostAdapterStatus; + *TargetStatus = CommandPacket.TargetStatus; + *SenseDataLength = CommandPacket.SenseDataLength; + *DataLength = CommandPacket.OutTransferLength; + + return Status; +} + +/** + Execute Read(16) SCSI command on a specific SCSI target. + + Executes the SCSI Read(16) command on the SCSI target specified by ScsiIo. + If Timeout is zero, then this function waits indefinitely for the command to complete. + If Timeout is greater than zero, then the command is executed and will timeout + after Timeout 100 ns units. The StartLba and SectorSize parameters are used to + construct the CDB for this SCSI command. + If ScsiIo is NULL, then ASSERT(). + If SenseDataLength is NULL, then ASSERT(). + If HostAdapterStatus is NULL, then ASSERT(). + If TargetStatus is NULL, then ASSERT(). + If DataLength is NULL, then ASSERT(). + + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + @param[in] ScsiIo A pointer to SCSI IO protocol. + @param[in] Timeout The length of timeout period. + @param[in, out] SenseData A pointer to output sense data. + @param[in, out] SenseDataLength The length of output sense data. + @param[out] HostAdapterStatus The status of Host Adapter. + @param[out] TargetStatus The status of the target. + @param[in, out] DataBuffer Read 16 command data. + @param[in, out] DataLength The length of data buffer. + @param[in] StartLba The start address of LBA. + @param[in] SectorSize The number of contiguous logical blocks of data that shall be transferred. + + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could + not be transferred. The actual number of bytes transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many + SCSI Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by + the SCSI initiator(i.e., SCSI Host Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. + +**/ +EFI_STATUS +EFIAPI +ScsiRead16Command ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN OUT VOID *SenseData, OPTIONAL + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN OUT VOID *DataBuffer, OPTIONAL + IN OUT UINT32 *DataLength, + IN UINT64 StartLba, + IN UINT32 SectorSize + ) +{ + EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; + EFI_STATUS Status; + UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIXTEEN]; + + ASSERT (SenseDataLength != NULL); + ASSERT (HostAdapterStatus != NULL); + ASSERT (TargetStatus != NULL); + ASSERT (DataLength != NULL); + ASSERT (ScsiIo != NULL); + + ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET)); + ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIXTEEN); + + CommandPacket.Timeout = Timeout; + CommandPacket.InDataBuffer = DataBuffer; + CommandPacket.SenseData = SenseData; + CommandPacket.InTransferLength = *DataLength; + CommandPacket.Cdb = Cdb; + // + // Fill Cdb for Read (16) Command + // + Cdb[0] = EFI_SCSI_OP_READ16; + WriteUnaligned64 ((UINT64 *)&Cdb[2], SwapBytes64 (StartLba)); + WriteUnaligned32 ((UINT32 *)&Cdb[10], SwapBytes32 (SectorSize)); + + CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_SIXTEEN; + CommandPacket.DataDirection = EFI_SCSI_DATA_IN; + CommandPacket.SenseDataLength = *SenseDataLength; + + Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL); + + *HostAdapterStatus = CommandPacket.HostAdapterStatus; + *TargetStatus = CommandPacket.TargetStatus; + *SenseDataLength = CommandPacket.SenseDataLength; + *DataLength = CommandPacket.InTransferLength; + + return Status; +} + + +/** + Execute Write(16) SCSI command on a specific SCSI target. + + Executes the SCSI Write(16) command on the SCSI target specified by ScsiIo. + If Timeout is zero, then this function waits indefinitely for the command to complete. + If Timeout is greater than zero, then the command is executed and will timeout after + Timeout 100 ns units. The StartLba and SectorSize parameters are used to construct + the CDB for this SCSI command. + If ScsiIo is NULL, then ASSERT(). + If SenseDataLength is NULL, then ASSERT(). + If HostAdapterStatus is NULL, then ASSERT(). + If TargetStatus is NULL, then ASSERT(). + If DataLength is NULL, then ASSERT(). + + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + @param[in] ScsiIo SCSI IO Protocol to use + @param[in] Timeout The length of timeout period. + @param[in, out] SenseData A pointer to output sense data. + @param[in, out] SenseDataLength The length of output sense data. + @param[out] HostAdapterStatus The status of Host Adapter. + @param[out] TargetStatus The status of the target. + @param[in, out] DataBuffer A pointer to a data buffer. + @param[in, out] DataLength The length of data buffer. + @param[in] StartLba The start address of LBA. + @param[in] SectorSize The number of contiguous logical blocks of data that shall be transferred. + + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could + not be transferred. The actual number of bytes transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many + SCSI Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by + the SCSI initiator(i.e., SCSI Host Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. + +**/ +EFI_STATUS +EFIAPI +ScsiWrite16Command ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN OUT VOID *SenseData, OPTIONAL + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN OUT VOID *DataBuffer, OPTIONAL + IN OUT UINT32 *DataLength, + IN UINT64 StartLba, + IN UINT32 SectorSize + ) +{ + EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; + EFI_STATUS Status; + UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIXTEEN]; + + ASSERT (SenseDataLength != NULL); + ASSERT (HostAdapterStatus != NULL); + ASSERT (TargetStatus != NULL); + ASSERT (DataLength != NULL); + ASSERT (ScsiIo != NULL); + + ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET)); + ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIXTEEN); + + CommandPacket.Timeout = Timeout; + CommandPacket.OutDataBuffer = DataBuffer; + CommandPacket.SenseData = SenseData; + CommandPacket.OutTransferLength = *DataLength; + CommandPacket.Cdb = Cdb; + // + // Fill Cdb for Write (16) Command + // + Cdb[0] = EFI_SCSI_OP_WRITE16; + Cdb[1] = EFI_SCSI_BLOCK_FUA; + WriteUnaligned64 ((UINT64 *)&Cdb[2], SwapBytes64 (StartLba)); + WriteUnaligned32 ((UINT32 *)&Cdb[10], SwapBytes32 (SectorSize)); + + CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_SIXTEEN; + CommandPacket.DataDirection = EFI_SCSI_DATA_OUT; + CommandPacket.SenseDataLength = *SenseDataLength; + + Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL); + + *HostAdapterStatus = CommandPacket.HostAdapterStatus; + *TargetStatus = CommandPacket.TargetStatus; + *SenseDataLength = CommandPacket.SenseDataLength; + *DataLength = CommandPacket.OutTransferLength; + + return Status; +} + + +/** + Execute Security Protocol In SCSI command on a specific SCSI target. + + Executes the SCSI Security Protocol In command on the SCSI target specified by ScsiIo. + If Timeout is zero, then this function waits indefinitely for the command to complete. + If Timeout is greater than zero, then the command is executed and will timeout after + Timeout 100 ns units. + If ScsiIo is NULL, then ASSERT(). + If SenseDataLength is NULL, then ASSERT(). + If HostAdapterStatus is NULL, then ASSERT(). + If TargetStatus is NULL, then ASSERT(). + If TransferLength is NULL, then ASSERT(). + + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + @param[in] ScsiIo SCSI IO Protocol to use. + @param[in] Timeout The length of timeout period. + @param[in, out] SenseData A pointer to output sense data. + @param[in, out] SenseDataLength The length of output sense data. + @param[out] HostAdapterStatus The status of Host Adapter. + @param[out] TargetStatus The status of the target. + @param[in] SecurityProtocol The Security Protocol to use. + @param[in] SecurityProtocolSpecific The Security Protocol Specific data. + @param[in] Inc512 If TRUE, 512 increment (INC_512) bit will be set for the + SECURITY PROTOCOL IN command. + @param[in] DataLength The size in bytes of the data buffer. + @param[in, out] DataBuffer A pointer to a data buffer. + @param[out] TransferLength A pointer to a buffer to store the size in + bytes of the data written to the data buffer. + + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could + not be transferred. The actual number of bytes transferred is returned in TransferLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many + SCSI Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by + the SCSI initiator(i.e., SCSI Host Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. + +**/ +EFI_STATUS +EFIAPI +ScsiSecurityProtocolInCommand ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN OUT VOID *SenseData, OPTIONAL + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN UINT8 SecurityProtocol, + IN UINT16 SecurityProtocolSpecific, + IN BOOLEAN Inc512, + IN UINTN DataLength, + IN OUT VOID *DataBuffer, OPTIONAL + OUT UINTN *TransferLength + ) +{ + EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; + EFI_STATUS Status; + UINT8 Cdb[EFI_SCSI_OP_LENGTH_TWELVE]; + + ASSERT (SenseDataLength != NULL); + ASSERT (HostAdapterStatus != NULL); + ASSERT (TargetStatus != NULL); + ASSERT (ScsiIo != NULL); + ASSERT (TransferLength != NULL); + ASSERT (DataLength <= MAX_UINT32); + + ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET)); + ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TWELVE); + + CommandPacket.Timeout = Timeout; + CommandPacket.InDataBuffer = DataBuffer; + CommandPacket.SenseData = SenseData; + CommandPacket.InTransferLength = (UINT32) DataLength; + CommandPacket.Cdb = Cdb; + // + // Fill Cdb for Security Protocol In Command + // + Cdb[0] = EFI_SCSI_OP_SECURITY_PROTOCOL_IN; + Cdb[1] = SecurityProtocol; + WriteUnaligned16 ((UINT16 *)&Cdb[2], SwapBytes16 (SecurityProtocolSpecific)); + + if (Inc512) { + if (DataLength % 512 != 0) { + return EFI_INVALID_PARAMETER; + } + Cdb[4] = BIT7; + WriteUnaligned32 ((UINT32 *)&Cdb[6], SwapBytes32 ((UINT32) DataLength / 512)); + } else { + WriteUnaligned32 ((UINT32 *)&Cdb[6], SwapBytes32 ((UINT32) DataLength)); + } + + CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TWELVE; + CommandPacket.DataDirection = EFI_SCSI_DATA_IN; + CommandPacket.SenseDataLength = *SenseDataLength; + + Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL); + + *HostAdapterStatus = CommandPacket.HostAdapterStatus; + *TargetStatus = CommandPacket.TargetStatus; + *SenseDataLength = CommandPacket.SenseDataLength; + *TransferLength = (UINTN) CommandPacket.InTransferLength; + + return Status; +} + + +/** + Execute Security Protocol Out SCSI command on a specific SCSI target. + + Executes the SCSI Security Protocol Out command on the SCSI target specified by ScsiIo. + If Timeout is zero, then this function waits indefinitely for the command to complete. + If Timeout is greater than zero, then the command is executed and will timeout after + Timeout 100 ns units. + If ScsiIo is NULL, then ASSERT(). + If SenseDataLength is NULL, then ASSERT(). + If HostAdapterStatus is NULL, then ASSERT(). + If TargetStatus is NULL, then ASSERT(). + + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer + alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER + gets returned. + + @param[in] ScsiIo SCSI IO Protocol to use. + @param[in] Timeout The length of timeout period. + @param[in, out] SenseData A pointer to output sense data. + @param[in, out] SenseDataLength The length of output sense data. + @param[out] HostAdapterStatus The status of Host Adapter. + @param[out] TargetStatus The status of the target. + @param[in] SecurityProtocol The Security Protocol to use. + @param[in] SecurityProtocolSpecific The Security Protocol Specific data. + @param[in] Inc512 If TRUE, 512 increment (INC_512) bit will be set for the + SECURITY PROTOCOL OUT command. + @param[in] DataLength The size in bytes of the transfer data. + @param[in, out] DataBuffer A pointer to a data buffer. + + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could + not be transferred. The actual number of bytes transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many + SCSI Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by + the SCSI initiator(i.e., SCSI Host Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid. + +**/ +EFI_STATUS +EFIAPI +ScsiSecurityProtocolOutCommand ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN OUT VOID *SenseData, OPTIONAL + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN UINT8 SecurityProtocol, + IN UINT16 SecurityProtocolSpecific, + IN BOOLEAN Inc512, + IN UINTN DataLength, + IN OUT VOID *DataBuffer OPTIONAL + ) +{ + EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; + EFI_STATUS Status; + UINT8 Cdb[EFI_SCSI_OP_LENGTH_TWELVE]; + + ASSERT (SenseDataLength != NULL); + ASSERT (HostAdapterStatus != NULL); + ASSERT (TargetStatus != NULL); + ASSERT (ScsiIo != NULL); + ASSERT (DataLength <= MAX_UINT32); + + ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET)); + ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TWELVE); + + CommandPacket.Timeout = Timeout; + CommandPacket.OutDataBuffer = DataBuffer; + CommandPacket.SenseData = SenseData; + CommandPacket.OutTransferLength = (UINT32) DataLength; + CommandPacket.Cdb = Cdb; + // + // Fill Cdb for Security Protocol Out Command + // + Cdb[0] = EFI_SCSI_OP_SECURITY_PROTOCOL_OUT; + Cdb[1] = SecurityProtocol; + WriteUnaligned16 ((UINT16 *)&Cdb[2], SwapBytes16 (SecurityProtocolSpecific)); + + if (Inc512) { + if (DataLength % 512 != 0) { + return EFI_INVALID_PARAMETER; + } + Cdb[4] = BIT7; + WriteUnaligned32 ((UINT32 *)&Cdb[6], SwapBytes32 ((UINT32) DataLength / 512)); + } else { + WriteUnaligned32 ((UINT32 *)&Cdb[6], SwapBytes32 ((UINT32) DataLength)); + } + + CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TWELVE; + CommandPacket.DataDirection = EFI_SCSI_DATA_OUT; + CommandPacket.SenseDataLength = *SenseDataLength; + + Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL); + + *HostAdapterStatus = CommandPacket.HostAdapterStatus; + *TargetStatus = CommandPacket.TargetStatus; + *SenseDataLength = CommandPacket.SenseDataLength; + + return Status; +} + + +/** + Internal helper notify function in which update the result of the + non-blocking SCSI Read/Write commands and signal caller event. + + @param Event The instance of EFI_EVENT. + @param Context The parameter passed in. + +**/ +VOID +EFIAPI +ScsiLibNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_SCSI_LIB_ASYNC_CONTEXT *LibContext; + EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket; + EFI_EVENT CallerEvent; + + LibContext = (EFI_SCSI_LIB_ASYNC_CONTEXT *) Context; + CommandPacket = &LibContext->CommandPacket; + CallerEvent = LibContext->CallerEvent; + + // + // Update SCSI Read/Write operation results + // + *LibContext->SenseDataLength = CommandPacket->SenseDataLength; + *LibContext->HostAdapterStatus = CommandPacket->HostAdapterStatus; + *LibContext->TargetStatus = CommandPacket->TargetStatus; + if (CommandPacket->InDataBuffer != NULL) { + *LibContext->DataLength = CommandPacket->InTransferLength; + } else { + *LibContext->DataLength = CommandPacket->OutTransferLength; + } + + if (CommandPacket->Cdb != NULL) { + FreePool (CommandPacket->Cdb); + } + FreePool (Context); + + gBS->CloseEvent (Event); + gBS->SignalEvent (CallerEvent); +} + + +/** + Execute blocking/non-blocking Read(10) SCSI command on a specific SCSI + target. + + Executes the SCSI Read(10) command on the SCSI target specified by ScsiIo. + When Event is NULL, blocking command will be executed. Otherwise non-blocking + command will be executed. + For blocking I/O, if Timeout is zero, this function will wait indefinitely + for the command to complete. If Timeout is greater than zero, then the + command is executed and will timeout after Timeout 100 ns units. + For non-blocking I/O, if Timeout is zero, Event will be signaled only after + the command to completes. If Timeout is greater than zero, Event will also be + signaled after Timeout 100 ns units. + The StartLba and SectorSize parameters are used to construct the CDB for this + SCSI command. + + If ScsiIo is NULL, then ASSERT(). + If SenseDataLength is NULL, then ASSERT(). + If HostAdapterStatus is NULL, then ASSERT(). + If TargetStatus is NULL, then ASSERT(). + If DataLength is NULL, then ASSERT(). + + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet + buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet + buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + @param[in] ScsiIo A pointer to SCSI IO protocol. + @param[in] Timeout The length of timeout period. + @param[in, out] SenseData A pointer to output sense data. + @param[in, out] SenseDataLength The length of output sense data. + @param[out] HostAdapterStatus The status of Host Adapter. + @param[out] TargetStatus The status of the target. + @param[in, out] DataBuffer Read 16 command data. + @param[in, out] DataLength The length of data buffer. + @param[in] StartLba The start address of LBA. + @param[in] SectorSize The number of contiguous logical blocks + of data that shall be transferred. + @param[in] Event If the SCSI target does not support + non-blocking I/O, then Event is ignored, + and blocking I/O is performed. If Event + is NULL, then blocking I/O is performed. + If Event is not NULL and non-blocking + I/O is supported, then non-blocking I/O + is performed, and Event will be signaled + when the SCSI Read(10) command + completes. + + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, + but the entire DataBuffer could not be + transferred. The actual number of bytes + transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be + sent because there are too many SCSI + Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting + to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI + Request Packet is not supported by the + SCSI initiator(i.e., SCSI Host + Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the + SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet + are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due + to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +ScsiRead10CommandEx ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN OUT VOID *SenseData, OPTIONAL + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN OUT VOID *DataBuffer, OPTIONAL + IN OUT UINT32 *DataLength, + IN UINT32 StartLba, + IN UINT32 SectorSize, + IN EFI_EVENT Event OPTIONAL + ) +{ + EFI_SCSI_LIB_ASYNC_CONTEXT *Context; + EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket; + EFI_STATUS Status; + UINT8 *Cdb; + EFI_EVENT SelfEvent; + + if (Event == NULL) { + return ScsiRead10Command ( + ScsiIo, + Timeout, + SenseData, + SenseDataLength, + HostAdapterStatus, + TargetStatus, + DataBuffer, + DataLength, + StartLba, + SectorSize + ); + } + + ASSERT (SenseDataLength != NULL); + ASSERT (HostAdapterStatus != NULL); + ASSERT (TargetStatus != NULL); + ASSERT (DataLength != NULL); + ASSERT (ScsiIo != NULL); + + Context = AllocateZeroPool (sizeof (EFI_SCSI_LIB_ASYNC_CONTEXT)); + if (Context == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Cdb = AllocateZeroPool (EFI_SCSI_OP_LENGTH_TEN); + if (Cdb == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + Context->SenseDataLength = SenseDataLength; + Context->HostAdapterStatus = HostAdapterStatus; + Context->TargetStatus = TargetStatus; + Context->CallerEvent = Event; + + CommandPacket = &Context->CommandPacket; + CommandPacket->Timeout = Timeout; + CommandPacket->InDataBuffer = DataBuffer; + CommandPacket->SenseData = SenseData; + CommandPacket->InTransferLength = *DataLength; + CommandPacket->Cdb = Cdb; + // + // Fill Cdb for Read (10) Command + // + Cdb[0] = EFI_SCSI_OP_READ10; + WriteUnaligned32 ((UINT32 *)&Cdb[2], SwapBytes32 (StartLba)); + WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 ((UINT16) SectorSize)); + + CommandPacket->CdbLength = EFI_SCSI_OP_LENGTH_TEN; + CommandPacket->DataDirection = EFI_SCSI_DATA_IN; + CommandPacket->SenseDataLength = *SenseDataLength; + + // + // Create Event + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + ScsiLibNotify, + Context, + &SelfEvent + ); + if (EFI_ERROR(Status)) { + goto ErrorExit; + } + + Status = ScsiIo->ExecuteScsiCommand (ScsiIo, CommandPacket, SelfEvent); + if (EFI_ERROR(Status)) { + // + // Since ScsiLibNotify() will not be signaled if ExecuteScsiCommand() + // returns with error, close the event here. + // + gBS->CloseEvent (SelfEvent); + goto ErrorExit; + } else { + return EFI_SUCCESS; + } + +ErrorExit: + if (Context != NULL) { + FreePool (Context); + } + + return Status; +} + + +/** + Execute blocking/non-blocking Write(10) SCSI command on a specific SCSI + target. + + Executes the SCSI Write(10) command on the SCSI target specified by ScsiIo. + When Event is NULL, blocking command will be executed. Otherwise non-blocking + command will be executed. + For blocking I/O, if Timeout is zero, this function will wait indefinitely + for the command to complete. If Timeout is greater than zero, then the + command is executed and will timeout after Timeout 100 ns units. + For non-blocking I/O, if Timeout is zero, Event will be signaled only after + the command to completes. If Timeout is greater than zero, Event will also be + signaled after Timeout 100 ns units. + The StartLba and SectorSize parameters are used to construct the CDB for this + SCSI command. + + If ScsiIo is NULL, then ASSERT(). + If SenseDataLength is NULL, then ASSERT(). + If HostAdapterStatus is NULL, then ASSERT(). + If TargetStatus is NULL, then ASSERT(). + If DataLength is NULL, then ASSERT(). + + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet + buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet + buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + @param[in] ScsiIo SCSI IO Protocol to use + @param[in] Timeout The length of timeout period. + @param[in, out] SenseData A pointer to output sense data. + @param[in, out] SenseDataLength The length of output sense data. + @param[out] HostAdapterStatus The status of Host Adapter. + @param[out] TargetStatus The status of the target. + @param[in, out] DataBuffer A pointer to a data buffer. + @param[in, out] DataLength The length of data buffer. + @param[in] StartLba The start address of LBA. + @param[in] SectorSize The number of contiguous logical blocks + of data that shall be transferred. + @param[in] Event If the SCSI target does not support + non-blocking I/O, then Event is ignored, + and blocking I/O is performed. If Event + is NULL, then blocking I/O is performed. + If Event is not NULL and non-blocking + I/O is supported, then non-blocking I/O + is performed, and Event will be signaled + when the SCSI Write(10) command + completes. + + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, + but the entire DataBuffer could not be + transferred. The actual number of bytes + transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be + sent because there are too many SCSI + Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting + to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI + Request Packet is not supported by the + SCSI initiator(i.e., SCSI Host + Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the + SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet + are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due + to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +ScsiWrite10CommandEx ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN OUT VOID *SenseData, OPTIONAL + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN OUT VOID *DataBuffer, OPTIONAL + IN OUT UINT32 *DataLength, + IN UINT32 StartLba, + IN UINT32 SectorSize, + IN EFI_EVENT Event OPTIONAL + ) +{ + EFI_SCSI_LIB_ASYNC_CONTEXT *Context; + EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket; + EFI_STATUS Status; + UINT8 *Cdb; + EFI_EVENT SelfEvent; + + if (Event == NULL) { + return ScsiWrite10Command ( + ScsiIo, + Timeout, + SenseData, + SenseDataLength, + HostAdapterStatus, + TargetStatus, + DataBuffer, + DataLength, + StartLba, + SectorSize + ); + } + + ASSERT (SenseDataLength != NULL); + ASSERT (HostAdapterStatus != NULL); + ASSERT (TargetStatus != NULL); + ASSERT (DataLength != NULL); + ASSERT (ScsiIo != NULL); + + Context = AllocateZeroPool (sizeof (EFI_SCSI_LIB_ASYNC_CONTEXT)); + if (Context == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Cdb = AllocateZeroPool (EFI_SCSI_OP_LENGTH_TEN); + if (Cdb == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + Context->SenseDataLength = SenseDataLength; + Context->HostAdapterStatus = HostAdapterStatus; + Context->TargetStatus = TargetStatus; + Context->CallerEvent = Event; + + CommandPacket = &Context->CommandPacket; + CommandPacket->Timeout = Timeout; + CommandPacket->OutDataBuffer = DataBuffer; + CommandPacket->SenseData = SenseData; + CommandPacket->OutTransferLength = *DataLength; + CommandPacket->Cdb = Cdb; + // + // Fill Cdb for Write (10) Command + // + Cdb[0] = EFI_SCSI_OP_WRITE10; + WriteUnaligned32 ((UINT32 *)&Cdb[2], SwapBytes32 (StartLba)); + WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 ((UINT16) SectorSize)); + + CommandPacket->CdbLength = EFI_SCSI_OP_LENGTH_TEN; + CommandPacket->DataDirection = EFI_SCSI_DATA_OUT; + CommandPacket->SenseDataLength = *SenseDataLength; + + // + // Create Event + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + ScsiLibNotify, + Context, + &SelfEvent + ); + if (EFI_ERROR(Status)) { + goto ErrorExit; + } + + Status = ScsiIo->ExecuteScsiCommand (ScsiIo, CommandPacket, SelfEvent); + if (EFI_ERROR(Status)) { + // + // Since ScsiLibNotify() will not be signaled if ExecuteScsiCommand() + // returns with error, close the event here. + // + gBS->CloseEvent (SelfEvent); + goto ErrorExit; + } else { + return EFI_SUCCESS; + } + +ErrorExit: + if (Context != NULL) { + FreePool (Context); + } + + return Status; +} + + +/** + Execute blocking/non-blocking Read(16) SCSI command on a specific SCSI + target. + + Executes the SCSI Read(16) command on the SCSI target specified by ScsiIo. + When Event is NULL, blocking command will be executed. Otherwise non-blocking + command will be executed. + For blocking I/O, if Timeout is zero, this function will wait indefinitely + for the command to complete. If Timeout is greater than zero, then the + command is executed and will timeout after Timeout 100 ns units. + For non-blocking I/O, if Timeout is zero, Event will be signaled only after + the command to completes. If Timeout is greater than zero, Event will also be + signaled after Timeout 100 ns units. + The StartLba and SectorSize parameters are used to construct the CDB for this + SCSI command. + + If ScsiIo is NULL, then ASSERT(). + If SenseDataLength is NULL, then ASSERT(). + If HostAdapterStatus is NULL, then ASSERT(). + If TargetStatus is NULL, then ASSERT(). + If DataLength is NULL, then ASSERT(). + + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet + buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet + buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + @param[in] ScsiIo A pointer to SCSI IO protocol. + @param[in] Timeout The length of timeout period. + @param[in, out] SenseData A pointer to output sense data. + @param[in, out] SenseDataLength The length of output sense data. + @param[out] HostAdapterStatus The status of Host Adapter. + @param[out] TargetStatus The status of the target. + @param[in, out] DataBuffer Read 16 command data. + @param[in, out] DataLength The length of data buffer. + @param[in] StartLba The start address of LBA. + @param[in] SectorSize The number of contiguous logical blocks + of data that shall be transferred. + @param[in] Event If the SCSI target does not support + non-blocking I/O, then Event is ignored, + and blocking I/O is performed. If Event + is NULL, then blocking I/O is performed. + If Event is not NULL and non-blocking + I/O is supported, then non-blocking I/O + is performed, and Event will be signaled + when the SCSI Read(16) command + completes. + + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, + but the entire DataBuffer could not be + transferred. The actual number of bytes + transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be + sent because there are too many SCSI + Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting + to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI + Request Packet is not supported by the + SCSI initiator(i.e., SCSI Host + Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the + SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet + are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due + to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +ScsiRead16CommandEx ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN OUT VOID *SenseData, OPTIONAL + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN OUT VOID *DataBuffer, OPTIONAL + IN OUT UINT32 *DataLength, + IN UINT64 StartLba, + IN UINT32 SectorSize, + IN EFI_EVENT Event OPTIONAL + ) +{ + EFI_SCSI_LIB_ASYNC_CONTEXT *Context; + EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket; + EFI_STATUS Status; + UINT8 *Cdb; + EFI_EVENT SelfEvent; + + if (Event == NULL) { + return ScsiRead16Command ( + ScsiIo, + Timeout, + SenseData, + SenseDataLength, + HostAdapterStatus, + TargetStatus, + DataBuffer, + DataLength, + StartLba, + SectorSize + ); + } + + ASSERT (SenseDataLength != NULL); + ASSERT (HostAdapterStatus != NULL); + ASSERT (TargetStatus != NULL); + ASSERT (DataLength != NULL); + ASSERT (ScsiIo != NULL); + + Context = AllocateZeroPool (sizeof (EFI_SCSI_LIB_ASYNC_CONTEXT)); + if (Context == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Cdb = AllocateZeroPool (EFI_SCSI_OP_LENGTH_SIXTEEN); + if (Cdb == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + Context->SenseDataLength = SenseDataLength; + Context->HostAdapterStatus = HostAdapterStatus; + Context->TargetStatus = TargetStatus; + Context->CallerEvent = Event; + + CommandPacket = &Context->CommandPacket; + CommandPacket->Timeout = Timeout; + CommandPacket->InDataBuffer = DataBuffer; + CommandPacket->SenseData = SenseData; + CommandPacket->InTransferLength = *DataLength; + CommandPacket->Cdb = Cdb; + // + // Fill Cdb for Read (16) Command + // + Cdb[0] = EFI_SCSI_OP_READ16; + WriteUnaligned64 ((UINT64 *)&Cdb[2], SwapBytes64 (StartLba)); + WriteUnaligned32 ((UINT32 *)&Cdb[10], SwapBytes32 (SectorSize)); + + CommandPacket->CdbLength = EFI_SCSI_OP_LENGTH_SIXTEEN; + CommandPacket->DataDirection = EFI_SCSI_DATA_IN; + CommandPacket->SenseDataLength = *SenseDataLength; + + // + // Create Event + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + ScsiLibNotify, + Context, + &SelfEvent + ); + if (EFI_ERROR(Status)) { + goto ErrorExit; + } + + Status = ScsiIo->ExecuteScsiCommand (ScsiIo, CommandPacket, SelfEvent); + if (EFI_ERROR(Status)) { + // + // Since ScsiLibNotify() will not be signaled if ExecuteScsiCommand() + // returns with error, close the event here. + // + gBS->CloseEvent (SelfEvent); + goto ErrorExit; + } else { + return EFI_SUCCESS; + } + +ErrorExit: + if (Context != NULL) { + FreePool (Context); + } + + return Status; +} + + +/** + Execute blocking/non-blocking Write(16) SCSI command on a specific SCSI + target. + + Executes the SCSI Write(16) command on the SCSI target specified by ScsiIo. + When Event is NULL, blocking command will be executed. Otherwise non-blocking + command will be executed. + For blocking I/O, if Timeout is zero, this function will wait indefinitely + for the command to complete. If Timeout is greater than zero, then the + command is executed and will timeout after Timeout 100 ns units. + For non-blocking I/O, if Timeout is zero, Event will be signaled only after + the command to completes. If Timeout is greater than zero, Event will also be + signaled after Timeout 100 ns units. + The StartLba and SectorSize parameters are used to construct the CDB for this + SCSI command. + + If ScsiIo is NULL, then ASSERT(). + If SenseDataLength is NULL, then ASSERT(). + If HostAdapterStatus is NULL, then ASSERT(). + If TargetStatus is NULL, then ASSERT(). + If DataLength is NULL, then ASSERT(). + + If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet + buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet + buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise + EFI_INVALID_PARAMETER gets returned. + + @param[in] ScsiIo SCSI IO Protocol to use + @param[in] Timeout The length of timeout period. + @param[in, out] SenseData A pointer to output sense data. + @param[in, out] SenseDataLength The length of output sense data. + @param[out] HostAdapterStatus The status of Host Adapter. + @param[out] TargetStatus The status of the target. + @param[in, out] DataBuffer A pointer to a data buffer. + @param[in, out] DataLength The length of data buffer. + @param[in] StartLba The start address of LBA. + @param[in] SectorSize The number of contiguous logical blocks + of data that shall be transferred. + @param[in] Event If the SCSI target does not support + non-blocking I/O, then Event is ignored, + and blocking I/O is performed. If Event + is NULL, then blocking I/O is performed. + If Event is not NULL and non-blocking + I/O is supported, then non-blocking I/O + is performed, and Event will be signaled + when the SCSI Write(16) command + completes. + + @retval EFI_SUCCESS Command is executed successfully. + @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, + but the entire DataBuffer could not be + transferred. The actual number of bytes + transferred is returned in DataLength. + @retval EFI_NOT_READY The SCSI Request Packet could not be + sent because there are too many SCSI + Command Packets already queued. + @retval EFI_DEVICE_ERROR A device error occurred while attempting + to send SCSI Request Packet. + @retval EFI_UNSUPPORTED The command described by the SCSI + Request Packet is not supported by the + SCSI initiator(i.e., SCSI Host + Controller) + @retval EFI_TIMEOUT A timeout occurred while waiting for the + SCSI Request Packet to execute. + @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet + are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due + to a lack of resources. + +**/ +EFI_STATUS +EFIAPI +ScsiWrite16CommandEx ( + IN EFI_SCSI_IO_PROTOCOL *ScsiIo, + IN UINT64 Timeout, + IN OUT VOID *SenseData, OPTIONAL + IN OUT UINT8 *SenseDataLength, + OUT UINT8 *HostAdapterStatus, + OUT UINT8 *TargetStatus, + IN OUT VOID *DataBuffer, OPTIONAL + IN OUT UINT32 *DataLength, + IN UINT64 StartLba, + IN UINT32 SectorSize, + IN EFI_EVENT Event OPTIONAL + ) +{ + EFI_SCSI_LIB_ASYNC_CONTEXT *Context; + EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket; + EFI_STATUS Status; + UINT8 *Cdb; + EFI_EVENT SelfEvent; + + if (Event == NULL) { + return ScsiWrite16Command ( + ScsiIo, + Timeout, + SenseData, + SenseDataLength, + HostAdapterStatus, + TargetStatus, + DataBuffer, + DataLength, + StartLba, + SectorSize + ); + } + + ASSERT (SenseDataLength != NULL); + ASSERT (HostAdapterStatus != NULL); + ASSERT (TargetStatus != NULL); + ASSERT (DataLength != NULL); + ASSERT (ScsiIo != NULL); + + Context = AllocateZeroPool (sizeof (EFI_SCSI_LIB_ASYNC_CONTEXT)); + if (Context == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Cdb = AllocateZeroPool (EFI_SCSI_OP_LENGTH_SIXTEEN); + if (Cdb == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + Context->SenseDataLength = SenseDataLength; + Context->HostAdapterStatus = HostAdapterStatus; + Context->TargetStatus = TargetStatus; + Context->CallerEvent = Event; + + CommandPacket = &Context->CommandPacket; + CommandPacket->Timeout = Timeout; + CommandPacket->OutDataBuffer = DataBuffer; + CommandPacket->SenseData = SenseData; + CommandPacket->OutTransferLength = *DataLength; + CommandPacket->Cdb = Cdb; + // + // Fill Cdb for Write (16) Command + // + Cdb[0] = EFI_SCSI_OP_WRITE16; + WriteUnaligned64 ((UINT64 *)&Cdb[2], SwapBytes64 (StartLba)); + WriteUnaligned32 ((UINT32 *)&Cdb[10], SwapBytes32 (SectorSize)); + + CommandPacket->CdbLength = EFI_SCSI_OP_LENGTH_SIXTEEN; + CommandPacket->DataDirection = EFI_SCSI_DATA_OUT; + CommandPacket->SenseDataLength = *SenseDataLength; + + // + // Create Event + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + ScsiLibNotify, + Context, + &SelfEvent + ); + if (EFI_ERROR(Status)) { + goto ErrorExit; + } + + Status = ScsiIo->ExecuteScsiCommand (ScsiIo, CommandPacket, SelfEvent); + if (EFI_ERROR(Status)) { + // + // Since ScsiLibNotify() will not be signaled if ExecuteScsiCommand() + // returns with error, close the event here. + // + gBS->CloseEvent (SelfEvent); + goto ErrorExit; + } else { + return EFI_SUCCESS; + } + +ErrorExit: + if (Context != NULL) { + FreePool (Context); + } + + return Status; +} |