diff mbox series

ata/scsi: Prevent FS corruption on chromebook pixel2 at reboot

Message ID 20200205184358.116927-1-gwendal@chromium.org (mailing list archive)
State Not Applicable
Headers show
Series ata/scsi: Prevent FS corruption on chromebook pixel2 at reboot | expand

Commit Message

Gwendal Grignou Feb. 5, 2020, 6:43 p.m. UTC
On Samus, even when rebooting, the root device is power cycled.
Normally, during reboot, root device is not power cycled, so the device
does not have to flush its volatle drive cache to permanent media.

However, in case of Samus, given the SSD is power cycled, we force the SSD
to flush its cache by issuing a SCSI START_STOP command, translated into
an ATA STANDBY command.

Reviewed-by: Guenter Roeck <groeck@chromium.org>
Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
---
 drivers/ata/ahci.c         | 25 +++++++++++++++++++++++++
 drivers/scsi/sd.c          |  5 +++--
 include/scsi/scsi_device.h |  1 +
 3 files changed, 29 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index dd92faf197d5e..0677c9f1d14af 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -29,6 +29,7 @@ 
 #include <linux/msi.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
 #include <linux/libata.h>
 #include <linux/ahci-remap.h>
 #include <linux/io-64-nonatomic-lo-hi.h>
@@ -88,6 +89,8 @@  static void ahci_mcp89_apple_enable(struct pci_dev *pdev);
 static bool is_mcp89_apple(struct pci_dev *pdev);
 static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
 				unsigned long deadline);
+static int ahci_slave_configure(struct scsi_device *sdev);
+
 #ifdef CONFIG_PM
 static int ahci_pci_device_runtime_suspend(struct device *dev);
 static int ahci_pci_device_runtime_resume(struct device *dev);
@@ -99,6 +102,7 @@  static int ahci_pci_device_resume(struct device *dev);
 
 static struct scsi_host_template ahci_sht = {
 	AHCI_SHT("ahci"),
+	.slave_configure	= ahci_slave_configure,
 };
 
 static struct ata_port_operations ahci_vt8251_ops = {
@@ -1398,6 +1402,27 @@  static inline void ahci_gtf_filter_workaround(struct ata_host *host)
 {}
 #endif
 
+static int ahci_slave_configure(struct scsi_device *sdev)
+{
+	/*
+	 * Machines cutting power to the SSD during a warm reboot must send
+	 * a STANDBY_IMMEDIATE before to prevent unclean shutdown of the disk.
+	 */
+	static struct dmi_system_id sysids[] = {
+		{
+			/* x86-samus, the Chromebook Pixel 2. */
+			.matches = {
+				DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
+				DMI_MATCH(DMI_PRODUCT_NAME, "Samus"),
+			},
+		},
+		{ /* sentinel */ }
+	};
+	if (dmi_check_system(sysids))
+		sdev->send_stop_reboot = 1;
+	return ata_scsi_slave_config(sdev);
+}
+
 /*
  * On the Acer Aspire Switch Alpha 12, sometimes all SATA ports are detected
  * as DUMMY, or detected but eventually get a "link down" and never get up
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 5abdf03083ae8..248e04cc46a9e 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -3533,8 +3533,9 @@  static void sd_shutdown(struct device *dev)
 		sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n");
 		sd_sync_cache(sdkp, NULL);
 	}
-
-	if (system_state != SYSTEM_RESTART && sdkp->device->manage_start_stop) {
+	if ((sdkp->device->send_stop_reboot ||
+	     system_state != SYSTEM_RESTART) &&
+	    sdkp->device->manage_start_stop) {
 		sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n");
 		sd_start_stop_device(sdkp, 0);
 	}
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 202f4d6a43421..eca9e5cf281f2 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -199,6 +199,7 @@  struct scsi_device {
 	unsigned broken_fua:1;		/* Don't set FUA bit */
 	unsigned lun_in_cdb:1;		/* Store LUN bits in CDB[1] */
 	unsigned unmap_limit_for_ws:1;	/* Use the UNMAP limit for WRITE SAME */
+	unsigned send_stop_reboot:1;	/* Send START_STOP_UNIT at reboot */
 
 	atomic_t disk_events_disable_depth; /* disable depth for disk events */