From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: mx.groups.io; dkim=missing; spf=fail (domain: intel.com, ip: , mailfrom: christopher.j.zurcher@intel.com) Received: from mga05.intel.com (mga05.intel.com []) by groups.io with SMTP; Fri, 06 Sep 2019 15:12:20 -0700 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga105.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 06 Sep 2019 15:12:19 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.64,474,1559545200"; d="scan'208";a="195568586" Received: from cjzurch-desk.amr.corp.intel.com ([10.9.70.181]) by orsmga002.jf.intel.com with ESMTP; 06 Sep 2019 15:12:17 -0700 From: "Zurcher, Christopher J" To: devel@edk2.groups.io Cc: Michael D Kinney , Jiewen Yao , Jian J Wang , Liming Gao Subject: [PATCH v6 4/4] MdeModulePkg/ScsiDiskDxe: Support Storage Security Command Protocol Date: Fri, 6 Sep 2019 15:12:16 -0700 Message-Id: <20190906221217.34180-5-christopher.j.zurcher@intel.com> X-Mailer: git-send-email 2.16.2.windows.1 In-Reply-To: <20190906221217.34180-1-christopher.j.zurcher@intel.com> References: <20190906221217.34180-1-christopher.j.zurcher@intel.com> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=1546 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: Michael D Kinney Cc: Jiewen Yao Cc: Jian J Wang Cc: Liming Gao Signed-off-by: Christopher J Zurcher --- MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf | 3 +- MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h | 171 +++++- MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c | 616 +++++++++++++++++++- 3 files changed, 774 insertions(+), 16 deletions(-) diff --git a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf index 5500d828e9..40818e669b 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.
+# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
# SPDX-License-Identifier: BSD-2-Clause-Patent # ## @@ -52,6 +52,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 42c0aaaa95..2d8679ec6f 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.
+Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -22,6 +22,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include +#include #include @@ -38,6 +39,10 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #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; @@ -51,6 +56,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; @@ -95,6 +102,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) @@ -638,6 +646,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. @@ -1428,4 +1581,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/ScsiDiskDxe/ScsiDisk.c b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c index fbdf927a11..6bfcf03a4b 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.
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -151,7 +151,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; @@ -238,6 +240,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; @@ -258,6 +262,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 @@ -309,8 +317,8 @@ ScsiDiskDriverBindingStart ( // Determine if Block IO & Block IO2 should be produced on this controller // handle // - if (DetermineInstallBlockIo(Controller)) { - InitializeInstallDiskInfo(ScsiDiskDevice, Controller); + if (DetermineInstallBlockIo (Controller)) { + InitializeInstallDiskInfo (ScsiDiskDevice, Controller); Status = gBS->InstallMultipleProtocolInterfaces ( &Controller, &gEfiBlockIoProtocolGuid, @@ -321,16 +329,27 @@ ScsiDiskDriverBindingStart ( &ScsiDiskDevice->DiskInfo, NULL ); - if (!EFI_ERROR(Status)) { - if (DetermineInstallEraseBlock(ScsiDiskDevice, Controller)) { + if (!EFI_ERROR (Status)) { + if (DetermineInstallEraseBlock (ScsiDiskDevice, Controller)) { Status = gBS->InstallProtocolInterface ( &Controller, &gEfiEraseBlockProtocolGuid, EFI_NATIVE_INTERFACE, &ScsiDiskDevice->EraseBlock ); - if (EFI_ERROR(Status)) { - DEBUG ((EFI_D_ERROR, "ScsiDisk: Failed to install the Erase Block Protocol! Status = %r\n", Status)); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "ScsiDisk: Failed to install the Erase Block Protocol! Status = %r\n", Status)); + } + } + if (DetermineInstallStorageSecurity (ScsiDiskDevice, Controller)) { + Status = gBS->InstallProtocolInterface ( + &Controller, + &gEfiStorageSecurityCommandProtocolGuid, + EFI_NATIVE_INTERFACE, + &ScsiDiskDevice->StorageSecurity + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "ScsiDisk: Failed to install the Storage Security Command Protocol! Status = %r\n", Status)); } } ScsiDiskDevice->ControllerNameTable = NULL; @@ -585,7 +604,7 @@ ScsiDiskReadBlocks ( &ScsiDiskDevice->BlkIo2, &ScsiDiskDevice->BlkIo2 ); - if (DetermineInstallEraseBlock(ScsiDiskDevice, ScsiDiskDevice->Handle)) { + if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) { gBS->ReinstallProtocolInterface ( ScsiDiskDevice->Handle, &gEfiEraseBlockProtocolGuid, @@ -593,6 +612,14 @@ ScsiDiskReadBlocks ( &ScsiDiskDevice->EraseBlock ); } + if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) { + gBS->ReinstallProtocolInterface ( + ScsiDiskDevice->Handle, + &gEfiStorageSecurityCommandProtocolGuid, + &ScsiDiskDevice->StorageSecurity, + &ScsiDiskDevice->StorageSecurity + ); + } if (Media->MediaPresent) { Status = EFI_MEDIA_CHANGED; } else { @@ -606,6 +633,11 @@ ScsiDiskReadBlocks ( // BlockSize = Media->BlockSize; + if (BlockSize == 0) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + NumberOfBlocks = BufferSize / BlockSize; if (!(Media->MediaPresent)) { @@ -721,7 +753,7 @@ ScsiDiskWriteBlocks ( &ScsiDiskDevice->BlkIo2, &ScsiDiskDevice->BlkIo2 ); - if (DetermineInstallEraseBlock(ScsiDiskDevice, ScsiDiskDevice->Handle)) { + if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) { gBS->ReinstallProtocolInterface ( ScsiDiskDevice->Handle, &gEfiEraseBlockProtocolGuid, @@ -729,6 +761,14 @@ ScsiDiskWriteBlocks ( &ScsiDiskDevice->EraseBlock ); } + if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) { + gBS->ReinstallProtocolInterface ( + ScsiDiskDevice->Handle, + &gEfiStorageSecurityCommandProtocolGuid, + &ScsiDiskDevice->StorageSecurity, + &ScsiDiskDevice->StorageSecurity + ); + } if (Media->MediaPresent) { Status = EFI_MEDIA_CHANGED; } else { @@ -742,6 +782,11 @@ ScsiDiskWriteBlocks ( // BlockSize = Media->BlockSize; + if (BlockSize == 0) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + NumberOfBlocks = BufferSize / BlockSize; if (!(Media->MediaPresent)) { @@ -947,7 +992,7 @@ ScsiDiskReadBlocksEx ( &ScsiDiskDevice->BlkIo2, &ScsiDiskDevice->BlkIo2 ); - if (DetermineInstallEraseBlock(ScsiDiskDevice, ScsiDiskDevice->Handle)) { + if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) { gBS->ReinstallProtocolInterface ( ScsiDiskDevice->Handle, &gEfiEraseBlockProtocolGuid, @@ -955,6 +1000,14 @@ ScsiDiskReadBlocksEx ( &ScsiDiskDevice->EraseBlock ); } + if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) { + gBS->ReinstallProtocolInterface ( + ScsiDiskDevice->Handle, + &gEfiStorageSecurityCommandProtocolGuid, + &ScsiDiskDevice->StorageSecurity, + &ScsiDiskDevice->StorageSecurity + ); + } if (Media->MediaPresent) { Status = EFI_MEDIA_CHANGED; } else { @@ -968,6 +1021,11 @@ ScsiDiskReadBlocksEx ( // BlockSize = Media->BlockSize; + if (BlockSize == 0) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + NumberOfBlocks = BufferSize / BlockSize; if (!(Media->MediaPresent)) { @@ -1110,7 +1168,7 @@ ScsiDiskWriteBlocksEx ( &ScsiDiskDevice->BlkIo2, &ScsiDiskDevice->BlkIo2 ); - if (DetermineInstallEraseBlock(ScsiDiskDevice, ScsiDiskDevice->Handle)) { + if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) { gBS->ReinstallProtocolInterface ( ScsiDiskDevice->Handle, &gEfiEraseBlockProtocolGuid, @@ -1118,6 +1176,14 @@ ScsiDiskWriteBlocksEx ( &ScsiDiskDevice->EraseBlock ); } + if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) { + gBS->ReinstallProtocolInterface ( + ScsiDiskDevice->Handle, + &gEfiStorageSecurityCommandProtocolGuid, + &ScsiDiskDevice->StorageSecurity, + &ScsiDiskDevice->StorageSecurity + ); + } if (Media->MediaPresent) { Status = EFI_MEDIA_CHANGED; } else { @@ -1131,6 +1197,11 @@ ScsiDiskWriteBlocksEx ( // BlockSize = Media->BlockSize; + if (BlockSize == 0) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + NumberOfBlocks = BufferSize / BlockSize; if (!(Media->MediaPresent)) { @@ -1263,7 +1334,7 @@ ScsiDiskFlushBlocksEx ( &ScsiDiskDevice->BlkIo2, &ScsiDiskDevice->BlkIo2 ); - if (DetermineInstallEraseBlock(ScsiDiskDevice, ScsiDiskDevice->Handle)) { + if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) { gBS->ReinstallProtocolInterface ( ScsiDiskDevice->Handle, &gEfiEraseBlockProtocolGuid, @@ -1271,6 +1342,14 @@ ScsiDiskFlushBlocksEx ( &ScsiDiskDevice->EraseBlock ); } + if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) { + gBS->ReinstallProtocolInterface ( + ScsiDiskDevice->Handle, + &gEfiStorageSecurityCommandProtocolGuid, + &ScsiDiskDevice->StorageSecurity, + &ScsiDiskDevice->StorageSecurity + ); + } if (Media->MediaPresent) { Status = EFI_MEDIA_CHANGED; } else { @@ -1644,7 +1723,7 @@ ScsiDiskEraseBlocks ( &ScsiDiskDevice->BlkIo2, &ScsiDiskDevice->BlkIo2 ); - if (DetermineInstallEraseBlock(ScsiDiskDevice, ScsiDiskDevice->Handle)) { + if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) { gBS->ReinstallProtocolInterface ( ScsiDiskDevice->Handle, &gEfiEraseBlockProtocolGuid, @@ -1652,6 +1731,14 @@ ScsiDiskEraseBlocks ( &ScsiDiskDevice->EraseBlock ); } + if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) { + gBS->ReinstallProtocolInterface ( + ScsiDiskDevice->Handle, + &gEfiStorageSecurityCommandProtocolGuid, + &ScsiDiskDevice->StorageSecurity, + &ScsiDiskDevice->StorageSecurity + ); + } Status = EFI_MEDIA_CHANGED; goto Done; } @@ -1708,6 +1795,431 @@ 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; + + AlignedBuffer = NULL; + 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 (!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, + &gEfiBlockIoProtocolGuid, + &ScsiDiskDevice->BlkIo, + &ScsiDiskDevice->BlkIo + ); + gBS->ReinstallProtocolInterface ( + ScsiDiskDevice->Handle, + &gEfiBlockIo2ProtocolGuid, + &ScsiDiskDevice->BlkIo2, + &ScsiDiskDevice->BlkIo2 + ); + if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) { + gBS->ReinstallProtocolInterface ( + ScsiDiskDevice->Handle, + &gEfiEraseBlockProtocolGuid, + &ScsiDiskDevice->EraseBlock, + &ScsiDiskDevice->EraseBlock + ); + } + if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) { + 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, + FALSE, + PayloadBufferSize, + AlignedBuffer, + 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) { + ZeroMem (AlignedBuffer, PayloadBufferSize); + 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; + + AlignedBuffer = NULL; + 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 (!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, + &gEfiBlockIoProtocolGuid, + &ScsiDiskDevice->BlkIo, + &ScsiDiskDevice->BlkIo + ); + gBS->ReinstallProtocolInterface ( + ScsiDiskDevice->Handle, + &gEfiBlockIo2ProtocolGuid, + &ScsiDiskDevice->BlkIo2, + &ScsiDiskDevice->BlkIo2 + ); + if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) { + gBS->ReinstallProtocolInterface ( + ScsiDiskDevice->Handle, + &gEfiEraseBlockProtocolGuid, + &ScsiDiskDevice->EraseBlock, + &ScsiDiskDevice->EraseBlock + ); + } + if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) { + 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 (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, + FALSE, + 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) { + ZeroMem (AlignedBuffer, PayloadBufferSize); + FreeAlignedBuffer (AlignedBuffer, PayloadBufferSize); + } + gBS->RestoreTPL (OldTpl); + return Status; +} + /** Detect Device and read out capacity ,if error occurs, parse the sense key. @@ -1812,6 +2324,15 @@ ScsiDiskDetectMedia ( NeedReadCapacity = TRUE; } + // + // READ_CAPACITY command is not supported by any of the UFS WLUNs. + // + if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_WLUN) { + NeedReadCapacity = FALSE; + MustReadCapacity = FALSE; + ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE; + } + // // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE, // retrieve capacity via Read Capacity command @@ -5358,6 +5879,14 @@ DetermineInstallEraseBlock ( RetVal = TRUE; CapacityData16 = NULL; + // + // UNMAP command is not supported by any of the UFS WLUNs. + // + if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_WLUN) { + RetVal = FALSE; + goto Done; + } + Status = gBS->HandleProtocol ( ChildHandle, &gEfiDevicePathProtocolGuid, @@ -5460,6 +5989,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. -- 2.16.2.windows.1