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 */