MdeModulePkg/ScsiDiskDxe: Support Storage Security Command Protocol

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 <michael.d.kinney@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Christopher J Zurcher <christopher.j.zurcher@intel.com>
Reviewed-by: Hao A Wu <hao.a.wu@intel.com>
This commit is contained in:
Zurcher, Christopher J 2019-09-27 10:20:00 +08:00 committed by Hao A Wu
parent 1ff7ed2cfa
commit ac81789c3b
3 changed files with 774 additions and 16 deletions

View File

@ -1,7 +1,7 @@
/** @file /** @file
SCSI disk driver that layers on every SCSI IO protocol in the system. 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>
SPDX-License-Identifier: BSD-2-Clause-Patent SPDX-License-Identifier: BSD-2-Clause-Patent
**/ **/
@ -151,7 +151,9 @@ ScsiDiskDriverBindingSupported (
Status = ScsiIo->GetDeviceType (ScsiIo, &DeviceType); Status = ScsiIo->GetDeviceType (ScsiIo, &DeviceType);
if (!EFI_ERROR (Status)) { 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; Status = EFI_SUCCESS;
} else { } else {
Status = EFI_UNSUPPORTED; Status = EFI_UNSUPPORTED;
@ -238,6 +240,8 @@ ScsiDiskDriverBindingStart (
ScsiDiskDevice->BlkIo2.ReadBlocksEx = ScsiDiskReadBlocksEx; ScsiDiskDevice->BlkIo2.ReadBlocksEx = ScsiDiskReadBlocksEx;
ScsiDiskDevice->BlkIo2.WriteBlocksEx = ScsiDiskWriteBlocksEx; ScsiDiskDevice->BlkIo2.WriteBlocksEx = ScsiDiskWriteBlocksEx;
ScsiDiskDevice->BlkIo2.FlushBlocksEx = ScsiDiskFlushBlocksEx; ScsiDiskDevice->BlkIo2.FlushBlocksEx = ScsiDiskFlushBlocksEx;
ScsiDiskDevice->StorageSecurity.ReceiveData = ScsiDiskReceiveData;
ScsiDiskDevice->StorageSecurity.SendData = ScsiDiskSendData;
ScsiDiskDevice->EraseBlock.Revision = EFI_ERASE_BLOCK_PROTOCOL_REVISION; ScsiDiskDevice->EraseBlock.Revision = EFI_ERASE_BLOCK_PROTOCOL_REVISION;
ScsiDiskDevice->EraseBlock.EraseLengthGranularity = 1; ScsiDiskDevice->EraseBlock.EraseLengthGranularity = 1;
ScsiDiskDevice->EraseBlock.EraseBlocks = ScsiDiskEraseBlocks; ScsiDiskDevice->EraseBlock.EraseBlocks = ScsiDiskEraseBlocks;
@ -258,6 +262,10 @@ ScsiDiskDriverBindingStart (
ScsiDiskDevice->BlkIo.Media->ReadOnly = TRUE; ScsiDiskDevice->BlkIo.Media->ReadOnly = TRUE;
MustReadCapacity = FALSE; MustReadCapacity = FALSE;
break; break;
case EFI_SCSI_TYPE_WLUN:
MustReadCapacity = FALSE;
break;
} }
// //
// The Sense Data Array's initial size is 6 // 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 // Determine if Block IO & Block IO2 should be produced on this controller
// handle // handle
// //
if (DetermineInstallBlockIo(Controller)) { if (DetermineInstallBlockIo (Controller)) {
InitializeInstallDiskInfo(ScsiDiskDevice, Controller); InitializeInstallDiskInfo (ScsiDiskDevice, Controller);
Status = gBS->InstallMultipleProtocolInterfaces ( Status = gBS->InstallMultipleProtocolInterfaces (
&Controller, &Controller,
&gEfiBlockIoProtocolGuid, &gEfiBlockIoProtocolGuid,
@ -321,16 +329,27 @@ ScsiDiskDriverBindingStart (
&ScsiDiskDevice->DiskInfo, &ScsiDiskDevice->DiskInfo,
NULL NULL
); );
if (!EFI_ERROR(Status)) { if (!EFI_ERROR (Status)) {
if (DetermineInstallEraseBlock(ScsiDiskDevice, Controller)) { if (DetermineInstallEraseBlock (ScsiDiskDevice, Controller)) {
Status = gBS->InstallProtocolInterface ( Status = gBS->InstallProtocolInterface (
&Controller, &Controller,
&gEfiEraseBlockProtocolGuid, &gEfiEraseBlockProtocolGuid,
EFI_NATIVE_INTERFACE, EFI_NATIVE_INTERFACE,
&ScsiDiskDevice->EraseBlock &ScsiDiskDevice->EraseBlock
); );
if (EFI_ERROR(Status)) { if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "ScsiDisk: Failed to install the Erase Block Protocol! Status = %r\n", 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; ScsiDiskDevice->ControllerNameTable = NULL;
@ -585,7 +604,7 @@ ScsiDiskReadBlocks (
&ScsiDiskDevice->BlkIo2, &ScsiDiskDevice->BlkIo2,
&ScsiDiskDevice->BlkIo2 &ScsiDiskDevice->BlkIo2
); );
if (DetermineInstallEraseBlock(ScsiDiskDevice, ScsiDiskDevice->Handle)) { if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
gBS->ReinstallProtocolInterface ( gBS->ReinstallProtocolInterface (
ScsiDiskDevice->Handle, ScsiDiskDevice->Handle,
&gEfiEraseBlockProtocolGuid, &gEfiEraseBlockProtocolGuid,
@ -593,6 +612,14 @@ ScsiDiskReadBlocks (
&ScsiDiskDevice->EraseBlock &ScsiDiskDevice->EraseBlock
); );
} }
if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
gBS->ReinstallProtocolInterface (
ScsiDiskDevice->Handle,
&gEfiStorageSecurityCommandProtocolGuid,
&ScsiDiskDevice->StorageSecurity,
&ScsiDiskDevice->StorageSecurity
);
}
if (Media->MediaPresent) { if (Media->MediaPresent) {
Status = EFI_MEDIA_CHANGED; Status = EFI_MEDIA_CHANGED;
} else { } else {
@ -606,6 +633,11 @@ ScsiDiskReadBlocks (
// //
BlockSize = Media->BlockSize; BlockSize = Media->BlockSize;
if (BlockSize == 0) {
Status = EFI_DEVICE_ERROR;
goto Done;
}
NumberOfBlocks = BufferSize / BlockSize; NumberOfBlocks = BufferSize / BlockSize;
if (!(Media->MediaPresent)) { if (!(Media->MediaPresent)) {
@ -721,7 +753,7 @@ ScsiDiskWriteBlocks (
&ScsiDiskDevice->BlkIo2, &ScsiDiskDevice->BlkIo2,
&ScsiDiskDevice->BlkIo2 &ScsiDiskDevice->BlkIo2
); );
if (DetermineInstallEraseBlock(ScsiDiskDevice, ScsiDiskDevice->Handle)) { if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
gBS->ReinstallProtocolInterface ( gBS->ReinstallProtocolInterface (
ScsiDiskDevice->Handle, ScsiDiskDevice->Handle,
&gEfiEraseBlockProtocolGuid, &gEfiEraseBlockProtocolGuid,
@ -729,6 +761,14 @@ ScsiDiskWriteBlocks (
&ScsiDiskDevice->EraseBlock &ScsiDiskDevice->EraseBlock
); );
} }
if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
gBS->ReinstallProtocolInterface (
ScsiDiskDevice->Handle,
&gEfiStorageSecurityCommandProtocolGuid,
&ScsiDiskDevice->StorageSecurity,
&ScsiDiskDevice->StorageSecurity
);
}
if (Media->MediaPresent) { if (Media->MediaPresent) {
Status = EFI_MEDIA_CHANGED; Status = EFI_MEDIA_CHANGED;
} else { } else {
@ -742,6 +782,11 @@ ScsiDiskWriteBlocks (
// //
BlockSize = Media->BlockSize; BlockSize = Media->BlockSize;
if (BlockSize == 0) {
Status = EFI_DEVICE_ERROR;
goto Done;
}
NumberOfBlocks = BufferSize / BlockSize; NumberOfBlocks = BufferSize / BlockSize;
if (!(Media->MediaPresent)) { if (!(Media->MediaPresent)) {
@ -947,7 +992,7 @@ ScsiDiskReadBlocksEx (
&ScsiDiskDevice->BlkIo2, &ScsiDiskDevice->BlkIo2,
&ScsiDiskDevice->BlkIo2 &ScsiDiskDevice->BlkIo2
); );
if (DetermineInstallEraseBlock(ScsiDiskDevice, ScsiDiskDevice->Handle)) { if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
gBS->ReinstallProtocolInterface ( gBS->ReinstallProtocolInterface (
ScsiDiskDevice->Handle, ScsiDiskDevice->Handle,
&gEfiEraseBlockProtocolGuid, &gEfiEraseBlockProtocolGuid,
@ -955,6 +1000,14 @@ ScsiDiskReadBlocksEx (
&ScsiDiskDevice->EraseBlock &ScsiDiskDevice->EraseBlock
); );
} }
if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
gBS->ReinstallProtocolInterface (
ScsiDiskDevice->Handle,
&gEfiStorageSecurityCommandProtocolGuid,
&ScsiDiskDevice->StorageSecurity,
&ScsiDiskDevice->StorageSecurity
);
}
if (Media->MediaPresent) { if (Media->MediaPresent) {
Status = EFI_MEDIA_CHANGED; Status = EFI_MEDIA_CHANGED;
} else { } else {
@ -968,6 +1021,11 @@ ScsiDiskReadBlocksEx (
// //
BlockSize = Media->BlockSize; BlockSize = Media->BlockSize;
if (BlockSize == 0) {
Status = EFI_DEVICE_ERROR;
goto Done;
}
NumberOfBlocks = BufferSize / BlockSize; NumberOfBlocks = BufferSize / BlockSize;
if (!(Media->MediaPresent)) { if (!(Media->MediaPresent)) {
@ -1110,7 +1168,7 @@ ScsiDiskWriteBlocksEx (
&ScsiDiskDevice->BlkIo2, &ScsiDiskDevice->BlkIo2,
&ScsiDiskDevice->BlkIo2 &ScsiDiskDevice->BlkIo2
); );
if (DetermineInstallEraseBlock(ScsiDiskDevice, ScsiDiskDevice->Handle)) { if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
gBS->ReinstallProtocolInterface ( gBS->ReinstallProtocolInterface (
ScsiDiskDevice->Handle, ScsiDiskDevice->Handle,
&gEfiEraseBlockProtocolGuid, &gEfiEraseBlockProtocolGuid,
@ -1118,6 +1176,14 @@ ScsiDiskWriteBlocksEx (
&ScsiDiskDevice->EraseBlock &ScsiDiskDevice->EraseBlock
); );
} }
if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
gBS->ReinstallProtocolInterface (
ScsiDiskDevice->Handle,
&gEfiStorageSecurityCommandProtocolGuid,
&ScsiDiskDevice->StorageSecurity,
&ScsiDiskDevice->StorageSecurity
);
}
if (Media->MediaPresent) { if (Media->MediaPresent) {
Status = EFI_MEDIA_CHANGED; Status = EFI_MEDIA_CHANGED;
} else { } else {
@ -1131,6 +1197,11 @@ ScsiDiskWriteBlocksEx (
// //
BlockSize = Media->BlockSize; BlockSize = Media->BlockSize;
if (BlockSize == 0) {
Status = EFI_DEVICE_ERROR;
goto Done;
}
NumberOfBlocks = BufferSize / BlockSize; NumberOfBlocks = BufferSize / BlockSize;
if (!(Media->MediaPresent)) { if (!(Media->MediaPresent)) {
@ -1263,7 +1334,7 @@ ScsiDiskFlushBlocksEx (
&ScsiDiskDevice->BlkIo2, &ScsiDiskDevice->BlkIo2,
&ScsiDiskDevice->BlkIo2 &ScsiDiskDevice->BlkIo2
); );
if (DetermineInstallEraseBlock(ScsiDiskDevice, ScsiDiskDevice->Handle)) { if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
gBS->ReinstallProtocolInterface ( gBS->ReinstallProtocolInterface (
ScsiDiskDevice->Handle, ScsiDiskDevice->Handle,
&gEfiEraseBlockProtocolGuid, &gEfiEraseBlockProtocolGuid,
@ -1271,6 +1342,14 @@ ScsiDiskFlushBlocksEx (
&ScsiDiskDevice->EraseBlock &ScsiDiskDevice->EraseBlock
); );
} }
if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
gBS->ReinstallProtocolInterface (
ScsiDiskDevice->Handle,
&gEfiStorageSecurityCommandProtocolGuid,
&ScsiDiskDevice->StorageSecurity,
&ScsiDiskDevice->StorageSecurity
);
}
if (Media->MediaPresent) { if (Media->MediaPresent) {
Status = EFI_MEDIA_CHANGED; Status = EFI_MEDIA_CHANGED;
} else { } else {
@ -1644,7 +1723,7 @@ ScsiDiskEraseBlocks (
&ScsiDiskDevice->BlkIo2, &ScsiDiskDevice->BlkIo2,
&ScsiDiskDevice->BlkIo2 &ScsiDiskDevice->BlkIo2
); );
if (DetermineInstallEraseBlock(ScsiDiskDevice, ScsiDiskDevice->Handle)) { if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
gBS->ReinstallProtocolInterface ( gBS->ReinstallProtocolInterface (
ScsiDiskDevice->Handle, ScsiDiskDevice->Handle,
&gEfiEraseBlockProtocolGuid, &gEfiEraseBlockProtocolGuid,
@ -1652,6 +1731,14 @@ ScsiDiskEraseBlocks (
&ScsiDiskDevice->EraseBlock &ScsiDiskDevice->EraseBlock
); );
} }
if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
gBS->ReinstallProtocolInterface (
ScsiDiskDevice->Handle,
&gEfiStorageSecurityCommandProtocolGuid,
&ScsiDiskDevice->StorageSecurity,
&ScsiDiskDevice->StorageSecurity
);
}
Status = EFI_MEDIA_CHANGED; Status = EFI_MEDIA_CHANGED;
goto Done; goto Done;
} }
@ -1708,6 +1795,431 @@ Done:
return Status; 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. Detect Device and read out capacity ,if error occurs, parse the sense key.
@ -1812,6 +2324,15 @@ ScsiDiskDetectMedia (
NeedReadCapacity = TRUE; 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, // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
// retrieve capacity via Read Capacity command // retrieve capacity via Read Capacity command
@ -5358,6 +5879,14 @@ DetermineInstallEraseBlock (
RetVal = TRUE; RetVal = TRUE;
CapacityData16 = NULL; 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 ( Status = gBS->HandleProtocol (
ChildHandle, ChildHandle,
&gEfiDevicePathProtocolGuid, &gEfiDevicePathProtocolGuid,
@ -5460,6 +5989,65 @@ Done:
return RetVal; 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. Provides inquiry information for the controller type.

View File

@ -1,7 +1,7 @@
/** @file /** @file
Header file for SCSI Disk Driver. 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>
SPDX-License-Identifier: BSD-2-Clause-Patent SPDX-License-Identifier: BSD-2-Clause-Patent
**/ **/
@ -22,6 +22,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include <Protocol/ScsiPassThruExt.h> #include <Protocol/ScsiPassThruExt.h>
#include <Protocol/ScsiPassThru.h> #include <Protocol/ScsiPassThru.h>
#include <Protocol/DiskInfo.h> #include <Protocol/DiskInfo.h>
#include <Protocol/StorageSecurityCommand.h>
#include <Library/DebugLib.h> #include <Library/DebugLib.h>
@ -38,6 +39,10 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#define IS_DEVICE_FIXED(a) (a)->FixedDevice ? 1 : 0 #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 { typedef struct {
UINT32 MaxLbaCnt; UINT32 MaxLbaCnt;
UINT32 MaxBlkDespCnt; UINT32 MaxBlkDespCnt;
@ -51,6 +56,8 @@ typedef struct {
EFI_HANDLE Handle; EFI_HANDLE Handle;
EFI_STORAGE_SECURITY_COMMAND_PROTOCOL StorageSecurity;
EFI_BLOCK_IO_PROTOCOL BlkIo; EFI_BLOCK_IO_PROTOCOL BlkIo;
EFI_BLOCK_IO2_PROTOCOL BlkIo2; EFI_BLOCK_IO2_PROTOCOL BlkIo2;
EFI_BLOCK_IO_MEDIA BlkIoMedia; 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_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_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_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) #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. Provides inquiry information for the controller type.
@ -1428,4 +1581,20 @@ DetermineInstallEraseBlock (
IN EFI_HANDLE ChildHandle 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 #endif

View File

@ -3,7 +3,7 @@
# It detects the SCSI disk media and installs Block I/O and Block I/O2 Protocol on # It detects the SCSI disk media and installs Block I/O and Block I/O2 Protocol on
# the device handle. # the device handle.
# #
# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> # Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent # SPDX-License-Identifier: BSD-2-Clause-Patent
# #
## ##
@ -52,6 +52,7 @@
gEfiBlockIoProtocolGuid ## BY_START gEfiBlockIoProtocolGuid ## BY_START
gEfiBlockIo2ProtocolGuid ## BY_START gEfiBlockIo2ProtocolGuid ## BY_START
gEfiEraseBlockProtocolGuid ## BY_START gEfiEraseBlockProtocolGuid ## BY_START
gEfiStorageSecurityCommandProtocolGuid ## BY_START
gEfiScsiIoProtocolGuid ## TO_START gEfiScsiIoProtocolGuid ## TO_START
gEfiScsiPassThruProtocolGuid ## TO_START gEfiScsiPassThruProtocolGuid ## TO_START
gEfiExtScsiPassThruProtocolGuid ## TO_START gEfiExtScsiPassThruProtocolGuid ## TO_START