diff --git a/sbin/natacontrol/natacontrol.8 b/sbin/natacontrol/natacontrol.8 index 74d078b97a7e..390f9147f463 100644 --- a/sbin/natacontrol/natacontrol.8 +++ b/sbin/natacontrol/natacontrol.8 @@ -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 @@ -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 @@ -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 . diff --git a/sbin/natacontrol/natacontrol.c b/sbin/natacontrol/natacontrol.c index 8f3805af37fb..cdf03efdd8e5 100644 --- a/sbin/natacontrol/natacontrol.c +++ b/sbin/natacontrol/natacontrol.c @@ -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); @@ -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]; diff --git a/sys/sys/nata.h b/sys/sys/nata.h index 6b0af7e552f2..38a8489080a7 100644 --- a/sys/sys/nata.h +++ b/sys/sys/nata.h @@ -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 */