X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=MdePkg%2FLibrary%2FUefiScsiLib%2FUefiScsiLib.c;h=c7491d1436908f88160302721772b59e16440a79;hb=9344f0921518309295da89c221d10cbead8531aa;hp=8fcc3d157dce8684d716443184632d8318109b6f;hpb=3e0c79b57baca799c3d46f429d6e70b1a5ac2113;p=mirror_edk2.git diff --git a/MdePkg/Library/UefiScsiLib/UefiScsiLib.c b/MdePkg/Library/UefiScsiLib/UefiScsiLib.c index 8fcc3d157d..c7491d1436 100644 --- a/MdePkg/Library/UefiScsiLib/UefiScsiLib.c +++ b/MdePkg/Library/UefiScsiLib/UefiScsiLib.c @@ -1,14 +1,8 @@ /** @file UEFI SCSI Library implementation - Copyright (c) 2006 - 2008, Intel Corporation.
- All rights reserved. This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -18,26 +12,51 @@ #include #include #include - +#include +#include + #include - - - // - // Max bytes needed to represent ID of a SCSI device - // -#define EFI_SCSI_TARGET_MAX_BYTES (0x10) - - // - // bit5..7 are for Logical unit number - // 11100000b (0xe0) - // -#define EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK 0xe0 - + + // - // Scsi Command Length six or ten + // Scsi Command Length // -#define EFI_SCSI_OP_LENGTH_SIX 0x6 -#define EFI_SCSI_OP_LENGTH_TEN 0xa +#define EFI_SCSI_OP_LENGTH_SIX 0x6 +#define EFI_SCSI_OP_LENGTH_TEN 0xa +#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; @@ -52,6 +71,9 @@ 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. @@ -69,7 +91,7 @@ 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. + 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. @@ -79,29 +101,30 @@ 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. + 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 @@ -116,9 +139,6 @@ ScsiTestUnitReadyCommand ( ) { EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; - UINT64 Lun; - UINT8 *Target; - UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES]; EFI_STATUS Status; UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIX]; @@ -140,11 +160,7 @@ ScsiTestUnitReadyCommand ( // // Fill Cdb for Test Unit Ready Command // - Target = &TargetArray[0]; - ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun); - Cdb[0] = EFI_SCSI_OP_TEST_UNIT_READY; - Cdb[1] = (UINT8) (LShiftU64 (Lun, 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK); CommandPacket.CdbLength = (UINT8) EFI_SCSI_OP_LENGTH_SIX; CommandPacket.SenseDataLength = *SenseDataLength; @@ -170,6 +186,14 @@ ScsiTestUnitReadyCommand ( 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 @@ -185,7 +209,7 @@ ScsiTestUnitReadyCommand ( 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. + 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 @@ -197,48 +221,51 @@ ScsiTestUnitReadyCommand ( executed on the SCSI Host Controller. See the EFI SCSI I/O Protocol in the UEFI Specification for details on the possible - return values. + 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. + 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. + data for the PageCode 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. + 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 -ScsiInquiryCommand ( +ScsiInquiryCommandEx ( IN EFI_SCSI_IO_PROTOCOL *ScsiIo, IN UINT64 Timeout, IN OUT VOID *SenseData, OPTIONAL @@ -247,13 +274,11 @@ ScsiInquiryCommand ( OUT UINT8 *TargetStatus, IN OUT VOID *InquiryDataBuffer, OPTIONAL IN OUT UINT32 *InquiryDataLength, - IN BOOLEAN EnableVitalProductData + IN BOOLEAN EnableVitalProductData, + IN UINT8 PageCode ) { EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; - UINT64 Lun; - UINT8 *Target; - UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES]; EFI_STATUS Status; UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIX]; @@ -273,13 +298,10 @@ ScsiInquiryCommand ( CommandPacket.SenseDataLength = *SenseDataLength; CommandPacket.Cdb = Cdb; - Target = &TargetArray[0]; - ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun); - Cdb[0] = EFI_SCSI_OP_INQUIRY; - Cdb[1] = (UINT8) (LShiftU64 (Lun, 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK); if (EnableVitalProductData) { Cdb[1] |= 0x01; + Cdb[2] = PageCode; } if (*InquiryDataLength > 0xff) { @@ -301,6 +323,121 @@ ScsiInquiryCommand ( } +/** + 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. @@ -315,6 +452,13 @@ ScsiInquiryCommand ( 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. @@ -331,7 +475,7 @@ ScsiInquiryCommand ( 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. + 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 @@ -347,39 +491,40 @@ ScsiInquiryCommand ( 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. + 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. + 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. + @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 @@ -399,9 +544,6 @@ ScsiModeSense10Command ( ) { EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; - UINT64 Lun; - UINT8 *Target; - UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES]; EFI_STATUS Status; UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN]; @@ -422,14 +564,11 @@ ScsiModeSense10Command ( // // Fill Cdb for Mode Sense (10) Command // - Target = &TargetArray[0]; - ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun); - Cdb[0] = EFI_SCSI_OP_MODE_SEN10; // // DBDField is in Cdb[1] bit3 of (bit7..0) // - Cdb[1] = (UINT8) ((LShiftU64 (Lun, 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK) + ((DBDField << 3) & 0x08)); + Cdb[1] = (UINT8) ((DBDField << 3) & 0x08); // // PageControl is in Cdb[2] bit7..6, PageCode is in Cdb[2] bit5..0 // @@ -463,6 +602,10 @@ ScsiModeSense10Command ( 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. @@ -477,6 +620,7 @@ ScsiModeSense10Command ( @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 @@ -491,9 +635,6 @@ ScsiRequestSenseCommand ( ) { EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; - UINT64 Lun; - UINT8 *Target; - UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES]; EFI_STATUS Status; UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIX]; @@ -513,11 +654,7 @@ ScsiRequestSenseCommand ( // // Fill Cdb for Request Sense Command // - Target = &TargetArray[0]; - ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun); - Cdb[0] = EFI_SCSI_OP_REQUEST_SENSE; - Cdb[1] = (UINT8) (LShiftU64 (Lun, 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK); Cdb[4] = (UINT8) (*SenseDataLength); CommandPacket.CdbLength = (UINT8) EFI_SCSI_OP_LENGTH_SIX; @@ -547,6 +684,14 @@ ScsiRequestSenseCommand ( 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. @@ -557,16 +702,17 @@ ScsiRequestSenseCommand ( @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_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 @@ -584,9 +730,6 @@ ScsiReadCapacityCommand ( ) { EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; - UINT64 Lun; - UINT8 *Target; - UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES]; EFI_STATUS Status; UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN]; @@ -607,11 +750,7 @@ ScsiReadCapacityCommand ( // // Fill Cdb for Read Capacity Command // - Target = &TargetArray[0]; - ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun); - Cdb[0] = EFI_SCSI_OP_READ_CAPACITY; - Cdb[1] = (UINT8) (LShiftU64 (Lun, 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK); if (!Pmi) { // // Partial medium indicator,if Pmi is FALSE, the Cdb.2 ~ Cdb.5 MUST BE ZERO. @@ -649,6 +788,14 @@ ScsiReadCapacityCommand ( 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. @@ -659,16 +806,17 @@ ScsiReadCapacityCommand ( @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_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 @@ -686,12 +834,15 @@ ScsiReadCapacity16Command ( ) { EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; - UINT64 Lun; - UINT8 *Target; - UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES]; 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); @@ -703,9 +854,6 @@ ScsiReadCapacity16Command ( // // Fill Cdb for Read Capacity Command // - Target = &TargetArray[0]; - ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun); - Cdb[0] = EFI_SCSI_OP_READ_CAPACITY16; Cdb[1] = 0x10; if (!Pmi) { @@ -747,6 +895,13 @@ ScsiReadCapacity16Command ( 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. @@ -757,17 +912,18 @@ ScsiReadCapacity16Command ( @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 sector size. - - @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. + @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 @@ -786,9 +942,6 @@ ScsiRead10Command ( ) { EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; - UINT64 Lun; - UINT8 *Target; - UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES]; EFI_STATUS Status; UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN]; @@ -809,17 +962,9 @@ ScsiRead10Command ( // // Fill Cdb for Read (10) Command // - Target = &TargetArray[0]; - ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun); - Cdb[0] = EFI_SCSI_OP_READ10; - Cdb[1] = (UINT8) (LShiftU64 (Lun, 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK); - Cdb[2] = (UINT8) (StartLba >> 24); - Cdb[3] = (UINT8) (StartLba >> 16); - Cdb[4] = (UINT8) (StartLba >> 8); - Cdb[5] = (UINT8) (StartLba & 0xff); - Cdb[7] = (UINT8) (SectorSize >> 8); - Cdb[8] = (UINT8) (SectorSize & 0xff); + 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; @@ -850,6 +995,14 @@ ScsiRead10Command ( 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. @@ -859,17 +1012,18 @@ ScsiRead10Command ( @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 sector size. - - @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. + @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 @@ -888,9 +1042,6 @@ ScsiWrite10Command ( ) { EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; - UINT64 Lun; - UINT8 *Target; - UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES]; EFI_STATUS Status; UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN]; @@ -911,17 +1062,9 @@ ScsiWrite10Command ( // // Fill Cdb for Write (10) Command // - Target = &TargetArray[0]; - ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun); - Cdb[0] = EFI_SCSI_OP_WRITE10; - Cdb[1] = (UINT8) (LShiftU64 (Lun, 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK); - Cdb[2] = (UINT8) (StartLba >> 24); - Cdb[3] = (UINT8) (StartLba >> 16); - Cdb[4] = (UINT8) (StartLba >> 8); - Cdb[5] = (UINT8) StartLba; - Cdb[7] = (UINT8) (SectorSize >> 8); - Cdb[8] = (UINT8) SectorSize; + 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; @@ -937,3 +1080,982 @@ ScsiWrite10Command ( 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; + 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; +} + + +/** + 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; +}