From 754b489b46fa2c940f90b4048cc868991cda92a2 Mon Sep 17 00:00:00 2001 From: Tian Feng Date: Tue, 16 Jun 2015 01:04:47 +0000 Subject: [PATCH] MdeModulePkg/NvmExpressDxe: Add SecurityStorageProtocol support Produce this protocol for each namespace at NVMe controller. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Tian Feng Reviewed-by: Star Zeng git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17638 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Bus/Pci/NvmExpressDxe/NvmExpress.c | 68 +++- .../Bus/Pci/NvmExpressDxe/NvmExpress.h | 39 ++- .../Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.c | 326 ++++++++++++++++++ .../Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.h | 160 ++++++++- .../Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf | 1 + .../Bus/Pci/NvmExpressDxe/NvmExpressHci.c | 8 +- .../Bus/Pci/NvmExpressDxe/NvmExpressHci.h | 32 +- .../Pci/NvmExpressDxe/NvmExpressPassthru.c | 36 +- 8 files changed, 628 insertions(+), 42 deletions(-) diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c index d107d96387..9938bf4541 100644 --- a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c +++ b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c @@ -154,6 +154,12 @@ EnumerateNvmeDevNamespace ( Device->BlockIo.WriteBlocks = NvmeBlockIoWriteBlocks; Device->BlockIo.FlushBlocks = NvmeBlockIoFlushBlocks; + // + // Create StorageSecurityProtocol Instance + // + Device->StorageSecurity.ReceiveData = NvmeStorageSecurityReceiveData; + Device->StorageSecurity.SendData = NvmeStorageSecuritySendData; + // // Create DiskInfo Protocol instance // @@ -211,6 +217,32 @@ EnumerateNvmeDevNamespace ( if(EFI_ERROR(Status)) { goto Exit; } + + // + // Check if the NVMe controller supports the Security Send and Security Receive commands + // + if ((Private->ControllerData->Oacs & SECURITY_SEND_RECEIVE_SUPPORTED) != 0) { + Status = gBS->InstallProtocolInterface ( + &Device->DeviceHandle, + &gEfiStorageSecurityCommandProtocolGuid, + EFI_NATIVE_INTERFACE, + &Device->StorageSecurity + ); + if(EFI_ERROR(Status)) { + gBS->UninstallMultipleProtocolInterfaces ( + &Device->DeviceHandle, + &gEfiDevicePathProtocolGuid, + Device->DevicePath, + &gEfiBlockIoProtocolGuid, + &Device->BlockIo, + &gEfiDiskInfoProtocolGuid, + &Device->DiskInfo, + NULL + ); + goto Exit; + } + } + gBS->OpenProtocol ( Private->ControllerHandle, &gEfiNvmExpressPassThruProtocolGuid, @@ -339,6 +371,7 @@ UnregisterNvmeNamespace ( EFI_BLOCK_IO_PROTOCOL *BlockIo; NVME_DEVICE_PRIVATE_DATA *Device; NVME_CONTROLLER_PRIVATE_DATA *Private; + EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *StorageSecurity; BlockIo = NULL; @@ -394,6 +427,37 @@ UnregisterNvmeNamespace ( return Status; } + // + // If Storage Security Command Protocol is installed, then uninstall this protocol. + // + Status = gBS->OpenProtocol ( + Handle, + &gEfiStorageSecurityCommandProtocolGuid, + (VOID **) &StorageSecurity, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (!EFI_ERROR (Status)) { + Status = gBS->UninstallProtocolInterface ( + Handle, + &gEfiStorageSecurityCommandProtocolGuid, + &Device->StorageSecurity + ); + if (EFI_ERROR (Status)) { + gBS->OpenProtocol ( + Controller, + &gEfiNvmExpressPassThruProtocolGuid, + (VOID **) &Private->Passthru, + This->DriverBindingHandle, + Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + return Status; + } + } + if(Device->DevicePath != NULL) { FreePool (Device->DevicePath); } @@ -480,8 +544,8 @@ NvmExpressDriverBindingSupported ( if ((DevicePathNode.DevPath->Type != MESSAGING_DEVICE_PATH) || (DevicePathNode.DevPath->SubType != MSG_NVME_NAMESPACE_DP) || - DevicePathNodeLength(DevicePathNode.DevPath) != sizeof(NVME_NAMESPACE_DEVICE_PATH)) { - return EFI_UNSUPPORTED; + (DevicePathNodeLength(DevicePathNode.DevPath) != sizeof(NVME_NAMESPACE_DEVICE_PATH))) { + return EFI_UNSUPPORTED; } } } diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.h b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.h index 54baac6f00..21c6255caa 100644 --- a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.h +++ b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -152,29 +153,30 @@ struct _NVME_CONTROLLER_PRIVATE_DATA { // Nvme device private data structure // struct _NVME_DEVICE_PRIVATE_DATA { - UINT32 Signature; + UINT32 Signature; - EFI_HANDLE DeviceHandle; - EFI_HANDLE ControllerHandle; - EFI_HANDLE DriverBindingHandle; + EFI_HANDLE DeviceHandle; + EFI_HANDLE ControllerHandle; + EFI_HANDLE DriverBindingHandle; - EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; - EFI_UNICODE_STRING_TABLE *ControllerNameTable; + EFI_UNICODE_STRING_TABLE *ControllerNameTable; - UINT32 NamespaceId; - UINT64 NamespaceUuid; + UINT32 NamespaceId; + UINT64 NamespaceUuid; - EFI_BLOCK_IO_MEDIA Media; - EFI_BLOCK_IO_PROTOCOL BlockIo; - EFI_DISK_INFO_PROTOCOL DiskInfo; + EFI_BLOCK_IO_MEDIA Media; + EFI_BLOCK_IO_PROTOCOL BlockIo; + EFI_DISK_INFO_PROTOCOL DiskInfo; + EFI_STORAGE_SECURITY_COMMAND_PROTOCOL StorageSecurity; - EFI_LBA NumBlocks; + EFI_LBA NumBlocks; - CHAR16 ModelName[80]; - NVME_ADMIN_NAMESPACE_DATA NamespaceData; + CHAR16 ModelName[80]; + NVME_ADMIN_NAMESPACE_DATA NamespaceData; - NVME_CONTROLLER_PRIVATE_DATA *Controller; + NVME_CONTROLLER_PRIVATE_DATA *Controller; }; @@ -195,6 +197,13 @@ struct _NVME_DEVICE_PRIVATE_DATA { NVME_DEVICE_PRIVATE_DATA_SIGNATURE \ ) +#define NVME_DEVICE_PRIVATE_DATA_FROM_STORAGE_SECURITY(a)\ + CR (a, \ + NVME_DEVICE_PRIVATE_DATA, \ + StorageSecurity, \ + NVME_DEVICE_PRIVATE_DATA_SIGNATURE \ + ) + /** Retrieves a Unicode string that is the user readable name of the driver. diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.c b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.c index e7d7651322..6cb2f92e8d 100644 --- a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.c +++ b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.c @@ -345,6 +345,10 @@ NvmeBlockIoReset ( Status = NvmeControllerInit (Private); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + } + gBS->RestoreTPL (OldTpl); return Status; @@ -555,3 +559,325 @@ NvmeBlockIoFlushBlocks ( return Status; } + +/** + Trust transfer data from/to NVMe device. + + This function performs one NVMe transaction to do a trust transfer from/to NVMe device. + + @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure. + @param Buffer The pointer to the current transaction buffer. + @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 TransferLength The block number or sector count of the transfer. + @param IsTrustSend Indicates whether it is a trust send operation or not. + @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 TransferLengthOut A pointer to a buffer to store the size in bytes of the data + written to the buffer. Ignore it when IsTrustSend is TRUE. + + @retval EFI_SUCCESS The data transfer is complete successfully. + @return others Some error occurs when transferring data. + +**/ +EFI_STATUS +TrustTransferNvmeDevice ( + IN OUT NVME_CONTROLLER_PRIVATE_DATA *Private, + IN OUT VOID *Buffer, + IN UINT8 SecurityProtocolId, + IN UINT16 SecurityProtocolSpecificData, + IN UINTN TransferLength, + IN BOOLEAN IsTrustSend, + IN UINT64 Timeout, + OUT UINTN *TransferLengthOut + ) +{ + EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket; + EFI_NVM_EXPRESS_COMMAND Command; + EFI_NVM_EXPRESS_COMPLETION Completion; + EFI_STATUS Status; + UINT16 SpecificData; + + ZeroMem (&CommandPacket, sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET)); + ZeroMem (&Command, sizeof (EFI_NVM_EXPRESS_COMMAND)); + ZeroMem (&Completion, sizeof (EFI_NVM_EXPRESS_COMPLETION)); + + CommandPacket.NvmeCmd = &Command; + CommandPacket.NvmeCompletion = &Completion; + + // + // Change Endianness of SecurityProtocolSpecificData + // + SpecificData = (((SecurityProtocolSpecificData << 8) & 0xFF00) | (SecurityProtocolSpecificData >> 8)); + + if (IsTrustSend) { + Command.Cdw0.Opcode = NVME_ADMIN_SECURITY_SEND_CMD; + CommandPacket.TransferBuffer = Buffer; + CommandPacket.TransferLength = (UINT32)TransferLength; + CommandPacket.NvmeCmd->Cdw10 = (UINT32)((SecurityProtocolId << 24) | (SpecificData << 8)); + CommandPacket.NvmeCmd->Cdw11 = (UINT32)TransferLength; + } else { + Command.Cdw0.Opcode = NVME_ADMIN_SECURITY_RECEIVE_CMD; + CommandPacket.TransferBuffer = Buffer; + CommandPacket.TransferLength = (UINT32)TransferLength; + CommandPacket.NvmeCmd->Cdw10 = (UINT32)((SecurityProtocolId << 24) | (SpecificData << 8)); + CommandPacket.NvmeCmd->Cdw11 = (UINT32)TransferLength; + } + + CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID; + CommandPacket.NvmeCmd->Nsid = NVME_CONTROLLER_ID; + CommandPacket.CommandTimeout = Timeout; + CommandPacket.QueueType = NVME_ADMIN_QUEUE; + + Status = Private->Passthru.PassThru ( + &Private->Passthru, + NVME_CONTROLLER_ID, + &CommandPacket, + NULL + ); + + if (!IsTrustSend) { + if (EFI_ERROR (Status)) { + *TransferLengthOut = 0; + } else { + *TransferLengthOut = (UINTN) TransferLength; + } + } + + 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. + + For devices supporting the ATA command set, the security protocol command is sent + using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize + is non-zero. + + If the PayloadBufferSize is zero, the security protocol command is sent using the + Trusted Non-Data command defined in ATA8-ACS. + + 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 +NvmeStorageSecurityReceiveData ( + IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This, + IN UINT32 MediaId, + IN UINT64 Timeout, + IN UINT8 SecurityProtocolId, + IN UINT16 SecurityProtocolSpecificData, + IN UINTN PayloadBufferSize, + OUT VOID *PayloadBuffer, + OUT UINTN *PayloadTransferSize + ) +{ + EFI_STATUS Status; + NVME_DEVICE_PRIVATE_DATA *Device; + + Status = EFI_SUCCESS; + + if ((PayloadBuffer == NULL) || (PayloadTransferSize == NULL) || (PayloadBufferSize == 0)) { + return EFI_INVALID_PARAMETER; + } + + Device = NVME_DEVICE_PRIVATE_DATA_FROM_STORAGE_SECURITY (This); + + if (MediaId != Device->BlockIo.Media->MediaId) { + return EFI_MEDIA_CHANGED; + } + + if (!Device->BlockIo.Media->MediaPresent) { + return EFI_NO_MEDIA; + } + + Status = TrustTransferNvmeDevice ( + Device->Controller, + PayloadBuffer, + SecurityProtocolId, + SecurityProtocolSpecificData, + PayloadBufferSize, + FALSE, + Timeout, + PayloadTransferSize + ); + + 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. + + For devices supporting the ATA command set, the security protocol command is sent + using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize + is non-zero. If the PayloadBufferSize is zero, the security protocol command is + sent using the Trusted Non-Data command defined in ATA8-ACS. + + 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 send 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 +NvmeStorageSecuritySendData ( + IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This, + IN UINT32 MediaId, + IN UINT64 Timeout, + IN UINT8 SecurityProtocolId, + IN UINT16 SecurityProtocolSpecificData, + IN UINTN PayloadBufferSize, + IN VOID *PayloadBuffer + ) +{ + EFI_STATUS Status; + NVME_DEVICE_PRIVATE_DATA *Device; + + Status = EFI_SUCCESS; + + if ((PayloadBuffer == NULL) && (PayloadBufferSize != 0)) { + return EFI_INVALID_PARAMETER; + } + + Device = NVME_DEVICE_PRIVATE_DATA_FROM_STORAGE_SECURITY (This); + + if (MediaId != Device->BlockIo.Media->MediaId) { + return EFI_MEDIA_CHANGED; + } + + if (!Device->BlockIo.Media->MediaPresent) { + return EFI_NO_MEDIA; + } + + Status = TrustTransferNvmeDevice ( + Device->Controller, + PayloadBuffer, + SecurityProtocolId, + SecurityProtocolSpecificData, + PayloadBufferSize, + TRUE, + Timeout, + NULL + ); + + return Status; +} + + + + diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.h b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.h index 5f896fed81..1c71a81ec5 100644 --- a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.h +++ b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.h @@ -1,7 +1,7 @@ /** @file Header file for EFI_BLOCK_IO_PROTOCOL interface. -Copyright (c) 2013, Intel Corporation. All rights reserved.
+Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.
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 @@ -108,4 +108,162 @@ NvmeBlockIoFlushBlocks ( IN EFI_BLOCK_IO_PROTOCOL *This ); +/** + 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. + + For devices supporting the ATA command set, the security protocol command is sent + using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize + is non-zero. + + If the PayloadBufferSize is zero, the security protocol command is sent using the + Trusted Non-Data command defined in ATA8-ACS. + + 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 +NvmeStorageSecurityReceiveData ( + IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This, + IN UINT32 MediaId, + 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. + + For devices supporting the ATA command set, the security protocol command is sent + using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize + is non-zero. If the PayloadBufferSize is zero, the security protocol command is + sent using the Trusted Non-Data command defined in ATA8-ACS. + + 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 +NvmeStorageSecuritySendData ( + IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This, + IN UINT32 MediaId, + IN UINT64 Timeout, + IN UINT8 SecurityProtocolId, + IN UINT16 SecurityProtocolSpecificData, + IN UINTN PayloadBufferSize, + IN VOID *PayloadBuffer + ); + #endif diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf index f73d6af8af..00acf2b5cf 100644 --- a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf +++ b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf @@ -68,6 +68,7 @@ gEfiNvmExpressPassThruProtocolGuid ## BY_START gEfiBlockIoProtocolGuid ## BY_START gEfiDiskInfoProtocolGuid ## BY_START + gEfiStorageSecurityCommandProtocolGuid ## BY_START gEfiDriverSupportedEfiVersionProtocolGuid ## PRODUCES # [Event] diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.c b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.c index e35f3c0751..f6b6288f65 100644 --- a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.c +++ b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.c @@ -582,7 +582,7 @@ NvmeIdentifyController ( ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND)); ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION)); - Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_OPC; + Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_CMD; // // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h. // For the Identify command, the Namespace Identifier is only used for the Namespace data structure. @@ -641,7 +641,7 @@ NvmeIdentifyNamespace ( CommandPacket.NvmeCmd = &Command; CommandPacket.NvmeCompletion = &Completion; - Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_OPC; + Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_CMD; Command.Nsid = NamespaceId; CommandPacket.TransferBuffer = Buffer; CommandPacket.TransferLength = sizeof (NVME_ADMIN_NAMESPACE_DATA); @@ -691,7 +691,7 @@ NvmeCreateIoCompletionQueue ( CommandPacket.NvmeCmd = &Command; CommandPacket.NvmeCompletion = &Completion; - Command.Cdw0.Opcode = NVME_ADMIN_CRIOCQ_OPC; + Command.Cdw0.Opcode = NVME_ADMIN_CRIOCQ_CMD; CommandPacket.TransferBuffer = Private->CqBufferPciAddr[1]; CommandPacket.TransferLength = EFI_PAGE_SIZE; CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT; @@ -741,7 +741,7 @@ NvmeCreateIoSubmissionQueue ( CommandPacket.NvmeCmd = &Command; CommandPacket.NvmeCompletion = &Completion; - Command.Cdw0.Opcode = NVME_ADMIN_CRIOSQ_OPC; + Command.Cdw0.Opcode = NVME_ADMIN_CRIOSQ_CMD; CommandPacket.TransferBuffer = Private->SqBufferPciAddr[1]; CommandPacket.TransferLength = EFI_PAGE_SIZE; CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT; diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.h b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.h index aa0ac35c30..06c1db7d8e 100644 --- a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.h +++ b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.h @@ -2,7 +2,7 @@ NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows NVM Express specification. - Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.
+ Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.
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 @@ -348,6 +348,10 @@ typedef struct { // Admin Command Set Attributes // UINT16 Oacs; /* Optional Admin Command Support */ + #define NAMESPACE_MANAGEMENT_SUPPORTED BIT3 + #define FW_DOWNLOAD_ACTIVATE_SUPPORTED BIT2 + #define FORMAT_NVM_SUPPORTED BIT1 + #define SECURITY_SEND_RECEIVE_SUPPORTED BIT0 UINT8 Acl; /* Abort Command Limit */ UINT8 Aerl; /* Async Event Request Limit */ UINT8 Frmw; /* Firmware updates */ @@ -556,9 +560,9 @@ typedef struct { // CDW 10 // UINT32 Lid:8; /* Log Page Identifier */ - #define LID_ERROR_INFO - #define LID_SMART_INFO - #define LID_FW_SLOT_INFO + #define LID_ERROR_INFO 0x1 + #define LID_SMART_INFO 0x2 + #define LID_FW_SLOT_INFO 0x3 UINT32 Rsvd1:8; UINT32 Numd:12; /* Number of Dwords */ UINT32 Rsvd2:4; /* Reserved as of Nvm Express 1.1 Spec */ @@ -724,9 +728,23 @@ typedef struct { // // Nvm Express Admin cmd opcodes // -#define NVME_ADMIN_CRIOSQ_OPC 1 -#define NVME_ADMIN_CRIOCQ_OPC 5 -#define NVME_ADMIN_IDENTIFY_OPC 6 +#define NVME_ADMIN_DEIOSQ_CMD 0x00 +#define NVME_ADMIN_CRIOSQ_CMD 0x01 +#define NVME_ADMIN_GET_LOG_PAGE_CMD 0x02 +#define NVME_ADMIN_DEIOCQ_CMD 0x04 +#define NVME_ADMIN_CRIOCQ_CMD 0x05 +#define NVME_ADMIN_IDENTIFY_CMD 0x06 +#define NVME_ADMIN_ABORT_CMD 0x08 +#define NVME_ADMIN_SET_FEATURES_CMD 0x09 +#define NVME_ADMIN_GET_FEATURES_CMD 0x0A +#define NVME_ADMIN_ASYNC_EVENT_REQUEST_CMD 0x0C +#define NVME_ADMIN_NAMESACE_MANAGEMENT_CMD 0x0D +#define NVME_ADMIN_FW_COMMIT_CMD 0x10 +#define NVME_ADMIN_FW_IAMGE_DOWNLOAD_CMD 0x11 +#define NVME_ADMIN_NAMESACE_ATTACHMENT_CMD 0x15 +#define NVME_ADMIN_FORMAT_NVM_CMD 0x80 +#define NVME_ADMIN_SECURITY_SEND_CMD 0x81 +#define NVME_ADMIN_SECURITY_RECEIVE_CMD 0x82 #define NVME_IO_FLUSH_OPC 0 #define NVME_IO_WRITE_OPC 1 diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c index d37194a910..f9871527dd 100644 --- a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c +++ b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c @@ -433,7 +433,7 @@ NvmExpressPassThru ( // these two cmds are special which requires their data buffer must support simultaneous access by both the // processor and a PCI Bus Master. It's caller's responsbility to ensure this. // - if (((Sq->Opc & (BIT0 | BIT1)) != 0) && (Sq->Opc != NVME_ADMIN_CRIOCQ_OPC) && (Sq->Opc != NVME_ADMIN_CRIOSQ_OPC)) { + if (((Sq->Opc & (BIT0 | BIT1)) != 0) && (Sq->Opc != NVME_ADMIN_CRIOCQ_CMD) && (Sq->Opc != NVME_ADMIN_CRIOSQ_CMD)) { if ((Sq->Opc & BIT0) != 0) { Flag = EfiPciIoOperationBusMasterRead; } else { @@ -567,22 +567,32 @@ NvmExpressPassThru ( } } + // + // Check the NVMe cmd execution result + // + if (Status != EFI_TIMEOUT) { + if ((Cq->Sct == 0) && (Cq->Sc == 0)) { + Status = EFI_SUCCESS; + } else { + Status = EFI_DEVICE_ERROR; + // + // Copy the Respose Queue entry for this command to the callers response buffer + // + CopyMem(Packet->NvmeCompletion, Cq, sizeof(EFI_NVM_EXPRESS_COMPLETION)); + + // + // Dump every completion entry status for debugging. + // + DEBUG_CODE_BEGIN(); + NvmeDumpStatus(Cq); + DEBUG_CODE_END(); + } + } + if ((Private->CqHdbl[QueueType].Cqh ^= 1) == 0) { Private->Pt[QueueType] ^= 1; } - // - // Copy the Respose Queue entry for this command to the callers response buffer - // - CopyMem(Packet->NvmeCompletion, Cq, sizeof(EFI_NVM_EXPRESS_COMPLETION)); - - // - // Dump every completion entry status for debugging. - // - DEBUG_CODE_BEGIN(); - NvmeDumpStatus(Cq); - DEBUG_CODE_END(); - Data = ReadUnaligned32 ((UINT32*)&Private->CqHdbl[QueueType]); PciIo->Mem.Write ( PciIo,