Changes of Revision 2
[-] | Added | ataidle.changes |
1
2 +------------------------------------------------------------------- 3 +Mon Nov 14 17:48:58 UTC 2011 - cs@linux-administrator.com 4 + 5 +- Update to version 2.7.1 6 + 7 |
||
[-] | Changed | ataidle.spec ^ |
16 1
2 %define pkg_name ataidle 3 Name: ATAidle 4 -Version: 2.4 5 +Version: 2.7.1 6 Release: 1 7 Group: System 8 Summary: spin down ATA drives 9 License: see COPYING 10 URL: http://www.cran.org.uk/bruce/software/ataidle.php 11 -Source: %{pkg_name}-%{version}.tar.gz 12 +Source: %{pkg_name}-%{version}.tar.bz2 13 Patch0: %{pkg_name}.patch 14 BuildRoot: %{_tmppath}/%{name}-%{version}-build 15 Provides: %{pkg_name} 16 |
||
[+] | Changed | ataidle.patch ^ |
@@ -1,31 +1,29 @@ ---- Makefile.orig 2008-08-31 19:13:57.000000000 +0200 -+++ Makefile 2008-08-31 19:15:49.000000000 +0200 +--- Makefile.orig 2010-11-02 21:26:09.000000000 +0100 ++++ Makefile 2011-11-14 18:48:16.451883985 +0100 @@ -1,4 +1,4 @@ -PREFIX = /usr/local +PREFIX := /usr/local CC ?= gcc LD ?= ld - CFLAGS += -Wall -ansi -pedantic -@@ -30,16 +30,16 @@ - $(CC) $(CFLAGS) -c mi/util.c - - install: ataidle ataidle.8 freebsd/ataidle_rc -- install $(PROG) $(PREFIX)/sbin -+ install $(PROG) $(DESTDIR)$(PREFIX)/sbin + CFLAGS += -Wall -pedantic -std=c99 +@@ -37,14 +37,14 @@ + install $(PROG) $(PREFIX)/sbin if [ "$(OS)" = Linux ]; then \ -- if [ ! -d $(PREFIX)/share/man/man8 ]; then \ -- mkdir -p $(PREFIX)/share/man/man8; \ -+ if [ ! -d $(DESTDIR)$(PREFIX)/share/man/man8 ]; then \ -+ mkdir -p $(DESTDIR)$(PREFIX)/share/man/man8; \ - fi; \ -- install $(MAN) $(PREFIX)/share/man/man8; \ -+ install $(MAN) $(DESTDIR)$(PREFIX)/share/man/man8; \ +- if [ ! -d $(PREFIX)/share/man/man8 ]; then \ +- mkdir -p $(PREFIX)/share/man/man8; \ ++ if [ ! -d $(DESTDIR)$(PREFIX)/share/man/man8 ]; then \ ++ mkdir -p $(DESTDIR)$(PREFIX)/share/man/man8; \ + fi; \ +- install $(MAN) $(PREFIX)/share/man/man8; \ ++ install $(MAN) $(DESTDIR)$(PREFIX)/share/man/man8; \ else \ -- install $(MAN) $(PREFIX)/man/man8; \ -- install freebsd/ataidle_rc $(PREFIX)/etc/rc.d/ataidle; \ -+ install $(MAN) $(DESTDIR)$(PREFIX)/man/man8; \ -+ install freebsd/ataidle_rc $(DESTDIR)$(PREFIX)/etc/rc.d/ataidle; \ +- install $(MAN) $(PREFIX)/man/man8; \ +- install freebsd/ataidle_rc $(PREFIX)/etc/rc.d/ataidle; \ +- sed -I '' s:%%PREFIX%%:$(PREFIX):g $(PREFIX)/etc/rc.d/ataidle; \ ++ install $(MAN) $(DESTDIR)$(PREFIX)/man/man8; \ ++ install freebsd/ataidle_rc $(DESTDIR)$(PREFIX)/etc/rc.d/ataidle; \ ++ sed -I '' s:%%PREFIX%%:$(PREFIX):g $(DESTDIR)$(PREFIX)/etc/rc.d/ataidle; \ fi uninstall: | ||
[+] | Deleted | ataidle-2.4.tar.gz/mi/atadefs.h ^ |
@@ -1,34 +0,0 @@ -#ifndef ATADEFS_H -#define ATADEFS_H - -#include <stdint.h> - -static const uint32_t ATA__SETFEATURES = 0xEF; -static const uint32_t ATA__IDENTIFY = 0xEC; -static const uint32_t ATA__ATAPI_IDENTIFY = 0xA1; -static const uint32_t ATA_IDLE = 0xE3; -static const uint32_t ATA_STANDBY = 0xE2; - -#ifndef ATA_SLEEP -static const uint32_t ATA_SLEEP = 0xE6; -#endif - -static const uint32_t ATA_AUTOACOUSTIC_ENABLE = 0x42; -static const uint32_t ATA_AUTOACOUSTIC_DISABLE = 0xC2; -static const uint32_t ATA_APM_ENABLE = 0x05; -static const uint32_t ATA_APM_DISABLE = 0x85; -static const uint32_t ATA_AUTOACOUSTIC_MAXPERF = 0xFE; -static const uint32_t ATA_AUTOACOUSTIC_MINPERF = 0x80; -static const uint32_t ATA_APM_MINPOWER_NO_STANDBY = 0x80; -static const uint32_t ATA_APM_MINPERF = 0x01; -static const uint32_t ATA_APM_MAXPERF = 0xFE; -static const uint32_t ATA_POWERSTATUS_GET = 0xE5; -static const uint32_t ATA_CMD_TIMEOUT = 10; -static const uint32_t ATA_IDLEVAL_IMMEDIATE = 900; - -#ifndef __FreeBSD__ -static const uint32_t ATA_STANDBY_IMMEDIATE = 0xE0; -static const uint32_t ATA_IDLE_IMMEDIATE = 0xE1; -#endif - -#endif /* ATADEFS_H */ | ||
[+] | Deleted | ataidle-2.4.tar.gz/mi/util.h ^ |
@@ -1,20 +0,0 @@ -#ifndef UTIL_H -#define UTIL_H - -#include <stdint.h> -#include <stdbool.h> - -#define ATAIDLE_VERSION "2.4" - -void usage(void); -int ata_strtolong( const char *src, long * dest ); -int ata_getidleval( uint32_t idle_mins, uint16_t *timer_val ); -char* ata_getversionstring(uint16_t ata_version); -void byteswap(char * buf, int from, int to); -void strpack(char * buf, int from, int to); -bool checkargs( int argc, char ** argv, const char *optstr, bool * needchandev ); -void byteswap_ata_data( int16_t * buf ); -void hexdump( const char *data, int count ); -void mem_swap(int16_t * val); - -#endif /* UTIL_H */ | ||
[+] | Changed | ataidle-2.7.1.tar.bz2/COPYING ^ |
@@ -1,4 +1,4 @@ -Copyright 2004-2008 Bruce Cran <bruce@cran.org.uk>. All rights reserved. +Copyright 2004-2010 Bruce Cran <bruce@cran.org.uk>. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions | ||
[+] | Changed | ataidle-2.7.1.tar.bz2/Changelog ^ |
@@ -95,3 +95,20 @@ Sat Aug 30 02:55 2008 brucec * Fixed endian issue. ataidle now runs correctly on FreeBSD/powerpc. + +Sun Sep 15 01:44 2008 brucec + * Cleanup. Make function static where possible. + +Tue Oct 02 19:00 2010 brucec + * Added support for ATA disks using ATA_CAM + and ahci(4) in FreeBSD. +Thu Sep 22 20:47 2011 brucec + * Integrated cleanup and write cache support + from FreeBSD. + Fixed bug that caused problems on some + controllers due to setting CAM_OUT for commands + where no data is transferred. +Sun Oct 23 13:23 2011 brucec + * Resolve symlinks when checking which device + interface to use, since FreeBSD 9.0 creates + symlinks from adX to adaX. | ||
[+] | Changed | ataidle-2.7.1.tar.bz2/Makefile ^ |
@@ -1,7 +1,7 @@ PREFIX = /usr/local CC ?= gcc LD ?= ld -CFLAGS += -Wall -ansi -pedantic +CFLAGS += -Wall -pedantic -std=c99 LIBS = -lm SOURCES = ataidle.c MAN = ataidle.8 @@ -11,35 +11,40 @@ OS ?= $(shell uname -s) REV:sh = uname -r | head -c 1 -all: ataidle +all: ataidle -ataidle: ataidle.o util.o main.o - $(CC) $(CFLAGS) $(LIBS) -o ataidle main.o ataidle.o util.o +ataidle: ataidle.o util.o main.o + @if [ "$(OS)" = FreeBSD ]; then \ + $(CC) $(CFLAGS) $(LIBS) -lcam -o ataidle main.o ataidle.o util.o; \ + else \ + $(CC) $(CFLAGS) $(LIBS) -o ataidle main.o ataidle.o util.o; \ + fi -main.o: main.c mi/atadefs.h mi/atagen.h mi/util.h +main.o: main.c mi/atagen.h $(CC) $(CFLAGS) -c main.c -ataidle.o: linux/ataidle.c freebsd/ataidle.c mi/atagen.h mi/atadefs.h mi/util.h +ataidle.o: linux/ataidle.c freebsd/ataidle.c mi/atagen.h @if [ "$(OS)" = Linux ]; then \ - $(CC) $(CFLAGS) -c linux/ataidle.c; \ + $(CC) $(CFLAGS) -c linux/ataidle.c; \ elif [ "$(OS)" = FreeBSD ]; then \ - $(CC) $(CFLAGS) -c freebsd/ataidle.c; \ + $(CC) $(CFLAGS) -c freebsd/ataidle.c; \ fi -util.o: mi/util.c mi/util.h mi/atadefs.h mi/atagen.h +util.o: mi/util.c mi/atagen.h $(CC) $(CFLAGS) -c mi/util.c install: ataidle ataidle.8 freebsd/ataidle_rc install $(PROG) $(PREFIX)/sbin if [ "$(OS)" = Linux ]; then \ - if [ ! -d $(PREFIX)/share/man/man8 ]; then \ - mkdir -p $(PREFIX)/share/man/man8; \ - fi; \ - install $(MAN) $(PREFIX)/share/man/man8; \ + if [ ! -d $(PREFIX)/share/man/man8 ]; then \ + mkdir -p $(PREFIX)/share/man/man8; \ + fi; \ + install $(MAN) $(PREFIX)/share/man/man8; \ else \ - install $(MAN) $(PREFIX)/man/man8; \ - install freebsd/ataidle_rc $(PREFIX)/etc/rc.d/ataidle; \ + install $(MAN) $(PREFIX)/man/man8; \ + install freebsd/ataidle_rc $(PREFIX)/etc/rc.d/ataidle; \ + sed -I '' s:%%PREFIX%%:$(PREFIX):g $(PREFIX)/etc/rc.d/ataidle; \ fi uninstall: | ||
[+] | Changed | ataidle-2.7.1.tar.bz2/README ^ |
@@ -1,33 +1,27 @@ -ATAidle sets the idle timer on ATA hard drives, so they spin down when the -period of inactivity has expired. To use it, you must be running FreeBSD 6.2 -or newer - alternatively, you can also -run it on Linux - it's been tested with kernel 2.6.1, but should work with -any recent kernel. +ATAidle sets the standby timer on ATA hard drives so they spin down when the +period of inactivity has expired. To use it you must be running FreeBSD 6.2 +or newer - alternatively, you can also run it on Linux - it's been tested with +kernel 2.6.1, but should work with any recent kernel. Supplying a device name without any parameters will display information about the specified device. Notes on Auto Acoustic Management (AAM) and APM support -Use of this feature is experimental, and may crash your computer - although -it is believed to be stable, it is modifying hard disk behaviour as data is -being read or written, so any fault in the drive could have disastrous -consequenses for your data. - Meaning of various AutoAcoustic values: -0 Acoustic management disabled -1 Minimum acoustic output -2-126 Intermediate acoustic output levels -127 Maximum performance, maximum acoustic output +0 Acoustic management disabled. +1 Minimum noise. +2-126 Intermediate noise levels. +127 Maximum performance, maximum noise. Meaning of various APM values: -1 Minimum power usage with Standby (spindown) -2-127 Intermediate power usage with Standby -128 Minimum power usage without Standby (no spindown) -129-253 Intermediate power usage without Standby -254 Maximum performance, maximum power usage +1 Minimum power usage with Standby (spindown). +2-127 Intermediate power usage with Standby. +128 Minimum power usage without Standby (no spindown). +129-253 Intermediate power usage without Standby. +254 Maximum performance, maximum power usage. Some values may not be supported, in this case you will see an error message 'Set APM failed: Inappropriate ioctl for device'. | ||
[+] | Changed | ataidle-2.7.1.tar.bz2/ataidle.8 ^ |
@@ -1,100 +1,101 @@ .\" man page for ATAidle .\" Contact bruce@cran.org.uk to correct errors or omissions -.TH man 8 "August 2008" "2.4" "ATAidle" +.TH man 8 "November 2011" "2.7.1" "ATAidle" .SH NAME ataidle \- a utility to spin down ATA drives .SH SYNOPSIS -.\" Syntax goes here. -.B ataidle [-h] [-i] [-s] [-o] [-I -.I idle_mins +.\" Syntax goes here. +.B ataidle [-h] [-i] [-s] [-o] [-I +.I standby_mins .B ] [-S .I standby_mins .B ] [-A -.I acoustic_level +.I aam_level .B ] [-P .I apm_level .B ] .I device .SH DESCRIPTION .B ATAidle -sets various power management features on hard drives, including -timeouts to switch to idle and standby power saving modes, -and setting the APM (power) and AAM (acoustic) levels. -If only a device is specified, without options, information -about the selected device will be shown. +sets various power management features on hard drives, including timeouts to +switch to idle and standby power saving modes, and setting the +APM (power) and AAM (acoustic) levels. +If only a device is specified, without options, information about the +selected device will be shown. .SH OPTIONS .IP -h -show usage information +Show usage information .IP -i -put the drive into idle mode +Puts the drive into Idle mode .IP -s -put the drive into standby mode +Puts the drive into Standby mode .IP -o -put the drive into sleep mode -.IP -I -spins down the drive into -.B idle -mode after idle_mins minutes of inactivity +Puts the drive into Sleep mode +.IP -I +Puts the drive into +.B Idle +mode and configures the standby timer to put the drive into +.B Standby +mode after standby_mins minutes of inactivity. .IP -S -spins down the drive into -.B standby +Puts the drive into +.B Standby +mode and configures the standby timer to put the drive into +.B Standby mode after standby_mins minutes of inactivity. -However, using this mode usually immediately spins -down the drive. .IP -A -set the +Set the .B acoustic level of the hard drive. This allows you to reduce the acoustic output of the drive at the expense of performance. .IP -P -set the +Set the .B Advanced Power Management -level of the drive. This allows you to lower the power -consumption of the drive, at the expense of performance. -A very low +level of the drive. This allows you to reduce the power +consumption of the drive at the expense of performance. +A low .B apm_level -will make the drive go into standby mode to save power. +will cause the drive to go into +.B Standby +mode to save power. .SH NOTES Notes on Auto Acoustic Management (AAM) and APM support -These features are experimental, and should only be used -after verifying that the drive works when sent those commands. - -AAM and APM settings are vendor-specific, and not all intermediate values -may be valid. If you set an invalid APM value, you will be notified that -it failed - when setting an AAM value you should check the output of - 'ataidle <device>' to see if it has been updated. If it hasn't, the -value isn't supported and you should try a higher or lower setting. +AAM and APM settings are vendor-specific and not all intermediate values may be valid. +If you set an invalid APM value you will be notified that it failed - when +setting an AAM value you should check the output of 'ataidle <device>' to see +if it has been updated. +If it hasn't, the value isn't supported and you should try a higher or lower setting. .IP Meaning of AAM values: -.IP 0 -Acoustic management disabled -.IP 1 -Minimum acoustic output -.IP 2-126 -Intermediate acoustic output levels -.IP 127 -Maximum performance, maximum acoustic output +.IP 0 +Acoustic management disabled. +.IP 1 +Minimum noise. +.IP 2-126 +Intermediate noise levels. +.IP 127 +Maximum performance, maximum noise. Meaning of APM values: .IP 0 APM disabled -.IP 1 -Minimum power usage with Standby (spindown) -.IP 2-127 -Intermediate power usage with Standby -.IP 128 -Minimum power usage without Standby (no spindown) -.IP 129-253 -Intermediate power usage without Standby -.IP 254 -Maximum performance, maximum power usage +.IP 1 +Minimum power usage with Standby (spindown). +.IP 2-127 +Intermediate power usage with Standby. +.IP 128 +Minimum power usage without Standby (no spindown). +.IP 129-253 +Intermediate power usage without Standby. +.IP 254 +Maximum performance, maximum power usage. .SH AUTHOR Bruce Cran <bruce@cran.org.uk> .SH "SEE ALSO" | ||
[+] | Changed | ataidle-2.7.1.tar.bz2/freebsd/ataidle.c ^ |
@@ -1,6 +1,6 @@ /*- * - * Copyright 2004-2008 Bruce Cran <bruce@cran.org.uk>. All rights reserved. + * Copyright 2004-2011 Bruce Cran <bruce@cran.org.uk>. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,77 +26,203 @@ * */ +#include <errno.h> +#include <fcntl.h> +#include <libgen.h> +#include <limits.h> +#include <osreldate.h> +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <fcntl.h> -#include <limits.h> #include <unistd.h> -#include <errno.h> #include <sys/types.h> #include <sys/ata.h> #include <sys/ioctl.h> +#include <sys/param.h> +#include <camlib.h> +#include <cam/cam_ccb.h> +#include <cam/scsi/scsi_all.h> +#include <cam/scsi/scsi_message.h> -#include "ataidle.h" #include "../mi/atagen.h" -#include "../mi/atadefs.h" -#include "../mi/util.h" +#include "ataidle.h" -/* send a command to the drive */ -int ata_cmd(ATA *ata, int atacmd, int drivercmd) +ATA* +ata_open(const char *path) +{ + ATA *ata = NULL; + bool using_cam = false; + + ata = malloc(sizeof(ATA)); + if (ata == NULL) + return NULL; + + char *fullpath = realpath(path, NULL); + if (fullpath == NULL) + return NULL; + + char *bp = basename(fullpath); + + /* Check which driver we're using: ata(4), ahci(4) or da(4) */ + if (bp[0] == 'a' && bp[1] == 'd') { + if (bp[2] == 'a') { + ata->disk_protocol = DISK_PROTO_ATA_CAM; + using_cam = true; + } else { + ata->disk_protocol = DISK_PROTO_ATA; + ata->ata_fd = open(fullpath, O_RDONLY); + if (ata->ata_fd < 0) { + free(ata); + free(fullpath); + return NULL; + } + } + } else { + ata->disk_protocol = DISK_PROTO_SCSI; + using_cam = true; + } + + if (using_cam) { + ata->cam_dev = cam_open_device( fullpath, O_RDWR ); + if (ata->cam_dev == NULL) { + free(ata); + free(fullpath); + return NULL; + } + } + + free(fullpath); + return ata; +} + +void +ata_close( ATA *ata ) +{ + if (ata->ata_fd >= 0) + close(ata->ata_fd); + + free(ata); +} + +int +atacmd_ata(ATA *ata, int atacmd, int feature, int feature_val) +{ + int rc; + + ata->atacmd.u.ata.command = atacmd; + ata->atacmd.u.ata.feature = feature; + ata->atacmd.u.ata.count = feature_val; + + rc = ioctl(ata->ata_fd, IOCATAREQUEST, &(ata->atacmd)); + return rc; +} + +#if __FreeBSD_version > 800000 +int +atacmd_cam(ATA *ata, int atacmd, int feature, int feature_val) { + union ccb *ccb = cam_getccb(ata->cam_dev); + + int direction; int rc = 0; + uint32_t timeout = ATA_CMD_TIMEOUT*1000; - if (atacmd > 0) - ata->atacmd.ata_cmd.u.ata.command = atacmd; + if (atacmd == ATA__IDENTIFY || atacmd == ATA__ATAPI_IDENTIFY) + direction = CAM_DIR_IN; + else + direction = CAM_DIR_NONE; + memset(&(&ccb->ccb_h)[1], 0, sizeof(struct ccb_ataio) - sizeof(struct ccb_hdr)); - if (drivercmd == IOCATAGMAXCHANNEL) { - int maxchan = 0; - rc = ioctl( ata->fd, drivercmd, &maxchan ); - ata->atacmd.ata_cmd.data = malloc(sizeof(int)); - *ata->atacmd.ata_cmd.data = maxchan; - } else { - rc = ioctl( ata->fd, IOCATAREQUEST, &(ata->atacmd.ata_cmd) ); + cam_fill_ataio(&ccb->ataio, + 5, NULL, + direction, MSG_SIMPLE_Q_TAG, + (uint8_t*)ata->outbuffer, ata->outbuffer_size, + timeout); + + ata_28bit_cmd(&ccb->ataio, atacmd, feature, 0, feature_val); + + ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; + + if (cam_send_ccb(ata->cam_dev, ccb) < 0) { + cam_error_print(ata->cam_dev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); + rc = 1; } + if (!rc && (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { + cam_error_print(ata->cam_dev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); + rc = 1; + } + + cam_freeccb(ccb); + return rc; } +#endif -/* initialize the ata_cmd structure with supplied values */ -int ata_setataparams( ATA *ata, int seccount, int count) +/* send a command to the drive */ +int +ata_cmd(ATA *ata, int atacmd, int feature, int feature_val) { - /* clear the structure to remove any random values */ - memset(& ata->atacmd, 0, sizeof(struct ata_cmd)); - ata->atacmd.ata_cmd.u.ata.command = (uint8_t) IOCATAREQUEST; - ata->atacmd.ata_cmd.flags = ATA_CMD_CONTROL; - ata->atacmd.ata_cmd.timeout = ATA_CMD_TIMEOUT; - ata->atacmd.ata_cmd.count = count; - ata->atacmd.ata_cmd.u.ata.count = seccount; + int rc = 0; + + if (ata->disk_protocol == DISK_PROTO_ATA) + rc = atacmd_ata(ata, atacmd, feature, feature_val); +#if __FreeBSD_version > 800000 + else if (ata->disk_protocol == DISK_PROTO_ATA_CAM) + rc = atacmd_cam(ata, atacmd, feature, feature_val); +#endif + + return rc; - return 0; } -void ata_setfeature_param( ATA *ata, int feature_val) +/* initialize the ata_cmd structure with supplied values */ +void +ata_init(ATA *ata) { - ata->atacmd.ata_cmd.u.ata.feature = feature_val; + if (ata->disk_protocol == DISK_PROTO_ATA) { + memset(&ata->atacmd, 0, sizeof(struct ata_ioc_request)); + + ata->atacmd.u.ata.command = (uint8_t) IOCATAREQUEST; + ata->atacmd.flags = ATA_CMD_CONTROL; + ata->atacmd.timeout = ATA_CMD_TIMEOUT; + ata->atacmd.count = 0; + } } -void ata_setdataout_params( ATA *ata, char ** databuf, int nbytes) + +char* +ata_setup_buffer(ATA *ata, int nbytes) { - *databuf = malloc(nbytes); + char *databuf = malloc(nbytes); - if(*databuf == 0) + if (databuf == NULL) { /* malloc failed, there's no way to recover here */ - fprintf(stderr, "malloc failed. aborting\n"); - exit(EXIT_FAILURE); + fprintf(stderr, "malloc failed.\n"); + exit(1); } - memset(*databuf, 0, nbytes); - ata->atacmd.ata_cmd.data = *databuf; - ata->atacmd.ata_cmd.count = nbytes; - ata->atacmd.ata_cmd.flags = ATA_CMD_READ; + memset(databuf, 0, nbytes); + + if (ata->disk_protocol == DISK_PROTO_ATA) { + ata->atacmd.data = databuf; + ata->atacmd.count = nbytes; + ata->atacmd.flags = ATA_CMD_READ; + } + + ata->outbuffer = databuf; + ata->outbuffer_size = nbytes; + + return databuf; } +void +ata_free(ATA *ata) +{ + if (ata->outbuffer != NULL) + free(ata->outbuffer); +} | ||
[+] | Changed | ataidle-2.7.1.tar.bz2/freebsd/ataidle.h ^ |
@@ -1,7 +1,7 @@ /*- - * - * Copyright 2004-2008 Bruce Cran <bruce@cran.org.uk>. All rights reserved. - * + * + * Copyright 2004-2010 Bruce Cran <bruce@cran.org.uk>. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -12,7 +12,7 @@ * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. @@ -23,7 +23,7 @@ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * */ @@ -33,9 +33,19 @@ #include <sys/types.h> #include <sys/ata.h> -struct ata_cmd +#include <stdio.h> +#include <camlib.h> + +typedef struct { - struct ata_ioc_request ata_cmd; -}; + int ata_fd; + struct cam_device *cam_dev; + uint32_t cmd; + struct ata_ioc_request atacmd; + enum DISK_PROTO disk_protocol; + char *outbuffer; + size_t outbuffer_size; + +} ATA; #endif /* ATAIDLE_H */ | ||
[+] | Changed | ataidle-2.7.1.tar.bz2/freebsd/ataidle_rc ^ |
@@ -9,27 +9,24 @@ # ataidle_enable (bool): set to NO by default. # Set to YES to enable ataidle. # ataidle_devices: list of devices on which to run ataidle -# ataidle_adX: parameters to pass to ataidle(8) +# ataidle_adaX: parameters to pass to ataidle(8) # Example: -# Put the disks ad0, ad1 and ad2 into Idle mode after 60 -# minutes and Standby mode after 120 minutes. Also, set the -# AAM and APM values to their maximum so the drives run at -# their maximum performance. +# Put the disks ada0, ada1 and ada2 into Standby mode after 60 minutes: # -# ataidle_devices="ad0 ad1 ad2" -# ataidle_ad0="-I 60 -S 120 -A 127 -P 254" -# ataidle_ad1="-I 60 -S 120 -A 127 -P 254" -# ataidle_ad2="-I 60 -S 120 -A 127 -P 254" +# ataidle_devices="ada0 ada1 ada2" +# ataidle_ada0="-S 60" +# ataidle_ada1="-S 60" +# ataidle_ada2="-S 60" # -. %%RC_SUBR%% +. /etc/rc.subr name="ataidle" rcvar=${name}_enable -command="%%PREFIX%%/sbin/${name}" -start_cmd="ataidle_start" +command=%%PREFIX%%/sbin/${name} +start_cmd=ataidle_start load_rc_config $name @@ -45,7 +42,7 @@ if [ -n "${ataidle_devices}" ]; then for i in ${ataidle_devices}; do eval ataidle_args=\$ataidle_${i} - echo "ATAidle: configuring device /dev/${i}" + echo "ataidle: configuring device /dev/${i}" ${command} ${ataidle_args} /dev/${i} done fi | ||
[+] | Changed | ataidle-2.7.1.tar.bz2/linux/ataidle.c ^ |
@@ -1,7 +1,7 @@ /*- - * - * Copyright 2004-2008 Bruce Cran <bruce@cran.org.uk>. All rights reserved. - * + * + * Copyright 2004-2010 Bruce Cran <bruce@cran.org.uk>. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -12,7 +12,7 @@ * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. @@ -23,10 +23,9 @@ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * */ -/* standard includes */ #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -40,44 +39,70 @@ #include <sys/stat.h> #include <linux/hdreg.h> -/* application-specific includes */ -#include "ataidle.h" #include "../mi/atagen.h" -#include "../mi/atadefs.h" -#include "../mi/util.h" /* send a command to the drive */ -int ata_cmd(ATA *ata, int cmd, int drivercmd) +int +ata_cmd(ATA *ata, int cmd, int feature, int feature_val) { int rc = 0; - + + ata->atacmd.feature = feature; + + if(feature != 0) + ata->atacmd.sector_number = feature; + else + ata->atacmd.sector_count = 1; + ata->atacmd.cmd = cmd; - rc = ioctl( ata->fd, HDIO_DRIVE_CMD, &ata->atacmd ); - + rc = ioctl( ata->ata_fd, HDIO_DRIVE_CMD, &ata->atacmd ); + return rc; } /* initialize the ata_cmd structure with supplied values */ -int ata_setataparams(ATA *ata, int seccount, int count) +void +ata_init(ATA *ata) { - /* clear the structure to remove any random values */ memset(&ata->atacmd, 0, sizeof(struct ata_cmd)); - - if(seccount != 0) - ata->atacmd.sector_number = seccount; - else - ata->atacmd.sector_count = 1; - - return 0; } -void ata_setdataout_params(ATA *ata, char ** databuf, int nbytes) +char* +ata_setup_buffer(ATA *ata, int nbytes) { - *databuf = (char*) ata->atacmd.buf; + return (char*) ata->atacmd.buf; } +ATA* +ata_open(const char *path) +{ + ATA *ata = NULL; + + ata = malloc(sizeof(ATA)); + if (ata == NULL) + return NULL; + + ata->disk_protocol = DISK_PROTO_ATA; + ata->ata_fd = open(path, O_RDONLY); + if (ata->ata_fd < 0) { + free(ata); + return NULL; + } -void ata_setfeature_param(ATA *ata, int feature) + return ata; +} + +void +ata_close(ATA *ata) { - ata->atacmd.feature = feature; + if (ata->ata_fd >= 0) + close(ata->ata_fd); + + free(ata); +} + +void +ata_free(ATA *ata) +{ + /* nothing to do */ } | ||
[+] | Changed | ataidle-2.7.1.tar.bz2/linux/ataidle.h ^ |
@@ -1,7 +1,7 @@ /*- - * - * Copyright 2004-2008 Bruce Cran <bruce@cran.org.uk>. All rights reserved. - * + * + * Copyright 2004-2010 Bruce Cran <bruce@cran.org.uk>. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -12,7 +12,7 @@ * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. @@ -23,7 +23,7 @@ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * */ @@ -31,7 +31,6 @@ #define ATAIDLE_H #include <stdint.h> -#include <stdbool.h> struct ata_cmd { unsigned char cmd; @@ -41,4 +40,15 @@ unsigned char buf[512]; }; +typedef struct +{ + int ata_fd; + uint32_t cmd; + struct ata_cmd atacmd; + enum DISK_PROTO disk_protocol; + char *outbuffer; + size_t outbuffer_size; +} ATA; + + #endif /* ATAIDLE_H */ | ||
[+] | Changed | ataidle-2.7.1.tar.bz2/main.c ^ |
@@ -1,6 +1,6 @@ /*- * - * Copyright 2004-2008 Bruce Cran <bruce@cran.org.uk>. All rights reserved. + * Copyright 2004-2010 Bruce Cran <bruce@cran.org.uk>. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,19 +28,12 @@ #include <err.h> #include <errno.h> -#include <fcntl.h> #include <getopt.h> #include <limits.h> #include <stdio.h> #include <stdlib.h> -#include <string.h> -#include <sysexits.h> #include <unistd.h> -#include <sys/stat.h> -#include <sys/types.h> -#include "mi/atadefs.h" -#include "mi/util.h" #include "mi/atagen.h" #ifdef __FreeBSD__ @@ -51,100 +44,76 @@ #endif #endif -int main( int argc, char ** argv ) +int +main(int argc, char ** argv) { int rc = 0; - ATA *ata; + ATA *ata = NULL; long opt_val; int ch; struct ata_ident ident; - const char * const optstr = "hA:S:sI:iP:o"; - - ata = malloc(sizeof(ATA)); - - if (ata == NULL) - err(EX_SOFTWARE, NULL); + const char * const optstr = "hA:S:sI:iP:owW"; /* need more than just the executable name */ if( argc == 1 ) usage(); - ata->fd = -1; + ata = ata_open(argv[argc-1]); - /* now we've done all the checking of parameters etc., - * let's see what the user wants us to do. - */ - - /* if we've got a non-option string, - * see if it's a device node */ - if (argv[argc-1][0] != '-') { - struct stat sb; - rc = stat( argv[argc-1], &sb ); - if (rc) - err(EX_OSFILE, "%s", argv[argc-1]); - - if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) - rc = open( argv[argc-1], O_RDONLY ); - else - errx(EX_OSFILE, "%s isn't a device node", argv[argc-1]); - - if (rc > 0) - ata->fd = rc; - else - err(EX_IOERR, "error opening %s", argv[argc-1]); - - if (argc == 2) - ata_showdeviceinfo(ata); - } + if (ata == NULL) + errx(1, "error opening %s", argv[argc-1]); - optind = 1; - opterr = 1; + rc = ata_identify(ata, &ident); - if (ata->fd != -1) { - rc = ata_ident( ata, &ident ); - if (rc) - errx(EX_SOFTWARE, "an error occurred identifying the device %s\n", argv[argc-1]); - } + if (rc) + errx(1, "error: identify device %s\n", argv[argc-1]); + if (argc == 2) + ata_showdeviceinfo(ata, ident); + + optind = 1; + opterr = 1; while ((ch = getopt(argc, argv, optstr)) != -1) { switch(ch) { - /* S = Standby */ + /* Standby */ case 'S': - opt_val = strtol( optarg, NULL, 10 ); - if(opt_val == LONG_MIN || opt_val == LONG_MAX) - warnx("invalid standby value"); + opt_val = strtol(optarg, NULL, 10); + if(opt_val == LONG_MIN || opt_val == LONG_MAX || + (opt_val == 0 && errno == EINVAL)) + warnx("invalid standby timer value"); else { if (ident.cmd_supp1 & ATA_PM_SUPPORTED) - rc = ata_setstandbytimer( ata, opt_val ); + rc = ata_setstandbytimer(ata, opt_val); else warnx("the device does not support power management"); } break; case 's': - rc = ata_setstandbytimer( ata, ATA_IDLEVAL_IMMEDIATE ); + rc = ata_setstandbytimer(ata, ATA_IDLEVAL_IMMEDIATE); break; /* o = Sleep (off) */ case 'o': if (ident.cmd_supp1 & ATA_PM_SUPPORTED) - rc = ata_sleep( ata ); + rc = ata_sleep(ata); else warnx("the device does not support power management"); break; - /* I = Idle */ + /* Idle */ case 'I': - opt_val = strtol( optarg, NULL, 10 ); + opt_val = strtol(optarg, NULL, 10); - if(opt_val == LONG_MIN || opt_val == LONG_MAX) - warnx("invalid idle value"); + if(opt_val == LONG_MIN || opt_val == LONG_MAX || + (opt_val == 0 && errno == EINVAL)) + warnx("invalid standby timer value"); else { if (ident.cmd_supp1 & ATA_PM_SUPPORTED) - rc = ata_setidletimer( ata, opt_val ); + rc = ata_setidletimer(ata, opt_val); else warnx("the device does not support power management"); } @@ -154,32 +123,52 @@ rc = ata_setidletimer(ata, ATA_IDLEVAL_IMMEDIATE); break; - /* A = AutoAcoustic */ + /* Acoustic */ case 'A': - opt_val = strtol( optarg, NULL, 10 ); - if(opt_val == LONG_MIN || opt_val == LONG_MAX) - warnx("invalid acoustic value"); + opt_val = strtol(optarg, NULL, 10); + if(opt_val == LONG_MIN || opt_val == LONG_MAX || + (opt_val == 0 && errno == EINVAL)) + warnx("invalid AAM value"); else { if (ident.cmd_supp2 & ATA_AAM_SUPPORTED) - rc = ata_setacoustic( ata, opt_val ); + rc = ata_setacoustic(ata, opt_val); else warnx("the device does not support acoustic management"); } break; - /* P = Power (APM) */ + /* Power (APM) */ case 'P': - opt_val = strtol( optarg, NULL, 10 ); - if(opt_val == LONG_MIN || opt_val == LONG_MAX) - warnx("invalid apm value"); + opt_val = strtol(optarg, NULL, 10); + if(opt_val == LONG_MIN || opt_val == LONG_MAX || + (opt_val == 0 && errno == EINVAL)) + warnx("invalid APM value"); else { if (ident.cmd_supp2 & ATA_APM_SUPPORTED) - rc = ata_setapm( ata, opt_val ); + rc = ata_setapm(ata, opt_val); else warnx("the device does not support advanced power management"); } break; + /* Write Cache Disable */ + case 'w': + if (!(ident.cmd_supp1 & ATA_WC_SUPPORTED)) { + warnx("the device does not support write cache"); + break; + } + rc = ata_setwc(ata, 0); + break; + + /* Write Cache Enable */ + case 'W': + if (!(ident.cmd_supp1 & ATA_WC_SUPPORTED)) { + warnx("the device does not support write cache"); + break; + } + rc = ata_setwc(ata, 1); + break; + case 'h': default: usage(); @@ -188,13 +177,8 @@ } if (ata != NULL) - { - if (ata->fd > 0) - close(ata->fd); + ata_close(ata); - free(ata); - } - return (rc); } | ||
[+] | Changed | ataidle-2.7.1.tar.bz2/mi/atagen.h ^ |
@@ -1,29 +1,30 @@ /*- -* Copyright 2004-2008 Bruce Cran <bruce@cran.org.uk>. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* 3. The name of the author may not be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -*/ + * + * Copyright 2004-2010 Bruce Cran <bruce@cran.org.uk>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ /* Generic definitions (applicable to all supported operating systems) */ @@ -33,6 +34,15 @@ #include <stdint.h> #include <stdbool.h> +#define ATAIDLE_VERSION "2.7.1" + +enum DISK_PROTO +{ + DISK_PROTO_ATA, + DISK_PROTO_ATA_CAM, + DISK_PROTO_SCSI +}; + #ifdef __FreeBSD__ #include <osreldate.h> #include <sys/ata.h> @@ -41,6 +51,50 @@ #include "../linux/ataidle.h" #endif +#define ATA_PM_SUPPORTED 0x0008 + +#define ATA_APM_SUPPORTED 0x0008 +#define ATA_APM_ENABLED 0x0008 + +#define ATA_AAM_SUPPORTED 0x0200 +#define ATA_AAM_ENABLED 0x0200 + +#define ATA_SMART_SUPPORTED 0x0001 +#define ATA_SMART_ENABLED 0x0001 + +#define ATA_WC_SUPPORTED 0x0020 +#define ATA_WC_ENABLED 0x0020 + +#define ATA__SETFEATURES 0xEF +#define ATA__IDENTIFY 0xEC +#define ATA__ATAPI_IDENTIFY 0xA1 +#define ATA_IDLE 0xE3 +#define ATA_STANDBY 0xE2 + +#ifndef ATA_SLEEP +#define ATA_SLEEP 0xE6 +#endif + +#define ATA_AUTOACOUSTIC_ENABLE 0x42 +#define ATA_AUTOACOUSTIC_DISABLE 0xC2 +#define ATA_APM_ENABLE 0x05 +#define ATA_APM_DISABLE 0x85 +#define ATA_WC_ENABLE 0x02 +#define ATA_WC_DISABLE 0x82 +#define ATA_AUTOACOUSTIC_MAXPERF 0xFE +#define ATA_AUTOACOUSTIC_MINPERF 0x80 +#define ATA_APM_MINPOWER_NO_STANDBY 0x80 +#define ATA_APM_MINPERF 0x01 +#define ATA_APM_MAXPERF 0xFE +#define ATA_POWERSTATUS_GET 0xE5 +#define ATA_CMD_TIMEOUT 30 +#define ATA_IDLEVAL_IMMEDIATE 900 + +#ifndef __FreeBSD__ +#define ATA_STANDBY_IMMEDIATE 0xE0 +#define ATA_IDLE_IMMEDIATE 0xE1 +#endif + struct ata_ident { uint16_t config; @@ -104,41 +158,24 @@ uint16_t integrity; }; -#define ATA_PM_SUPPORTED 0x0008 - -#define ATA_APM_SUPPORTED 0x0008 -#define ATA_APM_ENABLED 0x0008 - -#define ATA_AAM_SUPPORTED 0x0200 -#define ATA_AAM_ENABLED 0x0200 - -#define ATA_SMART_SUPPORTED 0x0001 -#define ATA_SMART_ENABLED 0x0001 - -typedef struct -{ - int fd; - uint32_t chan; - uint32_t dev; - uint32_t cmd; - struct ata_cmd atacmd; -} ATA; - -int ata_open( ATA *ata, const char *device ); -void ata_close( ATA *ata ); -int ata_setidletimer( ATA *ata, uint32_t idle_mins ); -int ata_sleep( ATA *ata ); -int ata_setstandbytimer( ATA *ata, uint32_t standby_mins ); -int ata_setacoustic( ATA *ata, uint32_t acoustic_val); -int ata_setapm( ATA *ata, uint32_t apm_val); -void ata_listdevices( ATA *ata ); -int ata_getmaxchan( ATA *ata, uint32_t *maxchan ); -int ata_cmd( ATA *ata, int atacmd, int drivercmd ); -bool ata_devpresent( ATA *ata ); -int ata_ident( ATA *ata, struct ata_ident * identity); -void ata_showdeviceinfo( ATA *ata ); -void ata_setfeature_param( ATA *ata, int feature_val); -int ata_setataparams( ATA *ata, int seccount, int count); -void ata_setdataout_params( ATA *ata, char ** databuf, int nbytes); +ATA* ata_open(const char *device); +void ata_close(ATA *ata); +int ata_setidletimer(ATA *ata, uint32_t idle_mins); +int ata_setwc(ATA *ata, int enable); +int ata_sleep(ATA *ata); +int ata_setstandbytimer(ATA *ata, uint32_t standby_mins); +int ata_setacoustic(ATA *ata, uint32_t acoustic_val); +int ata_setapm(ATA *ata, uint32_t apm_val); +void ata_listdevices(ATA *ata); +int ata_getmaxchan(ATA *ata, uint32_t *maxchan); +int ata_cmd(ATA *ata, int atacmd, int feature, int feature_val); +bool ata_devpresent(ATA *ata); +int ata_identify(ATA *ata, struct ata_ident *identity); +void ata_showdeviceinfo(ATA *ata, struct ata_ident ident); +void ata_setfeature(ATA *ata, int feature_val); +void ata_init(ATA *ata); +char* ata_setup_buffer(ATA *ata, int nbytes); +void ata_free(ATA *ata); +void usage(void); #endif /* ATAIDLE_H */ | ||
[+] | Changed | ataidle-2.7.1.tar.bz2/mi/util.c ^ |
@@ -1,5 +1,6 @@ /*- - * Copyright 2004-2008 Bruce Cran <bruce@cran.org.uk>. All rights reserved. + * + * Copyright 2004-2010 Bruce Cran <bruce@cran.org.uk>. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,17 +33,21 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sysexits.h> #include <unistd.h> -#include "atadefs.h" #include "atagen.h" -#include "util.h" static int is_big_endian(void); - -/* calculate the idle timer value to send to the drive. */ -int ata_getidleval(uint32_t idle_mins, uint16_t *timer_val) +static int ata_getidleval(uint32_t idle_mins, uint16_t *timer_val); +static char* ata_getversionstring(uint16_t ata_version); +static void byteswap(char *buf, int from, int to); +static void strpack(char *buf, int from, int to); +static void byteswap_ata_data(int16_t *buf); +static void mem_swap(int16_t *val); + +/* calculate the standby timer value to send to the drive. */ +static int +ata_getidleval(uint32_t idle_mins, uint16_t *timer_val) { int rc = 0; @@ -60,86 +65,90 @@ /* there is no encoding for values between 21 and 30 minutes */ if( (idle_mins > 21) && (idle_mins < 30) ) { - printf("cannot set timeout for values 20-30 minutes\n" ); - rc = -2; + fprintf(stderr, "Cannot set timeout for 22-29 minutes\n" ); + rc = -1; } /* after 30 mins, encoding is (idle_mins-29)*30, so you * can only encode multiples of 30 minutes */ if( idle_mins >= 30 ) { - /* if it's not a multiple of 30 minutes, or it's greater than 5 hours, - * we can't handle it. + /* if it's not a multiple of 30 minutes, + * or it's greater than 5 hours, we can't handle it. */ - if( (((idle_mins % 30) != 0) || (idle_mins > 330)) + if ((((idle_mins % 30) != 0) || (idle_mins > 330)) && (idle_mins != ATA_IDLEVAL_IMMEDIATE) ) { - printf( "idle value must be a multiple of 30 minutes, " - "up to 5 hours\n" ); - rc = -2; + fprintf(stderr, "Idle timer must be 1-21, or a multiple of 30 " + "up to 330 (5.5 hours)\n"); + rc = -1; } /* otherwise, calculate the timer value */ if(idle_mins == ATA_IDLEVAL_IMMEDIATE) *timer_val = ATA_IDLEVAL_IMMEDIATE; else - *timer_val = 241 + (idle_mins/30); + *timer_val = 240 + (idle_mins/30); } return rc; } - -char * ata_getversionstring( unsigned short ata_version ) +static char* +ata_getversionstring(uint16_t ata_version) { const int ATAVERSION_LEN = 16; char * version = malloc(ATAVERSION_LEN); int i; - if(version == 0) { /* malloc failed */ + if (version == 0) { /* malloc failed */ fprintf(stderr, "malloc failed\n"); return NULL; } memset(version, 0, ATAVERSION_LEN); - for(i = 0; i < 15; i++) { - if( (ata_version >> i) > 0 ) { + for (i = 0; i < 15; i++) { + if ((ata_version >> i) > 0) sprintf(version, "ATA-%d", i); - } } return version; } - -void usage(void) +void +usage(void) { - printf( "ataidle version " ATAIDLE_VERSION "\n\n" + printf("ataidle version " ATAIDLE_VERSION "\n\n" "usage: \n" - "ataidle [-h] [-i] [-s] [-o] [-I idle] [-S standby] [-A acoustic] [-P apm]\n" - "\tdevice\n\n" + "ataidle [-h] [-i] [-s] [-o] [-I standby_mins] [-S standby_mins]\n" + " [-A aam] [-P apm] device\n\n" "Options:\n"); printf( - "-h\t\tdisplay this help and exit\n" - "-I\t\tset the idle timeout in minutes\n" - "-i\t\tput the drive into idle mode\n" - "-S\t\tset the standby timeout in minutes\n" - "-s\t\tput the drive into standby mode\n" - "-o\t\tput the drive into sleep mode\n" - "-A\t\tset the acoustic level, values 1-127\n" - "-P\t\tset the power management level, values 1-254\n" - "device\t\tthe device node e.g /dev/ad0\n\n" - "if no options are specified, information\n" - "about the device will be displayed\n\n"); + "-h\t\tdisplay this help\n" + "-I\t\tenter idle mode and set the standby timer (minutes)\n" + "-i\t\tenter idle mode\n" + "-S\t\tenter standby mode and set the standby timer (minutes)\n" + "-s\t\tenter standby mode\n" + "-o\t\tenter sleep mode\n" + "-A\t\tset the AAM (acoustic) level (1-127)\n" + "-P\t\tset the APM (power) level, (1-254)\n" + "-W\t\tenable the write cache\n" + "-w\t\tdisable the write cache\n" + "device\t\tthe device node e.g. /dev/ada0\n\n" + "standby_mins is in minutes and has a range of 1-21, then 30-330 in 30\n" + "minute steps.\n\n" + "If no options are specified, information about the device will be displayed.\n"); - exit(EX_USAGE); + exit(1); } -void byteswap(char * buf, int from, int to) +static void +byteswap(char * buf, int from, int to) { int i; - for(i = from; i <= to; i+=2) + + for (i = from; i <= to; i+=2) { char b1 = buf[i]; buf[i] = buf[i+1]; @@ -147,13 +156,15 @@ } } -void strpack(char * buf, int from, int to) +/* Trim leading whitespace */ +static void +strpack(char *buf, int from, int to) { int i = 0, j= 0, k = 0; int numchars = (to-from)+1; char *tmpbuf = malloc(numchars*sizeof(char)); - if(tmpbuf == 0) { /* malloc failed, skip the string packing */ + if(tmpbuf == NULL) { /* malloc failed, skip the string packing */ fprintf(stderr, "malloc failed\n"); return; } @@ -178,7 +189,9 @@ free(tmpbuf); } -void mem_swap(int16_t * val) +/* swap the bytes */ +static void +mem_swap(int16_t * val) { int8_t * smallval = (int8_t*) val; int8_t tmp = smallval[0]; @@ -187,17 +200,18 @@ smallval[1] = tmp; } -static int is_big_endian(void) +/* detect if we're running on a big-endian platform */ +static int +is_big_endian(void) { int i = 0; ((char*)(&i))[0] = 1; return (i != 1); } -void ata_showdeviceinfo( ATA *ata ) +void +ata_showdeviceinfo(ATA *ata, struct ata_ident ident) { - int rc = 0; - struct ata_ident ident; int16_t *buf; unsigned int mbsize; char model[41]; @@ -205,15 +219,6 @@ char firmware[9]; char *ata_version = NULL; - memset(&ident, 0, sizeof(struct ata_ident)); - - rc = ata_ident( ata,(struct ata_ident*) &ident ); - - if (rc) { - printf("could not get device information: is a device attached?\n"); - return; - } - buf = (int16_t*) &ident; memset(model, 0, 41); @@ -227,61 +232,87 @@ printf("Model:\t\t\t%s\n", model); printf("Serial:\t\t\t%s\n", serial); printf("Firmware Rev:\t\t%s\n", firmware); - ata_version = ata_getversionstring(buf[80]); + ata_version = ata_getversionstring(ident.version_major); printf("ATA revision:\t\t%s\n", (ident.version_major > 1)? ata_version : "unknown/pre ATA-2"); - printf("LBA 48:\t\t\t%s\n", (buf[86] & 0x400)? "yes" : "no"); - printf("Geometry:\t\t%d cyls, %d heads, %d spt\n", buf[1], buf[3], buf[6]); + printf("LBA 48:\t\t\t%s\n", (ident.cmd_enabled2 & 0x400)? "yes" : "no"); + printf("Geometry:\t\t%d cyls, %d heads, %d spt\n", + ident.word1, ident.word3, ident.word6); if (ata_version != NULL) free(ata_version); mbsize = 0; - if (buf[86] & 0x400) + if (ident.cmd_enabled2 & 0x400) { mbsize = (((uint64_t)ident.max_lba48_address[0] + ((uint64_t)ident.max_lba48_address[1] << 16) + ((uint64_t)ident.max_lba48_address[2] << 32) + ((uint64_t)ident.max_lba48_address[3] << 48))*512)/1048576; } - else + else { mbsize = ((ident.nsect[0] + (ident.nsect[1] << 16))*512)/1048576; } + bool smart_supported = ident.cmd_supp1 & ATA_SMART_SUPPORTED; + bool smart_enabled = ident.cmd_enabled1 & ATA_SMART_ENABLED; + bool wc_supported = ident.cmd_supp1 & ATA_WC_SUPPORTED; + bool wc_enabled = ident.cmd_enabled1 & ATA_WC_ENABLED; + bool apm_supported = ident.cmd_supp2 & ATA_APM_SUPPORTED; + bool apm_enabled = ident.cmd_enabled2 & ATA_APM_ENABLED; + bool aam_supported = ident.cmd_supp2 & ATA_AAM_SUPPORTED; + bool aam_enabled = ident.cmd_enabled2 & ATA_AAM_ENABLED; + printf("Capacity:\t\t%u%s\n", (mbsize < 1024)? mbsize : mbsize/1024, (mbsize < 1024)? "MB" : "GB"); - printf("SMART Supported: \t%s\n", (buf[82] & 1)? "yes" : "no" ); - if(buf[82] & 1) - printf("SMART Enabled: \t\t%s\n", (buf[85] & 1)? "yes" : "no" ); - printf("APM Supported: \t\t%s\n", (buf[83] & 8)? "yes" : "no" ); - if(buf[83] & 8) - printf("APM Enabled: \t\t%s\n", (buf[86] & 8)? "yes" : "no" ); - printf("AAM Supported: \t\t%s\n", (buf[83] & 0x200)? "yes" : "no" ); - printf("AAM Enabled: \t\t%s\n", (buf[86] & 0x200)? "yes" : "no"); - if((buf[86] & 0x200)) { - printf("Current AAM: \t\t%d\n", ((buf[94] & 0x00FF))-127); - printf("Vendor Recommends AAM: \t%d\n", ((buf[94] & 0xFF00) >> 8)-127); + + printf("SMART Supported: \t%s\n", smart_supported? "yes" : "no" ); + + if (smart_supported) + printf("SMART Enabled: \t\t%s\n", smart_enabled? "yes" : "no" ); + + printf("Write Cache Supported: \t%s\n", wc_supported? "yes" : "no" ); + + if (wc_supported) + printf("Write Cache Enabled: \t%s\n", wc_enabled? "yes" : "no" ); + + printf("APM Supported: \t\t%s\n", apm_supported? "yes" : "no" ); + + if (apm_supported) { + printf("APM Enabled: \t\t%s\n", apm_enabled? "yes" : "no" ); + if (apm_enabled) + printf("APM Value: \t\t%d\n", ident.apm_value); } - if((buf[86] & 8)) - printf("APM Value: \t\t%d\n", buf[91]); + printf("AAM Supported: \t\t%s\n", aam_supported? "yes" : "no" ); + + if (aam_supported) { + printf("AAM Enabled: \t\t%s\n", aam_enabled? "yes" : "no"); + if (aam_enabled) + printf("AAM Value: \t\t%d\n", ((ident.aam_value & 0x00FF))-127); + + printf("Vendor Recommended AAM: %d\n", ((ident.aam_value & 0xFF00) >> 8)-127); + } } -void byteswap_ata_data( int16_t * buf ) +static void +byteswap_ata_data(int16_t * buf) { int i; - for (i = 0; i < 10; i++) + for (i = 0; i < 10; i++) { mem_swap(buf+i); + } - for (i = 20; i < 23; i++) + for (i = 20; i < 23; i++) { mem_swap(buf+i); + } - for (i = 47; i < 255; i++) + for (i = 47; i < 255; i++) { mem_swap(buf + i); - + } } /* @@ -290,40 +321,50 @@ * lowest (least performance) to highest power consumption, which results * in the highest performance. */ -int ata_setapm( ATA *ata, uint32_t apm_val) +int +ata_setapm(ATA *ata, uint32_t apm_val) { int rc = 0; + int apm_onoff_setting; /* user inputs vale 1-126, 0x01-0xFE */ if (apm_val > ATA_APM_MAXPERF) { - printf("invalid APM value: must be %d-%d\n", ATA_APM_MINPERF, ATA_APM_MAXPERF); + fprintf(stderr, "Invalid APM value: must be %d-%d\n", + ATA_APM_MINPERF, ATA_APM_MAXPERF); rc = -1; } /* allocate and initialize the ata_cmd structure */ - ata_setataparams(ata, apm_val, 0); - ata_setfeature_param(ata, ATA_APM_ENABLE); + ata_init(ata); if(apm_val == 0) - ata_setfeature_param(ata, ATA_APM_DISABLE); + apm_onoff_setting = ATA_APM_DISABLE; + else + apm_onoff_setting = ATA_APM_ENABLE; /* send the APM command to the drive as a FEATURE */ if(!rc) { - rc = ata_cmd(ata, ATA__SETFEATURES, 0); + rc = ata_cmd(ata, ATA__SETFEATURES, apm_onoff_setting, apm_val); - if(rc) { - perror("set APM failed"); - } else { - printf("APM set to %d\n", apm_val); - if(apm_val == ATA_APM_MAXPERF) - printf("APM set to highest power consumption\n"); - else if(apm_val == ATA_APM_MINPERF) - printf("APM set to lowest power consumption\n"); - else if(apm_val == 0) - printf("APM Disabled\n"); - } + if(rc) + perror("Failed to configure APM"); } + + return rc; +} + +int +ata_setwc(ATA *ata, int enable) +{ + int rc, cmd; + + /* allocate and initialize the ata_cmd structure */ + ata_init(ata); + cmd = enable ? ATA_WC_ENABLE : ATA_WC_DISABLE; + rc = ata_cmd(ata, ATA__SETFEATURES, cmd, 0); + if(rc) + perror("Failed to configure Write Cache"); return rc; } @@ -331,49 +372,41 @@ * Sets the acoustic level on modern hard drives. This is used to run it * at a lower speed/performance level, which in turn reduces noise. */ -int ata_setacoustic(ATA *ata, uint32_t acoustic_val) +int +ata_setacoustic(ATA *ata, uint32_t acoustic_val) { int rc = 0; + int aam_onoff_setting; static const int aam_user_offset = 127; acoustic_val += aam_user_offset; /* scale it 0x80-0xFE, 128-254 */ /* range check our acoustic level parameter */ if (acoustic_val > ATA_AUTOACOUSTIC_MAXPERF) { - printf("invalid acoustic value: must be %d-%d\n", 1, ATA_AUTOACOUSTIC_MAXPERF - aam_user_offset); - rc = -1; + fprintf(stderr, "Invalid acoustic value: must be %d-%d\n", + 1, ATA_AUTOACOUSTIC_MAXPERF - aam_user_offset); + rc = 1; } - ata_setataparams(ata, acoustic_val, 0); - ata_setfeature_param(ata, ATA_AUTOACOUSTIC_ENABLE); + ata_init(ata); /* disable AAM if user specified 0, which is 127 once offset */ if(acoustic_val == 127) - ata_setfeature_param(ata, ATA_AUTOACOUSTIC_DISABLE); + aam_onoff_setting = ATA_AUTOACOUSTIC_DISABLE; + else + aam_onoff_setting = ATA_AUTOACOUSTIC_ENABLE; - /* send the drive a SET_FEATURES command - * with a FEATURE of ATA_AUTOACOUSTIC_ENABLE - */ if(!rc) { - rc = ata_cmd( ata, ATA__SETFEATURES, 0 ); + rc = ata_cmd(ata, ATA__SETFEATURES, aam_onoff_setting, acoustic_val); if(rc) - perror("set AAM failed"); - else - { - printf("AAM set to %d\n", acoustic_val-aam_user_offset); - if(acoustic_val == ATA_AUTOACOUSTIC_MAXPERF) - printf("AAM set to maximum performance\n"); - else if(acoustic_val == ATA_AUTOACOUSTIC_MINPERF) - printf("AAM set to quietest setting\n"); - else if(acoustic_val == 127) - printf("AAM disabled\n"); - } + perror("Failed to configure AAM."); } return rc; } /* command the device to spindown after idle_mins of no disk activity */ -int ata_setidletimer(ATA *ata, uint32_t idle_mins) +int +ata_setidletimer(ATA *ata, uint32_t idle_mins) { uint16_t timer_val = 0; int rc = 0; @@ -381,110 +414,92 @@ rc = ata_getidleval( idle_mins, &timer_val ); if(timer_val == ATA_IDLEVAL_IMMEDIATE) - ata_setataparams(ata, 0, 0); + ata_init(ata); else - ata_setataparams(ata, timer_val, 0); + ata_init(ata); /* send the IDLE command to the drive */ - if(!rc) { + if (!rc) { if(timer_val == ATA_IDLEVAL_IMMEDIATE) - rc = ata_cmd(ata, ATA_IDLE_IMMEDIATE, 0); + rc = ata_cmd(ata, ATA_IDLE_IMMEDIATE, 0, 0); else - rc = ata_cmd(ata, ATA_IDLE, 0); + rc = ata_cmd(ata, ATA_IDLE, 0, timer_val); } - if(rc) - { - if(rc == -2) - printf("error setting idle timeout\n"); - else - perror("error setting idle timeout"); - } - else + if (rc) { - if(timer_val == ATA_IDLEVAL_IMMEDIATE) - printf("drive set to idle immediately\n"); - else if(timer_val == 0) - printf("turned off idle timer\n"); - else - printf("idle timer set to %d minutes\n", idle_mins); + fprintf(stderr, "Failed to configure idle mode.\n"); } + return rc; } /* comand the drive to go into sleep mode */ -int ata_sleep(ATA *ata) +int +ata_sleep(ATA *ata) { int rc = 0; - ata_setataparams(ata, 0, 0); + ata_init(ata); /* send the SLEEP command to the drive */ - rc = ata_cmd(ata, ATA_SLEEP, 0); + rc = ata_cmd(ata, ATA_SLEEP, 0, 0); if (rc) - { - perror("error setting sleep mode"); - } - else - { - printf("drive set to sleep\n"); - } + perror("Failed to configure sleep mode"); return rc; } /* command the device to spindown after standby_mins of no disk activity */ -int ata_setstandbytimer( ATA *ata, uint32_t standby_mins) +int +ata_setstandbytimer(ATA *ata, uint32_t standby_mins) { uint16_t timer_val = 0; int rc = 0; rc = ata_getidleval( standby_mins, &timer_val ); - if (timer_val == ATA_IDLEVAL_IMMEDIATE) - ata_setataparams(ata, 0, 0); - else - ata_setataparams(ata, timer_val, 0); + if (rc) + return rc; + + ata_init(ata); /* send the STANDBY command to the drive */ - if(!rc) + if (!rc) { if(timer_val == ATA_IDLEVAL_IMMEDIATE) - rc = ata_cmd(ata, ATA_STANDBY_IMMEDIATE, 0); + rc = ata_cmd(ata, ATA_STANDBY_IMMEDIATE, 0, 0); else - rc = ata_cmd(ata, ATA_STANDBY, 0); + rc = ata_cmd(ata, ATA_STANDBY, 0, timer_val); } - if(rc) + + if (rc) { - perror("error setting idle timeout"); - } else { - if( timer_val == ATA_IDLEVAL_IMMEDIATE ) - printf("drive set to standby immediately\n"); - else if(timer_val == 0) - printf("turned off standby timer\n"); - else - printf("standby timer set to %d minutes\n", standby_mins); + perror("Failed to configure standby timer"); } + return rc; } /* this function sends an IDENTIFY command to a drive */ -int ata_ident(ATA *ata, struct ata_ident * identity) +int +ata_identify(ATA *ata, struct ata_ident * identity) { int rc = 0; - char * buf = NULL; + char *buf; - ata_setataparams(ata, 0, 0); - ata_setdataout_params(ata, &buf, 512); - rc = ata_cmd(ata, ATA__IDENTIFY, 0); + ata_init(ata); + buf = ata_setup_buffer(ata, 512); + rc = ata_cmd(ata, ATA__IDENTIFY, 0, 0); - if(rc) + if (rc) { - /* then try an ATAPI IDENTIFY, maybe it didn't like an ATA_IDENTIFY */ - ata_setataparams(ata, 0, 0); - ata_setdataout_params(ata, &buf, 512); - rc = ata_cmd(ata, ATA__ATAPI_IDENTIFY, 0); + /* then try an ATAPI IDENTIFY, maybe it didn't like + * an ATA_IDENTIFY */ + ata_init(ata); + buf = ata_setup_buffer(ata, 512); + rc = ata_cmd(ata, ATA__ATAPI_IDENTIFY, 0, 0); } if (!rc) @@ -498,17 +513,8 @@ if (is_big_endian()) byteswap_ata_data((int16_t*)buf); - if(!rc) + if (!rc) memcpy(identity, buf, sizeof(struct ata_ident)); return rc; } - -void hexdump(const char *data, int count) -{ - int i; - for (i = 0; i < count; i++) - { - printf( "%c ", data[i]); - } -} |