| /** @file | |
| UEFI SCSI Library implementation | |
| Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR> | |
| 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. | |
| **/ | |
| #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; | |
| } |