[ltp] (fwd) [PATCH] sd: implement stop_on_shutdown

Henrique de Moraes Holschuh linux-thinkpad@linux-thinkpad.org
Sun, 21 Jan 2007 16:22:09 -0200


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

This patch, plus adding the required module parameter or kernel commandline
parameter to enable stop_on_shutdown by default is an *extremely* good idea
on any ThinkPads that use libata (i.e. where disks show up as SCSI devices,
/dev/sd*).

Suspending to disk without it is a Bad Idea, unless you want to make sure
your HD will die soon, so as to be able to replace it under warranty or
somesuch.

If you notice the disk is being stopped twice (it will happen on Debian
Etch), you can either disable the stop_on_shutdown on your initscripts right
before a halt/shutdown, or preferably, tell halt(8) to not do it (i.e., make
sure halt is not called with the -h option) and let the kernel do it.

Eventually, after a stable kernel is released with this patch included, we
shall modify halt(8) upstream to do the sensible thing.

-- 
  "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

--G4iJoqBmSsgzjUCe
Content-Type: message/rfc822
Content-Disposition: inline

X-Original-To: hmh@khazad-dum.debian.net
Delivered-To: hmh@khazad-dum.debian.net
Received: from localhost (localhost [127.0.0.1])
	by localhost.khazad-dum.debian.net (Postfix) with ESMTP id EAD0828097
	for <hmh@khazad-dum.debian.net>; Sat, 20 Jan 2007 14:26:49 -0200 (BRST)
X-Virus-Scanned: Debian amavisd-new at khazad-dum.debian.net
Received: from khazad-dum.debian.net ([127.0.0.1])
	by localhost (khazad-dum.debian.net [127.0.0.1]) (amavisd-new, port 10024)
	with LMTP id 0nXKkP5eioU6 for <hmh@khazad-dum.debian.net>;
	Sat, 20 Jan 2007 14:26:46 -0200 (BRST)
Received: by khazad-dum.debian.net (Postfix, from userid 1000)
	id 1A0DB28093; Sat, 20 Jan 2007 14:26:46 -0200 (BRST)
Received: from mail.messagingengine.com (66.111.4.52) by
  khazad-dum.debian.net with IMAP4-SSL; 20 Jan 2007 16:26:46 -0000
Received: from mx5.internal (mx5.internal [10.202.2.204])
	 by store20m.internal (Cyrus v2.3.7-fmsvn9682) with LMTPA;
	 Fri, 19 Jan 2007 12:07:02 -0500
X-Sieve: CMU Sieve 2.3
X-Spam-source: Country='KR', FromHeader='com', MailFrom='org'
X-Delivered-to: hmh@hmh.eng.br
Received: from htj.dyndns.org (unknown [221.139.199.108])
	by mx1.messagingengine.com (Postfix) with ESMTP id 393A026D61E
	for <hmh@hmh.eng.br>; Fri, 19 Jan 2007 12:06:28 -0500 (EST)
Received: by htj.dyndns.org (Postfix, from userid 1000)
	id 6FFF0186C8; Sat, 20 Jan 2007 02:01:22 +0900 (KST)
Date: Sat, 20 Jan 2007 02:01:22 +0900
From: Tejun Heo <htejun@gmail.com>
To: James.Bottomley@SteelEye.com, Jeff Garzik <jgarzik@pobox.com>,
	hmh@hmh.eng.br
Cc: linux-ide@vger.kernel.org, linux-scsi@vger.kernel.org
Subject: [PATCH] sd: implement stop_on_shutdown
Message-ID: <20070119170122.GS10987@htj.dyndns.org>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
User-Agent: Mutt/1.5.13 (2006-08-11)

sd doesn't stop (unload head) on shutdown.  This behavior is necessary
for multi initiator cases.  Unloading head by powering off stresses
the drive and sometimes produces distinct clunking noise which
apparently disturbs users considering multiple reports on different
distributions.  halt(8) usually puts the drives to sleep prior to
shutdown but the implementation is fragile and it doesn't work with
sleep-to-disk.

This patch implements sd attribute stop_on_shutdown.  If set to 1, sd
stops the drive on non-restarting shutdown.  stop_on_shutdown is
initialized from sd parameter stop_on_shutdown_default which defaults
to 0.  So, this patch does not change the default behavior.

Signed-off-by: Tejun Heo <htejun@gmail.com>
Acked-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>

diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 978bfc1..f21e5fe 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -90,6 +90,12 @@ MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK13_MAJOR);
 MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK14_MAJOR);
 MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK15_MAJOR);
 
+static int sd_stop_on_shutdown_dfl = 0;
+module_param_named(stop_on_shutdown_default, sd_stop_on_shutdown_dfl,
+		   bool, 0644);
+MODULE_PARM_DESC(stop_on_shutdown_default, "Default setting for stopping "
+		 "disk on shutdown (0=disable, 1=enable)");
+
 /*
  * This is limited by the naming scheme enforced in sd_probe,
  * add another character to it if you really need more disks.
@@ -126,6 +132,7 @@ struct scsi_disk {
 	unsigned	WCE : 1;	/* state of disk WCE bit */
 	unsigned	RCD : 1;	/* state of disk RCD bit, unused */
 	unsigned	DPOFUA : 1;	/* state of disk DPOFUA bit */
+	unsigned	stop_on_shutdown : 1; /* stop on device shutdown */
 };
 #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,cdev)
 
@@ -207,6 +214,19 @@ static ssize_t sd_store_cache_type(struct class_device *cdev, const char *buf,
 	return count;
 }
 
+static ssize_t sd_store_stop_on_shutdown(struct class_device *cdev,
+					 const char *buf, size_t count)
+{
+	struct scsi_disk *sdkp = to_scsi_disk(cdev);
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	sdkp->stop_on_shutdown = simple_strtoul(buf, NULL, 10);
+
+	return count;
+}
+
 static ssize_t sd_store_allow_restart(struct class_device *cdev, const char *buf,
 				      size_t count)
 {
@@ -239,6 +259,13 @@ static ssize_t sd_show_fua(struct class_device *cdev, char *buf)
 	return snprintf(buf, 20, "%u\n", sdkp->DPOFUA);
 }
 
+static ssize_t sd_show_stop_on_shutdown(struct class_device *cdev, char *buf)
+{
+	struct scsi_disk *sdkp = to_scsi_disk(cdev);
+
+	return snprintf(buf, 20, "%u\n", sdkp->stop_on_shutdown);
+}
+
 static ssize_t sd_show_allow_restart(struct class_device *cdev, char *buf)
 {
 	struct scsi_disk *sdkp = to_scsi_disk(cdev);
@@ -252,6 +279,8 @@ static struct class_device_attribute sd_disk_attrs[] = {
 	__ATTR(FUA, S_IRUGO, sd_show_fua, NULL),
 	__ATTR(allow_restart, S_IRUGO|S_IWUSR, sd_show_allow_restart,
 	       sd_store_allow_restart),
+	__ATTR(stop_on_shutdown, S_IRUGO|S_IWUSR, sd_show_stop_on_shutdown,
+	       sd_store_stop_on_shutdown),
 	__ATTR_NULL,
 };
 
@@ -1662,6 +1691,7 @@ static int sd_probe(struct device *dev)
 	sdkp->disk = gd;
 	sdkp->index = index;
 	sdkp->openers = 0;
+	sdkp->stop_on_shutdown = sd_stop_on_shutdown_dfl;
 
 	if (!sdp->timeout) {
 		if (sdp->type != TYPE_MOD)
@@ -1766,6 +1796,29 @@ static void scsi_disk_release(struct class_device *cdev)
 	kfree(sdkp);
 }
 
+static int sd_stop_device(struct scsi_device *sdp)
+{
+	unsigned char cmd[6] = { START_STOP }; /* START_VALID and START == 0 */
+	struct scsi_sense_hdr sshdr;
+	int res;
+
+	if (!scsi_device_online(sdp))
+		return -ENODEV;
+
+	res = scsi_execute_req(sdp, cmd, DMA_NONE, NULL, 0, &sshdr,
+			       SD_TIMEOUT, SD_MAX_RETRIES);
+	if (res) {
+		printk(KERN_WARNING "FAILED\n  status = %x, message = %02x, "
+		       "host = %d, driver = %02x\n  ",
+		       status_byte(res), msg_byte(res),
+		       host_byte(res), driver_byte(res));
+		if (driver_byte(res) & DRIVER_SENSE)
+			scsi_print_sense_hdr("sd", &sshdr);
+	}
+
+	return res;
+}
+
 /*
  * Send a SYNCHRONIZE CACHE instruction down to the device through
  * the normal SCSI command structure.  Wait for the command to
@@ -1784,6 +1837,13 @@ static void sd_shutdown(struct device *dev)
 				sdkp->disk->disk_name);
 		sd_sync_cache(sdp);
 	}
+
+	if (system_state != SYSTEM_RESTART && sdkp->stop_on_shutdown) {
+ 		printk(KERN_NOTICE "Stopping disk %s: \n",
+		       sdkp->disk->disk_name);
+		sd_stop_device(sdp);
+	}
+
 	scsi_disk_put(sdkp);
 }
 

--G4iJoqBmSsgzjUCe--