lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20080225134558.GA1611@elf.ucw.cz>
Date:	Mon, 25 Feb 2008 14:45:58 +0100
From:	Pavel Machek <pavel@....cz>
To:	kernel list <linux-kernel@...r.kernel.org>,
	Linux-pm mailing list <linux-pm@...ts.osdl.org>,
	stern@...land.harvard.edu
Cc:	linux-ide@...r.kernel.org
Subject: [ugly patch] Save .15W-.5W by AHCI powersaving

Hi!

This is a patch (very ugly, assumes you have just one disk) to bring
powersaving to AHCI. You need Alan's SCSI autosuspend (attached) patch
as a base.

It saves .5W compared to config with disk spinning, and even .15W
compared to hdparm -y... on my thinkpad x60 anyway.

It is also mandatory first step towards sleepy linux ;-).

								Pavel
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 29e71bd..0197b1f 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -259,8 +260,8 @@ static void ahci_fill_cmd_slot(struct ah
 			       u32 opts);
 #ifdef CONFIG_PM
 static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
-static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
-static int ahci_pci_device_resume(struct pci_dev *pdev);
+int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
+int ahci_pci_device_resume(struct pci_dev *pdev);
 #endif
 
 static struct class_device_attribute *ahci_shost_attrs[] = {
@@ -268,6 +269,35 @@ static struct class_device_attribute *ah
 	NULL
 };
 
+struct pci_dev *my_pdev;
+int autosuspend_enabled;
+
+/* The host and its devices are all idle so we can autosuspend */
+static int autosuspend(struct Scsi_Host *host)
+{
+	if (my_pdev && autosuspend_enabled) {
+		printk("ahci: should autosuspend\n");
+		ahci_pci_device_suspend(my_pdev, PMSG_SUSPEND);
+		return 0;
+	} 
+	printk("ahci: autosuspend disabled\n");
+	return -EINVAL;
+}
+
+/* The host needs to be autoresumed */
+static int autoresume(struct Scsi_Host *host)
+{
+	if (my_pdev && autosuspend_enabled) {
+		printk("ahci: should autoresume\n");
+		ahci_pci_device_resume(my_pdev);
+		return 0;
+	}
+	printk("ahci: autoresume disabled\n");
+	return -EINVAL;
+}
+
+
+
 static struct scsi_host_template ahci_sht = {
 	.module			= THIS_MODULE,
 	.name			= DRV_NAME,
@@ -286,6 +322,8 @@ static struct scsi_host_template ahci_sh
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
 	.shost_attrs		= ahci_shost_attrs,
+	.autosuspend		= autosuspend,
+	.autoresume		= autoresume,
 };
 
 static const struct ata_port_operations ahci_ops = {
@@ -2300,8 +2356,12 @@ static int ahci_init_one(struct pci_dev 
 	ahci_print_info(host);
 
 	pci_set_master(pdev);
-	return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
+
+	rc = ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
 				 &ahci_sht);
+	pci_save_state(pdev);
+	my_pdev = pdev;
+	return rc;
 }
 
 static int __init ahci_init(void)
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 4e31071..5c40ac2 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -380,7 +381,7 @@ enum scsi_eh_timer_return ata_scsi_timed
  *	Inherited from SCSI layer (none, can sleep)
  *
  *	RETURNS:
- *	Zero.
+ *	Nothing.
  */
 void ata_scsi_error(struct Scsi_Host *host)
 {
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index c838e65..0edc25e 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -484,6 +484,8 @@ static int scsi_try_host_reset(struct sc
 	if (scsi_autoresume_host(shost) != 0)
 		return FAILED;
 
+	rtn = shost->hostt->eh_host_reset_handler(scmd);
+
 	if (rtn == SUCCESS) {
 		if (!shost->hostt->skip_settle_delay)
 			ssleep(HOST_RESET_SETTLE_TIME);
@@ -1577,7 +1579,11 @@ int scsi_error_handler(void *data)
 		 * what we need to do to get it up and online again (if we can).
 		 * If we fail, we end up taking the thing offline.
 		 */
+#if 0
+		/* libata uses scsi_error_handler to suspend its parts; we deadlock
+		   if we try to autoresume here */
 		autoresume_rc = scsi_autoresume_host(shost);
+#endif
 		if (shost->transportt->eh_strategy_handler)
 			shost->transportt->eh_strategy_handler(shost);
 		else
@@ -1591,8 +1597,10 @@ int scsi_error_handler(void *data)
 		 * which are still online.
 		 */
 		scsi_restart_operations(shost);
+#if 0
 		if (autoresume_rc == 0)
 			scsi_autosuspend_host(shost);
+#endif
 		set_current_state(TASK_INTERRUPTIBLE);
 	}
 	__set_current_state(TASK_RUNNING);
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 233feee..3c598e0 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -67,6 +67,8 @@ #undef SP
 
 static struct kmem_cache *scsi_bidi_sdb_cache;
 
+void scsi_run_queue(struct request_queue *q);
+
 /*
  * Function:	scsi_unprep_request()
  *
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 5393e15..25bebc1 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -340,6 +340,21 @@ static int scsi_bus_uevent(struct device
 	return 0;
 }
 
+static int scsi_bus_remove(struct device *dev)
+{
+	struct device_driver *drv = dev->driver;
+	struct scsi_device *sdev = to_scsi_device(dev);
+	int err = 0;
+
+	/* reset the prep_fn back to the default since the
+	 * driver may have altered it and it's being removed */
+	blk_queue_prep_rq(sdev->request_queue, scsi_prep_fn);
+
+	if (drv && drv->remove)
+		err = drv->remove(dev);
+
+	return 0;
+}
 
 struct bus_type scsi_bus_type = {
         .name		= "scsi",
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 16add9a..9ca12d1 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1596,6 +1596,8 @@ static int sd_revalidate_disk(struct gen
 	return 0;
 }
 
+struct device *my_scsi_disk; 
+
 /**
  *	sd_probe - called during driver initialization and whenever a
  *	new scsi device is attached to the system. It is called once
@@ -1715,6 +1717,7 @@ static int sd_probe(struct device *dev)
 
 	scsi_use_ULD_pm(sdp, 1);
 	scsi_autosuspend_device(sdp);
+	my_scsi_disk = dev;
 	return 0;
 
  out_suspend:
@@ -1835,6 +1838,8 @@ static int sd_suspend(struct device *dev
 	struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
 	int ret = 0;
 
+	printk("sleepy: sd_suspend start\n");
+
 	if (!sdkp)
 		return 0;	/* this can happen */
 



-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

View attachment "delme2" of type "text/plain" (28307 bytes)

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ