X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=MdePkg%2FLibrary%2FUefiScsiLib%2FUefiScsiLib.c;h=13a2a1912cbe8a23f5d018965d34db627902c162;hb=9b14509b16a90ebe5d418d403295efaff76d95d4;hp=c52f5009ee66fd15f6eb2462c871e2550a041d22;hpb=f158ee678ca89b882a08fe420c79983966a7dd37;p=mirror_edk2.git diff --git a/MdePkg/Library/UefiScsiLib/UefiScsiLib.c b/MdePkg/Library/UefiScsiLib/UefiScsiLib.c index c52f5009ee..13a2a1912c 100644 --- a/MdePkg/Library/UefiScsiLib/UefiScsiLib.c +++ b/MdePkg/Library/UefiScsiLib/UefiScsiLib.c @@ -1,42 +1,63 @@ /** @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 - 2019, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include +#include #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_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; @@ -51,6 +72,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. @@ -68,7 +92,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. @@ -78,29 +102,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 @@ -115,9 +140,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]; @@ -139,11 +161,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) (Lun & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK); CommandPacket.CdbLength = (UINT8) EFI_SCSI_OP_LENGTH_SIX; CommandPacket.SenseDataLength = *SenseDataLength; @@ -169,6 +187,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 @@ -184,7 +210,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 @@ -196,48 +222,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 @@ -246,13 +275,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]; @@ -272,13 +299,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) (Lun & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK); if (EnableVitalProductData) { Cdb[1] |= 0x01; + Cdb[2] = PageCode; } if (*InquiryDataLength > 0xff) { @@ -300,6 +324,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. @@ -314,6 +453,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. @@ -330,7 +476,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 @@ -346,39 +492,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 @@ -398,9 +545,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]; @@ -421,18 +565,15 @@ 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) ((Lun & 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 // - Cdb[2] = (UINT8) ((PageControl & 0xc0) | (PageCode & 0x3f)); + Cdb[2] = (UINT8) (((PageControl << 6) & 0xc0) | (PageCode & 0x3f)); Cdb[7] = (UINT8) (*DataLength >> 8); Cdb[8] = (UINT8) (*DataLength); @@ -462,6 +603,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. @@ -476,6 +621,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 @@ -490,9 +636,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]; @@ -512,11 +655,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) (Lun & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK); Cdb[4] = (UINT8) (*SenseDataLength); CommandPacket.CdbLength = (UINT8) EFI_SCSI_OP_LENGTH_SIX; @@ -546,6 +685,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. @@ -556,16 +703,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 @@ -583,9 +731,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]; @@ -606,11 +751,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) (Lun & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK); if (!Pmi) { // // Partial medium indicator,if Pmi is FALSE, the Cdb.2 ~ Cdb.5 MUST BE ZERO. @@ -648,6 +789,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. @@ -658,16 +807,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 @@ -685,12 +835,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); @@ -702,9 +855,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) { @@ -746,6 +896,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. @@ -756,17 +913,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 @@ -785,9 +943,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]; @@ -808,17 +963,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) (Lun & 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; @@ -849,6 +996,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. @@ -858,17 +1013,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 @@ -887,9 +1043,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]; @@ -910,17 +1063,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) (Lun & 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; @@ -936,3 +1081,1208 @@ 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; +} + + +/** + 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; +}