]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdePkg/Library/UefiScsiLib/UefiScsiLib.c
MdePkg: Implement SCSI commands for Security Protocol In/Out
[mirror_edk2.git] / MdePkg / Library / UefiScsiLib / UefiScsiLib.c
index c7491d1436908f88160302721772b59e16440a79..13a2a1912cbe8a23f5d018965d34db627902c162 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   UEFI SCSI Library implementation\r
 \r
-  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
   SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
@@ -23,6 +23,7 @@
   //\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
@@ -1280,6 +1281,232 @@ ScsiWrite16Command (
 }\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