This patch implements the EFI_STORAGE_SECURITY_COMMAND_PROTOCOL in the
ScsiDiskDxe driver.

Support is currently limited to the RPMB Well-known LUN for UFS devices.

Cc: Jiewen Yao <jiewen....@intel.com>
Cc: Jian J Wang <jian.j.w...@intel.com>
Cc: Liming Gao <liming....@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Christopher J Zurcher <christopher.j.zurc...@intel.com>
---
 MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf |   3 +-
 MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h      | 171 +++++++-
 MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c        |   5 +-
 MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ComponentName.c |  14 +-
 MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c      | 510 +++++++++++++++++++++-
 MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c |  19 +-
 6 files changed, 698 insertions(+), 24 deletions(-)

diff --git a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf 
b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf
index 14010802a8..2122aa4b01 100644
--- a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf
+++ b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf
@@ -3,7 +3,7 @@
 #  It detects the SCSI disk media and installs Block I/O and Block I/O2 
Protocol on
 #  the device handle.
 #
-#  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#  Copyright (c) 2006 - 2019, 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
@@ -58,6 +58,7 @@
   gEfiBlockIoProtocolGuid                       ## BY_START
   gEfiBlockIo2ProtocolGuid                      ## BY_START
   gEfiEraseBlockProtocolGuid                    ## BY_START
+  gEfiStorageSecurityCommandProtocolGuid        ## BY_START
   gEfiScsiIoProtocolGuid                        ## TO_START
   gEfiScsiPassThruProtocolGuid                  ## TO_START
   gEfiExtScsiPassThruProtocolGuid               ## TO_START
diff --git a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h 
b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h
index bb6232676d..4731258018 100644
--- a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h
+++ b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h
@@ -1,7 +1,7 @@
 /** @file
   Header file for SCSI Disk Driver.
 
-Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2004 - 2019, 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
@@ -28,6 +28,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER 
EXPRESS OR IMPLIED.
 #include <Protocol/ScsiPassThruExt.h>
 #include <Protocol/ScsiPassThru.h>
 #include <Protocol/DiskInfo.h>
+#include <Protocol/StorageSecurityCommand.h>
 
 
 #include <Library/DebugLib.h>
@@ -44,6 +45,10 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER 
EXPRESS OR IMPLIED.
 
 #define IS_DEVICE_FIXED(a)        (a)->FixedDevice ? 1 : 0
 
+#define IS_ALIGNED(addr, size)    (((UINTN) (addr) & (size - 1)) == 0)
+
+#define UFS_WLUN_RPMB 0xC4
+
 typedef struct {
   UINT32                    MaxLbaCnt;
   UINT32                    MaxBlkDespCnt;
@@ -57,6 +62,8 @@ typedef struct {
 
   EFI_HANDLE                Handle;
 
+  EFI_STORAGE_SECURITY_COMMAND_PROTOCOL   StorageSecurity;
+
   EFI_BLOCK_IO_PROTOCOL     BlkIo;
   EFI_BLOCK_IO2_PROTOCOL    BlkIo2;
   EFI_BLOCK_IO_MEDIA        BlkIoMedia;
@@ -101,6 +108,7 @@ typedef struct {
 #define SCSI_DISK_DEV_FROM_BLKIO(a)  CR (a, SCSI_DISK_DEV, BlkIo, 
SCSI_DISK_DEV_SIGNATURE)
 #define SCSI_DISK_DEV_FROM_BLKIO2(a)  CR (a, SCSI_DISK_DEV, BlkIo2, 
SCSI_DISK_DEV_SIGNATURE)
 #define SCSI_DISK_DEV_FROM_ERASEBLK(a)  CR (a, SCSI_DISK_DEV, EraseBlock, 
SCSI_DISK_DEV_SIGNATURE)
+#define SCSI_DISK_DEV_FROM_STORSEC(a)  CR (a, SCSI_DISK_DEV, StorageSecurity, 
SCSI_DISK_DEV_SIGNATURE)
 
 #define SCSI_DISK_DEV_FROM_DISKINFO(a) CR (a, SCSI_DISK_DEV, DiskInfo, 
SCSI_DISK_DEV_SIGNATURE)
 
@@ -644,6 +652,151 @@ ScsiDiskEraseBlocks (
   );
 
 
+/**
+  Send a security protocol command to a device that receives data and/or the 
result
+  of one or more commands sent by SendData.
+
+  The ReceiveData function sends a security protocol command to the given 
MediaId.
+  The security protocol command sent is defined by SecurityProtocolId and 
contains
+  the security protocol specific data SecurityProtocolSpecificData. The 
function
+  returns the data from the security protocol command in PayloadBuffer.
+
+  For devices supporting the SCSI command set, the security protocol command 
is sent
+  using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+  If PayloadBufferSize is too small to store the available data from the 
security
+  protocol command, the function shall copy PayloadBufferSize bytes into the
+  PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+  If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is 
non-zero,
+  the function shall return EFI_INVALID_PARAMETER.
+
+  If the given MediaId does not support security protocol commands, the 
function shall
+  return EFI_UNSUPPORTED. If there is no media in the device, the function 
returns
+  EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the 
device,
+  the function returns EFI_MEDIA_CHANGED.
+
+  If the security protocol fails to complete within the Timeout period, the 
function
+  shall return EFI_TIMEOUT.
+
+  If the security protocol command completes without an error, the function 
shall
+  return EFI_SUCCESS. If the security protocol command completes with an 
error, the
+  function shall return EFI_DEVICE_ERROR.
+
+  @param  This                         Indicates a pointer to the calling 
context.
+  @param  MediaId                      ID of the medium to receive data from.
+  @param  Timeout                      The timeout, in 100ns units, to use for 
the execution
+                                       of the security protocol command. A 
Timeout value of 0
+                                       means that this function will wait 
indefinitely for the
+                                       security protocol command to execute. 
If Timeout is greater
+                                       than zero, then this function will 
return EFI_TIMEOUT if the
+                                       time required to execute the receive 
data command is greater than Timeout.
+  @param  SecurityProtocolId           The value of the "Security Protocol" 
parameter of
+                                       the security protocol command to be 
sent.
+  @param  SecurityProtocolSpecificData The value of the "Security Protocol 
Specific" parameter
+                                       of the security protocol command to be 
sent.
+  @param  PayloadBufferSize            Size in bytes of the payload data 
buffer.
+  @param  PayloadBuffer                A pointer to a destination buffer to 
store the security
+                                       protocol command specific payload data 
for the security
+                                       protocol command. The caller is 
responsible for having
+                                       either implicit or explicit ownership 
of the buffer.
+  @param  PayloadTransferSize          A pointer to a buffer to store the size 
in bytes of the
+                                       data written to the payload data buffer.
+
+  @retval EFI_SUCCESS                  The security protocol command completed 
successfully.
+  @retval EFI_WARN_BUFFER_TOO_SMALL    The PayloadBufferSize was too small to 
store the available
+                                       data from the device. The PayloadBuffer 
contains the truncated data.
+  @retval EFI_UNSUPPORTED              The given MediaId does not support 
security protocol commands.
+  @retval EFI_DEVICE_ERROR             The security protocol command completed 
with an error.
+  @retval EFI_NO_MEDIA                 There is no media in the device.
+  @retval EFI_MEDIA_CHANGED            The MediaId is not for the current 
media.
+  @retval EFI_INVALID_PARAMETER        The PayloadBuffer or 
PayloadTransferSize is NULL and
+                                       PayloadBufferSize is non-zero.
+  @retval EFI_TIMEOUT                  A timeout occurred while waiting for 
the security
+                                       protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskReceiveData (
+  IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL    *This,
+  IN UINT32                                   MediaId   OPTIONAL,
+  IN UINT64                                   Timeout,
+  IN UINT8                                    SecurityProtocolId,
+  IN UINT16                                   SecurityProtocolSpecificData,
+  IN UINTN                                    PayloadBufferSize,
+  OUT VOID                                    *PayloadBuffer,
+  OUT UINTN                                   *PayloadTransferSize
+  );
+
+/**
+  Send a security protocol command to a device.
+
+  The SendData function sends a security protocol command containing the 
payload
+  PayloadBuffer to the given MediaId. The security protocol command sent is
+  defined by SecurityProtocolId and contains the security protocol specific 
data
+  SecurityProtocolSpecificData. If the underlying protocol command requires a
+  specific padding for the command payload, the SendData function shall add 
padding
+  bytes to the command payload to satisfy the padding requirements.
+
+  For devices supporting the SCSI command set, the security protocol command 
is sent
+  using the SECURITY PROTOCOL OUT command defined in SPC-4.
+
+  If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function 
shall
+  return EFI_INVALID_PARAMETER.
+
+  If the given MediaId does not support security protocol commands, the 
function
+  shall return EFI_UNSUPPORTED. If there is no media in the device, the 
function
+  returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in 
the
+  device, the function returns EFI_MEDIA_CHANGED.
+
+  If the security protocol fails to complete within the Timeout period, the 
function
+  shall return EFI_TIMEOUT.
+
+  If the security protocol command completes without an error, the function 
shall return
+  EFI_SUCCESS. If the security protocol command completes with an error, the 
function
+  shall return EFI_DEVICE_ERROR.
+
+  @param  This                         Indicates a pointer to the calling 
context.
+  @param  MediaId                      ID of the medium to receive data from.
+  @param  Timeout                      The timeout, in 100ns units, to use for 
the execution
+                                       of the security protocol command. A 
Timeout value of 0
+                                       means that this function will wait 
indefinitely for the
+                                       security protocol command to execute. 
If Timeout is greater
+                                       than zero, then this function will 
return EFI_TIMEOUT if the
+                                       time required to execute the receive 
data command is greater than Timeout.
+  @param  SecurityProtocolId           The value of the "Security Protocol" 
parameter of
+                                       the security protocol command to be 
sent.
+  @param  SecurityProtocolSpecificData The value of the "Security Protocol 
Specific" parameter
+                                       of the security protocol command to be 
sent.
+  @param  PayloadBufferSize            Size in bytes of the payload data 
buffer.
+  @param  PayloadBuffer                A pointer to a destination buffer to 
store the security
+                                       protocol command specific payload data 
for the security
+                                       protocol command.
+
+  @retval EFI_SUCCESS                  The security protocol command completed 
successfully.
+  @retval EFI_UNSUPPORTED              The given MediaId does not support 
security protocol commands.
+  @retval EFI_DEVICE_ERROR             The security protocol command completed 
with an error.
+  @retval EFI_NO_MEDIA                 There is no media in the device.
+  @retval EFI_MEDIA_CHANGED            The MediaId is not for the current 
media.
+  @retval EFI_INVALID_PARAMETER        The PayloadBuffer is NULL and 
PayloadBufferSize is non-zero.
+  @retval EFI_TIMEOUT                  A timeout occurred while waiting for 
the security
+                                       protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskSendData (
+  IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL    *This,
+  IN UINT32                                   MediaId   OPTIONAL,
+  IN UINT64                                   Timeout,
+  IN UINT8                                    SecurityProtocolId,
+  IN UINT16                                   SecurityProtocolSpecificData,
+  IN UINTN                                    PayloadBufferSize,
+  OUT VOID                                    *PayloadBuffer
+  );
+
+
 /**
   Provides inquiry information for the controller type.
 
@@ -1434,4 +1587,20 @@ DetermineInstallEraseBlock (
   IN  EFI_HANDLE             ChildHandle
   );
 
+/**
+  Determine if EFI Storage Security Command Protocol should be produced.
+
+  @param   ScsiDiskDevice    The pointer of SCSI_DISK_DEV.
+  @param   ChildHandle       Handle of device.
+
+  @retval  TRUE    Should produce EFI Storage Security Command Protocol.
+  @retval  FALSE   Should not produce EFI Storage Security Command Protocol.
+
+**/
+BOOLEAN
+DetermineInstallStorageSecurity (
+  IN  SCSI_DISK_DEV          *ScsiDiskDevice,
+  IN  EFI_HANDLE             ChildHandle
+  );
+
 #endif
diff --git a/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c 
b/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c
index 11a7f2a927..0b4c51764e 100644
--- a/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c
+++ b/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c
@@ -2,7 +2,7 @@
   SCSI Bus driver that layers on every SCSI Pass Thru and
   Extended SCSI Pass Thru protocol in the system.
 
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2019, 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
@@ -1374,7 +1374,8 @@ DiscoverScsiDevice (
     goto Done;
   }
 
-  if (0x1e >= InquiryData->Peripheral_Type && InquiryData->Peripheral_Type >= 
0xa) {
+  if ((InquiryData->Peripheral_Type >= EFI_SCSI_TYPE_RESERVED_LOW) &&
+      (InquiryData->Peripheral_Type <= EFI_SCSI_TYPE_RESERVED_HIGH)) {
     ScsiDeviceFound = FALSE;
     goto Done;
   }
diff --git a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ComponentName.c 
b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ComponentName.c
index f2da7af8fb..cba833d4ca 100644
--- a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ComponentName.c
+++ b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ComponentName.c
@@ -1,7 +1,7 @@
 /** @file
   UEFI Component Name(2) protocol implementation for SCSI disk driver.
 
-Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2004 - 2019, 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
@@ -173,9 +173,9 @@ ScsiDiskComponentNameGetControllerName (
   OUT CHAR16                                          **ControllerName
   )
 {
-  EFI_STATUS            Status;
-  SCSI_DISK_DEV         *ScsiDiskDevice;
-  EFI_BLOCK_IO_PROTOCOL *BlockIo;
+  EFI_STATUS              Status;
+  SCSI_DISK_DEV           *ScsiDiskDevice;
+  EFI_DISK_INFO_PROTOCOL  *DiskInfo;
 
   //
   // This is a device driver, so ChildHandle must be NULL.
@@ -200,8 +200,8 @@ ScsiDiskComponentNameGetControllerName (
   //
   Status = gBS->OpenProtocol (
                   ControllerHandle,
-                  &gEfiBlockIoProtocolGuid,
-                  (VOID **) &BlockIo,
+                  &gEfiDiskInfoProtocolGuid,
+                  (VOID **) &DiskInfo,
                   gScsiDiskDriverBinding.DriverBindingHandle,
                   ControllerHandle,
                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
@@ -211,7 +211,7 @@ ScsiDiskComponentNameGetControllerName (
     return Status;
   }
 
-  ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (BlockIo);
+  ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (DiskInfo);
 
   return LookupUnicodeString2 (
            Language,
diff --git a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c 
b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
index 0d63c85e44..75eb13ca20 100644
--- a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
+++ b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
@@ -1,7 +1,7 @@
 /** @file
   SCSI disk driver that layers on every SCSI IO protocol in the system.
 
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2019, 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
@@ -157,7 +157,9 @@ ScsiDiskDriverBindingSupported (
 
   Status = ScsiIo->GetDeviceType (ScsiIo, &DeviceType);
   if (!EFI_ERROR (Status)) {
-    if ((DeviceType == EFI_SCSI_TYPE_DISK) || (DeviceType == 
EFI_SCSI_TYPE_CDROM)) {
+    if ((DeviceType == EFI_SCSI_TYPE_DISK) ||
+        (DeviceType == EFI_SCSI_TYPE_CDROM) ||
+        (DeviceType == EFI_SCSI_TYPE_WLUN)) {
       Status = EFI_SUCCESS;
     } else {
       Status = EFI_UNSUPPORTED;
@@ -244,6 +246,8 @@ ScsiDiskDriverBindingStart (
   ScsiDiskDevice->BlkIo2.ReadBlocksEx               = ScsiDiskReadBlocksEx;
   ScsiDiskDevice->BlkIo2.WriteBlocksEx              = ScsiDiskWriteBlocksEx;
   ScsiDiskDevice->BlkIo2.FlushBlocksEx              = ScsiDiskFlushBlocksEx;
+  ScsiDiskDevice->StorageSecurity.ReceiveData       = ScsiDiskReceiveData;
+  ScsiDiskDevice->StorageSecurity.SendData          = ScsiDiskSendData;
   ScsiDiskDevice->EraseBlock.Revision               = 
EFI_ERASE_BLOCK_PROTOCOL_REVISION;
   ScsiDiskDevice->EraseBlock.EraseLengthGranularity = 1;
   ScsiDiskDevice->EraseBlock.EraseBlocks            = ScsiDiskEraseBlocks;
@@ -264,6 +268,10 @@ ScsiDiskDriverBindingStart (
     ScsiDiskDevice->BlkIo.Media->ReadOnly  = TRUE;
     MustReadCapacity = FALSE;
     break;
+
+  case EFI_SCSI_TYPE_WLUN:
+    MustReadCapacity = FALSE;
+    break;
   }
   //
   // The Sense Data Array's initial size is 6
@@ -311,11 +319,45 @@ ScsiDiskDriverBindingStart (
   //
   Status = ScsiDiskDetectMedia (ScsiDiskDevice, MustReadCapacity, &Temp);
   if (!EFI_ERROR (Status)) {
+
+    //
+    // Determine if StorageSecurity should be produced on this controller
+    //
+    if (DetermineInstallStorageSecurity(ScsiDiskDevice, Controller) &&
+        DetermineInstallBlockIo(Controller)) {
+      InitializeInstallDiskInfo(ScsiDiskDevice, Controller);
+      Status = gBS->InstallMultipleProtocolInterfaces (
+                      &Controller,
+                      &gEfiStorageSecurityCommandProtocolGuid,
+                      &ScsiDiskDevice->StorageSecurity,
+                      &gEfiDiskInfoProtocolGuid,
+                      &ScsiDiskDevice->DiskInfo,
+                      NULL
+                      );
+      if (!EFI_ERROR(Status)) {
+        ScsiDiskDevice->ControllerNameTable = NULL;
+        AddUnicodeString2 (
+          "eng",
+          gScsiDiskComponentName.SupportedLanguages,
+          &ScsiDiskDevice->ControllerNameTable,
+          L"SCSI Secure Disk Device",
+          TRUE
+          );
+        AddUnicodeString2 (
+          "en",
+          gScsiDiskComponentName2.SupportedLanguages,
+          &ScsiDiskDevice->ControllerNameTable,
+          L"SCSI Secure Disk Device",
+          FALSE
+          );
+        return EFI_SUCCESS;
+      }
+
     //
     // Determine if Block IO & Block IO2 should be produced on this controller
     // handle
     //
-    if (DetermineInstallBlockIo(Controller)) {
+    } else if (DetermineInstallBlockIo(Controller)) {
       InitializeInstallDiskInfo(ScsiDiskDevice, Controller);
       Status = gBS->InstallMultipleProtocolInterfaces (
                       &Controller,
@@ -1714,6 +1756,396 @@ Done:
   return Status;
 }
 
+/**
+  Send a security protocol command to a device that receives data and/or the 
result
+  of one or more commands sent by SendData.
+
+  The ReceiveData function sends a security protocol command to the given 
MediaId.
+  The security protocol command sent is defined by SecurityProtocolId and 
contains
+  the security protocol specific data SecurityProtocolSpecificData. The 
function
+  returns the data from the security protocol command in PayloadBuffer.
+
+  For devices supporting the SCSI command set, the security protocol command 
is sent
+  using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+  If PayloadBufferSize is too small to store the available data from the 
security
+  protocol command, the function shall copy PayloadBufferSize bytes into the
+  PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+  If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is 
non-zero,
+  the function shall return EFI_INVALID_PARAMETER.
+
+  If the given MediaId does not support security protocol commands, the 
function shall
+  return EFI_UNSUPPORTED. If there is no media in the device, the function 
returns
+  EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the 
device,
+  the function returns EFI_MEDIA_CHANGED.
+
+  If the security protocol fails to complete within the Timeout period, the 
function
+  shall return EFI_TIMEOUT.
+
+  If the security protocol command completes without an error, the function 
shall
+  return EFI_SUCCESS. If the security protocol command completes with an 
error, the
+  function shall return EFI_DEVICE_ERROR.
+
+  @param  This                         Indicates a pointer to the calling 
context.
+  @param  MediaId                      ID of the medium to receive data from.
+  @param  Timeout                      The timeout, in 100ns units, to use for 
the execution
+                                       of the security protocol command. A 
Timeout value of 0
+                                       means that this function will wait 
indefinitely for the
+                                       security protocol command to execute. 
If Timeout is greater
+                                       than zero, then this function will 
return EFI_TIMEOUT if the
+                                       time required to execute the receive 
data command is greater than Timeout.
+  @param  SecurityProtocolId           The value of the "Security Protocol" 
parameter of
+                                       the security protocol command to be 
sent.
+  @param  SecurityProtocolSpecificData The value of the "Security Protocol 
Specific" parameter
+                                       of the security protocol command to be 
sent.
+  @param  PayloadBufferSize            Size in bytes of the payload data 
buffer.
+  @param  PayloadBuffer                A pointer to a destination buffer to 
store the security
+                                       protocol command specific payload data 
for the security
+                                       protocol command. The caller is 
responsible for having
+                                       either implicit or explicit ownership 
of the buffer.
+  @param  PayloadTransferSize          A pointer to a buffer to store the size 
in bytes of the
+                                       data written to the payload data buffer.
+
+  @retval EFI_SUCCESS                  The security protocol command completed 
successfully.
+  @retval EFI_WARN_BUFFER_TOO_SMALL    The PayloadBufferSize was too small to 
store the available
+                                       data from the device. The PayloadBuffer 
contains the truncated data.
+  @retval EFI_UNSUPPORTED              The given MediaId does not support 
security protocol commands.
+  @retval EFI_DEVICE_ERROR             The security protocol command completed 
with an error.
+  @retval EFI_NO_MEDIA                 There is no media in the device.
+  @retval EFI_MEDIA_CHANGED            The MediaId is not for the current 
media.
+  @retval EFI_INVALID_PARAMETER        The PayloadBuffer or 
PayloadTransferSize is NULL and
+                                       PayloadBufferSize is non-zero.
+  @retval EFI_TIMEOUT                  A timeout occurred while waiting for 
the security
+                                       protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskReceiveData (
+  IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL    *This,
+  IN UINT32                                   MediaId   OPTIONAL,
+  IN UINT64                                   Timeout,
+  IN UINT8                                    SecurityProtocolId,
+  IN UINT16                                   SecurityProtocolSpecificData,
+  IN UINTN                                    PayloadBufferSize,
+  OUT VOID                                    *PayloadBuffer,
+  OUT UINTN                                   *PayloadTransferSize
+  )
+{
+  SCSI_DISK_DEV       *ScsiDiskDevice;
+  EFI_BLOCK_IO_MEDIA  *Media;
+  EFI_STATUS          Status;
+  BOOLEAN             MediaChange;
+  EFI_TPL             OldTpl;
+  UINT8               SenseDataLength;
+  UINT8               HostAdapterStatus;
+  UINT8               TargetStatus;
+  VOID                *AlignedBuffer;
+  BOOLEAN             AlignedBufferAllocated;
+
+  MediaChange             = FALSE;
+  AlignedBufferAllocated  = FALSE;
+  OldTpl                  = gBS->RaiseTPL (TPL_CALLBACK);
+  ScsiDiskDevice          = SCSI_DISK_DEV_FROM_STORSEC (This);
+  Media                   = ScsiDiskDevice->BlkIo.Media;
+
+  SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof 
(EFI_SCSI_SENSE_DATA));
+
+  if (!DetermineInstallStorageSecurity(ScsiDiskDevice, 
ScsiDiskDevice->Handle)) {
+    Status = EFI_UNSUPPORTED;
+    goto Done;
+  }
+
+  if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
+    Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
+    if (EFI_ERROR (Status)) {
+      Status = EFI_DEVICE_ERROR;
+      goto Done;
+    }
+
+    if (MediaChange) {
+      gBS->ReinstallProtocolInterface (
+              ScsiDiskDevice->Handle,
+              &gEfiStorageSecurityCommandProtocolGuid,
+              &ScsiDiskDevice->StorageSecurity,
+              &ScsiDiskDevice->StorageSecurity
+              );
+      if (Media->MediaPresent) {
+        Status = EFI_MEDIA_CHANGED;
+      } else {
+        Status = EFI_NO_MEDIA;
+      }
+      goto Done;
+    }
+  }
+
+  //
+  // Validate Media
+  //
+  if (!(Media->MediaPresent)) {
+    Status = EFI_NO_MEDIA;
+    goto Done;
+  }
+
+  if ((MediaId != 0) && (MediaId != Media->MediaId)) {
+    Status = EFI_MEDIA_CHANGED;
+    goto Done;
+  }
+
+  if (PayloadBufferSize != 0) {
+    if ((PayloadBuffer == NULL) || (PayloadTransferSize == NULL)) {
+      Status = EFI_INVALID_PARAMETER;
+      goto Done;
+    }
+
+    if ((ScsiDiskDevice->ScsiIo->IoAlign > 1) && !IS_ALIGNED(PayloadBuffer, 
ScsiDiskDevice->ScsiIo->IoAlign)) {
+      AlignedBuffer = AllocateAlignedBuffer (ScsiDiskDevice, 
PayloadBufferSize);
+      if (AlignedBuffer == NULL) {
+        Status = EFI_OUT_OF_RESOURCES;
+        goto Done;
+      }
+      ZeroMem (AlignedBuffer, PayloadBufferSize);
+      AlignedBufferAllocated = TRUE;
+    } else {
+      AlignedBuffer = PayloadBuffer;
+    }
+  }
+
+  Status = ScsiSecurityProtocolInCommand (
+            ScsiDiskDevice->ScsiIo,
+            Timeout,
+            ScsiDiskDevice->SenseData,
+            &SenseDataLength,
+            &HostAdapterStatus,
+            &TargetStatus,
+            SecurityProtocolId,
+            SecurityProtocolSpecificData,
+            (UINT32) PayloadBufferSize,
+            AlignedBuffer,
+            (UINT32 *) PayloadTransferSize
+          );
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  if (AlignedBufferAllocated) {
+    CopyMem (PayloadBuffer, AlignedBuffer, PayloadBufferSize);
+  }
+
+  if (PayloadBufferSize < *PayloadTransferSize) {
+    Status = EFI_WARN_BUFFER_TOO_SMALL;
+    goto Done;
+  }
+
+  Status = CheckHostAdapterStatus (HostAdapterStatus);
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  Status = CheckTargetStatus (TargetStatus);
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+Done:
+  if (AlignedBufferAllocated) {
+    FreeAlignedBuffer (AlignedBuffer, PayloadBufferSize);
+  }
+  gBS->RestoreTPL (OldTpl);
+  return Status;
+}
+
+/**
+  Send a security protocol command to a device.
+
+  The SendData function sends a security protocol command containing the 
payload
+  PayloadBuffer to the given MediaId. The security protocol command sent is
+  defined by SecurityProtocolId and contains the security protocol specific 
data
+  SecurityProtocolSpecificData. If the underlying protocol command requires a
+  specific padding for the command payload, the SendData function shall add 
padding
+  bytes to the command payload to satisfy the padding requirements.
+
+  For devices supporting the SCSI command set, the security protocol command 
is sent
+  using the SECURITY PROTOCOL OUT command defined in SPC-4.
+
+  If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function 
shall
+  return EFI_INVALID_PARAMETER.
+
+  If the given MediaId does not support security protocol commands, the 
function
+  shall return EFI_UNSUPPORTED. If there is no media in the device, the 
function
+  returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in 
the
+  device, the function returns EFI_MEDIA_CHANGED.
+
+  If the security protocol fails to complete within the Timeout period, the 
function
+  shall return EFI_TIMEOUT.
+
+  If the security protocol command completes without an error, the function 
shall return
+  EFI_SUCCESS. If the security protocol command completes with an error, the 
function
+  shall return EFI_DEVICE_ERROR.
+
+  @param  This                         Indicates a pointer to the calling 
context.
+  @param  MediaId                      ID of the medium to receive data from.
+  @param  Timeout                      The timeout, in 100ns units, to use for 
the execution
+                                       of the security protocol command. A 
Timeout value of 0
+                                       means that this function will wait 
indefinitely for the
+                                       security protocol command to execute. 
If Timeout is greater
+                                       than zero, then this function will 
return EFI_TIMEOUT if the
+                                       time required to execute the receive 
data command is greater than Timeout.
+  @param  SecurityProtocolId           The value of the "Security Protocol" 
parameter of
+                                       the security protocol command to be 
sent.
+  @param  SecurityProtocolSpecificData The value of the "Security Protocol 
Specific" parameter
+                                       of the security protocol command to be 
sent.
+  @param  PayloadBufferSize            Size in bytes of the payload data 
buffer.
+  @param  PayloadBuffer                A pointer to a destination buffer to 
store the security
+                                       protocol command specific payload data 
for the security
+                                       protocol command.
+
+  @retval EFI_SUCCESS                  The security protocol command completed 
successfully.
+  @retval EFI_UNSUPPORTED              The given MediaId does not support 
security protocol commands.
+  @retval EFI_DEVICE_ERROR             The security protocol command completed 
with an error.
+  @retval EFI_NO_MEDIA                 There is no media in the device.
+  @retval EFI_MEDIA_CHANGED            The MediaId is not for the current 
media.
+  @retval EFI_INVALID_PARAMETER        The PayloadBuffer is NULL and 
PayloadBufferSize is non-zero.
+  @retval EFI_TIMEOUT                  A timeout occurred while waiting for 
the security
+                                       protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+ScsiDiskSendData (
+  IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL    *This,
+  IN UINT32                                   MediaId   OPTIONAL,
+  IN UINT64                                   Timeout,
+  IN UINT8                                    SecurityProtocolId,
+  IN UINT16                                   SecurityProtocolSpecificData,
+  IN UINTN                                    PayloadBufferSize,
+  OUT VOID                                    *PayloadBuffer
+  )
+{
+  SCSI_DISK_DEV       *ScsiDiskDevice;
+  EFI_BLOCK_IO_MEDIA  *Media;
+  EFI_STATUS          Status;
+  BOOLEAN             MediaChange;
+  EFI_TPL             OldTpl;
+  UINT8               SenseDataLength;
+  UINT8               HostAdapterStatus;
+  UINT8               TargetStatus;
+  VOID                *AlignedBuffer;
+  BOOLEAN             AlignedBufferAllocated;
+
+  MediaChange             = FALSE;
+  AlignedBufferAllocated  = FALSE;
+  OldTpl                  = gBS->RaiseTPL (TPL_CALLBACK);
+  ScsiDiskDevice          = SCSI_DISK_DEV_FROM_STORSEC (This);
+  Media                   = ScsiDiskDevice->BlkIo.Media;
+
+  SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof 
(EFI_SCSI_SENSE_DATA));
+
+  if (!DetermineInstallStorageSecurity(ScsiDiskDevice, 
ScsiDiskDevice->Handle)) {
+    Status = EFI_UNSUPPORTED;
+    goto Done;
+  }
+
+  if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
+    Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
+    if (EFI_ERROR (Status)) {
+      Status = EFI_DEVICE_ERROR;
+      goto Done;
+    }
+
+    if (MediaChange) {
+      gBS->ReinstallProtocolInterface (
+              ScsiDiskDevice->Handle,
+              &gEfiStorageSecurityCommandProtocolGuid,
+              &ScsiDiskDevice->StorageSecurity,
+              &ScsiDiskDevice->StorageSecurity
+              );
+      if (Media->MediaPresent) {
+        Status = EFI_MEDIA_CHANGED;
+      } else {
+        Status = EFI_NO_MEDIA;
+      }
+      goto Done;
+    }
+  }
+
+  //
+  // Validate Media
+  //
+  if (!(Media->MediaPresent)) {
+    Status = EFI_NO_MEDIA;
+    goto Done;
+  }
+
+  if ((MediaId != 0) && (MediaId != Media->MediaId)) {
+    Status = EFI_MEDIA_CHANGED;
+    goto Done;
+  }
+
+  if (Media->ReadOnly) {
+    Status = EFI_WRITE_PROTECTED;
+    goto Done;
+  }
+
+  if ((PayloadBuffer == NULL) && (PayloadBufferSize != 0)) {
+    DEBUG ((DEBUG_ERROR, "ScsiDiskSendData: PayloadBuffer NULL!\n"));
+    Status = EFI_INVALID_PARAMETER;
+    goto Done;
+  }
+  if (PayloadBufferSize != 0) {
+    if (PayloadBuffer == NULL) {
+      Status = EFI_INVALID_PARAMETER;
+      goto Done;
+    }
+
+    if ((ScsiDiskDevice->ScsiIo->IoAlign > 1) && !IS_ALIGNED(PayloadBuffer, 
ScsiDiskDevice->ScsiIo->IoAlign)) {
+      AlignedBuffer = AllocateAlignedBuffer (ScsiDiskDevice, 
PayloadBufferSize);
+      if (AlignedBuffer == NULL) {
+        Status = EFI_OUT_OF_RESOURCES;
+        goto Done;
+      }
+      CopyMem (AlignedBuffer, PayloadBuffer, PayloadBufferSize);
+      AlignedBufferAllocated = TRUE;
+    } else {
+      AlignedBuffer = PayloadBuffer;
+    }
+  }
+
+  Status = ScsiSecurityProtocolOutCommand (
+            ScsiDiskDevice->ScsiIo,
+            Timeout,
+            ScsiDiskDevice->SenseData,
+            &SenseDataLength,
+            &HostAdapterStatus,
+            &TargetStatus,
+            SecurityProtocolId,
+            SecurityProtocolSpecificData,
+            (UINT32) PayloadBufferSize,
+            AlignedBuffer
+          );
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  Status = CheckHostAdapterStatus (HostAdapterStatus);
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  Status = CheckTargetStatus (TargetStatus);
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+Done:
+  if (AlignedBufferAllocated) {
+    FreeAlignedBuffer (AlignedBuffer, PayloadBufferSize);
+  }
+  gBS->RestoreTPL (OldTpl);
+  return Status;
+}
+
 
 /**
   Detect Device and read out capacity ,if error occurs, parse the sense key.
@@ -2267,6 +2699,8 @@ ScsiDiskTestUnitReady (
     return EFI_DEVICE_ERROR;
   }
 
+  ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;
+
   if (SenseDataLength != 0) {
     *NumberOfSenseKeys = SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA);
     *SenseDataArray    = ScsiDiskDevice->SenseData;
@@ -2321,13 +2755,12 @@ DetectMediaParsingSenseKeys (
   BOOLEAN RetryLater;
 
   //
-  // Default is to read capacity, unless..
+  // Default is no action
   //
-  *Action = ACTION_READ_CAPACITY;
+  *Action = ACTION_NO_ACTION;
 
   if (NumberOfSenseKeys == 0) {
     if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {
-      *Action = ACTION_NO_ACTION;
     }
     return EFI_SUCCESS;
   }
@@ -2337,7 +2770,6 @@ DetectMediaParsingSenseKeys (
     // No Sense Key returned from last submitted command
     //
     if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {
-      *Action = ACTION_NO_ACTION;
     }
     return EFI_SUCCESS;
   }
@@ -2345,13 +2777,13 @@ DetectMediaParsingSenseKeys (
   if (ScsiDiskIsNoMedia (SenseData, NumberOfSenseKeys)) {
     ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;
     ScsiDiskDevice->BlkIo.Media->LastBlock    = 0;
-    *Action = ACTION_NO_ACTION;
     DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsNoMedia\n"));
     return EFI_SUCCESS;
   }
 
   if (ScsiDiskIsMediaChange (SenseData, NumberOfSenseKeys)) {
     ScsiDiskDevice->BlkIo.Media->MediaId++;
+    *Action = ACTION_READ_CAPACITY;
     DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsMediaChange!\n"));
     return EFI_SUCCESS;
   }
@@ -2380,7 +2812,6 @@ DetectMediaParsingSenseKeys (
       DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskDriveNotReady!\n"));
       return EFI_SUCCESS;
     }
-    *Action = ACTION_NO_ACTION;
     return EFI_DEVICE_ERROR;
   }
 
@@ -2814,8 +3245,6 @@ GetMediaInfo (
       }
     }
   }
-
-  ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;
 }
 
 /**
@@ -5466,6 +5895,65 @@ Done:
   return RetVal;
 }
 
+/**
+  Determine if EFI Storage Security Command Protocol should be produced.
+
+  @param   ScsiDiskDevice    The pointer of SCSI_DISK_DEV.
+  @param   ChildHandle       Handle of device.
+
+  @retval  TRUE    Should produce EFI Storage Security Command Protocol.
+  @retval  FALSE   Should not produce EFI Storage Security Command Protocol.
+
+**/
+BOOLEAN
+DetermineInstallStorageSecurity (
+  IN  SCSI_DISK_DEV          *ScsiDiskDevice,
+  IN  EFI_HANDLE             ChildHandle
+  )
+{
+  EFI_STATUS                      Status;
+  UFS_DEVICE_PATH                 *UfsDevice;
+  BOOLEAN                         RetVal;
+  EFI_DEVICE_PATH_PROTOCOL        *DevicePathNode;
+
+  UfsDevice      = NULL;
+  RetVal         = TRUE;
+
+  Status = gBS->HandleProtocol (
+                  ChildHandle,
+                  &gEfiDevicePathProtocolGuid,
+                  (VOID **) &DevicePathNode
+                  );
+  //
+  // Device Path protocol must be installed on the device handle.
+  //
+  ASSERT_EFI_ERROR (Status);
+
+  while (!IsDevicePathEndType (DevicePathNode)) {
+    //
+    // For now, only support Storage Security Command Protocol on UFS devices.
+    //
+    if ((DevicePathNode->Type == MESSAGING_DEVICE_PATH) &&
+        (DevicePathNode->SubType == MSG_UFS_DP)) {
+      UfsDevice = (UFS_DEVICE_PATH *) DevicePathNode;
+      break;
+    }
+
+    DevicePathNode = NextDevicePathNode (DevicePathNode);
+  }
+  if (UfsDevice == NULL) {
+    RetVal = FALSE;
+    goto Done;
+  }
+
+  if (UfsDevice->Lun != UFS_WLUN_RPMB) {
+    RetVal = FALSE;
+  }
+
+Done:
+  return RetVal;
+}
+
 /**
   Provides inquiry information for the controller type.
 
diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c 
b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c
index ea329618dc..6ed5da21fd 100644
--- a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c
+++ b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c
@@ -1,6 +1,6 @@
 /** @file
 
-  Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2014 - 2019, 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
@@ -825,7 +825,9 @@ UfsPassThruDriverBindingStart (
   UINTN                                 UfsHcBase;
   UINT32                                Index;
   UFS_UNIT_DESC                         UnitDescriptor;
+  UFS_DEV_DESC                          DeviceDescriptor;
   UINT32                                UnitDescriptorSize;
+  UINT32                                DeviceDescriptorSize;
 
   Status    = EFI_SUCCESS;
   UfsHc     = NULL;
@@ -900,7 +902,6 @@ UfsPassThruDriverBindingStart (
 
   //
   // Check if 8 common luns are active and set corresponding bit mask.
-  // TODO: Parse device descriptor to decide if exposing RPMB LUN to upper 
layer for authentication access.
   //
   UnitDescriptorSize = sizeof (UFS_UNIT_DESC);
   for (Index = 0; Index < 8; Index++) {
@@ -915,6 +916,20 @@ UfsPassThruDriverBindingStart (
     }
   }
 
+  //
+  // Check if RPMB WLUN is supported and set corresponding bit mask.
+  //
+  DeviceDescriptorSize = sizeof (UFS_DEV_DESC);
+  Status = UfsRwDeviceDesc (Private, TRUE, UfsDeviceDesc, 0, 0, 
&DeviceDescriptor, &DeviceDescriptorSize);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to read device descriptor, status = %r\n", 
Status));
+  } else {
+    if (DeviceDescriptor.SecurityLun == 0x1) {
+      DEBUG ((DEBUG_INFO, "UFS WLUN RPMB is supported\n"));
+      Private->Luns.BitMask |= BIT11;
+    }
+  }
+
   //
   // Start the asynchronous interrupt monitor
   //
-- 
2.16.2.windows.1

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to