MdeModulePkg/ScsiDiskDxe: Check Write Caching and FUA support Check Write Caching and FUA support of the storage, then save the result if both are disabled. Signed-off-by: Annie Li <annie.li@oracle.com>
diff --git a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c index cf688d6..8e9fe50 100644 --- a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c +++ b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
@@ -337,6 +337,7 @@ ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt = 1; ScsiDiskDevice->BlockLimitsVpdSupported = FALSE; ScsiDiskDevice->Handle = Controller; + ScsiDiskDevice->FuaMode = TRUE; InitializeListHead (&ScsiDiskDevice->AsyncTaskQueue); ScsiIo->GetDeviceType (ScsiIo, &(ScsiDiskDevice->DeviceType)); @@ -2537,6 +2538,18 @@ } } + // + // Get FUA Mode + // + for (Retry = 0; Retry < MaxRetry; Retry++) { + if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_DISK) { + Status = ScsiDiskFuaMode (ScsiDiskDevice); + if (!EFI_ERROR (Status)) { + break; + } + } + } + if (ScsiDiskDevice->BlkIo.Media->MediaId != OldMedia.MediaId) { // // Media change information got from the device @@ -4400,6 +4413,95 @@ } /** + Get FUA Mode for the storage. + + @param ScsiDiskDevice The pointer of SCSI_DISK_DEV. + + @return EFI_STATUS is returned by calling ScsiDiskFuaMode(). +**/ +EFI_STATUS +ScsiDiskFuaMode ( + IN SCSI_DISK_DEV *ScsiDiskDevice + ) +{ + UINT8 HostAdapterStatus; + UINT8 TargetStatus; + UINT8 SenseDataLength; + UINT8 Buffer[CACHE_MODE_PAGE_LEN]; + UINT32 BufferLength; + EFI_STATUS ReturnStatus; + BOOLEAN DpoFua; + BOOLEAN WriteCaching; + + SenseDataLength = 0; + BufferLength = CACHE_MODE_PAGE_LEN; + DpoFua = TRUE; + WriteCaching = TRUE; + // + // Execute Mode Sense Command here to get the support of FUA + // through Mode page. FUA support locates in Mode parameter + // header that can be gotten through any Mode page. + // Here, Caching Mode Page (08) is used. + // + ReturnStatus = ScsiModeSense10Command ( + ScsiDiskDevice->ScsiIo, + SCSI_DISK_TIMEOUT, + NULL, + &SenseDataLength, + &HostAdapterStatus, + &TargetStatus, + Buffer, + &BufferLength, + 1, // Not return any block descriptors + 0x10, // Default threshold values + 0x08 // Caching Mode Page (08h) + ); + if (ReturnStatus != EFI_SUCCESS) { + // + // Mode Sense Command fails + // + return EFI_DEVICE_ERROR; + } + + // + // Page code locates at the byte 8(bit0 to bit5), + // byte 0 after the 8 bytes Mode parameter header(10). + // + if ((Buffer[8] & 0x08) != 0x08) { + // + // Return page is not right + // + return EFI_DEVICE_ERROR; + } + + // + // DPOFUA locates at the byte 3(bit4) in + // the Mode parameter header(10). + // + if ((Buffer[3] & 0x10) == 0x00) { + // + // 'DPOFUA' is disabled + // + DpoFua = FALSE; + } + + // + // Caching Mode locates at the byte 10(bit2), + // byte 2 after the 8 bytes Mode parameter header(10). + // + if ((Buffer[10] & 0x04) == 0x00) { + // + // 'write through' cache is enabled. + // + WriteCaching = FALSE; + } + + ScsiDiskDevice->FuaMode = DpoFua || WriteCaching; + + return EFI_SUCCESS; +} + +/** Submit Write(10) Command. @param ScsiDiskDevice The pointer of ScsiDiskDevice
diff --git a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h index 63d3447..a1fab62 100644 --- a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h +++ b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h
@@ -92,6 +92,11 @@ // The queue for asynchronous task requests // LIST_ENTRY AsyncTaskQueue; + + // + // The flag indicates FUA support + // + BOOLEAN FuaMode; } SCSI_DISK_DEV; #define SCSI_DISK_DEV_FROM_BLKIO(a) CR (a, SCSI_DISK_DEV, BlkIo, SCSI_DISK_DEV_SIGNATURE) @@ -193,6 +198,13 @@ // #define SCSI_DISK_TIMEOUT EFI_TIMER_PERIOD_SECONDS (30) +// +// The length of Mode parameter header(10) is 8 bytes. The +// length of Caching Mode page is 20 bytes. Without block +// descriptors, the buffer for Caching Mode page is 28. +// +#define CACHE_MODE_PAGE_LEN 28 + /** Test to see if this driver supports ControllerHandle. @@ -1590,3 +1602,14 @@ IN SCSI_DISK_DEV *ScsiDiskDevice, IN EFI_HANDLE ChildHandle ); + +/** + Get FUA Mode for the storage. + + @param ScsiDiskDevice The pointer of SCSI_DISK_DEV. + +**/ +EFI_STATUS +ScsiDiskFuaMode ( + IN SCSI_DISK_DEV *ScsiDiskDevice + );