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;
+}