Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 18 Jun 2005 18:17:44 +0200
From:      Michael Weiser <michael@weiser.dinsnail.net>
To:        freebsd-current@freebsd.org
Subject:   ata explicit idle/standby
Message-ID:  <20050618161744.GA993@weiser.dinsnail.net>

next in thread | raw e-mail | index | archive | help

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

Hi,

I've done a small patch to the -CURRENT atacontrol and ata driver to
allow explicit switch of drives to idle or standby mode and query the
current mode. I use it to spin down disks needed only very inregularly.
If extended by a means to set the idle timeout this might be
particularly useful to notebook users as well.

Or have I actually missed the some already present functionality to
achieve the same?
-- 
Cheers,
Micha

--qDbXVdCdHGoSgWSk
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="ata-sleep.patch"

--- sys/dev/ata/ata-all.c.orig	Tue Jun  7 17:33:23 2005
+++ sys/dev/ata/ata-all.c	Sat Jun 18 17:12:48 2005
@@ -493,6 +493,38 @@
     case IOCATAGMODE:
 	*mode = atadev->mode;
 	return 0;
+
+    case IOCATASTANDBY:
+	if (atadev->param.support.command2 & ATA_SUPPORT_FLUSHCACHE)
+	    ata_controlcmd(dev, ATA_FLUSHCACHE, 0, 0, 0);
+
+ 	ata_controlcmd(dev, ATA_STANDBY_IMMEDIATE, 0, 0, 0);
+	return 0;
+
+    case IOCATAIDLE:
+	if (atadev->param.support.command2 & ATA_SUPPORT_FLUSHCACHE)
+	    ata_controlcmd(dev, ATA_FLUSHCACHE, 0, 0, 0);
+
+    	ata_controlcmd(dev, ATA_IDLE_IMMEDIATE, 0, 0, 0);
+	return 0;
+
+    case IOCATACHECKPWRMODE:
+	if (!(request = ata_alloc_request()))
+		return ENOMEM;
+
+	request->dev = dev;
+	request->u.ata.command = ATA_CHECK_PWR_MODE;
+	request->u.ata.lba = 0;
+	request->u.ata.count = 0;
+	request->u.ata.feature = 0;
+	request->flags = ATA_R_CONTROL;
+	request->timeout = 1;
+	request->retries = 0;
+	ata_queue_request(request);
+	*mode = request->u.ata.count;
+	ata_free_request(request);
+	return 0;
+
     default:
 	return ENOTTY;
     }
--- sbin/atacontrol/atacontrol.c.orig	Tue Jun  7 17:27:41 2005
+++ sbin/atacontrol/atacontrol.c	Sat Jun 18 17:10:47 2005
@@ -109,6 +109,9 @@
 		"        atacontrol status array\n"
 		"        atacontrol mode device [mode]\n"
 		"        atacontrol cap device\n"
+		"        atacontrol pwrstatus device\n"
+		"        atacontrol standby device\n"
+		"        atacontrol idle device\n"
 	);
 	exit(EX_USAGE);
 }
@@ -337,6 +340,77 @@
 		if ((fd = open(device, O_RDONLY)) < 0)
 			err(1, "device not found");
 		ata_cap_print(fd);
+		exit(EX_OK);
+	}
+	if (!strcmp(argv[1], "idle") && argc == 3) {
+		int disk;
+		char device[64];
+
+		if (!(sscanf(argv[2], "ad%d", &disk) == 1 ||
+		      sscanf(argv[2], "acd%d", &disk) == 1 ||
+		      sscanf(argv[2], "afd%d", &disk) == 1 ||
+		      sscanf(argv[2], "ast%d", &disk) == 1)) {
+			fprintf(stderr, "atacontrol: Invalid device %s\n",
+				argv[2]);
+			exit(EX_USAGE);
+		}
+		sprintf(device, "/dev/%s", argv[2]);
+		if ((fd = open(device, O_RDONLY)) < 0)
+			err(1, "device not found");
+		if (ioctl(fd, IOCATAIDLE, &disk) < 0)
+			err(1, "ioctl(ATAIDLE)");	    	   
+		exit(EX_OK);
+	}
+	if (!strcmp(argv[1], "standby") && argc == 3) {
+		int disk;
+		char device[64];
+
+		if (!(sscanf(argv[2], "ad%d", &disk) == 1 ||
+		      sscanf(argv[2], "acd%d", &disk) == 1 ||
+		      sscanf(argv[2], "afd%d", &disk) == 1 ||
+		      sscanf(argv[2], "ast%d", &disk) == 1)) {
+			fprintf(stderr, "atacontrol: Invalid device %s\n",
+				argv[2]);
+			exit(EX_USAGE);
+		}
+		sprintf(device, "/dev/%s", argv[2]);
+		if ((fd = open(device, O_RDONLY)) < 0)
+			err(1, "device not found");
+		if (ioctl(fd, IOCATASTANDBY, &disk) < 0)
+			err(1, "ioctl(ATASTANDBY)");	    	   
+		exit(EX_OK);
+	}
+	if (!strcmp(argv[1], "pwrstatus") && argc == 3) {
+		int disk;
+		char device[64];
+
+		if (!(sscanf(argv[2], "ad%d", &disk) == 1 ||
+		      sscanf(argv[2], "acd%d", &disk) == 1 ||
+		      sscanf(argv[2], "afd%d", &disk) == 1 ||
+		      sscanf(argv[2], "ast%d", &disk) == 1)) {
+			fprintf(stderr, "atacontrol: Invalid device %s\n",
+				argv[2]);
+			exit(EX_USAGE);
+		}
+		sprintf(device, "/dev/%s", argv[2]);
+		if ((fd = open(device, O_RDONLY)) < 0)
+			err(1, "device not found");
+		if (ioctl(fd, IOCATACHECKPWRMODE, &disk) < 0)
+			err(1, "ioctl(ATACHECKPWRMODE)");	    	   
+		switch (disk) {
+			case 0x00:
+				printf("device is in standby mode\n");
+				break;
+			case 0x80:
+				printf("device is in idle mode\n");
+				break;
+			case 0xff:
+				printf("device is in active or idle mode\n");
+				break;
+			default:
+				printf("unknown mode\n");
+				break;
+		}
 		exit(EX_OK);
 	}
 
--- sys/sys/ata.h.orig	Tue Jun  7 17:42:52 2005
+++ sys/sys/ata.h	Sat Jun 18 18:01:30 2005
@@ -252,6 +252,7 @@
 #define ATA_STANDBY_CMD                 0xe2    /* standby */
 #define ATA_IDLE_CMD                    0xe3    /* idle */
 #define ATA_READ_BUFFER                 0xe4    /* read buffer */
+#define ATA_CHECK_PWR_MODE              0xe5	/* check power mode */ 
 #define ATA_SLEEP                       0xe6    /* sleep */
 #define ATA_FLUSHCACHE                  0xe7    /* flush cache to disk */
 #define ATA_FLUSHCACHE48                0xea    /* flush cache to disk */
@@ -372,6 +373,9 @@
 #define IOCATAGPARM             _IOR('a', 101, struct ata_params)
 #define IOCATAGMODE             _IOR('a', 102, int)
 #define IOCATASMODE             _IOW('a', 103, int)
+#define IOCATAIDLE              _IOW('a', 131, int)
+#define IOCATASTANDBY           _IOW('a', 132, int)
+#define IOCATACHECKPWRMODE      _IOR('a', 133, int)
 
 
 struct ata_ioc_raid_config {

--qDbXVdCdHGoSgWSk--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20050618161744.GA993>