ata: printf on every spinup/spindown?

Dimitry Andric dimitry at andric.com
Fri Mar 20 04:18:13 PDT 2009


On 2009-03-20 08:48, Bruce Cran wrote:
> Related to this, the ATA driver should probably have some means, either
> automatically or via atacontrol, of setting the APM value on disks; I
> bought a new laptop and immediately had to install
> sysutils/ataidle in order to stop the heads loading/unloading several
> times per minute by setting APM to 254.  Apparently it's fairly common
> for laptop drives to have overly aggressive power settings that need
> intervention from the OS.

I have been running with the attached patch since ages, and it still
applies to -stable, hopefully to -current too.  I have forgotten who the
original author is, so my apologies for not crediting it...
-------------- next part --------------
Index: sbin/atacontrol/atacontrol.8
===================================================================
RCS file: /home/ncvs/src/sbin/atacontrol/atacontrol.8,v
retrieving revision 1.28.2.4
diff -u -p -r1.28.2.4 atacontrol.8
--- sbin/atacontrol/atacontrol.8	3 Mar 2009 07:56:42 -0000	1.28.2.4
+++ sbin/atacontrol/atacontrol.8	20 Mar 2009 11:15:05 -0000
@@ -65,6 +65,16 @@
 .Ar device
 .Op Ar mode
 .Nm
+.Ic feature
+.Ar device
+.Ic apm
+.Ar apmlevel
+.Nm
+.Ic feature
+.Ar device
+.Ic acoustic
+.Ar soundsupplevel
+.Nm
 .Ic info
 .Ar channel
 .Nm
@@ -195,6 +205,44 @@ Currently supported modes are:
 .Cm SATA150 , SATA300 , USB , USB1 , USB2
 and
 .Cm BIOSDMA .
+.It Ic feature / apm
+Set disk drive Advanced Power Management (APM) level.
+This command is generally used on laptop (notebook) hard disks to control
+the power level consumed by the drive (at the expense of performance).
+.Pp
+The
+.Ar apmlevel
+may be set to one of:
+.Cm off
+(turn off APM),
+.Cm maxperf
+or
+.Cm minpower
+(optimize for maximum performance or minimum power, respectively), or
+a numeric level which can be 0 to 127 inclusive indicating an increasing
+level of performance over power savings.
+The numeric levels may be prefixed by
+.Cm s
+which will allow the drive to include suspension as part of the
+power savings.  Note that not all hard drives will support the
+.Cm off
+command, and that the number of incremental power savings levels
+do not typically have as wide of a range as this command will
+support.
+.It Ic feature / acoustic
+Control disk drive Acoustic Management level.  The
+.Ar soundsupplevel
+may be set to
+.Cm off
+which will turn off acoustic management,
+.Cm maxperf
+to optimize for maximum performance,
+.Cm maxquiet
+to optimize for maximum quiet, or a numeric level
+from 0 to 124.  The higher the numeric level, the higher the
+theoretical sound level emitted from the drive.  Note that few
+devices support this command and even fewer will allow the
+range of levels supported.
 .It Ic cap
 Show detailed info about the device on
 .Ar device .
Index: sbin/atacontrol/atacontrol.c
===================================================================
RCS file: /home/ncvs/src/sbin/atacontrol/atacontrol.c,v
retrieving revision 1.43.2.5
diff -u -p -r1.43.2.5 atacontrol.c
--- sbin/atacontrol/atacontrol.c	3 Mar 2009 07:56:42 -0000	1.43.2.5
+++ sbin/atacontrol/atacontrol.c	20 Mar 2009 11:15:05 -0000
@@ -107,6 +107,8 @@ usage(void)
 		"        atacontrol rebuild array\n"
 		"        atacontrol status array\n"
 		"        atacontrol mode device [mode]\n"
+		"        atacontrol feature device apm apmlevel\n"
+		"        atacontrol feature device acoustic soundsupplevel\n"
 		"        atacontrol cap device\n"
 		"        atacontrol spindown device [seconds]\n"
 	);
@@ -381,6 +383,88 @@ main(int argc, char **argv)
 		}
 		exit(EX_OK);
 	}
+	if (!strcmp(argv[1], "feature") && argc == 5) {
+		int disk;
+		char device[64];
+		struct ata_ioc_request request;
+
+		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");
+
+		bzero(&request, sizeof(struct ata_ioc_request));
+		request.u.ata.command = ATA_SETFEATURES;
+		request.flags = ATA_CMD_CONTROL;
+		request.timeout = 500;
+		if (!strcmp(argv[3], "apm")) {
+			if (!strcmp(argv[4], "off")) {
+				request.u.ata.feature = ATA_SF_DIS_APM;
+			}
+			else if (!strcmp(argv[4], "maxperf")) {
+				request.u.ata.feature = ATA_SF_ENAB_APM;
+				request.u.ata.count = 0xfe;
+			}
+			else if (!strcmp(argv[4], "minpower")) {
+				request.u.ata.feature = ATA_SF_ENAB_APM;
+				request.u.ata.count = 0x01;
+			}
+			else {
+				int offset = 0;
+
+				request.u.ata.feature = ATA_SF_ENAB_APM;
+				if (argv[4][0] == 's') {
+					offset = atoi(&argv[4][1]);
+					request.u.ata.count = 0x01;
+				} else {
+					offset = atoi(&argv[4][1]);
+					request.u.ata.count = 0x80;
+				}
+				if (offset >= 0 && offset <= 127)
+					request.u.ata.count += offset;
+			}
+		}
+		else if (!strcmp(argv[3], "acoustic")) {
+			if (!strcmp(argv[4], "off")) {
+				request.u.ata.feature = ATA_SF_DIS_ACCOUS;
+			}
+			else if (!strcmp(argv[4], "maxperf")) {
+				request.u.ata.feature = ATA_SF_ENAB_ACCOUS;
+				request.u.ata.count = 0xfe;
+			}
+			else if (!strcmp(argv[4], "maxquiet")) {
+				request.u.ata.feature = ATA_SF_ENAB_ACCOUS;
+				request.u.ata.count = 0x80;
+			}
+			else {
+				request.u.ata.feature = ATA_SF_ENAB_ACCOUS;
+				request.u.ata.count = atoi(argv[4]);
+				if (request.u.ata.count > 124)
+					request.u.ata.count = 124;
+			}
+		}
+		else
+			usage();
+
+		if (ioctl(fd, IOCATAREQUEST, &request) < 0)
+			err(1, "ioctl(IOCATAREQUEST)");
+
+		if (request.error != 0) {
+			fprintf(stderr,
+				"IOCATAREQUEST returned err status %d",
+				request.error);
+			exit(EX_IOERR);
+		}
+
+		exit(EX_OK);
+	}
 	if (!strcmp(argv[1], "cap") && argc == 3) {
 		fd = open_dev(argv[2], O_RDONLY);
 		ata_cap_print(fd);
Index: sys/sys/ata.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/ata.h,v
retrieving revision 1.36.2.3
diff -u -p -r1.36.2.3 ata.h
--- sys/sys/ata.h	8 Apr 2008 10:48:21 -0000	1.36.2.3
+++ sys/sys/ata.h	20 Mar 2009 11:15:05 -0000
@@ -281,6 +281,10 @@ struct ata_params {
 #define         ATA_SF_DIS_RELIRQ       0xdd    /* disable release interrupt */
 #define         ATA_SF_ENAB_SRVIRQ      0x5e    /* enable service interrupt */
 #define         ATA_SF_DIS_SRVIRQ       0xde    /* disable service interrupt */
+#define         ATA_SF_ENAB_APM         0x05    /* enable adv power mgmt */
+#define         ATA_SF_DIS_APM          0x85    /* disable adv power mgmt */
+#define         ATA_SF_ENAB_ACCOUS      0x42    /* enable acoustic mgmt */
+#define         ATA_SF_DIS_ACCOUS       0xc2    /* disable acoustic mgmt */
 #define ATA_SECURITY_FREEE_LOCK         0xf5    /* freeze security config */
 #define ATA_READ_NATIVE_MAX_ADDDRESS    0xf8    /* read native max address */
 #define ATA_SET_MAX_ADDRESS             0xf9    /* set max address */


More information about the freebsd-current mailing list