[ltp] [PATCH] 2.6.18: Unload disks heads before powering down

Henrique de Moraes Holschuh linux-thinkpad@linux-thinkpad.org
Sat, 23 Sep 2006 16:29:32 -0300


--vkogqOf2sHV7VnPd
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Here is a first version of the patch for 2.6.18.

S4 is untested.  S5 in ata_piix *is* tested, and seems to work fine.

Original author of these patches: 
Randy Dunlap <randy_d_dunlap@linux.intel.com>

2.6.18 libata EH forward port, and to blame for any bugs:
Henrique de Moraes Holschuh <hmh@hmh.eng.br>.

I will send the patches to Randy Dunlap to see what he thinks of them.

-- 
  "One disk to rule them all, One disk to find them. One disk to bring
  them all and in the darkness grind them. In the Land of Redmond
  where the shadows lie." -- The Silicon Valley Tarot
  Henrique Holschuh

--vkogqOf2sHV7VnPd
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="libata-s5-shutdown-all.patch"

Index: 2.6.18/drivers/scsi/scsi_sysfs.c
===================================================================
--- 2.6.18.orig/drivers/scsi/scsi_sysfs.c
+++ 2.6.18/drivers/scsi/scsi_sysfs.c
@@ -303,11 +303,28 @@ static int scsi_bus_resume(struct device
 	return err;
 }
 
+static void scsi_bus_shutdown(struct device * dev)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+	struct scsi_host_template *sht = sdev->host->hostt;
+	int err;
+
+	err = scsi_device_quiesce(sdev);
+	if (err)
+		printk(KERN_DEBUG "%s: error (0x%x) during shutdown\n",
+			__FUNCTION__, err);
+
+	if (sht->shutdown)
+		err = sht->shutdown(sdev);
+
+}
+
 struct bus_type scsi_bus_type = {
         .name		= "scsi",
         .match		= scsi_bus_match,
 	.suspend	= scsi_bus_suspend,
 	.resume		= scsi_bus_resume,
+	.shutdown	= scsi_bus_shutdown,
 };
 
 int scsi_sysfs_register(void)
Index: 2.6.18/include/scsi/scsi_host.h
===================================================================
--- 2.6.18.orig/include/scsi/scsi_host.h
+++ 2.6.18/include/scsi/scsi_host.h
@@ -286,6 +286,7 @@ struct scsi_host_template {
 	 */
 	int (*resume)(struct scsi_device *);
 	int (*suspend)(struct scsi_device *, pm_message_t state);
+	int (*shutdown)(struct scsi_device *);
 
 	/*
 	 * Name of proc directory
Index: 2.6.18/drivers/scsi/libata-core.c
===================================================================
--- 2.6.18.orig/drivers/scsi/libata-core.c
+++ 2.6.18/drivers/scsi/libata-core.c
@@ -6008,6 +6008,7 @@ EXPORT_SYMBOL_GPL(ata_pci_clear_simplex)
 
 EXPORT_SYMBOL_GPL(ata_scsi_device_suspend);
 EXPORT_SYMBOL_GPL(ata_scsi_device_resume);
+EXPORT_SYMBOL_GPL(ata_scsi_device_shutdown);
 
 EXPORT_SYMBOL_GPL(ata_eng_timeout);
 EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
Index: 2.6.18/drivers/scsi/libata-scsi.c
===================================================================
--- 2.6.18.orig/drivers/scsi/libata-scsi.c
+++ 2.6.18/drivers/scsi/libata-scsi.c
@@ -523,6 +523,52 @@ int ata_scsi_device_resume(struct scsi_d
 }
 
 /**
+ *	ata_scsi_device_shutdown - prepares ATA device associated
+ *	with sdev for shutdown
+ *	@sdev: the SCSI device to resume
+ *
+ *	Request suspend EH action on the ATA device associated
+ *	with @sdev in order to flush its cache and unload heads,
+ *	and wait for the operation to complete.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0.
+ */
+int ata_scsi_device_shutdown(struct scsi_device *sdev)
+{
+	struct ata_port *ap = ata_shost_to_port(sdev->host);
+	struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
+	unsigned long flags;
+	unsigned int action;
+
+	if (!dev)
+		return 0;
+
+	/* if @sdev is already detached, nothing to do */
+	if (sdev->sdev_state == SDEV_OFFLINE ||
+	    sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
+		return 0;
+
+	spin_lock_irqsave(ap->lock, flags);
+
+	/* request suspend to flush cache and unload device heads */
+	action = ATA_EH_SUSPEND;
+	ap->eh_info.dev_action[dev->devno] |= action;
+	ap->eh_info.flags |= ATA_EHI_QUIET;
+	ata_port_schedule_eh(ap);
+
+	spin_unlock_irqrestore(ap->lock, flags);
+
+	/* wait for EH to do the job */
+	ata_port_wait_eh(ap);
+
+	return 0;
+}
+
+/**
  *	ata_to_sense_error - convert ATA error to SCSI error
  *	@id: ATA device number
  *	@drv_stat: value contained in ATA status register
Index: 2.6.18/include/linux/libata.h
===================================================================
--- 2.6.18.orig/include/linux/libata.h
+++ 2.6.18/include/linux/libata.h
@@ -698,6 +698,7 @@ extern int ata_port_online(struct ata_po
 extern int ata_port_offline(struct ata_port *ap);
 extern int ata_scsi_device_resume(struct scsi_device *);
 extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t state);
+extern int ata_scsi_device_shutdown(struct scsi_device *);
 extern int ata_host_set_suspend(struct ata_host_set *host_set,
 				pm_message_t mesg);
 extern void ata_host_set_resume(struct ata_host_set *host_set);
Index: 2.6.18/drivers/scsi/ata_piix.c
===================================================================
--- 2.6.18.orig/drivers/scsi/ata_piix.c
+++ 2.6.18/drivers/scsi/ata_piix.c
@@ -229,6 +229,7 @@ static struct scsi_host_template piix_sh
 	.bios_param		= ata_std_bios_param,
 	.resume			= ata_scsi_device_resume,
 	.suspend		= ata_scsi_device_suspend,
+	.shutdown		= ata_scsi_device_shutdown,
 };
 
 static const struct ata_port_operations piix_pata_ops = {
Index: 2.6.18/drivers/scsi/sata_sil.c
===================================================================
--- 2.6.18.orig/drivers/scsi/sata_sil.c
+++ 2.6.18/drivers/scsi/sata_sil.c
@@ -183,6 +183,7 @@ static struct scsi_host_template sil_sht
 	.bios_param		= ata_std_bios_param,
 	.suspend		= ata_scsi_device_suspend,
 	.resume			= ata_scsi_device_resume,
+	.shutdown		= ata_scsi_device_shutdown,
 };
 
 static const struct ata_port_operations sil_ops = {
Index: 2.6.18/drivers/scsi/sata_sil24.c
===================================================================
--- 2.6.18.orig/drivers/scsi/sata_sil24.c
+++ 2.6.18/drivers/scsi/sata_sil24.c
@@ -378,6 +378,7 @@ static struct scsi_host_template sil24_s
 	.bios_param		= ata_std_bios_param,
 	.suspend		= ata_scsi_device_suspend,
 	.resume			= ata_scsi_device_resume,
+	.shutdown		= ata_scsi_device_shutdown,
 };
 
 static const struct ata_port_operations sil24_ops = {
Index: 2.6.18/drivers/scsi/ahci.c
===================================================================
--- 2.6.18.orig/drivers/scsi/ahci.c
+++ 2.6.18/drivers/scsi/ahci.c
@@ -231,6 +231,7 @@ 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,
+	.shutdown		= ata_scsi_device_shutdown,
 };
 
 static const struct ata_port_operations ahci_ops = {
Index: 2.6.18/drivers/scsi/pdc_adma.c
===================================================================
--- 2.6.18.orig/drivers/scsi/pdc_adma.c
+++ 2.6.18/drivers/scsi/pdc_adma.c
@@ -154,6 +154,7 @@ static struct scsi_host_template adma_at
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
+	.shutdown		= ata_scsi_device_shutdown,
 };
 
 static const struct ata_port_operations adma_ata_ops = {
Index: 2.6.18/drivers/scsi/sata_mv.c
===================================================================
--- 2.6.18.orig/drivers/scsi/sata_mv.c
+++ 2.6.18/drivers/scsi/sata_mv.c
@@ -392,6 +392,7 @@ static struct scsi_host_template mv_sht 
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
+	.shutdown		= ata_scsi_device_shutdown,
 };
 
 static const struct ata_port_operations mv5_ops = {
Index: 2.6.18/drivers/scsi/sata_nv.c
===================================================================
--- 2.6.18.orig/drivers/scsi/sata_nv.c
+++ 2.6.18/drivers/scsi/sata_nv.c
@@ -170,6 +170,7 @@ 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,
+	.shutdown		= ata_scsi_device_shutdown,
 };
 
 static const struct ata_port_operations nv_generic_ops = {
Index: 2.6.18/drivers/scsi/sata_promise.c
===================================================================
--- 2.6.18.orig/drivers/scsi/sata_promise.c
+++ 2.6.18/drivers/scsi/sata_promise.c
@@ -123,6 +123,7 @@ static struct scsi_host_template pdc_ata
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
+	.shutdown		= ata_scsi_device_shutdown,
 };
 
 static const struct ata_port_operations pdc_sata_ops = {
Index: 2.6.18/drivers/scsi/sata_qstor.c
===================================================================
--- 2.6.18.orig/drivers/scsi/sata_qstor.c
+++ 2.6.18/drivers/scsi/sata_qstor.c
@@ -144,6 +144,7 @@ static struct scsi_host_template qs_ata_
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
+	.shutdown		= ata_scsi_device_shutdown,
 };
 
 static const struct ata_port_operations qs_ata_ops = {
Index: 2.6.18/drivers/scsi/sata_sis.c
===================================================================
--- 2.6.18.orig/drivers/scsi/sata_sis.c
+++ 2.6.18/drivers/scsi/sata_sis.c
@@ -97,6 +97,7 @@ 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,
+	.shutdown		= ata_scsi_device_shutdown,
 };
 
 static const struct ata_port_operations sis_ops = {
Index: 2.6.18/drivers/scsi/sata_svw.c
===================================================================
--- 2.6.18.orig/drivers/scsi/sata_svw.c
+++ 2.6.18/drivers/scsi/sata_svw.c
@@ -303,6 +303,7 @@ static struct scsi_host_template k2_sata
 	.proc_info		= k2_sata_proc_info,
 #endif
 	.bios_param		= ata_std_bios_param,
+	.shutdown		= ata_scsi_device_shutdown,
 };
 
 
Index: 2.6.18/drivers/scsi/sata_sx4.c
===================================================================
--- 2.6.18.orig/drivers/scsi/sata_sx4.c
+++ 2.6.18/drivers/scsi/sata_sx4.c
@@ -193,6 +193,7 @@ static struct scsi_host_template pdc_sat
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
+	.shutdown		= ata_scsi_device_shutdown,
 };
 
 static const struct ata_port_operations pdc_20621_ops = {
Index: 2.6.18/drivers/scsi/sata_uli.c
===================================================================
--- 2.6.18.orig/drivers/scsi/sata_uli.c
+++ 2.6.18/drivers/scsi/sata_uli.c
@@ -91,6 +91,7 @@ static struct scsi_host_template uli_sht
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
+	.shutdown		= ata_scsi_device_shutdown,
 };
 
 static const struct ata_port_operations uli_ops = {
Index: 2.6.18/drivers/scsi/sata_via.c
===================================================================
--- 2.6.18.orig/drivers/scsi/sata_via.c
+++ 2.6.18/drivers/scsi/sata_via.c
@@ -107,6 +107,7 @@ static struct scsi_host_template svia_sh
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
+	.shutdown		= ata_scsi_device_shutdown,
 };
 
 static const struct ata_port_operations vt6420_sata_ops = {
Index: 2.6.18/drivers/scsi/sata_vsc.c
===================================================================
--- 2.6.18.orig/drivers/scsi/sata_vsc.c
+++ 2.6.18/drivers/scsi/sata_vsc.c
@@ -281,6 +281,7 @@ static struct scsi_host_template vsc_sat
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
+	.shutdown		= ata_scsi_device_shutdown,
 };
 
 

--vkogqOf2sHV7VnPd--