Skip to content

Commit

Permalink
natacontrol(8): Add commands to tweak power/acoustic management featu…
Browse files Browse the repository at this point in the history
…res.

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>
  • Loading branch information
Sascha Wildner committed Mar 23, 2013
1 parent 6d290ad commit 60779d5
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 2 deletions.
59 changes: 57 additions & 2 deletions sbin/natacontrol/natacontrol.8
Expand Up @@ -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
Expand Down Expand Up @@ -71,6 +70,12 @@
.Ic cap
.Ar device
.Nm
.Ic feature
.Ar device acoustic soundsupplevel
.Nm
.Ic feature
.Ar device apm apmlevel
.Nm
.Ic list
.Sh DESCRIPTION
The
Expand Down Expand Up @@ -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 .
Expand Down
76 changes: 76 additions & 0 deletions sbin/natacontrol/natacontrol.c
Expand Up @@ -110,6 +110,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);
Expand Down Expand Up @@ -327,6 +329,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];
Expand Down
4 changes: 4 additions & 0 deletions sys/sys/nata.h
Expand Up @@ -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 */
Expand Down

0 comments on commit 60779d5

Please sign in to comment.