Skip to contentSkip to conversation

libata: reimplement suspend/resume support and fix spindown on poweroff

PATCH In review Tejun Heo 3 participants 9 messages May 4, 2007 – May 11, 2007

Subsystems (2)
lore
Share & tools
lore

Tejun Heo

author
#0 lore raw

PATCH 1/1 libata: reimplement suspend/resume support and fix spindown on poweroff

Hello,

This is another take at using sdev->manage_start_stop to reimplement suspend/resume and fix spindown on poweroff. As Robert pointed out in the other thread[1], sadly, ATA spec does NOT require cache flush on standby and some distros don't flush cache prior to put the drive into standby mode during shutdown. This means that we can't skip cache flush in the kernel shutdown path because data loss is possible. Also, we just can't switch to new method because there are drives which spin up if told to spin down while it's already spun down.

So, that leaves us with migrating to new behavior (kernel side sync/shutdown) while maintaining backward compatibility. This patchset tries to do that by supplying a scheduled-to-be-removed module parameter libata.spindown_compat which defaults to 1. When set, it makes libata skip spindown during shutdown sequence thus maintaining the old behavior of issuing only cache flush on shutdown.

So, distros should update their shutdown(8) to do the followings.

* Check whether /sys/modules/libata/parameters/spindown_compat exists. If it does, write 0 to it.

* For each libata harddisk {
* Check whether /sys/class/scsi_disk/h:c:i:l/manage_start_stop exists. Iff it doesn't, synchronize cache and spin the disk down as before.
}

If shutdown(8) does the above, nothing will change on older kernels (some drives will spin up and have to do emergency unload but they aren't too many) and everything should work properly on kernels with spindown_compat or later ones which won't have it. If shutdown(8) isn't updated, the kernel will behave the same way as older kernels would.

To accelerate userland update, if shutdown(8) isn't updated (spindown_compat not cleared), libata will complain loudly about it, point the user to http://linux-ata.org/shutdown.html (which should be written) and pause for 5 seconds during shutdown. Hopefully, this makes the users bug distros sufficiently so that userland tools can be updated quickly. Note that the pausing happens only during shutdown not during reboot or suspend, so it shouldn't be too much of annoyance.

This change requires sdev->manage_start_stop updates from scsi-misc-2.6.
The merged git tree can be found at...

http://htj.dyndns.org/git/?p=libata-tj.git;a=shortlog;h=spindown
git://htj.dyndns.org/libata-tj spindown

Thanks.

Signature · 3 lines
tejun

[1] http://thread.gmane.org/gmane.linux.ide/18167
author
#1 lore raw

PATCH 1/2 libata: reimplement suspend/resume support using sdev->manage_start_stop

Reimplement suspend/resume support using sdev->manage_start_stop.

* Device suspend/resume is now SCSI layer's responsibility and the code is simplified a lot.

* DPM is dropped. This also simplifies code a lot. Suspend/resume status is port-wide now.

* ata_scsi_device_suspend/resume() and ata_dev_ready() removed.

* Resume now has to wait for disk to spin up before proceeding. I couldn't find easy way out as libata is in EH waiting for the disk to be ready and sd is waiting for EH to complete to issue START_STOP.

* sdev->manage_start_stop is set to 1 in ata_scsi_slave_config(). This fixes spindown on shutdown and suspend-to-disk.

---
 drivers/ata/ahci.c              |    4 -
 drivers/ata/ata_generic.c       |    6 +-
 drivers/ata/ata_piix.c          |    4 -
 drivers/ata/libata-core.c       |   39 +------
 drivers/ata/libata-eh.c         |  237 +--------------------------------------
 drivers/ata/libata-scsi.c       |  129 +---------------------
 drivers/ata/pata_ali.c          |    4 -
 drivers/ata/pata_amd.c          |    4 -
 drivers/ata/pata_atiixp.c       |    4 -
 drivers/ata/pata_cmd640.c       |    4 -
 drivers/ata/pata_cmd64x.c       |    4 -
 drivers/ata/pata_cs5520.c       |    4 -
 drivers/ata/pata_cs5530.c       |    4 -
 drivers/ata/pata_cs5535.c       |    4 -
 drivers/ata/pata_cypress.c      |    4 -
 drivers/ata/pata_efar.c         |    4 -
 drivers/ata/pata_hpt366.c       |    4 -
 drivers/ata/pata_hpt3x3.c       |    4 -
 drivers/ata/pata_it8213.c       |    4 -
 drivers/ata/pata_it821x.c       |    4 -
 drivers/ata/pata_ixp4xx_cf.c    |    2 +-
 drivers/ata/pata_jmicron.c      |    4 -
 drivers/ata/pata_marvell.c      |    4 -
 drivers/ata/pata_mpc52xx.c      |    4 -
 drivers/ata/pata_mpiix.c        |    4 -
 drivers/ata/pata_netcell.c      |    4 -
 drivers/ata/pata_ns87410.c      |    4 -
 drivers/ata/pata_oldpiix.c      |    4 -
 drivers/ata/pata_opti.c         |    4 -
 drivers/ata/pata_optidma.c      |    4 -
 drivers/ata/pata_pdc202xx_old.c |    4 -
 drivers/ata/pata_radisys.c      |    4 -
 drivers/ata/pata_rz1000.c       |    6 +-
 drivers/ata/pata_sc1200.c       |    4 -
 drivers/ata/pata_scc.c          |    4 -
 drivers/ata/pata_serverworks.c  |    4 -
 drivers/ata/pata_sil680.c       |    4 -
 drivers/ata/pata_sis.c          |    4 -
 drivers/ata/pata_triflex.c      |    4 -
 drivers/ata/pata_via.c          |    4 -
 drivers/ata/sata_inic162x.c     |    4 -
 drivers/ata/sata_nv.c           |    8 --
 drivers/ata/sata_sil.c          |    4 -
 drivers/ata/sata_sil24.c        |    4 -
 include/linux/libata.h          |   14 +--
 45 files changed, 14 insertions(+), 575 deletions(-)
drivers/ata/ahci.c +0 -4
index 34c5534..d730291 100644
@@ -250,10 +250,6 @@ static struct scsi_host_template ahci_sh
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.suspend		= ata_scsi_device_suspend,
-	.resume			= ata_scsi_device_resume,
-#endif
 };
 
 static const struct ata_port_operations ahci_ops = {
drivers/ata/ata_generic.c +1 -5
index 92a491d..0f19e32 100644
@@ -54,7 +54,7 @@ static int generic_set_mode(struct ata_p
 
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
 		struct ata_device *dev = &ap->device[i];
-		if (ata_dev_ready(dev)) {
+		if (ata_dev_enabled(dev)) {
 			/* We don't really care */
 			dev->pio_mode = XFER_PIO_0;
 			dev->dma_mode = XFER_MW_DMA_0;
@@ -90,10 +90,6 @@ static struct scsi_host_template generic
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static struct ata_port_operations generic_port_ops = {
drivers/ata/ata_piix.c +0 -4
index 55d306a..8421742 100644
@@ -275,10 +275,6 @@ static struct scsi_host_template piix_sh
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static const struct ata_port_operations piix_pata_ops = {
drivers/ata/libata-core.c +4 -35
index ca67484..ce5e080 100644
@@ -2858,7 +2858,7 @@ int ata_do_set_mode(struct ata_port *ap,
 		dev = &ap->device[i];
 
 		/* don't update suspended devices' xfer mode */
-		if (!ata_dev_ready(dev))
+		if (!ata_dev_enabled(dev))
 			continue;
 
 		rc = ata_dev_set_mode(dev);
@@ -5793,37 +5793,11 @@ static int ata_host_request_pm(struct at
  */
 int ata_host_suspend(struct ata_host *host, pm_message_t mesg)
 {
-	int i, j, rc;
+	int rc;
 
 	rc = ata_host_request_pm(host, mesg, 0, ATA_EHI_QUIET, 1);
-	if (rc)
-		goto fail;
-
-	/* EH is quiescent now.  Fail if we have any ready device.
-	 * This happens if hotplug occurs between completion of device
-	 * suspension and here.
-	 */
-	for (i = 0; i < host->n_ports; i++) {
-		struct ata_port *ap = host->ports[i];
-
-		for (j = 0; j < ATA_MAX_DEVICES; j++) {
-			struct ata_device *dev = &ap->device[j];
-
-			if (ata_dev_ready(dev)) {
-				ata_port_printk(ap, KERN_WARNING,
-						"suspend failed, device %d "
-						"still active\n", dev->devno);
-				rc = -EBUSY;
-				goto fail;
-			}
-		}
-	}
-
-	host->dev->power.power_state = mesg;
-	return 0;
-
- fail:
-	ata_host_resume(host);
+	if (rc == 0)
+		host->dev->power.power_state = mesg;
 	return rc;
 }
 
@@ -6836,11 +6810,6 @@ EXPORT_SYMBOL_GPL(ata_pci_default_filter
 EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
 #endif /* CONFIG_PCI */
 
-#ifdef CONFIG_PM
-EXPORT_SYMBOL_GPL(ata_scsi_device_suspend);
-EXPORT_SYMBOL_GPL(ata_scsi_device_resume);
-#endif /* CONFIG_PM */
-
 EXPORT_SYMBOL_GPL(ata_eng_timeout);
 EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
 EXPORT_SYMBOL_GPL(ata_port_abort);
drivers/ata/libata-eh.c +4 -233

307 lines not on this page · raw message

drivers/ata/libata-scsi.c +2 -127

141 lines not on this page · raw message

drivers/ata/pata_ali.c +0 -4
index d40edeb..48c7531 100644
@@ -291,10 +291,6 @@ static struct scsi_host_template ali_sht
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 /*
drivers/ata/pata_amd.c +0 -4
index 536ee89..23903c8 100644
@@ -323,10 +323,6 @@ static struct scsi_host_template amd_sht
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static struct ata_port_operations amd33_port_ops = {
drivers/ata/pata_atiixp.c +0 -4
index 39c871a..b4048f0 100644
@@ -229,10 +229,6 @@ static struct scsi_host_template atiixp_
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static struct ata_port_operations atiixp_port_ops = {
drivers/ata/pata_cmd640.c +0 -4
index 2105985..987dec9 100644
@@ -181,10 +181,6 @@ static struct scsi_host_template cmd640_
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static struct ata_port_operations cmd640_port_ops = {
drivers/ata/pata_cmd64x.c +0 -4
index 3989cc5..3e02c6a 100644
@@ -266,10 +266,6 @@ static struct scsi_host_template cmd64x_
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static struct ata_port_operations cmd64x_port_ops = {
drivers/ata/pata_cs5520.c +0 -4
index 79bef0d..83bcc5b 100644
@@ -155,10 +155,6 @@ static struct scsi_host_template cs5520_
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static struct ata_port_operations cs5520_port_ops = {
drivers/ata/pata_cs5530.c +0 -4
index 29642d5..637d8b3 100644
@@ -176,10 +176,6 @@ static struct scsi_host_template cs5530_
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static struct ata_port_operations cs5530_port_ops = {
drivers/ata/pata_cs5535.c +0 -4
index 08cccc9..54586ac 100644
@@ -172,10 +172,6 @@ static struct scsi_host_template cs5535_
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static struct ata_port_operations cs5535_port_ops = {
drivers/ata/pata_cypress.c +0 -4
index 6ec049c..30e5c54 100644
@@ -125,10 +125,6 @@ static struct scsi_host_template cy82c69
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static struct ata_port_operations cy82c693_port_ops = {
drivers/ata/pata_efar.c +0 -4
index a321685..38411f2 100644
@@ -246,10 +246,6 @@ static struct scsi_host_template efar_sh
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static const struct ata_port_operations efar_ops = {
drivers/ata/pata_hpt366.c +0 -4
index 93cfa6d..c412a9a 100644
@@ -331,10 +331,6 @@ static struct scsi_host_template hpt36x_
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 /*
drivers/ata/pata_hpt3x3.c +0 -4
index ac28ec8..84c636b 100644
@@ -100,10 +100,6 @@ static struct scsi_host_template hpt3x3_
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static struct ata_port_operations hpt3x3_port_ops = {
drivers/ata/pata_it8213.c +0 -4
index 011306e..e1bd263 100644
@@ -255,10 +255,6 @@ static struct scsi_host_template it8213_
 	.dma_boundary		= ATA_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static const struct ata_port_operations it8213_ops = {
drivers/ata/pata_it821x.c +0 -4
index f1f8cec..8e565a5 100644
@@ -620,10 +620,6 @@ static struct scsi_host_template it821x_
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static struct ata_port_operations it821x_smart_port_ops = {
drivers/ata/pata_ixp4xx_cf.c +1 -1
index 420c343..b994351 100644
@@ -31,7 +31,7 @@ static int ixp4xx_set_mode(struct ata_po
 
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
 		struct ata_device *dev = &ap->device[i];
-		if (ata_dev_ready(dev)) {
+		if (ata_dev_enabled(dev)) {
 			ata_dev_printk(dev, KERN_INFO, "configured for PIO0\n");
 			dev->pio_mode = XFER_PIO_0;
 			dev->xfer_mode = XFER_PIO_0;
drivers/ata/pata_jmicron.c +0 -4
index 43763c9..e3f6f5d 100644
@@ -137,10 +137,6 @@ static struct scsi_host_template jmicron
 	.slave_destroy		= ata_scsi_slave_destroy,
 	/* Use standard CHS mapping rules */
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.suspend		= ata_scsi_device_suspend,
-	.resume			= ata_scsi_device_resume,
-#endif
 };
 
 static const struct ata_port_operations jmicron_ops = {
drivers/ata/pata_marvell.c +0 -4
index d9b94a1..4c282ab 100644
@@ -104,10 +104,6 @@ static struct scsi_host_template marvell
 	.slave_destroy		= ata_scsi_slave_destroy,
 	/* Use standard CHS mapping rules */
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static const struct ata_port_operations marvell_ops = {
drivers/ata/pata_mpc52xx.c +0 -4
index 9587a89..368fac7 100644
@@ -280,10 +280,6 @@ static struct scsi_host_template mpc52xx
 	.dma_boundary		= ATA_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.suspend		= ata_scsi_device_suspend,
-	.resume			= ata_scsi_device_resume,
-#endif
 };
 
 static struct ata_port_operations mpc52xx_ata_port_ops = {
drivers/ata/pata_mpiix.c +0 -4
index 987c5fa..2858927 100644
@@ -164,10 +164,6 @@ static struct scsi_host_template mpiix_s
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static struct ata_port_operations mpiix_port_ops = {
drivers/ata/pata_netcell.c +0 -4
index dbba5b7..f15eb34 100644
@@ -37,10 +37,6 @@ static struct scsi_host_template netcell
 	.slave_destroy		= ata_scsi_slave_destroy,
 	/* Use standard CHS mapping rules */
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static const struct ata_port_operations netcell_ops = {
drivers/ata/pata_ns87410.c +0 -4
index 078aeda..2147172 100644
@@ -156,10 +156,6 @@ static struct scsi_host_template ns87410
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static struct ata_port_operations ns87410_port_ops = {
drivers/ata/pata_oldpiix.c +0 -4
index dea4690..9cc1d1e 100644
@@ -232,10 +232,6 @@ static struct scsi_host_template oldpiix
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static const struct ata_port_operations oldpiix_pata_ops = {
drivers/ata/pata_opti.c +0 -4
index 13b63e2..af00c26 100644
@@ -177,10 +177,6 @@ static struct scsi_host_template opti_sh
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static struct ata_port_operations opti_port_ops = {
drivers/ata/pata_optidma.c +0 -4
index b70e04c..d1569a7 100644
@@ -362,10 +362,6 @@ static struct scsi_host_template optidma
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static struct ata_port_operations optidma_port_ops = {
drivers/ata/pata_pdc202xx_old.c +0 -4
index ee636be..3e204c3 100644
@@ -244,10 +244,6 @@ static struct scsi_host_template pdc202x
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static struct ata_port_operations pdc2024x_port_ops = {
drivers/ata/pata_radisys.c +0 -4
index 1c54673..bc01b17 100644
@@ -200,10 +200,6 @@ static struct scsi_host_template radisys
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static const struct ata_port_operations radisys_pata_ops = {
drivers/ata/pata_rz1000.c +1 -5
index 85c4529..97785b4 100644
@@ -40,7 +40,7 @@ static int rz1000_set_mode(struct ata_po
 
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
 		struct ata_device *dev = &ap->device[i];
-		if (ata_dev_ready(dev)) {
+		if (ata_dev_enabled(dev)) {
 			/* We don't really care */
 			dev->pio_mode = XFER_PIO_0;
 			dev->xfer_mode = XFER_PIO_0;
@@ -69,10 +69,6 @@ static struct scsi_host_template rz1000_
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static struct ata_port_operations rz1000_port_ops = {
drivers/ata/pata_sc1200.c +0 -4
index 66e8ff4..2af9f8c 100644
@@ -194,10 +194,6 @@ static struct scsi_host_template sc1200_
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static struct ata_port_operations sc1200_port_ops = {
drivers/ata/pata_scc.c +0 -4
index 5df354d..243130e 100644
@@ -984,10 +984,6 @@ static struct scsi_host_template scc_sht
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static const struct ata_port_operations scc_pata_ops = {
drivers/ata/pata_serverworks.c +0 -4
index 3956ef2..fdd9a63 100644
@@ -313,10 +313,6 @@ static struct scsi_host_template serverw
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static struct ata_port_operations serverworks_osb4_port_ops = {
drivers/ata/pata_sil680.c +0 -4
index 6770820..8978186 100644
@@ -230,10 +230,6 @@ static struct scsi_host_template sil680_
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.suspend		= ata_scsi_device_suspend,
-	.resume			= ata_scsi_device_resume,
-#endif
 };
 
 static struct ata_port_operations sil680_port_ops = {
drivers/ata/pata_sis.c +0 -4
index a3fbcee..1d7dc0c 100644
@@ -520,10 +520,6 @@ static struct scsi_host_template sis_sht
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static const struct ata_port_operations sis_133_ops = {
drivers/ata/pata_triflex.c +0 -4
index e618ffd..33a1663 100644
@@ -192,10 +192,6 @@ static struct scsi_host_template triflex
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static struct ata_port_operations triflex_port_ops = {
drivers/ata/pata_via.c +0 -4
index 96b7179..969b98f 100644
@@ -300,10 +300,6 @@ static struct scsi_host_template via_sht
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.resume			= ata_scsi_device_resume,
-	.suspend		= ata_scsi_device_suspend,
-#endif
 };
 
 static struct ata_port_operations via_port_ops = {
drivers/ata/sata_inic162x.c +0 -4
index f099a1d..4c12d92 100644
@@ -135,10 +135,6 @@ static struct scsi_host_template inic_sh
 	.slave_configure	= inic_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.suspend		= ata_scsi_device_suspend,
-	.resume			= ata_scsi_device_resume,
-#endif
 };
 
 static const int scr_map[] = {
drivers/ata/sata_nv.c +0 -8
index 0216974..087f84b 100644
@@ -323,10 +323,6 @@ static struct scsi_host_template nv_sht
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.suspend		= ata_scsi_device_suspend,
-	.resume			= ata_scsi_device_resume,
-#endif
 };
 
 static struct scsi_host_template nv_adma_sht = {
@@ -345,10 +341,6 @@ static struct scsi_host_template nv_adma
 	.slave_configure	= nv_adma_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.suspend		= ata_scsi_device_suspend,
-	.resume			= ata_scsi_device_resume,
-#endif
 };
 
 static const struct ata_port_operations nv_generic_ops = {
drivers/ata/sata_sil.c +0 -4
index 0a1e417..e8483aa 100644
@@ -182,10 +182,6 @@ static struct scsi_host_template sil_sht
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.suspend		= ata_scsi_device_suspend,
-	.resume			= ata_scsi_device_resume,
-#endif
 };
 
 static const struct ata_port_operations sil_ops = {
drivers/ata/sata_sil24.c +0 -4
index e6223ba..b1945e6 100644
@@ -380,10 +380,6 @@ static struct scsi_host_template sil24_s
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
-#ifdef CONFIG_PM
-	.suspend		= ata_scsi_device_suspend,
-	.resume			= ata_scsi_device_resume,
-#endif
 };
 
 static const struct ata_port_operations sil24_ops = {
include/linux/libata.h +1 -13
index d8cfc72..c6745e6 100644
@@ -140,7 +140,6 @@ enum {
 
 	ATA_DFLAG_PIO		= (1 << 8), /* device limited to PIO mode */
 	ATA_DFLAG_NCQ_OFF	= (1 << 9), /* device limited to non-NCQ mode */
-	ATA_DFLAG_SUSPENDED	= (1 << 10), /* device suspended */
 	ATA_DFLAG_INIT_MASK	= (1 << 16) - 1,
 
 	ATA_DFLAG_DETACH	= (1 << 16),
@@ -268,13 +267,9 @@ enum {
 	ATA_EH_REVALIDATE	= (1 << 0),
 	ATA_EH_SOFTRESET	= (1 << 1),
 	ATA_EH_HARDRESET	= (1 << 2),
-	ATA_EH_SUSPEND		= (1 << 3),
-	ATA_EH_RESUME		= (1 << 4),
-	ATA_EH_PM_FREEZE	= (1 << 5),
 
 	ATA_EH_RESET_MASK	= ATA_EH_SOFTRESET | ATA_EH_HARDRESET,
-	ATA_EH_PERDEV_MASK	= ATA_EH_REVALIDATE | ATA_EH_SUSPEND |
-				  ATA_EH_RESUME | ATA_EH_PM_FREEZE,
+	ATA_EH_PERDEV_MASK	= ATA_EH_REVALIDATE,
 
 	/* ata_eh_info->flags */
 	ATA_EHI_HOTPLUGGED	= (1 << 0),  /* could have been hotplugged */
@@ -742,8 +737,6 @@ extern int sata_scr_write_flush(struct a
 extern int ata_port_online(struct ata_port *ap);
 extern int ata_port_offline(struct ata_port *ap);
 #ifdef CONFIG_PM
-extern int ata_scsi_device_resume(struct scsi_device *);
-extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t mesg);
 extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg);
 extern void ata_host_resume(struct ata_host *host);
 #endif
@@ -1018,11 +1011,6 @@ static inline unsigned int ata_dev_absen
 	return ata_class_absent(dev->class);
 }
 
-static inline unsigned int ata_dev_ready(const struct ata_device *dev)
-{
-	return ata_dev_enabled(dev) && !(dev->flags & ATA_DFLAG_SUSPENDED);
-}
-
 /*
  * port helpers
  */
Signature · 1 line
1.4.3.4
#2 lore raw

Re: [PATCH 1/2] libata: reimplement suspend/resume support using sdev->manage_start_stop

Quoted 15 lines · Tejun Heo

Reimplement suspend/resume support using sdev->manage_start_stop.

* Device suspend/resume is now SCSI layer's responsibility and the code is simplified a lot.

* DPM is dropped. This also simplifies code a lot. Suspend/resume status is port-wide now.

* ata_scsi_device_suspend/resume() and ata_dev_ready() removed.

* Resume now has to wait for disk to spin up before proceeding. I couldn't find easy way out as libata is in EH waiting for the disk to be ready and sd is waiting for EH to complete to issue START_STOP.

Quoted 4 lines

* sdev->manage_start_stop is set to 1 in ata_scsi_slave_config(). This fixes spindown on shutdown and suspend-to-disk.

applied patches 1-2, but explicitly did not send them upstream today.

I'm hoping we can get this into 2.6.22 -- but also expose it in -mm for a few days as well.

I agree it is important to fix this issue.

Jeff

author
#3 lore raw

Re: [PATCH 1/2] libata: reimplement suspend/resume support using sdev->manage_start_stop

Quoted 19 lines · Jeff Garzik
Quoted 18 lines · Tejun Heo

Reimplement suspend/resume support using sdev->manage_start_stop.

* Device suspend/resume is now SCSI layer's responsibility and the code is simplified a lot.

* DPM is dropped. This also simplifies code a lot. Suspend/resume status is port-wide now.

* ata_scsi_device_suspend/resume() and ata_dev_ready() removed.

* Resume now has to wait for disk to spin up before proceeding. I couldn't find easy way out as libata is in EH waiting for the disk to be ready and sd is waiting for EH to complete to issue START_STOP.

* sdev->manage_start_stop is set to 1 in ata_scsi_slave_config(). This fixes spindown on shutdown and suspend-to-disk.

Quoted 6 lines
Quoted 1 line

applied patches 1-2, but explicitly did not send them upstream today.

I'm hoping we can get this into 2.6.22 -- but also expose it in -mm for a few days as well.

Okay, will prepare the scary webpage then.

Signature · 1 line
tejun
#4 lore raw

Re: [PATCH 1/2] libata: reimplement suspend/resume support using sdev->manage_start_stop

Quoted 20 lines · Tejun Heo
Quoted 19 lines · Jeff Garzik
Quoted 18 lines · Tejun Heo

Reimplement suspend/resume support using sdev->manage_start_stop.

* Device suspend/resume is now SCSI layer's responsibility and the code is simplified a lot.

* DPM is dropped. This also simplifies code a lot. Suspend/resume status is port-wide now.

* ata_scsi_device_suspend/resume() and ata_dev_ready() removed.

* Resume now has to wait for disk to spin up before proceeding. I couldn't find easy way out as libata is in EH waiting for the disk to be ready and sd is waiting for EH to complete to issue START_STOP.

* sdev->manage_start_stop is set to 1 in ata_scsi_slave_config(). This fixes spindown on shutdown and suspend-to-disk.

Quoted 7 lines
Quoted 5 lines
Quoted 1 line

applied patches 1-2, but explicitly did not send them upstream today.

I'm hoping we can get this into 2.6.22 -- but also expose it in -mm for a few days as well.

Okay, will prepare the scary webpage then.

huh?

Jeff

author
#5 lore raw

PATCH 2/2 libata: implement libata.spindown_compat

In reply to Tejun Heo

Now that libata uses sd->manage_start_stop, libata spins down disk on shutdown. In an attempt to compensate libata's previous shortcoming, some distros sync and spin down disks attached via libata in their shutdown(8). Some disks spin back up just to spin down again on STANDBYNOW1 if the command is issued when the disk is spun down, so this double spinning down causes problem.

This patch implements module parameter libata.spindown_compat which, when set to one (default value), prevents libata from spinning down disks on shutdown thus avoiding double spinning down. Note that libata spins down disks for suspend to mem and disk, so with libata.spindown_compat set to one, disks should be properly spun down in all cases without modifying shutdown(8).

shutdown(8) should be fixed eventually. Some drive do spin up on SYNCHRONZE_CACHE even when their cache is clean. Those disks currently spin up briefly when sd tries to shutdown the device and then the machine powers off immediately, which can't be good for the head. We can't skip SYNCHRONIZE_CACHE during shudown as it can be dangerous data integrity-wise.

So, this spindown_compat parameter is already scheduled for removal by the end of the next year and here's what shutdown(8) should do.

* Check whether /sys/modules/libata/parameters/spindown_compat exists. If it does, write 0 to it.

* For each libata harddisk {
* Check whether /sys/class/scsi_disk/h:c:i:l/manage_start_stop exists. Iff it doesn't, synchronize cache and spin the disk down as before.
}

The above procedure will make shutdown(8) work properly with kernels before this change, ones with this workaround and later ones without it.

To accelerate shutdown(8) updates, if the compat mode is in use, this patch prints BIG FAT warning for five seconds during shutdown (the optimal interval to annoy the user just the right amount discovered by hours of tireless usability testing).

---
 Documentation/feature-removal-schedule.txt |   19 +++++++++++++++++++
 drivers/ata/libata-core.c                  |    6 ++++++
 drivers/ata/libata-scsi.c                  |   28 +++++++++++++++++++++++++++-
 drivers/ata/libata.h                       |    1 +
 4 files changed, 53 insertions(+), 1 deletions(-)
Documentation/feature-removal-schedule.txt +19 -0
index 5c88ba1..78b3aa6 100644
@@ -314,3 +314,22 @@ Why:	Code was merged, then submitter imm
 Who:	David S. Miller <[email protected]>
 
 ---------------------------
+
+What:	libata.spindown_compat module parameter
+When:	Dec 2008
+Why:	halt(8) synchronizes caches for and spins down libata disks
+	because libata didn't use to spin down disk on system halt
+	(only synchronized caches).
+	Spin down on system halt is now implemented and can be tested
+	using sysfs node /sys/class/scsi_disk/h:c:i:l/manage_start_stop.
+	Because issuing spin down command to an already spun down disk
+	makes some disks spin up just to spin down again, the old
+	behavior needs to be maintained till userspace tool is updated
+	to check the sysfs node and not to spin down disks with the
+	node set to one.
+	This module parameter is to give userspace tool the time to
+	get updated and should be removed after userspace is
+	reasonably updated.
+Who:	Tejun Heo <[email protected]>
+
+---------------------------
drivers/ata/libata-core.c +6 -0
index ce5e080..4a81549 100644
@@ -101,6 +101,12 @@ int libata_noacpi = 1;
 module_param_named(noacpi, libata_noacpi, int, 0444);
 MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in suspend/resume when set");
 
+int ata_spindown_compat = 1;
+module_param_named(spindown_compat, ata_spindown_compat, int, 0644);
+MODULE_PARM_DESC(spindown_compat, "Enable backward compatible spindown "
+		 "behavior.  Will be removed.  More info can be found in "
+		 "Documentation/feature-removal-schedule.txt\n");
+
 MODULE_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("Library module for ATA devices");
 MODULE_LICENSE("GPL");
drivers/ata/libata-scsi.c +27 -1
index 8f80019..dd81fa7 100644
@@ -944,9 +944,35 @@ static unsigned int ata_scsi_start_stop_
 		}
 
 		tf->command = ATA_CMD_VERIFY;	/* READ VERIFY */
-	} else
+	} else {
+		/* XXX: This is for backward compatibility, will be
+		 * removed.  Read Documentation/feature-removal-schedule.txt
+		 * for more info.
+		 */
+		if (ata_spindown_compat &&
+		    (system_state == SYSTEM_HALT ||
+		     system_state == SYSTEM_POWER_OFF)) {
+			static int warned = 0;
+
+			if (!warned) {
+				spin_unlock_irq(qc->ap->lock);
+				ata_dev_printk(qc->dev, KERN_WARNING,
+					"DISK MIGHT NOT BE SPUN DOWN PROPERLY. "
+					"UPDATE SHUTDOWN UTILITY\n");
+				ata_dev_printk(qc->dev, KERN_WARNING,
+					"For more info, visit "
+					"http://linux-ata.org/shutdown.html\n");
+				warned = 1;
+				ssleep(5);
+				spin_lock_irq(qc->ap->lock);
+			}
+			scmd->result = SAM_STAT_GOOD;
+			return 1;
+		}
+
 		/* Issue ATA STANDBY IMMEDIATE command */
 		tf->command = ATA_CMD_STANDBYNOW1;
+	}
 
 	/*
 	 * Standby and Idle condition timers could be implemented but that
drivers/ata/libata.h +1 -0
index 5f4d40c..316bf8a 100644
@@ -58,6 +58,7 @@ extern int atapi_enabled;
 extern int atapi_dmadir;
 extern int libata_fua;
 extern int libata_noacpi;
+extern int ata_spindown_compat;
 extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev);
 extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
 			   u64 block, u32 n_block, unsigned int tf_flags,
Signature · 1 line
1.4.3.4
#6 lore raw
In reply to Tejun Heo

Doesn't apply to today Linus' git tree:

[fcomolli@tycho linux-2.6]$ git pull git://htj.dyndns.org/libata-tj spindown
remote: Generating pack...
remote: Done counting 14283 objects.
remote: Result has 11254 objects.
remote: Deltifying 11254 objects.
remote: 100% (11254/11254) done
Indexing 11254 objects.
remote: Total 11254 (delta 9842), reused 11241 (delta 9832)
100% (11254/11254) done
Resolving 9842 deltas.
100% (9842/9842) done
1948 objects were added to complete this thin pack.
100% (44114/44114) done
Auto-merged Documentation/feature-removal-schedule.txt
CONFLICT (content): Merge conflict in Documentation/feature-removal-schedule.txt Automatic merge failed; fix conflicts and then commit the result.

I don't know git enough to identify the conflict. Can anyone help me?

Thanks in advance.
Fabio

Quoted 56 lines · Tejun Heo

Hello,

This is another take at using sdev->manage_start_stop to reimplement suspend/resume and fix spindown on poweroff. As Robert pointed out in the other thread[1], sadly, ATA spec does NOT require cache flush on standby and some distros don't flush cache prior to put the drive into standby mode during shutdown. This means that we can't skip cache flush in the kernel shutdown path because data loss is possible. Also, we just can't switch to new method because there are drives which spin up if told to spin down while it's already spun down.

So, that leaves us with migrating to new behavior (kernel side sync/shutdown) while maintaining backward compatibility. This patchset tries to do that by supplying a scheduled-to-be-removed module parameter libata.spindown_compat which defaults to 1. When set, it makes libata skip spindown during shutdown sequence thus maintaining the old behavior of issuing only cache flush on shutdown.

So, distros should update their shutdown(8) to do the followings.

* Check whether /sys/modules/libata/parameters/spindown_compat exists. If it does, write 0 to it.

* For each libata harddisk {
* Check whether /sys/class/scsi_disk/h:c:i:l/manage_start_stop exists. Iff it doesn't, synchronize cache and spin the disk down as before.
}

If shutdown(8) does the above, nothing will change on older kernels (some drives will spin up and have to do emergency unload but they aren't too many) and everything should work properly on kernels with spindown_compat or later ones which won't have it. If shutdown(8) isn't updated, the kernel will behave the same way as older kernels would.

To accelerate userland update, if shutdown(8) isn't updated (spindown_compat not cleared), libata will complain loudly about it, point the user to http://linux-ata.org/shutdown.html (which should be written) and pause for 5 seconds during shutdown. Hopefully, this makes the users bug distros sufficiently so that userland tools can be updated quickly. Note that the pausing happens only during shutdown not during reboot or suspend, so it shouldn't be too much of annoyance.

This change requires sdev->manage_start_stop updates from scsi-misc-2.6.
The merged git tree can be found at...

http://htj.dyndns.org/git/?p=libata-tj.git;a=shortlog;h=spindown
git://htj.dyndns.org/libata-tj spindown

Thanks.

--
tejun

[1] http://thread.gmane.org/gmane.linux.ide/18167

author
#7 lore raw
Quoted 21 lines · Fabio Comolli

Doesn't apply to today Linus' git tree:

[fcomolli@tycho linux-2.6]$ git pull git://htj.dyndns.org/libata-tj
spindown
remote: Generating pack...
remote: Done counting 14283 objects.
remote: Result has 11254 objects.
remote: Deltifying 11254 objects.
remote: 100% (11254/11254) done
Indexing 11254 objects.
remote: Total 11254 (delta 9842), reused 11241 (delta 9832) 100% (11254/11254) done
Resolving 9842 deltas.
100% (9842/9842) done
1948 objects were added to complete this thin pack.
100% (44114/44114) done
Auto-merged Documentation/feature-removal-schedule.txt CONFLICT (content): Merge conflict in Documentation/feature-removal-schedule.txt
Automatic merge failed; fix conflicts and then commit the result.

Quoted 1 line

I don't know git enough to identify the conflict. Can anyone help me?

That's a conflict in feature-removal-schedule.txt document. Open the file, look for <<<< or >>>> and fix them up, do "git-update-index Documentation/feature-removal-schedule.txt" followed by "git commit" and you should be done. Alternatively, you can just test the spindown branch as-is by doing 'git-fetch git://htj.dyndns.org/libata-tj
spindown:spindown', then 'git checkout spindown'.

Signature · 1 line
tejun
#8 lore raw
In reply to Fabio Comolli

OK, your instructions worked fine. I tested 4 combinations:

* libata.spindown_compat=1 (default): the "pop" remains with and without the "-n"
parameter added to the halt command;
* libata.spindown_compat=0: no "pop" with and without the "-n" parameter added to the halt command.

As I read somewhere (maybe on lkml, I don't remember) that the "-n" parameter was necessary to silence the "pop", I tried the old IDE layer without the "-n" and it works the same as libata.

The conclusion is that your patch works (if the parameter is set to 0).

Hope this helps. Regards,
Fabio

Quoted 84 lines · Fabio Comolli

Doesn't apply to today Linus' git tree:

[fcomolli@tycho linux-2.6]$ git pull git://htj.dyndns.org/libata-tj spindown
remote: Generating pack...
remote: Done counting 14283 objects.
remote: Result has 11254 objects.
remote: Deltifying 11254 objects.
remote: 100% (11254/11254) done
Indexing 11254 objects.
remote: Total 11254 (delta 9842), reused 11241 (delta 9832)
100% (11254/11254) done
Resolving 9842 deltas.
100% (9842/9842) done
1948 objects were added to complete this thin pack.
100% (44114/44114) done
Auto-merged Documentation/feature-removal-schedule.txt
CONFLICT (content): Merge conflict in Documentation/feature-removal-schedule.txt Automatic merge failed; fix conflicts and then commit the result.

I don't know git enough to identify the conflict. Can anyone help me?

Thanks in advance.
Fabio

Quoted 56 lines · Tejun Heo

Hello,

This is another take at using sdev->manage_start_stop to reimplement suspend/resume and fix spindown on poweroff. As Robert pointed out in the other thread[1], sadly, ATA spec does NOT require cache flush on standby and some distros don't flush cache prior to put the drive into standby mode during shutdown. This means that we can't skip cache flush in the kernel shutdown path because data loss is possible. Also, we just can't switch to new method because there are drives which spin up if told to spin down while it's already spun down.

So, that leaves us with migrating to new behavior (kernel side sync/shutdown) while maintaining backward compatibility. This patchset tries to do that by supplying a scheduled-to-be-removed module parameter libata.spindown_compat which defaults to 1. When set, it makes libata skip spindown during shutdown sequence thus maintaining the old behavior of issuing only cache flush on shutdown.

So, distros should update their shutdown(8) to do the followings.

* Check whether /sys/modules/libata/parameters/spindown_compat exists. If it does, write 0 to it.

* For each libata harddisk {
* Check whether /sys/class/scsi_disk/h:c:i:l/manage_start_stop exists. Iff it doesn't, synchronize cache and spin the disk down as before.
}

If shutdown(8) does the above, nothing will change on older kernels (some drives will spin up and have to do emergency unload but they aren't too many) and everything should work properly on kernels with spindown_compat or later ones which won't have it. If shutdown(8) isn't updated, the kernel will behave the same way as older kernels would.

To accelerate userland update, if shutdown(8) isn't updated (spindown_compat not cleared), libata will complain loudly about it, point the user to http://linux-ata.org/shutdown.html (which should be written) and pause for 5 seconds during shutdown. Hopefully, this makes the users bug distros sufficiently so that userland tools can be updated quickly. Note that the pausing happens only during shutdown not during reboot or suspend, so it shouldn't be too much of annoyance.

This change requires sdev->manage_start_stop updates from scsi-misc-2.6.
The merged git tree can be found at...

http://htj.dyndns.org/git/?p=libata-tj.git;a=shortlog;h=spindown
git://htj.dyndns.org/libata-tj spindown

Thanks.

--
tejun

[1] http://thread.gmane.org/gmane.linux.ide/18167