natacontrol(8): Add commands to tweak power/acoustic management features.
authorSascha Wildner <saw@online.de>
Sat, 23 Mar 2013 19:21:29 +0000 (20:21 +0100)
committerSascha Wildner <saw@online.de>
Sat, 23 Mar 2013 19:24:59 +0000 (20:24 +0100)
Sometimes disks designed to operate in low power mode by default
constantly spin up/down during operation which leads to reduced
performance.

This commit adds the 'feature' command to natacontrol(8) which
can be used to tweak the 'advanced power management' and 'automatic
acoustic management' features. Their current setting could already
be viewed before this commit using the 'natacontrol cap' command.

I'd like this to be possible with camcontrol(8) too for CAM attached
disks, but afaict these are ATA specific features so I guess we'd
have to integrate ATA into CAM too before that is possible.

Dragonfly-bug: <http://bugs.dragonflybsd.org/issues/2531>
Reported-by: Maurizio Lombardi <m.lombardi85@gmail.com>
Taken-from:    FreeBSD PR 81692
Tested-by: Maurizio Lombardi <m.lombardi85@gmail.com>
sbin/natacontrol/natacontrol.8
sbin/natacontrol/natacontrol.c
sys/sys/nata.h

index 74d078b..390f914 100644 (file)
@@ -24,9 +24,8 @@
 .\" SUCH DAMAGE.
 .\"
 .\" $FreeBSD: src/sbin/atacontrol/atacontrol.8,v 1.28 2005/11/18 10:32:09 ru Exp $
-.\" $DragonFly: src/sbin/natacontrol/natacontrol.8,v 1.3 2007/08/20 01:35:56 swildner Exp $
 .\"
-.Dd December 5, 2006
+.Dd March 23, 2013
 .Dt NATACONTROL 8
 .Os
 .Sh NAME
 .Ic cap
 .Ar device
 .Nm
+.Ic feature
+.Ar device acoustic soundsupplevel
+.Nm
+.Ic feature
+.Ar device apm apmlevel
+.Nm
 .Ic list
 .Sh DESCRIPTION
 The
@@ -194,6 +199,56 @@ The device name and manufacture/version strings are shown.
 .It Ic cap
 Show detailed info about the device on
 .Ar device .
+.It Ic feature
+Set disk drive features.
+Currently,
+.Ar acoustic
+and
+.Ar apm
+features are supported.
+.Bl -tag -width "acoustic"
+.It Ar acoustic soundsupplevel
+Controls the 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 Ar apm apmlevel
+Sets the 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.
+.El
 .It Ic info
 Show info about the attached devices on the
 .Ar channel .
index 594b4b0..8f2a726 100644 (file)
@@ -111,6 +111,8 @@ usage(void)
                "        natacontrol rebuild array\n"
                "        natacontrol status array\n"
                "        natacontrol mode device [mode]\n"
+               "        natacontrol feature device apm apmlevel\n"
+               "        natacontrol feature device acoustic soundsupplevel\n"
                "        natacontrol cap device\n"
        );
        exit(EX_USAGE);
@@ -328,6 +330,80 @@ 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, "natacontrol: 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) {
                int disk;
                char device[64];
index 6b0af7e..38a8489 100644 (file)
@@ -276,6 +276,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 */