/** @file\r
UEFI SCSI Library implementation\r
\r
- Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>\r
- This program and the accompanying materials \r
- are licensed and made available under the terms and conditions of the BSD License \r
- which accompanies this distribution. The full text of the license may be found at \r
- http://opensource.org/licenses/bsd-license.php. \r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+ Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
#include <Library/BaseMemoryLib.h>\r
#include <Library/MemoryAllocationLib.h>\r
#include <Library/UefiBootServicesTableLib.h>\r
- \r
+\r
#include <IndustryStandard/Scsi.h>\r
- \r
- \r
+\r
+\r
//\r
// Scsi Command Length\r
//\r
#define EFI_SCSI_OP_LENGTH_SIX 0x6\r
#define EFI_SCSI_OP_LENGTH_TEN 0xa\r
+#define EFI_SCSI_OP_LENGTH_TWELVE 0xc\r
#define EFI_SCSI_OP_LENGTH_SIXTEEN 0x10\r
\r
//\r
optional and may be NULL.\r
@param[in, out] SenseDataLength On input, a pointer to the length in bytes of\r
the SenseData buffer. On output, a pointer to\r
- the number of bytes written to the SenseData buffer. \r
+ the number of bytes written to the SenseData buffer.\r
@param[out] HostAdapterStatus The status of the SCSI Host Controller that produces\r
the SCSI bus containing the SCSI target specified by\r
ScsiIo when the SCSI Request Packet was executed.\r
by ScsiIo when the SCSI Request Packet was executed\r
on the SCSI Host Controller. See the EFI SCSI I/O\r
Protocol in the UEFI Specification for details on\r
- the possible return values. \r
+ the possible return values.\r
\r
@retval EFI_SUCCESS The command was executed successfully.\r
See HostAdapterStatus, TargetStatus, SenseDataLength,\r
If SenseDataLength is 0, then this parameter\r
is optional and may be NULL.\r
@param[in, out] SenseDataLength On input, the length in bytes of the SenseData buffer.\r
- On output, the number of bytes written to the SenseData buffer. \r
+ On output, the number of bytes written to the SenseData buffer.\r
@param[out] HostAdapterStatus The status of the SCSI Host Controller that\r
produces the SCSI bus containing the SCSI\r
target specified by ScsiIo when the SCSI\r
executed on the SCSI Host Controller.\r
See the EFI SCSI I/O Protocol in the UEFI\r
Specification for details on the possible\r
- return values. \r
+ return values.\r
@param[in, out] InquiryDataBuffer A pointer to inquiry data that was generated\r
by the execution of the SCSI Request Packet.\r
This buffer must be allocated by the caller.\r
If InquiryDataLength is 0, then this parameter\r
- is optional and may be NULL. \r
+ is optional and may be NULL.\r
@param[in, out] InquiryDataLength On input, a pointer to the length in bytes\r
of the InquiryDataBuffer buffer.\r
On output, a pointer to the number of bytes\r
If SenseDataLength is 0, then this parameter\r
is optional and may be NULL.\r
@param[in, out] SenseDataLength On input, the length in bytes of the SenseData buffer.\r
- On output, the number of bytes written to the SenseData buffer. \r
+ On output, the number of bytes written to the SenseData buffer.\r
@param[out] HostAdapterStatus The status of the SCSI Host Controller that\r
produces the SCSI bus containing the SCSI\r
target specified by ScsiIo when the SCSI\r
executed on the SCSI Host Controller.\r
See the EFI SCSI I/O Protocol in the UEFI\r
Specification for details on the possible\r
- return values. \r
+ return values.\r
@param[in, out] InquiryDataBuffer A pointer to inquiry data that was generated\r
by the execution of the SCSI Request Packet.\r
This buffer must be allocated by the caller.\r
If InquiryDataLength is 0, then this parameter\r
- is optional and may be NULL. \r
+ is optional and may be NULL.\r
@param[in, out] InquiryDataLength On input, a pointer to the length in bytes\r
of the InquiryDataBuffer buffer.\r
On output, a pointer to the number of bytes\r
@param[in] EnableVitalProductData If TRUE, then the supported vital product\r
data is returned in InquiryDataBuffer.\r
If FALSE, then the standard inquiry data is\r
- returned in InquiryDataBuffer. \r
+ returned in InquiryDataBuffer.\r
\r
@retval EFI_SUCCESS The command was executed successfully. See HostAdapterStatus,\r
TargetStatus, SenseDataLength, and SenseData in that order\r
If SenseDataLength is 0, then this parameter\r
is optional and may be NULL.\r
@param[in, out] SenseDataLength On input, the length in bytes of the SenseData buffer.\r
- On output, the number of bytes written to the SenseData buffer. \r
+ On output, the number of bytes written to the SenseData buffer.\r
@param[out] HostAdapterStatus The status of the SCSI Host Controller that\r
produces the SCSI bus containing the SCSI target\r
specified by ScsiIo when the SCSI Request Packet\r
execution of the SCSI Request Packet. This\r
buffer must be allocated by the caller. If\r
DataLength is 0, then this parameter is optional\r
- and may be NULL. \r
+ and may be NULL.\r
@param[in, out] DataLength On input, a pointer to the length in bytes of\r
the DataBuffer buffer. On output, a pointer\r
to the number of bytes written to the DataBuffer\r
- buffer. \r
+ buffer.\r
@param[in] DBDField Specifies the DBD field of the CDB for this SCSI Command.\r
- @param[in] PageControl Specifies the PC field of the CDB for this SCSI Command. \r
- @param[in] PageCode Specifies the Page Control field of the CDB for this SCSI Command. \r
+ @param[in] PageControl Specifies the PC field of the CDB for this SCSI Command.\r
+ @param[in] PageCode Specifies the Page Control field of the CDB for this SCSI Command.\r
\r
@retval EFI_SUCCESS The command was executed successfully.\r
See HostAdapterStatus, TargetStatus, SenseDataLength,\r
ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));\r
ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TEN);\r
\r
- CommandPacket.Timeout = Timeout;\r
- CommandPacket.OutDataBuffer = DataBuffer;\r
- CommandPacket.SenseData = SenseData;\r
- CommandPacket.OutTransferLength= *DataLength;\r
- CommandPacket.Cdb = Cdb;\r
+ CommandPacket.Timeout = Timeout;\r
+ CommandPacket.OutDataBuffer = DataBuffer;\r
+ CommandPacket.SenseData = SenseData;\r
+ CommandPacket.OutTransferLength = *DataLength;\r
+ CommandPacket.Cdb = Cdb;\r
//\r
// Fill Cdb for Write (10) Command\r
//\r
Cdb[0] = EFI_SCSI_OP_WRITE10;\r
+ Cdb[1] = EFI_SCSI_BLOCK_FUA;\r
WriteUnaligned32 ((UINT32 *)&Cdb[2], SwapBytes32 (StartLba));\r
WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 ((UINT16) SectorSize));\r
\r
// Fill Cdb for Write (16) Command\r
//\r
Cdb[0] = EFI_SCSI_OP_WRITE16;\r
+ Cdb[1] = EFI_SCSI_BLOCK_FUA;\r
WriteUnaligned64 ((UINT64 *)&Cdb[2], SwapBytes64 (StartLba));\r
WriteUnaligned32 ((UINT32 *)&Cdb[10], SwapBytes32 (SectorSize));\r
\r
}\r
\r
\r
+/**\r
+ Execute Security Protocol In SCSI command on a specific SCSI target.\r
+\r
+ Executes the SCSI Security Protocol In command on the SCSI target specified by ScsiIo.\r
+ If Timeout is zero, then this function waits indefinitely for the command to complete.\r
+ If Timeout is greater than zero, then the command is executed and will timeout after\r
+ Timeout 100 ns units.\r
+ If ScsiIo is NULL, then ASSERT().\r
+ If SenseDataLength is NULL, then ASSERT().\r
+ If HostAdapterStatus is NULL, then ASSERT().\r
+ If TargetStatus is NULL, then ASSERT().\r
+ If TransferLength is NULL, then ASSERT().\r
+\r
+ If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer\r
+ alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER\r
+ gets returned.\r
+\r
+ If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer\r
+ alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER\r
+ gets returned.\r
+\r
+ @param[in] ScsiIo SCSI IO Protocol to use.\r
+ @param[in] Timeout The length of timeout period.\r
+ @param[in, out] SenseData A pointer to output sense data.\r
+ @param[in, out] SenseDataLength The length of output sense data.\r
+ @param[out] HostAdapterStatus The status of Host Adapter.\r
+ @param[out] TargetStatus The status of the target.\r
+ @param[in] SecurityProtocol The Security Protocol to use.\r
+ @param[in] SecurityProtocolSpecific The Security Protocol Specific data.\r
+ @param[in] Inc512 If TRUE, 512 increment (INC_512) bit will be set for the\r
+ SECURITY PROTOCOL IN command.\r
+ @param[in] DataLength The size in bytes of the data buffer.\r
+ @param[in, out] DataBuffer A pointer to a data buffer.\r
+ @param[out] TransferLength A pointer to a buffer to store the size in\r
+ bytes of the data written to the data buffer.\r
+\r
+ @retval EFI_SUCCESS Command is executed successfully.\r
+ @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could\r
+ not be transferred. The actual number of bytes transferred is returned in TransferLength.\r
+ @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many\r
+ SCSI Command Packets already queued.\r
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.\r
+ @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by\r
+ the SCSI initiator(i.e., SCSI Host Controller)\r
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.\r
+ @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ScsiSecurityProtocolInCommand (\r
+ IN EFI_SCSI_IO_PROTOCOL *ScsiIo,\r
+ IN UINT64 Timeout,\r
+ IN OUT VOID *SenseData, OPTIONAL\r
+ IN OUT UINT8 *SenseDataLength,\r
+ OUT UINT8 *HostAdapterStatus,\r
+ OUT UINT8 *TargetStatus,\r
+ IN UINT8 SecurityProtocol,\r
+ IN UINT16 SecurityProtocolSpecific,\r
+ IN BOOLEAN Inc512,\r
+ IN UINTN DataLength,\r
+ IN OUT VOID *DataBuffer, OPTIONAL\r
+ OUT UINTN *TransferLength\r
+ )\r
+{\r
+ EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;\r
+ EFI_STATUS Status;\r
+ UINT8 Cdb[EFI_SCSI_OP_LENGTH_TWELVE];\r
+\r
+ ASSERT (SenseDataLength != NULL);\r
+ ASSERT (HostAdapterStatus != NULL);\r
+ ASSERT (TargetStatus != NULL);\r
+ ASSERT (ScsiIo != NULL);\r
+ ASSERT (TransferLength != NULL);\r
+ ASSERT (DataLength <= MAX_UINT32);\r
+\r
+ ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));\r
+ ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TWELVE);\r
+\r
+ CommandPacket.Timeout = Timeout;\r
+ CommandPacket.InDataBuffer = DataBuffer;\r
+ CommandPacket.SenseData = SenseData;\r
+ CommandPacket.InTransferLength = (UINT32) DataLength;\r
+ CommandPacket.Cdb = Cdb;\r
+ //\r
+ // Fill Cdb for Security Protocol In Command\r
+ //\r
+ Cdb[0] = EFI_SCSI_OP_SECURITY_PROTOCOL_IN;\r
+ Cdb[1] = SecurityProtocol;\r
+ WriteUnaligned16 ((UINT16 *)&Cdb[2], SwapBytes16 (SecurityProtocolSpecific));\r
+\r
+ if (Inc512) {\r
+ if (DataLength % 512 != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ Cdb[4] = BIT7;\r
+ WriteUnaligned32 ((UINT32 *)&Cdb[6], SwapBytes32 ((UINT32) DataLength / 512));\r
+ } else {\r
+ WriteUnaligned32 ((UINT32 *)&Cdb[6], SwapBytes32 ((UINT32) DataLength));\r
+ }\r
+\r
+ CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TWELVE;\r
+ CommandPacket.DataDirection = EFI_SCSI_DATA_IN;\r
+ CommandPacket.SenseDataLength = *SenseDataLength;\r
+\r
+ Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);\r
+\r
+ *HostAdapterStatus = CommandPacket.HostAdapterStatus;\r
+ *TargetStatus = CommandPacket.TargetStatus;\r
+ *SenseDataLength = CommandPacket.SenseDataLength;\r
+ *TransferLength = (UINTN) CommandPacket.InTransferLength;\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Execute Security Protocol Out SCSI command on a specific SCSI target.\r
+\r
+ Executes the SCSI Security Protocol Out command on the SCSI target specified by ScsiIo.\r
+ If Timeout is zero, then this function waits indefinitely for the command to complete.\r
+ If Timeout is greater than zero, then the command is executed and will timeout after\r
+ Timeout 100 ns units.\r
+ If ScsiIo is NULL, then ASSERT().\r
+ If SenseDataLength is NULL, then ASSERT().\r
+ If HostAdapterStatus is NULL, then ASSERT().\r
+ If TargetStatus is NULL, then ASSERT().\r
+\r
+ If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer\r
+ alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER\r
+ gets returned.\r
+\r
+ If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer\r
+ alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER\r
+ gets returned.\r
+\r
+ @param[in] ScsiIo SCSI IO Protocol to use.\r
+ @param[in] Timeout The length of timeout period.\r
+ @param[in, out] SenseData A pointer to output sense data.\r
+ @param[in, out] SenseDataLength The length of output sense data.\r
+ @param[out] HostAdapterStatus The status of Host Adapter.\r
+ @param[out] TargetStatus The status of the target.\r
+ @param[in] SecurityProtocol The Security Protocol to use.\r
+ @param[in] SecurityProtocolSpecific The Security Protocol Specific data.\r
+ @param[in] Inc512 If TRUE, 512 increment (INC_512) bit will be set for the\r
+ SECURITY PROTOCOL OUT command.\r
+ @param[in] DataLength The size in bytes of the transfer data.\r
+ @param[in, out] DataBuffer A pointer to a data buffer.\r
+\r
+ @retval EFI_SUCCESS Command is executed successfully.\r
+ @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could\r
+ not be transferred. The actual number of bytes transferred is returned in DataLength.\r
+ @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many\r
+ SCSI Command Packets already queued.\r
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.\r
+ @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by\r
+ the SCSI initiator(i.e., SCSI Host Controller)\r
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.\r
+ @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ScsiSecurityProtocolOutCommand (\r
+ IN EFI_SCSI_IO_PROTOCOL *ScsiIo,\r
+ IN UINT64 Timeout,\r
+ IN OUT VOID *SenseData, OPTIONAL\r
+ IN OUT UINT8 *SenseDataLength,\r
+ OUT UINT8 *HostAdapterStatus,\r
+ OUT UINT8 *TargetStatus,\r
+ IN UINT8 SecurityProtocol,\r
+ IN UINT16 SecurityProtocolSpecific,\r
+ IN BOOLEAN Inc512,\r
+ IN UINTN DataLength,\r
+ IN OUT VOID *DataBuffer OPTIONAL\r
+ )\r
+{\r
+ EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;\r
+ EFI_STATUS Status;\r
+ UINT8 Cdb[EFI_SCSI_OP_LENGTH_TWELVE];\r
+\r
+ ASSERT (SenseDataLength != NULL);\r
+ ASSERT (HostAdapterStatus != NULL);\r
+ ASSERT (TargetStatus != NULL);\r
+ ASSERT (ScsiIo != NULL);\r
+ ASSERT (DataLength <= MAX_UINT32);\r
+\r
+ ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));\r
+ ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TWELVE);\r
+\r
+ CommandPacket.Timeout = Timeout;\r
+ CommandPacket.OutDataBuffer = DataBuffer;\r
+ CommandPacket.SenseData = SenseData;\r
+ CommandPacket.OutTransferLength = (UINT32) DataLength;\r
+ CommandPacket.Cdb = Cdb;\r
+ //\r
+ // Fill Cdb for Security Protocol Out Command\r
+ //\r
+ Cdb[0] = EFI_SCSI_OP_SECURITY_PROTOCOL_OUT;\r
+ Cdb[1] = SecurityProtocol;\r
+ WriteUnaligned16 ((UINT16 *)&Cdb[2], SwapBytes16 (SecurityProtocolSpecific));\r
+\r
+ if (Inc512) {\r
+ if (DataLength % 512 != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ Cdb[4] = BIT7;\r
+ WriteUnaligned32 ((UINT32 *)&Cdb[6], SwapBytes32 ((UINT32) DataLength / 512));\r
+ } else {\r
+ WriteUnaligned32 ((UINT32 *)&Cdb[6], SwapBytes32 ((UINT32) DataLength));\r
+ }\r
+\r
+ CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TWELVE;\r
+ CommandPacket.DataDirection = EFI_SCSI_DATA_OUT;\r
+ CommandPacket.SenseDataLength = *SenseDataLength;\r
+\r
+ Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);\r
+\r
+ *HostAdapterStatus = CommandPacket.HostAdapterStatus;\r
+ *TargetStatus = CommandPacket.TargetStatus;\r
+ *SenseDataLength = CommandPacket.SenseDataLength;\r
+\r
+ return Status;\r
+}\r
+\r
+\r
/**\r
Internal helper notify function in which update the result of the\r
non-blocking SCSI Read/Write commands and signal caller event.\r
//\r
Status = gBS->CreateEvent (\r
EVT_NOTIFY_SIGNAL,\r
- TPL_CALLBACK,\r
+ TPL_NOTIFY,\r
ScsiLibNotify,\r
Context,\r
&SelfEvent\r
//\r
Status = gBS->CreateEvent (\r
EVT_NOTIFY_SIGNAL,\r
- TPL_CALLBACK,\r
+ TPL_NOTIFY,\r
ScsiLibNotify,\r
Context,\r
&SelfEvent\r
//\r
Status = gBS->CreateEvent (\r
EVT_NOTIFY_SIGNAL,\r
- TPL_CALLBACK,\r
+ TPL_NOTIFY,\r
ScsiLibNotify,\r
Context,\r
&SelfEvent\r
//\r
Status = gBS->CreateEvent (\r
EVT_NOTIFY_SIGNAL,\r
- TPL_CALLBACK,\r
+ TPL_NOTIFY,\r
ScsiLibNotify,\r
Context,\r
&SelfEvent\r