mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-12-27 16:58:09 +01:00
d7c710f9e3
Signed-off-by: SergeySlice <sergey.slice@gmail.com>
2062 lines
95 KiB
C
2062 lines
95 KiB
C
/** @file
|
|
UEFI SCSI Library implementation
|
|
|
|
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
|
|
#include <Uefi.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/UefiScsiLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
|
|
#include <IndustryStandard/Scsi.h>
|
|
|
|
|
|
//
|
|
// Scsi Command Length
|
|
//
|
|
#define EFI_SCSI_OP_LENGTH_SIX 0x6
|
|
#define EFI_SCSI_OP_LENGTH_TEN 0xa
|
|
#define EFI_SCSI_OP_LENGTH_SIXTEEN 0x10
|
|
|
|
//
|
|
// The context structure used when non-blocking SCSI read/write operation
|
|
// completes.
|
|
//
|
|
typedef struct {
|
|
///
|
|
/// The SCSI request packet to send to the SCSI controller specified by
|
|
/// the device handle.
|
|
///
|
|
EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
|
|
///
|
|
/// The length of the output sense data.
|
|
///
|
|
UINT8 *SenseDataLength;
|
|
///
|
|
/// The status of the SCSI host adapter.
|
|
///
|
|
UINT8 *HostAdapterStatus;
|
|
///
|
|
/// The status of the target SCSI device.
|
|
///
|
|
UINT8 *TargetStatus;
|
|
///
|
|
/// The length of the data buffer for the SCSI read/write command.
|
|
///
|
|
UINT32 *DataLength;
|
|
///
|
|
/// The caller event to be signaled when the SCSI read/write command
|
|
/// completes.
|
|
///
|
|
EFI_EVENT CallerEvent;
|
|
} EFI_SCSI_LIB_ASYNC_CONTEXT;
|
|
|
|
|
|
|
|
/**
|
|
Execute Test Unit Ready SCSI command on a specific SCSI target.
|
|
|
|
Executes the Test Unit Ready command on the SCSI target specified by ScsiIo.
|
|
If Timeout is zero, then this function waits indefinitely for the command to complete.
|
|
If Timeout is greater than zero, then the command is executed and will timeout after Timeout 100 ns units.
|
|
If ScsiIo is NULL, then ASSERT().
|
|
If SenseDataLength is NULL, then ASSERT().
|
|
If HostAdapterStatus is NULL, then ASSERT().
|
|
If TargetStatus is NULL, then ASSERT().
|
|
|
|
If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer
|
|
alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
|
|
gets returned.
|
|
|
|
@param[in] ScsiIo A pointer to the SCSI I/O Protocol instance
|
|
for the specific SCSI target.
|
|
@param[in] Timeout The timeout in 100 ns units to use for the execution
|
|
of this SCSI Request Packet. A Timeout value of
|
|
zero means that this function will wait indefinitely
|
|
for the SCSI Request Packet to execute. If Timeout
|
|
is greater than zero, then this function will return
|
|
EFI_TIMEOUT if the time required to execute the SCSI
|
|
Request Packet is greater than Timeout.
|
|
@param[in, out] SenseData A pointer to sense data that was generated by
|
|
the execution of the SCSI Request Packet. This
|
|
buffer must be allocated by the caller.
|
|
If SenseDataLength is 0, then this parameter is
|
|
optional and may be NULL.
|
|
@param[in, out] SenseDataLength On input, a pointer to the length in bytes of
|
|
the SenseData buffer. On output, a pointer to
|
|
the number of bytes written to the SenseData buffer.
|
|
@param[out] HostAdapterStatus The status of the SCSI Host Controller that produces
|
|
the SCSI bus containing the SCSI target specified by
|
|
ScsiIo when the SCSI Request Packet was executed.
|
|
See the EFI SCSI I/O Protocol in the UEFI Specification
|
|
for details on the possible return values.
|
|
@param[out] TargetStatus The status returned by the SCSI target specified
|
|
by ScsiIo when the SCSI Request Packet was executed
|
|
on the SCSI Host Controller. See the EFI SCSI I/O
|
|
Protocol in the UEFI Specification for details on
|
|
the possible return values.
|
|
|
|
@retval EFI_SUCCESS The command was executed successfully.
|
|
See HostAdapterStatus, TargetStatus, SenseDataLength,
|
|
and SenseData in that order for additional status
|
|
information.
|
|
@retval EFI_NOT_READY The SCSI Request Packet could not be sent because
|
|
there are too many SCSI Command Packets already
|
|
queued. The SCSI Request Packet was not sent, so
|
|
no additional status information is available.
|
|
The caller may retry again later.
|
|
@retval EFI_DEVICE_ERROR A device error occurred while attempting to send
|
|
SCSI Request Packet. See HostAdapterStatus,
|
|
TargetStatus, SenseDataLength, and SenseData in that
|
|
order for additional status information.
|
|
@retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
|
|
is not supported by the SCSI initiator(i.e., SCSI
|
|
Host Controller). The SCSI Request Packet was not
|
|
sent, so no additional status information is available.
|
|
@retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request
|
|
Packet to execute. See HostAdapterStatus, TargetStatus,
|
|
SenseDataLength, and SenseData in that order for
|
|
additional status information.
|
|
@retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScsiTestUnitReadyCommand (
|
|
IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
|
|
IN UINT64 Timeout,
|
|
IN OUT VOID *SenseData, OPTIONAL
|
|
IN OUT UINT8 *SenseDataLength,
|
|
OUT UINT8 *HostAdapterStatus,
|
|
OUT UINT8 *TargetStatus
|
|
)
|
|
{
|
|
EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
|
|
EFI_STATUS Status;
|
|
UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIX];
|
|
|
|
ASSERT (SenseDataLength != NULL);
|
|
ASSERT (HostAdapterStatus != NULL);
|
|
ASSERT (TargetStatus != NULL);
|
|
ASSERT (ScsiIo != NULL);
|
|
|
|
ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
|
|
ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIX);
|
|
|
|
CommandPacket.Timeout = Timeout;
|
|
CommandPacket.InDataBuffer = NULL;
|
|
CommandPacket.InTransferLength= 0;
|
|
CommandPacket.OutDataBuffer = NULL;
|
|
CommandPacket.OutTransferLength= 0;
|
|
CommandPacket.SenseData = SenseData;
|
|
CommandPacket.Cdb = Cdb;
|
|
//
|
|
// Fill Cdb for Test Unit Ready Command
|
|
//
|
|
Cdb[0] = EFI_SCSI_OP_TEST_UNIT_READY;
|
|
CommandPacket.CdbLength = (UINT8) EFI_SCSI_OP_LENGTH_SIX;
|
|
CommandPacket.SenseDataLength = *SenseDataLength;
|
|
|
|
Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
|
|
|
|
*HostAdapterStatus = CommandPacket.HostAdapterStatus;
|
|
*TargetStatus = CommandPacket.TargetStatus;
|
|
*SenseDataLength = CommandPacket.SenseDataLength;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Execute Inquiry SCSI command on a specific SCSI target.
|
|
|
|
Executes the Inquiry command on the SCSI target specified by ScsiIo.
|
|
If Timeout is zero, then this function waits indefinitely for the command to complete.
|
|
If Timeout is greater than zero, then the command is executed and will timeout after Timeout 100 ns units.
|
|
If ScsiIo is NULL, then ASSERT().
|
|
If SenseDataLength is NULL, then ASSERT().
|
|
If HostAdapterStatus is NULL, then ASSERT().
|
|
If TargetStatus is NULL, then ASSERT().
|
|
If InquiryDataLength is NULL, then ASSERT().
|
|
|
|
If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer
|
|
alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
|
|
gets returned.
|
|
|
|
If InquiryDataLength is non-zero and InquiryDataBuffer is not NULL, InquiryDataBuffer
|
|
must meet buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise
|
|
EFI_INVALID_PARAMETER gets returned.
|
|
|
|
@param[in] ScsiIo A pointer to the SCSI I/O Protocol instance
|
|
for the specific SCSI target.
|
|
@param[in] Timeout The timeout in 100 ns units to use for the
|
|
execution of this SCSI Request Packet. A Timeout
|
|
value of zero means that this function will wait
|
|
indefinitely for the SCSI Request Packet to execute.
|
|
If Timeout is greater than zero, then this function
|
|
will return EFI_TIMEOUT if the time required to
|
|
execute the SCSI Request Packet is greater than Timeout.
|
|
@param[in, out] SenseData A pointer to sense data that was generated
|
|
by the execution of the SCSI Request Packet.
|
|
This buffer must be allocated by the caller.
|
|
If SenseDataLength is 0, then this parameter
|
|
is optional and may be NULL.
|
|
@param[in, out] SenseDataLength On input, the length in bytes of the SenseData buffer.
|
|
On output, the number of bytes written to the SenseData buffer.
|
|
@param[out] HostAdapterStatus The status of the SCSI Host Controller that
|
|
produces the SCSI bus containing the SCSI
|
|
target specified by ScsiIo when the SCSI
|
|
Request Packet was executed. See the EFI
|
|
SCSI I/O Protocol in the UEFI Specification
|
|
for details on the possible return values.
|
|
@param[out] TargetStatus The status returned by the SCSI target specified
|
|
by ScsiIo when the SCSI Request Packet was
|
|
executed on the SCSI Host Controller.
|
|
See the EFI SCSI I/O Protocol in the UEFI
|
|
Specification for details on the possible
|
|
return values.
|
|
@param[in, out] InquiryDataBuffer A pointer to inquiry data that was generated
|
|
by the execution of the SCSI Request Packet.
|
|
This buffer must be allocated by the caller.
|
|
If InquiryDataLength is 0, then this parameter
|
|
is optional and may be NULL.
|
|
@param[in, out] InquiryDataLength On input, a pointer to the length in bytes
|
|
of the InquiryDataBuffer buffer.
|
|
On output, a pointer to the number of bytes
|
|
written to the InquiryDataBuffer buffer.
|
|
@param[in] EnableVitalProductData If TRUE, then the supported vital product
|
|
data for the PageCode is returned in InquiryDataBuffer.
|
|
If FALSE, then the standard inquiry data is
|
|
returned in InquiryDataBuffer and PageCode is ignored.
|
|
@param[in] PageCode The page code of the vital product data.
|
|
It's ignored if EnableVitalProductData is FALSE.
|
|
|
|
@retval EFI_SUCCESS The command executed successfully. See HostAdapterStatus,
|
|
TargetStatus, SenseDataLength, and SenseData in that order
|
|
for additional status information.
|
|
@retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire
|
|
InquiryDataBuffer could not be transferred. The actual
|
|
number of bytes transferred is returned in InquiryDataLength.
|
|
@retval EFI_NOT_READY The SCSI Request Packet could not be sent because there
|
|
are too many SCSI Command Packets already queued.
|
|
The SCSI Request Packet was not sent, so no additional
|
|
status information is available. The caller may retry again later.
|
|
@retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI
|
|
Request Packet. See HostAdapterStatus, TargetStatus,
|
|
SenseDataLength, and SenseData in that order for additional
|
|
status information.
|
|
@retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not
|
|
supported by the SCSI initiator(i.e., SCSI Host Controller).
|
|
The SCSI Request Packet was not sent, so no additional
|
|
status information is available.
|
|
@retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request
|
|
Packet to execute. See HostAdapterStatus, TargetStatus,
|
|
SenseDataLength, and SenseData in that order for
|
|
additional status information.
|
|
@retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScsiInquiryCommandEx (
|
|
IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
|
|
IN UINT64 Timeout,
|
|
IN OUT VOID *SenseData, OPTIONAL
|
|
IN OUT UINT8 *SenseDataLength,
|
|
OUT UINT8 *HostAdapterStatus,
|
|
OUT UINT8 *TargetStatus,
|
|
IN OUT VOID *InquiryDataBuffer, OPTIONAL
|
|
IN OUT UINT32 *InquiryDataLength,
|
|
IN BOOLEAN EnableVitalProductData,
|
|
IN UINT8 PageCode
|
|
)
|
|
{
|
|
EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
|
|
EFI_STATUS Status;
|
|
UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIX];
|
|
|
|
ASSERT (SenseDataLength != NULL);
|
|
ASSERT (HostAdapterStatus != NULL);
|
|
ASSERT (TargetStatus != NULL);
|
|
ASSERT (InquiryDataLength != NULL);
|
|
ASSERT (ScsiIo != NULL);
|
|
|
|
ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
|
|
ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIX);
|
|
|
|
CommandPacket.Timeout = Timeout;
|
|
CommandPacket.InDataBuffer = InquiryDataBuffer;
|
|
CommandPacket.InTransferLength= *InquiryDataLength;
|
|
CommandPacket.SenseData = SenseData;
|
|
CommandPacket.SenseDataLength = *SenseDataLength;
|
|
CommandPacket.Cdb = Cdb;
|
|
|
|
Cdb[0] = EFI_SCSI_OP_INQUIRY;
|
|
if (EnableVitalProductData) {
|
|
Cdb[1] |= 0x01;
|
|
Cdb[2] = PageCode;
|
|
}
|
|
|
|
if (*InquiryDataLength > 0xff) {
|
|
*InquiryDataLength = 0xff;
|
|
}
|
|
|
|
Cdb[4] = (UINT8) (*InquiryDataLength);
|
|
CommandPacket.CdbLength = (UINT8) EFI_SCSI_OP_LENGTH_SIX;
|
|
CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
|
|
|
|
Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
|
|
|
|
*HostAdapterStatus = CommandPacket.HostAdapterStatus;
|
|
*TargetStatus = CommandPacket.TargetStatus;
|
|
*SenseDataLength = CommandPacket.SenseDataLength;
|
|
*InquiryDataLength = CommandPacket.InTransferLength;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Execute Inquiry SCSI command on a specific SCSI target.
|
|
|
|
Executes the Inquiry command on the SCSI target specified by ScsiIo.
|
|
If Timeout is zero, then this function waits indefinitely for the command to complete.
|
|
If Timeout is greater than zero, then the command is executed and will timeout after Timeout 100 ns units.
|
|
If ScsiIo is NULL, then ASSERT().
|
|
If SenseDataLength is NULL, then ASSERT().
|
|
If HostAdapterStatus is NULL, then ASSERT().
|
|
If TargetStatus is NULL, then ASSERT().
|
|
If InquiryDataLength is NULL, then ASSERT().
|
|
|
|
If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer
|
|
alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
|
|
gets returned.
|
|
|
|
If InquiryDataLength is non-zero and InquiryDataBuffer is not NULL, InquiryDataBuffer
|
|
must meet buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise
|
|
EFI_INVALID_PARAMETER gets returned.
|
|
|
|
@param[in] ScsiIo A pointer to the SCSI I/O Protocol instance
|
|
for the specific SCSI target.
|
|
@param[in] Timeout The timeout in 100 ns units to use for the
|
|
execution of this SCSI Request Packet. A Timeout
|
|
value of zero means that this function will wait
|
|
indefinitely for the SCSI Request Packet to execute.
|
|
If Timeout is greater than zero, then this function
|
|
will return EFI_TIMEOUT if the time required to
|
|
execute the SCSI Request Packet is greater than Timeout.
|
|
@param[in, out] SenseData A pointer to sense data that was generated
|
|
by the execution of the SCSI Request Packet.
|
|
This buffer must be allocated by the caller.
|
|
If SenseDataLength is 0, then this parameter
|
|
is optional and may be NULL.
|
|
@param[in, out] SenseDataLength On input, the length in bytes of the SenseData buffer.
|
|
On output, the number of bytes written to the SenseData buffer.
|
|
@param[out] HostAdapterStatus The status of the SCSI Host Controller that
|
|
produces the SCSI bus containing the SCSI
|
|
target specified by ScsiIo when the SCSI
|
|
Request Packet was executed. See the EFI
|
|
SCSI I/O Protocol in the UEFI Specification
|
|
for details on the possible return values.
|
|
@param[out] TargetStatus The status returned by the SCSI target specified
|
|
by ScsiIo when the SCSI Request Packet was
|
|
executed on the SCSI Host Controller.
|
|
See the EFI SCSI I/O Protocol in the UEFI
|
|
Specification for details on the possible
|
|
return values.
|
|
@param[in, out] InquiryDataBuffer A pointer to inquiry data that was generated
|
|
by the execution of the SCSI Request Packet.
|
|
This buffer must be allocated by the caller.
|
|
If InquiryDataLength is 0, then this parameter
|
|
is optional and may be NULL.
|
|
@param[in, out] InquiryDataLength On input, a pointer to the length in bytes
|
|
of the InquiryDataBuffer buffer.
|
|
On output, a pointer to the number of bytes
|
|
written to the InquiryDataBuffer buffer.
|
|
@param[in] EnableVitalProductData If TRUE, then the supported vital product
|
|
data is returned in InquiryDataBuffer.
|
|
If FALSE, then the standard inquiry data is
|
|
returned in InquiryDataBuffer.
|
|
|
|
@retval EFI_SUCCESS The command was executed successfully. See HostAdapterStatus,
|
|
TargetStatus, SenseDataLength, and SenseData in that order
|
|
for additional status information.
|
|
@retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire
|
|
InquiryDataBuffer could not be transferred. The actual
|
|
number of bytes transferred is returned in InquiryDataLength.
|
|
@retval EFI_NOT_READY The SCSI Request Packet could not be sent because there
|
|
are too many SCSI Command Packets already queued.
|
|
The SCSI Request Packet was not sent, so no additional
|
|
status information is available. The caller may retry again later.
|
|
@retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI
|
|
Request Packet. See HostAdapterStatus, TargetStatus,
|
|
SenseDataLength, and SenseData in that order for additional
|
|
status information.
|
|
@retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not
|
|
supported by the SCSI initiator(i.e., SCSI Host Controller).
|
|
The SCSI Request Packet was not sent, so no additional
|
|
status information is available.
|
|
@retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request
|
|
Packet to execute. See HostAdapterStatus, TargetStatus,
|
|
SenseDataLength, and SenseData in that order for
|
|
additional status information.
|
|
@retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScsiInquiryCommand (
|
|
IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
|
|
IN UINT64 Timeout,
|
|
IN OUT VOID *SenseData, OPTIONAL
|
|
IN OUT UINT8 *SenseDataLength,
|
|
OUT UINT8 *HostAdapterStatus,
|
|
OUT UINT8 *TargetStatus,
|
|
IN OUT VOID *InquiryDataBuffer, OPTIONAL
|
|
IN OUT UINT32 *InquiryDataLength,
|
|
IN BOOLEAN EnableVitalProductData
|
|
)
|
|
{
|
|
return ScsiInquiryCommandEx (
|
|
ScsiIo,
|
|
Timeout,
|
|
SenseData,
|
|
SenseDataLength,
|
|
HostAdapterStatus,
|
|
TargetStatus,
|
|
InquiryDataBuffer,
|
|
InquiryDataLength,
|
|
EnableVitalProductData,
|
|
0
|
|
);
|
|
}
|
|
|
|
/**
|
|
Execute Mode Sense(10) SCSI command on a specific SCSI target.
|
|
|
|
Executes the SCSI Mode Sense(10) command on the SCSI target specified by ScsiIo.
|
|
If Timeout is zero, then this function waits indefinitely for the command to complete.
|
|
If Timeout is greater than zero, then the command is executed and will timeout
|
|
after Timeout 100 ns units. The DBDField, PageControl, and PageCode parameters
|
|
are used to construct the CDB for this SCSI command.
|
|
If ScsiIo is NULL, then ASSERT().
|
|
If SenseDataLength is NULL, then ASSERT().
|
|
If HostAdapterStatus is NULL, then ASSERT().
|
|
If TargetStatus is NULL, then ASSERT().
|
|
If DataLength is NULL, then ASSERT().
|
|
|
|
If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer
|
|
alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
|
|
gets returned.
|
|
|
|
If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer
|
|
alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
|
|
gets returned.
|
|
|
|
@param[in] ScsiIo A pointer to the SCSI I/O Protocol instance
|
|
for the specific SCSI target.
|
|
@param[in] Timeout The timeout in 100 ns units to use for the
|
|
execution of this SCSI Request Packet. A Timeout
|
|
value of zero means that this function will wait
|
|
indefinitely for the SCSI Request Packet to execute.
|
|
If Timeout is greater than zero, then this function
|
|
will return EFI_TIMEOUT if the time required to
|
|
execute the SCSI Request Packet is greater than Timeout.
|
|
@param[in, out] SenseData A pointer to sense data that was generated
|
|
by the execution of the SCSI Request Packet.
|
|
This buffer must be allocated by the caller.
|
|
If SenseDataLength is 0, then this parameter
|
|
is optional and may be NULL.
|
|
@param[in, out] SenseDataLength On input, the length in bytes of the SenseData buffer.
|
|
On output, the number of bytes written to the SenseData buffer.
|
|
@param[out] HostAdapterStatus The status of the SCSI Host Controller that
|
|
produces the SCSI bus containing the SCSI target
|
|
specified by ScsiIo when the SCSI Request Packet
|
|
was executed. See the EFI SCSI I/O Protocol in the
|
|
UEFI Specification for details on the possible
|
|
return values.
|
|
@param[out] TargetStatus The status returned by the SCSI target specified
|
|
by ScsiIo when the SCSI Request Packet was executed
|
|
on the SCSI Host Controller. See the EFI SCSI
|
|
I/O Protocol in the UEFI Specification for details
|
|
on the possible return values.
|
|
@param[in, out] DataBuffer A pointer to data that was generated by the
|
|
execution of the SCSI Request Packet. This
|
|
buffer must be allocated by the caller. If
|
|
DataLength is 0, then this parameter is optional
|
|
and may be NULL.
|
|
@param[in, out] DataLength On input, a pointer to the length in bytes of
|
|
the DataBuffer buffer. On output, a pointer
|
|
to the number of bytes written to the DataBuffer
|
|
buffer.
|
|
@param[in] DBDField Specifies the DBD field of the CDB for this SCSI Command.
|
|
@param[in] PageControl Specifies the PC field of the CDB for this SCSI Command.
|
|
@param[in] PageCode Specifies the Page Control field of the CDB for this SCSI Command.
|
|
|
|
@retval EFI_SUCCESS The command was executed successfully.
|
|
See HostAdapterStatus, TargetStatus, SenseDataLength,
|
|
and SenseData in that order for additional status information.
|
|
@retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the
|
|
entire DataBuffer could not be transferred.
|
|
The actual number of bytes transferred is returned
|
|
in DataLength.
|
|
@retval EFI_NOT_READY The SCSI Request Packet could not be sent because
|
|
there are too many SCSI Command Packets already queued.
|
|
The SCSI Request Packet was not sent, so no additional
|
|
status information is available. The caller may retry
|
|
again later.
|
|
@retval EFI_DEVICE_ERROR A device error occurred while attempting to send
|
|
SCSI Request Packet. See HostAdapterStatus, TargetStatus,
|
|
SenseDataLength, and SenseData in that order for
|
|
additional status information.
|
|
@retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
|
|
is not supported by the SCSI initiator(i.e., SCSI
|
|
Host Controller). The SCSI Request Packet was not
|
|
sent, so no additional status information is available.
|
|
@retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI
|
|
Request Packet to execute. See HostAdapterStatus,
|
|
TargetStatus, SenseDataLength, and SenseData in that
|
|
order for additional status information.
|
|
@retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScsiModeSense10Command (
|
|
IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
|
|
IN UINT64 Timeout,
|
|
IN OUT VOID *SenseData, OPTIONAL
|
|
IN OUT UINT8 *SenseDataLength,
|
|
OUT UINT8 *HostAdapterStatus,
|
|
OUT UINT8 *TargetStatus,
|
|
IN OUT VOID *DataBuffer, OPTIONAL
|
|
IN OUT UINT32 *DataLength,
|
|
IN UINT8 DBDField, OPTIONAL
|
|
IN UINT8 PageControl,
|
|
IN UINT8 PageCode
|
|
)
|
|
{
|
|
EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
|
|
EFI_STATUS Status;
|
|
UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN];
|
|
|
|
ASSERT (SenseDataLength != NULL);
|
|
ASSERT (HostAdapterStatus != NULL);
|
|
ASSERT (TargetStatus != NULL);
|
|
ASSERT (DataLength != NULL);
|
|
ASSERT (ScsiIo != NULL);
|
|
|
|
ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
|
|
ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TEN);
|
|
|
|
CommandPacket.Timeout = Timeout;
|
|
CommandPacket.InDataBuffer = DataBuffer;
|
|
CommandPacket.SenseData = SenseData;
|
|
CommandPacket.InTransferLength= *DataLength;
|
|
CommandPacket.Cdb = Cdb;
|
|
//
|
|
// Fill Cdb for Mode Sense (10) Command
|
|
//
|
|
Cdb[0] = EFI_SCSI_OP_MODE_SEN10;
|
|
//
|
|
// DBDField is in Cdb[1] bit3 of (bit7..0)
|
|
//
|
|
Cdb[1] = (UINT8) ((DBDField << 3) & 0x08);
|
|
//
|
|
// PageControl is in Cdb[2] bit7..6, PageCode is in Cdb[2] bit5..0
|
|
//
|
|
Cdb[2] = (UINT8) (((PageControl << 6) & 0xc0) | (PageCode & 0x3f));
|
|
Cdb[7] = (UINT8) (*DataLength >> 8);
|
|
Cdb[8] = (UINT8) (*DataLength);
|
|
|
|
CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TEN;
|
|
CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
|
|
CommandPacket.SenseDataLength = *SenseDataLength;
|
|
|
|
Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
|
|
|
|
*HostAdapterStatus = CommandPacket.HostAdapterStatus;
|
|
*TargetStatus = CommandPacket.TargetStatus;
|
|
*SenseDataLength = CommandPacket.SenseDataLength;
|
|
*DataLength = CommandPacket.InTransferLength;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Execute Request Sense SCSI command on a specific SCSI target.
|
|
|
|
Executes the Request Sense command on the SCSI target specified by ScsiIo.
|
|
If Timeout is zero, then this function waits indefinitely for the command to complete.
|
|
If Timeout is greater than zero, then the command is executed and will timeout after Timeout 100 ns units.
|
|
If ScsiIo is NULL, then ASSERT().
|
|
If SenseDataLength is NULL, then ASSERT().
|
|
If HostAdapterStatus is NULL, then ASSERT().
|
|
If TargetStatus is NULL, then ASSERT().
|
|
|
|
If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer
|
|
alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
|
|
gets returned.
|
|
|
|
@param[in] ScsiIo A pointer to SCSI IO protocol.
|
|
@param[in] Timeout The length of timeout period.
|
|
@param[in, out] SenseData A pointer to output sense data.
|
|
@param[in, out] SenseDataLength The length of output sense data.
|
|
@param[out] HostAdapterStatus The status of Host Adapter.
|
|
@param[out] TargetStatus The status of the target.
|
|
|
|
@retval EFI_SUCCESS Command is executed successfully.
|
|
@retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are
|
|
too many SCSI Command Packets already queued.
|
|
@retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
|
|
@retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by
|
|
the SCSI initiator(i.e., SCSI Host Controller)
|
|
@retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
|
|
@retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScsiRequestSenseCommand (
|
|
IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
|
|
IN UINT64 Timeout,
|
|
IN OUT VOID *SenseData, OPTIONAL
|
|
IN OUT UINT8 *SenseDataLength,
|
|
OUT UINT8 *HostAdapterStatus,
|
|
OUT UINT8 *TargetStatus
|
|
)
|
|
{
|
|
EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
|
|
EFI_STATUS Status;
|
|
UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIX];
|
|
|
|
ASSERT (SenseDataLength != NULL);
|
|
ASSERT (HostAdapterStatus != NULL);
|
|
ASSERT (TargetStatus != NULL);
|
|
ASSERT (ScsiIo != NULL);
|
|
|
|
ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
|
|
ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIX);
|
|
|
|
CommandPacket.Timeout = Timeout;
|
|
CommandPacket.InDataBuffer = SenseData;
|
|
CommandPacket.SenseData = NULL;
|
|
CommandPacket.InTransferLength= *SenseDataLength;
|
|
CommandPacket.Cdb = Cdb;
|
|
//
|
|
// Fill Cdb for Request Sense Command
|
|
//
|
|
Cdb[0] = EFI_SCSI_OP_REQUEST_SENSE;
|
|
Cdb[4] = (UINT8) (*SenseDataLength);
|
|
|
|
CommandPacket.CdbLength = (UINT8) EFI_SCSI_OP_LENGTH_SIX;
|
|
CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
|
|
CommandPacket.SenseDataLength = 0;
|
|
|
|
Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
|
|
|
|
*HostAdapterStatus = CommandPacket.HostAdapterStatus;
|
|
*TargetStatus = CommandPacket.TargetStatus;
|
|
*SenseDataLength = (UINT8) CommandPacket.InTransferLength;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Execute Read Capacity SCSI command on a specific SCSI target.
|
|
|
|
Executes the SCSI Read Capacity command on the SCSI target specified by ScsiIo.
|
|
If Timeout is zero, then this function waits indefinitely for the command to complete.
|
|
If Timeout is greater than zero, then the command is executed and will timeout after
|
|
Timeout 100 ns units. The Pmi parameter is used to construct the CDB for this SCSI command.
|
|
If ScsiIo is NULL, then ASSERT().
|
|
If SenseDataLength is NULL, then ASSERT().
|
|
If HostAdapterStatus is NULL, then ASSERT().
|
|
If TargetStatus is NULL, then ASSERT().
|
|
If DataLength is NULL, then ASSERT().
|
|
|
|
If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer
|
|
alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
|
|
gets returned.
|
|
|
|
If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer
|
|
alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
|
|
gets returned.
|
|
|
|
@param[in] ScsiIo A pointer to SCSI IO protocol.
|
|
@param[in] Timeout The length of timeout period.
|
|
@param[in, out] SenseData A pointer to output sense data.
|
|
@param[in, out] SenseDataLength The length of output sense data.
|
|
@param[out] HostAdapterStatus The status of Host Adapter.
|
|
@param[out] TargetStatus The status of the target.
|
|
@param[in, out] DataBuffer A pointer to a data buffer.
|
|
@param[in, out] DataLength The length of data buffer.
|
|
@param[in] Pmi Partial medium indicator.
|
|
|
|
@retval EFI_SUCCESS Command is executed successfully.
|
|
@retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire
|
|
DataBuffer could not be transferred. The actual
|
|
number of bytes transferred is returned in DataLength.
|
|
@retval EFI_NOT_READY The SCSI Request Packet could not be sent because
|
|
there are too many SCSI Command Packets already queued.
|
|
@retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
|
|
@retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
|
|
is not supported by the SCSI initiator(i.e., SCSI Host Controller)
|
|
@retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
|
|
@retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScsiReadCapacityCommand (
|
|
IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
|
|
IN UINT64 Timeout,
|
|
IN OUT VOID *SenseData, OPTIONAL
|
|
IN OUT UINT8 *SenseDataLength,
|
|
OUT UINT8 *HostAdapterStatus,
|
|
OUT UINT8 *TargetStatus,
|
|
IN OUT VOID *DataBuffer, OPTIONAL
|
|
IN OUT UINT32 *DataLength,
|
|
IN BOOLEAN Pmi
|
|
)
|
|
{
|
|
EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
|
|
EFI_STATUS Status;
|
|
UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN];
|
|
|
|
ASSERT (SenseDataLength != NULL);
|
|
ASSERT (HostAdapterStatus != NULL);
|
|
ASSERT (TargetStatus != NULL);
|
|
ASSERT (DataLength != NULL);
|
|
ASSERT (ScsiIo != NULL);
|
|
|
|
ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
|
|
ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TEN);
|
|
|
|
CommandPacket.Timeout = Timeout;
|
|
CommandPacket.InDataBuffer = DataBuffer;
|
|
CommandPacket.SenseData = SenseData;
|
|
CommandPacket.InTransferLength= *DataLength;
|
|
CommandPacket.Cdb = Cdb;
|
|
//
|
|
// Fill Cdb for Read Capacity Command
|
|
//
|
|
Cdb[0] = EFI_SCSI_OP_READ_CAPACITY;
|
|
if (!Pmi) {
|
|
//
|
|
// Partial medium indicator,if Pmi is FALSE, the Cdb.2 ~ Cdb.5 MUST BE ZERO.
|
|
//
|
|
ZeroMem ((Cdb + 2), 4);
|
|
} else {
|
|
Cdb[8] |= 0x01;
|
|
}
|
|
|
|
CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TEN;
|
|
CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
|
|
CommandPacket.SenseDataLength = *SenseDataLength;
|
|
|
|
Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
|
|
|
|
*HostAdapterStatus = CommandPacket.HostAdapterStatus;
|
|
*TargetStatus = CommandPacket.TargetStatus;
|
|
*SenseDataLength = CommandPacket.SenseDataLength;
|
|
*DataLength = CommandPacket.InTransferLength;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Execute Read Capacity SCSI 16 command on a specific SCSI target.
|
|
|
|
Executes the SCSI Read Capacity 16 command on the SCSI target specified by ScsiIo.
|
|
If Timeout is zero, then this function waits indefinitely for the command to complete.
|
|
If Timeout is greater than zero, then the command is executed and will timeout after
|
|
Timeout 100 ns units. The Pmi parameter is used to construct the CDB for this SCSI command.
|
|
If ScsiIo is NULL, then ASSERT().
|
|
If SenseDataLength is NULL, then ASSERT().
|
|
If HostAdapterStatus is NULL, then ASSERT().
|
|
If TargetStatus is NULL, then ASSERT().
|
|
If DataLength is NULL, then ASSERT().
|
|
|
|
If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer
|
|
alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
|
|
gets returned.
|
|
|
|
If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer
|
|
alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
|
|
gets returned.
|
|
|
|
@param[in] ScsiIo A pointer to SCSI IO protocol.
|
|
@param[in] Timeout The length of timeout period.
|
|
@param[in, out] SenseData A pointer to output sense data.
|
|
@param[in, out] SenseDataLength The length of output sense data.
|
|
@param[out] HostAdapterStatus The status of Host Adapter.
|
|
@param[out] TargetStatus The status of the target.
|
|
@param[in, out] DataBuffer A pointer to a data buffer.
|
|
@param[in, out] DataLength The length of data buffer.
|
|
@param[in] Pmi Partial medium indicator.
|
|
|
|
@retval EFI_SUCCESS Command is executed successfully.
|
|
@retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire
|
|
DataBuffer could not be transferred. The actual
|
|
number of bytes transferred is returned in DataLength.
|
|
@retval EFI_NOT_READY The SCSI Request Packet could not be sent because
|
|
there are too many SCSI Command Packets already queued.
|
|
@retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
|
|
@retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
|
|
is not supported by the SCSI initiator(i.e., SCSI Host Controller)
|
|
@retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
|
|
@retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScsiReadCapacity16Command (
|
|
IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
|
|
IN UINT64 Timeout,
|
|
IN OUT VOID *SenseData, OPTIONAL
|
|
IN OUT UINT8 *SenseDataLength,
|
|
OUT UINT8 *HostAdapterStatus,
|
|
OUT UINT8 *TargetStatus,
|
|
IN OUT VOID *DataBuffer, OPTIONAL
|
|
IN OUT UINT32 *DataLength,
|
|
IN BOOLEAN Pmi
|
|
)
|
|
{
|
|
EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
|
|
EFI_STATUS Status;
|
|
UINT8 Cdb[16];
|
|
|
|
ASSERT (SenseDataLength != NULL);
|
|
ASSERT (HostAdapterStatus != NULL);
|
|
ASSERT (TargetStatus != NULL);
|
|
ASSERT (DataLength != NULL);
|
|
ASSERT (ScsiIo != NULL);
|
|
|
|
ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
|
|
ZeroMem (Cdb, 16);
|
|
|
|
CommandPacket.Timeout = Timeout;
|
|
CommandPacket.InDataBuffer = DataBuffer;
|
|
CommandPacket.SenseData = SenseData;
|
|
CommandPacket.InTransferLength= *DataLength;
|
|
CommandPacket.Cdb = Cdb;
|
|
//
|
|
// Fill Cdb for Read Capacity Command
|
|
//
|
|
Cdb[0] = EFI_SCSI_OP_READ_CAPACITY16;
|
|
Cdb[1] = 0x10;
|
|
if (!Pmi) {
|
|
//
|
|
// Partial medium indicator,if Pmi is FALSE, the Cdb.2 ~ Cdb.9 MUST BE ZERO.
|
|
//
|
|
ZeroMem ((Cdb + 2), 8);
|
|
} else {
|
|
Cdb[14] |= 0x01;
|
|
}
|
|
|
|
Cdb[13] = 0x20;
|
|
CommandPacket.CdbLength = 16;
|
|
CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
|
|
CommandPacket.SenseDataLength = *SenseDataLength;
|
|
|
|
Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
|
|
|
|
*HostAdapterStatus = CommandPacket.HostAdapterStatus;
|
|
*TargetStatus = CommandPacket.TargetStatus;
|
|
*SenseDataLength = CommandPacket.SenseDataLength;
|
|
*DataLength = CommandPacket.InTransferLength;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Execute Read(10) SCSI command on a specific SCSI target.
|
|
|
|
Executes the SCSI Read(10) command on the SCSI target specified by ScsiIo.
|
|
If Timeout is zero, then this function waits indefinitely for the command to complete.
|
|
If Timeout is greater than zero, then the command is executed and will timeout
|
|
after Timeout 100 ns units. The StartLba and SectorSize parameters are used to
|
|
construct the CDB for this SCSI command.
|
|
If ScsiIo is NULL, then ASSERT().
|
|
If SenseDataLength is NULL, then ASSERT().
|
|
If HostAdapterStatus is NULL, then ASSERT().
|
|
If TargetStatus is NULL, then ASSERT().
|
|
If DataLength is NULL, then ASSERT().
|
|
|
|
If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer
|
|
alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
|
|
gets returned.
|
|
|
|
If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer
|
|
alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
|
|
gets returned.
|
|
|
|
@param[in] ScsiIo A pointer to SCSI IO protocol.
|
|
@param[in] Timeout The length of timeout period.
|
|
@param[in, out] SenseData A pointer to output sense data.
|
|
@param[in, out] SenseDataLength The length of output sense data.
|
|
@param[out] HostAdapterStatus The status of Host Adapter.
|
|
@param[out] TargetStatus The status of the target.
|
|
@param[in, out] DataBuffer Read 10 command data.
|
|
@param[in, out] DataLength The length of data buffer.
|
|
@param[in] StartLba The start address of LBA.
|
|
@param[in] SectorSize The number of contiguous logical blocks of data that shall be transferred.
|
|
|
|
@retval EFI_SUCCESS Command is executed successfully.
|
|
@retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could
|
|
not be transferred. The actual number of bytes transferred is returned in DataLength.
|
|
@retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many
|
|
SCSI Command Packets already queued.
|
|
@retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
|
|
@retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by
|
|
the SCSI initiator(i.e., SCSI Host Controller)
|
|
@retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
|
|
@retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScsiRead10Command (
|
|
IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
|
|
IN UINT64 Timeout,
|
|
IN OUT VOID *SenseData, OPTIONAL
|
|
IN OUT UINT8 *SenseDataLength,
|
|
OUT UINT8 *HostAdapterStatus,
|
|
OUT UINT8 *TargetStatus,
|
|
IN OUT VOID *DataBuffer, OPTIONAL
|
|
IN OUT UINT32 *DataLength,
|
|
IN UINT32 StartLba,
|
|
IN UINT32 SectorSize
|
|
)
|
|
{
|
|
EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
|
|
EFI_STATUS Status;
|
|
UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN];
|
|
|
|
ASSERT (SenseDataLength != NULL);
|
|
ASSERT (HostAdapterStatus != NULL);
|
|
ASSERT (TargetStatus != NULL);
|
|
ASSERT (DataLength != NULL);
|
|
ASSERT (ScsiIo != NULL);
|
|
|
|
ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
|
|
ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TEN);
|
|
|
|
CommandPacket.Timeout = Timeout;
|
|
CommandPacket.InDataBuffer = DataBuffer;
|
|
CommandPacket.SenseData = SenseData;
|
|
CommandPacket.InTransferLength= *DataLength;
|
|
CommandPacket.Cdb = Cdb;
|
|
//
|
|
// Fill Cdb for Read (10) Command
|
|
//
|
|
Cdb[0] = EFI_SCSI_OP_READ10;
|
|
WriteUnaligned32 ((UINT32 *)&Cdb[2], SwapBytes32 (StartLba));
|
|
WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 ((UINT16) SectorSize));
|
|
|
|
CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TEN;
|
|
CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
|
|
CommandPacket.SenseDataLength = *SenseDataLength;
|
|
|
|
Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
|
|
|
|
*HostAdapterStatus = CommandPacket.HostAdapterStatus;
|
|
*TargetStatus = CommandPacket.TargetStatus;
|
|
*SenseDataLength = CommandPacket.SenseDataLength;
|
|
*DataLength = CommandPacket.InTransferLength;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Execute Write(10) SCSI command on a specific SCSI target.
|
|
|
|
Executes the SCSI Write(10) command on the SCSI target specified by ScsiIo.
|
|
If Timeout is zero, then this function waits indefinitely for the command to complete.
|
|
If Timeout is greater than zero, then the command is executed and will timeout after
|
|
Timeout 100 ns units. The StartLba and SectorSize parameters are used to construct
|
|
the CDB for this SCSI command.
|
|
If ScsiIo is NULL, then ASSERT().
|
|
If SenseDataLength is NULL, then ASSERT().
|
|
If HostAdapterStatus is NULL, then ASSERT().
|
|
If TargetStatus is NULL, then ASSERT().
|
|
If DataLength is NULL, then ASSERT().
|
|
|
|
If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer
|
|
alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
|
|
gets returned.
|
|
|
|
If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer
|
|
alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
|
|
gets returned.
|
|
|
|
@param[in] ScsiIo SCSI IO Protocol to use
|
|
@param[in] Timeout The length of timeout period.
|
|
@param[in, out] SenseData A pointer to output sense data.
|
|
@param[in, out] SenseDataLength The length of output sense data.
|
|
@param[out] HostAdapterStatus The status of Host Adapter.
|
|
@param[out] TargetStatus The status of the target.
|
|
@param[in, out] DataBuffer A pointer to a data buffer.
|
|
@param[in, out] DataLength The length of data buffer.
|
|
@param[in] StartLba The start address of LBA.
|
|
@param[in] SectorSize The number of contiguous logical blocks of data that shall be transferred.
|
|
|
|
@retval EFI_SUCCESS Command is executed successfully.
|
|
@retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could
|
|
not be transferred. The actual number of bytes transferred is returned in DataLength.
|
|
@retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many
|
|
SCSI Command Packets already queued.
|
|
@retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
|
|
@retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by
|
|
the SCSI initiator(i.e., SCSI Host Controller)
|
|
@retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
|
|
@retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScsiWrite10Command (
|
|
IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
|
|
IN UINT64 Timeout,
|
|
IN OUT VOID *SenseData, OPTIONAL
|
|
IN OUT UINT8 *SenseDataLength,
|
|
OUT UINT8 *HostAdapterStatus,
|
|
OUT UINT8 *TargetStatus,
|
|
IN OUT VOID *DataBuffer, OPTIONAL
|
|
IN OUT UINT32 *DataLength,
|
|
IN UINT32 StartLba,
|
|
IN UINT32 SectorSize
|
|
)
|
|
{
|
|
EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
|
|
EFI_STATUS Status;
|
|
UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN];
|
|
|
|
ASSERT (SenseDataLength != NULL);
|
|
ASSERT (HostAdapterStatus != NULL);
|
|
ASSERT (TargetStatus != NULL);
|
|
ASSERT (DataLength != NULL);
|
|
ASSERT (ScsiIo != NULL);
|
|
|
|
ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
|
|
ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TEN);
|
|
|
|
CommandPacket.Timeout = Timeout;
|
|
CommandPacket.OutDataBuffer = DataBuffer;
|
|
CommandPacket.SenseData = SenseData;
|
|
CommandPacket.OutTransferLength= *DataLength;
|
|
CommandPacket.Cdb = Cdb;
|
|
//
|
|
// Fill Cdb for Write (10) Command
|
|
//
|
|
Cdb[0] = EFI_SCSI_OP_WRITE10;
|
|
WriteUnaligned32 ((UINT32 *)&Cdb[2], SwapBytes32 (StartLba));
|
|
WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 ((UINT16) SectorSize));
|
|
|
|
CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TEN;
|
|
CommandPacket.DataDirection = EFI_SCSI_DATA_OUT;
|
|
CommandPacket.SenseDataLength = *SenseDataLength;
|
|
|
|
Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
|
|
|
|
*HostAdapterStatus = CommandPacket.HostAdapterStatus;
|
|
*TargetStatus = CommandPacket.TargetStatus;
|
|
*SenseDataLength = CommandPacket.SenseDataLength;
|
|
*DataLength = CommandPacket.OutTransferLength;
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Execute Read(16) SCSI command on a specific SCSI target.
|
|
|
|
Executes the SCSI Read(16) command on the SCSI target specified by ScsiIo.
|
|
If Timeout is zero, then this function waits indefinitely for the command to complete.
|
|
If Timeout is greater than zero, then the command is executed and will timeout
|
|
after Timeout 100 ns units. The StartLba and SectorSize parameters are used to
|
|
construct the CDB for this SCSI command.
|
|
If ScsiIo is NULL, then ASSERT().
|
|
If SenseDataLength is NULL, then ASSERT().
|
|
If HostAdapterStatus is NULL, then ASSERT().
|
|
If TargetStatus is NULL, then ASSERT().
|
|
If DataLength is NULL, then ASSERT().
|
|
|
|
If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer
|
|
alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
|
|
gets returned.
|
|
|
|
If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer
|
|
alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
|
|
gets returned.
|
|
|
|
@param[in] ScsiIo A pointer to SCSI IO protocol.
|
|
@param[in] Timeout The length of timeout period.
|
|
@param[in, out] SenseData A pointer to output sense data.
|
|
@param[in, out] SenseDataLength The length of output sense data.
|
|
@param[out] HostAdapterStatus The status of Host Adapter.
|
|
@param[out] TargetStatus The status of the target.
|
|
@param[in, out] DataBuffer Read 16 command data.
|
|
@param[in, out] DataLength The length of data buffer.
|
|
@param[in] StartLba The start address of LBA.
|
|
@param[in] SectorSize The number of contiguous logical blocks of data that shall be transferred.
|
|
|
|
@retval EFI_SUCCESS Command is executed successfully.
|
|
@retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could
|
|
not be transferred. The actual number of bytes transferred is returned in DataLength.
|
|
@retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many
|
|
SCSI Command Packets already queued.
|
|
@retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
|
|
@retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by
|
|
the SCSI initiator(i.e., SCSI Host Controller)
|
|
@retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
|
|
@retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScsiRead16Command (
|
|
IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
|
|
IN UINT64 Timeout,
|
|
IN OUT VOID *SenseData, OPTIONAL
|
|
IN OUT UINT8 *SenseDataLength,
|
|
OUT UINT8 *HostAdapterStatus,
|
|
OUT UINT8 *TargetStatus,
|
|
IN OUT VOID *DataBuffer, OPTIONAL
|
|
IN OUT UINT32 *DataLength,
|
|
IN UINT64 StartLba,
|
|
IN UINT32 SectorSize
|
|
)
|
|
{
|
|
EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
|
|
EFI_STATUS Status;
|
|
UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIXTEEN];
|
|
|
|
ASSERT (SenseDataLength != NULL);
|
|
ASSERT (HostAdapterStatus != NULL);
|
|
ASSERT (TargetStatus != NULL);
|
|
ASSERT (DataLength != NULL);
|
|
ASSERT (ScsiIo != NULL);
|
|
|
|
ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
|
|
ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIXTEEN);
|
|
|
|
CommandPacket.Timeout = Timeout;
|
|
CommandPacket.InDataBuffer = DataBuffer;
|
|
CommandPacket.SenseData = SenseData;
|
|
CommandPacket.InTransferLength = *DataLength;
|
|
CommandPacket.Cdb = Cdb;
|
|
//
|
|
// Fill Cdb for Read (16) Command
|
|
//
|
|
Cdb[0] = EFI_SCSI_OP_READ16;
|
|
WriteUnaligned64 ((UINT64 *)&Cdb[2], SwapBytes64 (StartLba));
|
|
WriteUnaligned32 ((UINT32 *)&Cdb[10], SwapBytes32 (SectorSize));
|
|
|
|
CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_SIXTEEN;
|
|
CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
|
|
CommandPacket.SenseDataLength = *SenseDataLength;
|
|
|
|
Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
|
|
|
|
*HostAdapterStatus = CommandPacket.HostAdapterStatus;
|
|
*TargetStatus = CommandPacket.TargetStatus;
|
|
*SenseDataLength = CommandPacket.SenseDataLength;
|
|
*DataLength = CommandPacket.InTransferLength;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Execute Write(16) SCSI command on a specific SCSI target.
|
|
|
|
Executes the SCSI Write(16) command on the SCSI target specified by ScsiIo.
|
|
If Timeout is zero, then this function waits indefinitely for the command to complete.
|
|
If Timeout is greater than zero, then the command is executed and will timeout after
|
|
Timeout 100 ns units. The StartLba and SectorSize parameters are used to construct
|
|
the CDB for this SCSI command.
|
|
If ScsiIo is NULL, then ASSERT().
|
|
If SenseDataLength is NULL, then ASSERT().
|
|
If HostAdapterStatus is NULL, then ASSERT().
|
|
If TargetStatus is NULL, then ASSERT().
|
|
If DataLength is NULL, then ASSERT().
|
|
|
|
If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer
|
|
alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
|
|
gets returned.
|
|
|
|
If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer
|
|
alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
|
|
gets returned.
|
|
|
|
@param[in] ScsiIo SCSI IO Protocol to use
|
|
@param[in] Timeout The length of timeout period.
|
|
@param[in, out] SenseData A pointer to output sense data.
|
|
@param[in, out] SenseDataLength The length of output sense data.
|
|
@param[out] HostAdapterStatus The status of Host Adapter.
|
|
@param[out] TargetStatus The status of the target.
|
|
@param[in, out] DataBuffer A pointer to a data buffer.
|
|
@param[in, out] DataLength The length of data buffer.
|
|
@param[in] StartLba The start address of LBA.
|
|
@param[in] SectorSize The number of contiguous logical blocks of data that shall be transferred.
|
|
|
|
@retval EFI_SUCCESS Command is executed successfully.
|
|
@retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could
|
|
not be transferred. The actual number of bytes transferred is returned in DataLength.
|
|
@retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many
|
|
SCSI Command Packets already queued.
|
|
@retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
|
|
@retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by
|
|
the SCSI initiator(i.e., SCSI Host Controller)
|
|
@retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
|
|
@retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScsiWrite16Command (
|
|
IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
|
|
IN UINT64 Timeout,
|
|
IN OUT VOID *SenseData, OPTIONAL
|
|
IN OUT UINT8 *SenseDataLength,
|
|
OUT UINT8 *HostAdapterStatus,
|
|
OUT UINT8 *TargetStatus,
|
|
IN OUT VOID *DataBuffer, OPTIONAL
|
|
IN OUT UINT32 *DataLength,
|
|
IN UINT64 StartLba,
|
|
IN UINT32 SectorSize
|
|
)
|
|
{
|
|
EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
|
|
EFI_STATUS Status;
|
|
UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIXTEEN];
|
|
|
|
ASSERT (SenseDataLength != NULL);
|
|
ASSERT (HostAdapterStatus != NULL);
|
|
ASSERT (TargetStatus != NULL);
|
|
ASSERT (DataLength != NULL);
|
|
ASSERT (ScsiIo != NULL);
|
|
|
|
ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
|
|
ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIXTEEN);
|
|
|
|
CommandPacket.Timeout = Timeout;
|
|
CommandPacket.OutDataBuffer = DataBuffer;
|
|
CommandPacket.SenseData = SenseData;
|
|
CommandPacket.OutTransferLength = *DataLength;
|
|
CommandPacket.Cdb = Cdb;
|
|
//
|
|
// Fill Cdb for Write (16) Command
|
|
//
|
|
Cdb[0] = EFI_SCSI_OP_WRITE16;
|
|
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;
|
|
}
|