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

+  );