hdparm-9.43/0000755000000000000000000000000012051264146011423 5ustar rootroothdparm-9.43/TODO0000644000000000000000000000064612031352570012116 0ustar rootrootMark's TO-DO list for hdparm: ============================ - Add "wipe-drive" functionality via SCT WRITE_SAME (or manual). - Add "surface-scan" functionality via SG READ_VERIFY. - Add --automatically-find-and-fix-media-errors - Add utility to recover data from a drive with bad sectors. - Use SCSI Inquiry for -I on ATAPI, especially with libata. - Use read()/write() for non-ATA drives with --{read,write}-sectors hdparm-9.43/debian/0000755000000000000000000000000011161165375012652 5ustar rootroothdparm-9.43/debian/hdparm.docs0000644000000000000000000000004511103422364014764 0ustar rootrootREADME.acoustic debian/changelog.old hdparm-9.43/debian/README.Debian0000644000000000000000000001066411103423237014710 0ustar rootroothdparm for Debian ----------------- General hard disk tuning: To get the best performance out of your hard drive turn on DMA support in the kernel and enable 32bit IO (-c) and multiple sector I/O (-m) with hdparm. You can find out the number to use for -m by using -i and reading MaxMultSect. These settings can now be set in either /etc/hdparm.conf or in /etc/apm/20hdparm. I advise against setting the same features in both - unpredictable things could happen. Multiple disks with the same options: /etc/default/hdparm can take environment variables for simple options for a block of disks that are to be set up in the same way. This would be useful for a JBOD type array, or similar arrangement. Setting up disks in this way does not currently integrate with the more complicated checks and arrangements that are done with the settings in hdparm.conf. If you need to load modules before tuning a hard disk, or need to allow udev to run before hdparm, do not use this option. This is intended only for disks with normal device nodes, accessible early in the boot process, and with kernel support before module loading. A complete rewrite is really needed to better integrate this option. Hopefully I'll have the time soon (or somebody will send the patches :) APM and ACPI: APM and ACPI are handled somewhat differently in Debian. If you have a machine that uses APM, there is a script in /etc/apmd that you can use to have APM events trigger hdparm commands. For ACPI users, I recommend a package like powersaved, that will call hdparm as appropriate for ACPI events. Some problems with udev and module loading: hdparm's init script is set to run at /etc/rcS.d/S07 because there have been reports of data corruption with mounted disks. This particular placement may not work for you if the ability to use things like DMA relies on having modules for your motherboard or drive loaded, as it is run before the module loading init script. If this is the case for you, (and you don't use udev) do the following: In hdparm.conf, set ROOTFS to whatever drive / is mounted on, for example ROOTFS = /dev/hda Set up a second link, /etc/rcS.d/S29hdparm.second, pointing to /etc/init.d/hdparm. ln -s /etc/init.d/hdparm /etc/rcS.d/S29hdparm.second will do this for you. If you use an alternate init scheme, such as runit or minit or file-rc, set this up appropriately for your setup. The important thing is that the link name does not _end_ in 'hdparm' (the script checks this with case "$0" in *hdparm), so take care in your naming scheme. Now the init script will run once at 07 for your root drive, and then later for all other defined devices. This will give the other scripts a chance to load modules and create devices. hdparm now supports udev created device nodes, using the script /etc/udev/hdparm.rules. This allows users to set up regular stanzas in /etc/hdparm.conf, that will fail the first time (as the device nodes don't yet exist) but will be properly set up when udev gets to them. Known problems, limitations, and work-arounds: Additional information from David B Harris: The init script is probably not safe to run with an MD array, as there is a possibility of disk corruption during rebuild if the array was not stopped cleanly. As the rebuild process begins (at least on newer MD arrays) before init is started, there is no way to run the init script early enough for this to always be safe. Please do not add anything to hdparm.conf, and instead run hdparm by hand only after you are sure that your array has finished rebuilding. For this reason, the init script aborts if it detects that the raid array is not rebuilt, or otherwise 'dirty'. See below for ways to bypass these checks. If the init script gives you problems, you can boot the kernel with the command line option 'nohdparm' (without the single quotes), and the init script will not run. If one of the built-in checks that aborts the hdparm init script is triggered (RAID array is rebuilding, nohdparm was passed on the kernel command line), the init script will not run at boot time. If you want to run the init script anyway, you can override the safety features by passing the environment variable FORCE_RUN=yes to the init script. i.e.: FORCE_RUN=yes /etc/init.d/hdparm start -- Stephen Gran Wed, 10 Aug 2005 14:48:31 -0400 hdparm-9.43/debian/hdparm-udeb.install0000644000000000000000000000002711103422073016414 0ustar rootrootdebian/tmp/sbin/hdparm hdparm-9.43/debian/20hdparm0000644000000000000000000000433111103422703014176 0ustar rootroot#!/bin/sh # Copyright (c) 2000-2002 Massachusetts Institute of Technology # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or (at # your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. set -e # The APMD_DRIVES setting specifies the drives to be changed. Set # this to an empty string to disable any changes. #APMD_DRIVES= # The spindown timeout is set to the value of APMD_SPINDOWN when the # computer is running on battery power. When the computer is on AC # power, the spindown timeout is disabled. The number specified here # is encoded in a complicated way. See the man page for hdparm(8) for # details. For small timeouts, numbers between 1 and 240 specify # multiples of 5 seconds. So the default value of 18 means 18*5=90 # seconds, or 1.5 minutes. APMD_SPINDOWN=18 HDPARM=/sbin/hdparm [ -x "${HDPARM}" ] || exit 0 [ -n "${APMD_DRIVES}" ] || exit 0 for DRIVE in $APMD_DRIVES; do [ -b "${DRIVE}" ] || exit 0 done [ "${APMD_SPINDOWN}" -gt 0 ] || exit 0 power_conserve () { # Set IDE hard disk spindown time to a short time. for DRIVE in $APMD_DRIVES; do "${HDPARM}" -q -S "${APMD_SPINDOWN}" "${DRIVE}" || true done } power_performance () { # Disable IDE hard disk spindown. for DRIVE in $APMD_DRIVES; do "${HDPARM}" -q -S 0 "${DRIVE}" || true done } choose_power () { if on_ac_power > /dev/null then power_performance else power_conserve fi } if [ "${1}" = "start" ]; then choose_power elif [ "${1}" = "resume" ] && [ "${2}" != "standby" ]; then choose_power elif [ "${1},${2}" = "change,power" ]; then choose_power elif [ "${1}" = "stop" ]; then power_performance fi exit 0 hdparm-9.43/debian/hdparm.conf.50000644000000000000000000001107711103422447015135 0ustar rootroot.\" Text automatically generated by txt2man-1.4.7 .TH hdparm.conf "5" "August 10, 2005" "Stephen Gran" "hdparm configuration file" .SH "NAME" .LP hdparm.conf \- Debian configuration file for hdparm .SH "DESCRIPTION" .LP This is the default configuration for hdparm for Debian. It is a rather simple script, so please follow the following guidelines :) Any line that begins with a comment is ignored \- add as many as you like. .LP Note that an in\-line comment is not supported. If a line consists of whitespace only (tabs, spaces, carriage return), it will be ignored, so you can space control fields as you like. ANYTHING ELSE IS PARSED!! .LP This means that lines with stray characters or lines that use non # comment characters will be interpreted by the initscript. This has probably minor, but potentially serious, side effects for your hard drives, so please follow the guidelines. Patches to improve flexibilty welcome. .LP Please read /usr/share/doc/hdparm/README.Debian for notes about known issues, especially if you have an MD array. .LP Note that if the init script causes boot problems, you can pass 'nohdparm' on the kernel command line, and the script will not be run. .LP Setting an option outside of one of the stanzas enables it for all drives. .LP If an option is listed twice, the second instance replaces the first. .LP /sbin/hdparm is not run unless a block of the form: .LP .B DEV { .TP option .TP option .TP } .LP exists. This blocks will cause /sbin/hdparm OPTIONS DEV to be run. Where OPTIONS is the concatenation of all options previously defined outside of a block and all options defined with in the block. .SH "OPTIONS" .TP \fB\-q\fR be quiet quiet .TP \fB\-a\fR sector count for filesystem read-ahead read_ahead_sect = 12 .TP \fB\-A\fR disable/enable the IDE drive's read-lookahead feature lookahead = on .TP \fB\-b\fR bus state bus = on .TP \fB\-B\fR apm setting apm = 255 .TP \fB\-c\fR enable (E)IDE 32-bit I/O support - can be any of 0,1,3 io32_support = 1 .TP \fB\-d\fR disable/enable the "using_dma" flag for this drive dma = off .TP \fB\-D\fR enable/disable the on-drive defect management defect_mana = off .TP \fB\-E\fR cdrom speed cd_speed = 16 .TP \fB\-k\fR disable/enable the "keep_settings_over_reset" flag for this drive keep_settings_over_reset = off .TP \fB\-K\fR disable/enable the drive's "keep_features_over_reset" flag keep_features_over_reset = on .TP \fB\-m\fR sector count for multiple sector I/O mult_sect_io = 32 .TP \fB\-P\fR maximum sector count for the drive's internal prefetch mechanism prefetch_sect = 12 .TP \fB\-r\fR read-only flag for device read_only = off .TP \fB\-s\fR Enable/disable the power-on in standby feature poweron_standby = off .TP \fB\-S\fR standby (spindown) timeout for the drive spindown_time = 24 .TP \fB\-u\fR interrupt-unmask flag for the drive interrupt_unmask = on .TP \fB\-W\fR Disable/enable the IDE drive's write-caching feature write_cache = off .TP \fB\-X\fR IDE transfer mode for newer (E)IDE/ATA2 drives transfer_mode = 34 .TP \fB\-y\fR force to immediately enter the standby mode standby .TP \fB\-Y\fR force to immediately enter the sleep mode sleep .TP \fB\-Z\fR Disable the power-saving function of certain Seagate drives disable_seagate .TP \fB\-M\fR Set the acoustic management properties of a drive acoustic_management .TP \fB\-p\fR Set the chipset PIO mode chipset_pio_mode .TP \fB--security-freeze\fR Freeze the drive's security status security_freeze .TP \fB--security-unlock\fR Unlock the drive's security security_unlock = PWD .TP \fB--security-set-pass\fR Set security password security_pass = password .TP \fB--security-disable\fR Disable drive locking security_disable .TP \fB--user-master\fR Specifies which password to select security_mode = u .TP \fB--security-mode\fR Set the security mode security_mode = h .TP Root file systems. Please see README.Debian for details. ROOTFS = /dev/hda .PP You can use straight hdparm commands in this config file as well \- the set up is ugly, but it keeps backwards compatibility. Additionally, it should be noted that any blocks that begin with the keyword 'command_line' are not run until after the root filesystem is mounted. This is done to avoid running blocks twice. If you need to run hdparm to set parameters for your root disk, please use the standard format. .SH AUTHOR hdparm was written by Mark Lord The init script and configuration file are currently maintained by Stephen Gran , but are the result of the work of many people. .PP This manual page was created by Stephen Gran for the Debian GNU/Linux system (but may be used by others). hdparm-9.43/debian/watch0000644000000000000000000000021011103422611013655 0ustar rootrootversion=2 http://www.ibiblio.org/pub/Linux/system/hardware (?:.*/)?hdparm-?_?([\w+\d+\.]+|\d+)(\.tar|\.tgz)(\.gz|\.bz2|) debian uupdate hdparm-9.43/debian/hdparm.dirs0000644000000000000000000000002111103423167014771 0ustar rootrootetc/udev/rules.d hdparm-9.43/debian/hdparm.rules0000644000000000000000000000013411103422545015166 0ustar rootrootACTION=="add", SUBSYSTEM=="block", KERNEL=="[sh]d[a-z]", RUN+="/etc/init.d/hdparm hotplug" hdparm-9.43/debian/hdparm.manpages0000644000000000000000000000003611103422562015627 0ustar rootroothdparm.8 debian/hdparm.conf.5 hdparm-9.43/debian/hdparm.postinst0000755000000000000000000000041111103424236015717 0ustar rootroot#!/bin/sh if [ -z "$2" ] || dpkg --compare-versions "$2" lt 6.1-6 ; then ln -s ../hdparm.rules /etc/udev/rules.d/z60_hdparm.rules fi if [ -n "$2" ] && dpkg --compare-versions "$2" lt 8.9-2; then rm -fv /etc/rc0.d/K75hdparm /etc/rc6.d/K75hdparm fi #DEBHELPER# hdparm-9.43/debian/hdparm.conf0000644000000000000000000001127311103417045014766 0ustar rootroot## This is the default configuration for hdparm for Debian. It is a ## rather simple script, so please follow the following guidelines :) ## Any line that begins with a comment is ignored - add as many as you ## like. Note that an in-line comment is not supported. If a line ## consists of whitespace only (tabs, spaces, carriage return), it will be ## ignored, so you can space control fields as you like. ANYTHING ELSE ## IS PARSED!! This means that lines with stray characters or lines that ## use non # comment characters will be interpreted by the initscript. ## This has probably minor, but potentially serious, side effects for your ## hard drives, so please follow the guidelines. Patches to improve ## flexibilty welcome. Please read /usr/share/doc/hdparm/README.Debian for ## notes about known issues, especially if you have an MD array. ## ## Note that if the init script causes boot problems, you can pass 'nohdparm' ## on the kernel command line, and the script will not be run. ## ## Uncommenting the options below will cause them to be added to the DEFAULT ## string which is prepended to options listed in the blocks below. ## ## If an option is listed twice, the second instance replaces the first. ## ## /sbin/hdparm is not run unless a block of the form: ## DEV { ## option ## option ## ... ## } ## exists. This blocks will cause /sbin/hdparm OPTIONS DEV to be run. ## Where OPTIONS is the concatenation of all options previously defined ## outside of a block and all options defined with in the block. # -q be quiet quiet # -a sector count for filesystem read-ahead #read_ahead_sect = 12 # -A disable/enable the IDE drive's read-lookahead feature #lookahead = on # -b bus state #bus = on # -B apm setting #apm = 255 # -c enable (E)IDE 32-bit I/O support - can be any of 0,1,3 #io32_support = 1 # -d disable/enable the "using_dma" flag for this drive #dma = off # -D enable/disable the on-drive defect management #defect_mana = off # -E cdrom speed #cd_speed = 16 # -k disable/enable the "keep_settings_over_reset" flag for this drive #keep_settings_over_reset = off # -K disable/enable the drive's "keep_features_over_reset" flag #keep_features_over_reset = on # -m sector count for multiple sector I/O #mult_sect_io = 32 # -P maximum sector count for the drive's internal prefetch mechanism #prefetch_sect = 12 # -r read-only flag for device #read_only = off # -s Turn on/off power on in standby mode # poweron_standby = off # -S standby (spindown) timeout for the drive #spindown_time = 24 # -u interrupt-unmask flag for the drive #interrupt_unmask = on # -W Disable/enable the IDE drive's write-caching feature #write_cache = off # -X IDE transfer mode for newer (E)IDE/ATA2 drives #transfer_mode = 34 # -y force to immediately enter the standby mode #standby # -Y force to immediately enter the sleep mode #sleep # -Z Disable the power-saving function of certain Seagate drives #disable_seagate # -M Set the acoustic management properties of a drive #acoustic_management # -p Set the chipset PIO mode # chipset_pio_mode # --security-freeze Freeze the drive's security status # security_freeze # --security-unlock Unlock the drive's security # security_unlock = PWD # --security-set-pass Set security password # security_pass = password # --security-disable Disable drive locking # security_disable # --user-master Select password to use # user-master = u # --security-mode Set the security mode # security_mode = h # Root file systems. Please see README.Debian for details # ROOTFS = /dev/hda ## New note - you can use straight hdparm commands in this config file ## as well - the set up is ugly, but it keeps backwards compatibility ## Additionally, it should be noted that any blocks that begin with ## the keyword 'command_line' are not run until after the root filesystem ## is mounted. This is done to avoid running blocks twice. If you need ## to run hdparm to set parameters for your root disk, please use the ## standard format. #Samples follow: #First three are good for devfs systems, fourth one for systems that do #not use devfs. The fifth example uses straight hdparm command line #syntax. Any of the blocks that use command line syntax must begin with #the keyword 'command_line', and no attempt is made to validate syntax. #It is provided for those more comfortable with hdparm syntax. #/dev/discs/disc0/disc { # mult_sect_io = 16 # write_cache = off # spindown_time = 240 #} #/dev/discs/disc1/disc { # mult_sect_io = 32 # spindown_time = 36 # write_cache = off #} #/dev/cdroms/cdrom0 { # dma = on # interrupt_unmask = on # io32_support = 0 #} #/dev/hda { # mult_sect_io = 16 # write_cache = off # dma = on #} #command_line { # hdparm -q -m16 -q -W0 -q -d1 /dev/hda #} hdparm-9.43/debian/hdparm.postrm0000755000000000000000000000021711103422302015354 0ustar rootroot#!/bin/sh case "$1" in purge) [ ! -L /etc/udev/rules.d/z60_hdparm.rules ] || rm /etc/udev/rules.d/z60_hdparm.rules ;; esac #DEBHELPER# hdparm-9.43/debian/hdparm.install0000644000000000000000000000045311103423575015512 0ustar rootrootdebian/20hdparm etc/apm/event.d/ debian/tmp/sbin/hdparm contrib/fix_standby.c usr/share/doc/hdparm/contrib contrib/idectl usr/share/doc/hdparm/contrib contrib/README usr/share/doc/hdparm/contrib contrib/ultrabayd usr/share/doc/hdparm/contrib debian/hdparm.conf etc/ debian/hdparm.rules etc/udev/ hdparm-9.43/debian/copyright0000644000000000000000000000106611103420720014570 0ustar rootrootThis package was debianized by Christopher L Cheney on Wed, 21 Nov 2001 15:51:14 -0600. It was downloaded from http://www.ibiblio.org/pub/Linux/system/hardware Upstream Author: Mark S. Lord Copyright: /* hdparm.c - Command line interface to get/set hard disk parameters */ /* - by Mark Lord © 1994-2008 -- freely distributable */ You are free to distribute this software under the terms of the BSD License. On Debian systems, the complete text of the BSD License can be found in /usr/share/common-licenses/BSD hdparm-9.43/debian/control0000644000000000000000000000172411103421557014252 0ustar rootrootSource: hdparm Section: admin Priority: optional Maintainer: Stephen Gran Build-Depends: cdbs (>> 0.4.37), debhelper (>= 5.0), dpatch, dpkg-dev (>= 1.13.19) Standards-Version: 3.8.0 Package: hdparm Architecture: any Depends: ${shlibs:Depends}, lsb-base Suggests: apmd Replaces: apmd (<= 3.0.2-1.15) Description: tune hard disk parameters for high performance Get/set device parameters for Linux SATA/IDE drives. Primary use is for enabling irq-unmasking and IDE multiplemode. Package: hdparm-dbg Architecture: any Priority: extra Depends: hdparm (= ${binary:Version}) Description: debug files for hdparm This package contains the stripped debugging symbols for hdparm Package: hdparm-udeb XC-Package-Type: udeb Section: debian-installer Architecture: any Depends: ${shlibs:Depends} Description: tune hard disk parameters for high performance Get/set device parameters for Linux SATA/IDE drives. . This is a minimal package for use in debian-installer. hdparm-9.43/debian/compat0000644000000000000000000000000211103421611014030 0ustar rootroot5 hdparm-9.43/debian/hdparm.default0000644000000000000000000000152711103422244015463 0ustar rootroot# To set the same options for a block of harddisks, do so with something # like the following example options: # harddisks="/dev/hda /dev/hdb" # hdparm_opts="-d1 -X66" # This is run before the configuration in hdparm.conf. Do not use # this arrangement if you need modules loaded for your hard disks, # or need udev to create the nodes, or have some other local quirk # These are better addressed with the options in /etc/hdparm.conf # # harddisks="" # hdparm_opts="" # By default, hdparm will refuse to set harddisk options on any drive # if the system has software RAID running, and one or more disk arrays # are in the process of resynchronisation. # With this variable set to 'yes', /etc/init.d/hdparm will suspend the # RAID resynchronisation process before setting harddisk options, and # will resume it after setting is done. RAID_WORKAROUND=no hdparm-9.43/debian/hdparm.dev0000755000000000000000000000037511103421776014631 0ustar rootroot#!/bin/sh # $DEVNAME device name # $ACTION action add/remove [ -n "$DEVNAME" ] || exit 0 [ "$DEVNAME" != "${DEVNAME#/}" ] || exit 0 [ "$ACTION" = 'add' ] || exit 0 [ -x /etc/init.d/hdparm ] && ACTION=$ACTION DEVNAME=$DEVNAME /etc/init.d/hdparm hotplug hdparm-9.43/debian/hdparm.preinst0000755000000000000000000000275211103422346015532 0ustar rootroot#!/bin/sh # Remove a no-longer used conffile rm_conffile() { CONFFILE="$1" if [ -e "$CONFFILE" ]; then md5sum="`md5sum \"$CONFFILE\" | sed -e \"s/ .*//\"`" old_md5sum="`dpkg-query -W -f='${Conffiles}' $PKGNAME | sed -n -e \"\\\\' $CONFFILE'{s/ obsolete$//;s/.* //p}\"`" if [ "$md5sum" != "$old_md5sum" ]; then echo "Obsolete conffile $CONFFILE has been modified by you." echo "Saving as $CONFFILE.dpkg-bak ..." mv -f "$CONFFILE" "$CONFFILE".dpkg-bak else echo "Removing obsolete conffile $CONFFILE ..." rm -f "$CONFFILE" fi fi } if [ "$1" = install ] || [ "$1" = upgrade ]; then if dpkg --compare-versions "$2" le 6.1-6; then if dpkg --compare-versions "$2" gt 6.1-2; then for conffile in /etc/init.d/hdparm.dev /etc/dev.d/block//hdparm.block /etc/dev.d/block/hdparm.dev; do [ ! -e "$conffile" ] || rm_conffile "$conffile" done elif dpkg --compare-versions "$2" lt 5.5-5; then update-rc.d -f hdparm remove > /dev/null 2>&1 if dpkg --compare-versions "$2" lt 5.4-6; then [ ! -e /etc/hdparm.conf ] || rm_conffile "/etc/hdparm.conf" if dpkg --compare-versions "$2" ge 5.4-3; then if [ -e /etc/default/hdparm ]; then echo -n "Moving old /etc/default/hdparm to /etc/hdparm.conf . . " mv /etc/default/hdparm /etc/hdparm.conf echo "done." fi fi fi fi fi fi #DEBHELPER# hdparm-9.43/debian/hdparm.init0000755000000000000000000002474511103423132015011 0ustar rootroot#!/bin/sh ### BEGIN INIT INFO # Provides: hdparm # Required-Start: mountdevsubfs # Required-Stop: # Should-Start: udev # Default-Start: S # Default-Stop: # Short-Description: Tune IDE hard disks ### END INIT INFO set -e . /lib/lsb/init-functions # Defaults for configuration variables. RAID_WORKAROUND=no # Source the defaults file. [ -e /etc/default/hdparm ] && . /etc/default/hdparm raid_speed_limit_min= raid_speed_limit_max= case "$0" in *hdparm) FIRST=yes ;; *) FIRST=no ;; esac case "$1" in start|restart|reload|force-reload) UDEV=no ;; hotplug) UDEV=yes [ "$DEVNAME" ] || exit 1 ;; stop) exit 0 ;; *) log_failure_msg "Usage: $0 {stop|start|restart|reload|force-reload|hotplug}" >&2 exit 3 ;; esac if [ "$FORCE_RUN" != 'yes' ]; then if [ -e /proc/cmdline ]; then #linux only - future proofing against BSD and Hurd :) if grep -wq "nohdparm" /proc/cmdline ; then log_warning_msg "Skipping setup of disc parameters." exit 0 fi fi raidstat=OK if [ -e /proc/mdstat ]; then if egrep -iq "resync|repair|recover|check" /proc/mdstat; then raidstat=RESYNC fi elif [ -e /proc/rd/status ]; then raidstat=`cat /proc/rd/status` fi if ! [ "$raidstat" = 'OK' ] && [ "$RAID_WORKAROUND" != "yes" ]; then log_failure_msg "RAID status not OK. Exiting." exit 0 fi fi slow_down_raid_sync() { if [ -f /proc/sys/dev/raid/speed_limit_min ]; then raid_speed_limit_min=`cat /proc/sys/dev/raid/speed_limit_min` echo 0 >/proc/sys/dev/raid/speed_limit_min fi if [ -f /proc/sys/dev/raid/speed_limit_max ]; then raid_speed_limit_max=`cat /proc/sys/dev/raid/speed_limit_max` echo 0 >/proc/sys/dev/raid/speed_limit_max fi sleep 2 } undo_slow_down_raid_sync() { if [ -f /proc/sys/dev/raid/speed_limit_min ] && [ "x$raid_speed_limit_min" != "x" ]; then echo $raid_speed_limit_min >/proc/sys/dev/raid/speed_limit_min fi if [ -f /proc/sys/dev/raid/speed_limit_max ] && [ "x$raid_speed_limit_max" != "x" ]; then echo $raid_speed_limit_max >/proc/sys/dev/raid/speed_limit_max fi } set_option() { if test -n "$DISC"; then NEW_OPT= for i in $OPTIONS; do if test x${i%${i#??}} != x${1%${1#??}}; then NEW_OPT="$NEW_OPT $i" else NEW_OPT=${NEW_OPT%-q} fi done OPTIONS="$NEW_OPT $OPT_QUIET $1" else NEW_DEF= for i in $DEFAULT; do if test x${i%${i#??}} != x${1%${1#??}}; then NEW_DEF="$NEW_DEF $i" else NEW_DEF=${NEW_DEF%-q} fi done DEFAULT="$NEW_DEF $DEF_QUIET $1" fi } eval_value() { case $1 in off|0) set_option "$2"0 ;; on|1) set_option "$2"1 ;; *) log_failure_msg "Unknown Value for $2: $1" exit 1 ;; esac } WAS_RUN=0 # Turn off RAID synchronisation if needed and asked for. if [ "$raidstat" != 'OK' ] && [ "$RAID_WORKAROUND" = "yes" ]; then slow_down_raid_sync fi # Get blocks as far as the drive's write cache. /bin/sync [ "$UDEV" = 'yes' ] || log_daemon_msg "Setting parameters of disc" DISC= DEFAULT= OPTIONS= DEF_QUIET= OPT_QUIET= egrep -v '^[[:space:]]*(#|$)' /etc/hdparm.conf | { while read KEY SEP VALUE; do if [ "$NEXT_LINE" != 'go' ]; then case $SEP in '{') case $KEY in command_line) NEXT_LINE=go unset DISC unset OPTIONS unset OPT_QUIET if [ "$UDEV" = 'yes' ]; then IN_BLOCK=0 fi ;; *) DISC=$KEY OPTIONS=$DEFAULT OPT_QUIET=$DEF_QUIET WAS_RUN=0 if [ "$UDEV" = 'yes' ]; then if [ "$DISC" = "$DEVNAME" ]; then IN_BLOCK=1 else IN_BLOCK=0 fi fi ;; esac ;; =) case $KEY in read_ahead_sect) set_option -a$VALUE ;; lookahead) eval_value $VALUE -A ;; bus) eval_value $VALUE -b ;; apm) set_option -B$VALUE ;; io32_support) set_option -c$VALUE ;; dma) eval_value $VALUE -d ;; defect_mana) eval_value $VALUE -D ;; cd_speed) set_option -E$VALUE ;; mult_sect_io) set_option -m$VALUE ;; prefetch_sect) set_option -P$VALUE ;; read_only) eval_value $VALUE -r ;; spindown_time) case "$VALUE" in *[hms]) case "$VALUE" in *h) time=$((${VALUE%h} * 3600)) ;; *m) time=$((${VALUE%m} * 60)) ;; *s) time=${VALUE%s} ;; esac if [ $time -lt 1260 ]; then # up to 21 minutes new_VALUE=$(($time / 5)) if [ $new_VALUE -gt 240 ]; then new_VALUE=240 fi if [ $(($new_VALUE * 5)) -ne $time ]; then log_warning_msg "$VALUE not possible, using $(($new_VALUE * 5)) seconds" fi VALUE=$new_VALUE elif [ $time -lt 1800 ]; then if [ $time -ne 1260 ]; then log_warning_msg "$VALUE not possible, using 21 minutes" fi VALUE=252 else new_time=$(($time / 1800)) if [ $new_time -gt 11 ]; then new_time=11 fi if [ $((new_time * 1800)) -ne $time ]; then log_warning_msg "$VALUE not possible, using $(($new_time * 30)) minutes" fi VALUE=$((new_time + 240)) fi ;; esac set_option -S$VALUE ;; poweron_standby) eval_value $VALUE -s ;; interrupt_unmask) eval_value $VALUE -u ;; write_cache) eval_value $VALUE -W ;; transfer_mode) set_option -X$VALUE ;; acoustic_management) set_option -M$VALUE ;; keep_settings_over_reset) eval_value $VALUE -k ;; keep_features_over_reset) eval_value $VALUE -K ;; chipset_pio_mode) set_option -p$VALUE ;; security_unlock) set_option --security-unlock $VALUE ;; security_pass) set_option --security-set-pass $VALUE ;; security_disable) set_option --security-disable $VALUE ;; user-master) set_option --user-master $VALUE ;; security_mode) set_option --security-mode $VALUE ;; ROOTFS) ROOTFS=$VALUE ;; *) log_failure_msg "Unknown option $KEY" undo_slow_down_raid_sync exit 1 ;; esac ;; "") case $KEY in '}') if [ -z "$DISC" ] && [ "$WAS_RUN" != '1' ]; then log_failure_msg "No disk enabled. Exiting" undo_slow_down_raid_sync exit 1 fi if [ -n "$OPTIONS" ] && [ -b "$DISC" ]; then if [ -n "$ROOTFS" ]; then if [ "$FIRST" = 'yes' ] && [ "$DISC" != "$ROOTFS" ]; then continue fi if [ "$FIRST" = 'no' ] && [ "$DISC" = "$ROOTFS" ]; then continue fi fi ret=0 if [ "$UDEV" = 'yes' ] && [ "$IN_BLOCK" = 1 ]; then # Flush the drive's internal write cache to the disk. /sbin/hdparm -q -f $DISC 2>/dev/null || ret=$? /sbin/hdparm $OPTIONS $DISC 2>/dev/null || ret=$? if [ "$VERBOSE" = 'yes' ]; then log_progress_msg " $DISC" log_end_msg $ret || true fi elif [ "$UDEV" = 'no' ]; then /sbin/hdparm -q -f $DISC 2>/dev/null || ret=$? /sbin/hdparm $OPTIONS $DISC 2>/dev/null || ret=$? WAS_RUN=1 log_progress_msg " $DISC" log_end_msg $ret || true fi fi ;; quiet) if [ -n "$DISC" ]; then OPT_QUIET=-q else DEF_QUIET=-q fi ;; standby) set_option -y ;; sleep) set_option -Y ;; disable_seagate) set_option -Z ;; security_freeze) set_option --security-freeze ;; *) log_failure_msg "unknown option $KEY" undo_slow_down_raid_sync exit 1 ;; esac ;; *) log_failure_msg "unknown separator $SEP" undo_slow_down_raid_sync exit 1 ;; esac else $KEY $SEP $VALUE NEXT_LINE=no-go WAS_RUN=1 fi done if [ -n "$harddisks" ] && [ -n "$hdparm_opts" ] && [ "$UDEV" = 'no' ]; then ret=0 for drive in $harddisks; do WAS_RUN=1 /sbin/hdparm -q -f $drive 2>/dev/null|| ret=$? /sbin/hdparm -q $hdparm_opts -q $drive 2>/dev/null|| ret=$? log_progress_msg "$drive " done log_end_msg $ret || true fi if [ "$UDEV" = 'no' -a "$WAS_RUN" = 0 ]; then log_progress_msg "(none)" log_end_msg 0 fi } # Turn back on RAID synchronisation if we turned it off. if [ "$raidstat" != 'OK' ] && [ "$RAID_WORKAROUND" = "yes" ]; then undo_slow_down_raid_sync fi exit 0 hdparm-9.43/debian/rules0000644000000000000000000000246011103422045013713 0ustar rootroot#!/usr/bin/make -f # -*- mode: makefile; coding: utf-8 -*- # Copyright © 2003 Jeff Bailey # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2, or (at # your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA. DEB_DH_INSTALLINIT_ARGS := '--no-start' #DEB_DH_LINK_ARGS := ../init.d/hdparm /etc/rcS.d/S07hdparm.first DEB_UPDATE_RCD_PARAMS := 'start 07 S . ' DEB_FIXPERMS_EXCLUDE:= 20hdparm include /usr/share/cdbs/1/rules/dpatch.mk include /usr/share/cdbs/1/rules/debhelper.mk include /usr/share/cdbs/1/class/makefile.mk DEB_MAKE_INSTALL_TARGET := install DESTDIR=$(CURDIR)/debian/tmp common-install-prehook-arch:: install -d $(CURDIR)/debian/tmp/sbin binary-predeb/hdparm:: chmod 755 $(CURDIR)/debian/hdparm/etc/apm/event.d/20hdparm hdparm-9.43/debian/hdparm.postinit0000755000000000000000000000026211103420142015701 0ustar rootroot#!/bin/sh # Clean up cdbs damage rm -f /etc/udev/rules.d/50-hdparm.rules if dpkg --compare-versions "$2" lt "8.6-1ubuntu1"; then update-rc.d -f hdparm remove fi #DEBHELPER# hdparm-9.43/sgio.h.xx0000644000000000000000000001306112031356632013174 0ustar rootroot/* prototypes and stuff for ATA command ioctls */ #include enum { ATA_OP_DSM = 0x06, // Data Set Management (TRIM) ATA_OP_READ_PIO = 0x20, ATA_OP_READ_PIO_ONCE = 0x21, ATA_OP_READ_LONG = 0x22, ATA_OP_READ_LONG_ONCE = 0x23, ATA_OP_READ_PIO_EXT = 0x24, ATA_OP_READ_DMA_EXT = 0x25, ATA_OP_READ_FPDMA = 0x60, // NCQ ATA_OP_WRITE_PIO = 0x30, ATA_OP_WRITE_LONG = 0x32, ATA_OP_WRITE_LONG_ONCE = 0x33, ATA_OP_WRITE_PIO_EXT = 0x34, ATA_OP_WRITE_DMA_EXT = 0x35, ATA_OP_WRITE_FPDMA = 0x61, // NCQ ATA_OP_READ_VERIFY = 0x40, ATA_OP_READ_VERIFY_ONCE = 0x41, ATA_OP_READ_VERIFY_EXT = 0x42, ATA_OP_WRITE_UNC_EXT = 0x45, // lba48, no data, uses feat reg ATA_OP_FORMAT_TRACK = 0x50, ATA_OP_DOWNLOAD_MICROCODE = 0x92, ATA_OP_STANDBYNOW2 = 0x94, ATA_OP_CHECKPOWERMODE2 = 0x98, ATA_OP_SLEEPNOW2 = 0x99, ATA_OP_PIDENTIFY = 0xa1, ATA_OP_READ_NATIVE_MAX = 0xf8, ATA_OP_READ_NATIVE_MAX_EXT = 0x27, ATA_OP_SMART = 0xb0, ATA_OP_DCO = 0xb1, ATA_OP_ERASE_SECTORS = 0xc0, ATA_OP_READ_DMA = 0xc8, ATA_OP_WRITE_DMA = 0xca, ATA_OP_DOORLOCK = 0xde, ATA_OP_DOORUNLOCK = 0xdf, ATA_OP_STANDBYNOW1 = 0xe0, ATA_OP_IDLEIMMEDIATE = 0xe1, ATA_OP_SETIDLE = 0xe3, ATA_OP_SET_MAX = 0xf9, ATA_OP_SET_MAX_EXT = 0x37, ATA_OP_SET_MULTIPLE = 0xc6, ATA_OP_CHECKPOWERMODE1 = 0xe5, ATA_OP_SLEEPNOW1 = 0xe6, ATA_OP_FLUSHCACHE = 0xe7, ATA_OP_FLUSHCACHE_EXT = 0xea, ATA_OP_IDENTIFY = 0xec, ATA_OP_SETFEATURES = 0xef, ATA_OP_SECURITY_SET_PASS = 0xf1, ATA_OP_SECURITY_UNLOCK = 0xf2, ATA_OP_SECURITY_ERASE_PREPARE = 0xf3, ATA_OP_SECURITY_ERASE_UNIT = 0xf4, ATA_OP_SECURITY_FREEZE_LOCK = 0xf5, ATA_OP_SECURITY_DISABLE = 0xf6, ATA_OP_VENDOR_SPECIFIC_0x80 = 0x80, }; /* * Some useful ATA register bits */ enum { ATA_USING_LBA = (1 << 6), ATA_STAT_DRQ = (1 << 3), ATA_STAT_ERR = (1 << 0), }; /* * Useful parameters for init_hdio_taskfile(): */ enum { RW_READ = 0, RW_WRITE = 1, LBA28_OK = 0, LBA48_FORCE = 1, }; /* * Definitions and structures for use with SG_IO + ATA_16: */ struct ata_lba_regs { __u8 feat; __u8 nsect; __u8 lbal; __u8 lbam; __u8 lbah; }; struct ata_tf { __u8 dev; __u8 command; __u8 error; __u8 status; __u8 is_lba48; struct ata_lba_regs lob; struct ata_lba_regs hob; }; /* * Definitions and structures for use with HDIO_DRIVE_TASKFILE: */ enum { /* * These (redundantly) specify the category of the request */ TASKFILE_CMD_REQ_NODATA = 0, /* ide: IDE_DRIVE_TASK_NO_DATA */ TASKFILE_CMD_REQ_IN = 2, /* ide: IDE_DRIVE_TASK_IN */ TASKFILE_CMD_REQ_OUT = 3, /* ide: IDE_DRIVE_TASK_OUT */ TASKFILE_CMD_REQ_RAW_OUT= 4, /* ide: IDE_DRIVE_TASK_RAW_WRITE */ /* * These specify the method of transfer (pio, dma, multi, ..) */ TASKFILE_DPHASE_NONE = 0, /* ide: TASKFILE_IN */ TASKFILE_DPHASE_PIO_IN = 1, /* ide: TASKFILE_IN */ TASKFILE_DPHASE_PIO_OUT = 4, /* ide: TASKFILE_OUT */ }; union reg_flags { unsigned all :16; union { unsigned lob_all : 8; struct { unsigned data : 1; unsigned feat : 1; unsigned lbal : 1; unsigned nsect : 1; unsigned lbam : 1; unsigned lbah : 1; unsigned dev : 1; unsigned command : 1; } lob; }; union { unsigned hob_all : 8; struct { unsigned data : 1; unsigned feat : 1; unsigned lbal : 1; unsigned nsect : 1; unsigned lbam : 1; unsigned lbah : 1; unsigned dev : 1; unsigned command : 1; } hob; }; } __attribute__((packed)); struct taskfile_regs { __u8 data; __u8 feat; __u8 nsect; __u8 lbal; __u8 lbam; __u8 lbah; __u8 dev; __u8 command; }; struct hdio_taskfile { struct taskfile_regs lob; struct taskfile_regs hob; union reg_flags oflags; union reg_flags iflags; int dphase; int cmd_req; /* IDE command_type */ unsigned long obytes; unsigned long ibytes; __u16 data[0]; }; struct scsi_sg_io_hdr { int interface_id; int dxfer_direction; unsigned char cmd_len; unsigned char mx_sb_len; unsigned short iovec_count; unsigned int dxfer_len; void * dxferp; unsigned char * cmdp; void * sbp; unsigned int timeout; unsigned int flags; int pack_id; void * usr_ptr; unsigned char status; unsigned char masked_status; unsigned char msg_status; unsigned char sb_len_wr; unsigned short host_status; unsigned short driver_status; int resid; unsigned int duration; unsigned int info; }; #ifndef SG_DXFER_NONE #define SG_DXFER_NONE -1 #define SG_DXFER_TO_DEV -2 #define SG_DXFER_FROM_DEV -3 #define SG_DXFER_TO_FROM_DEV -4 #endif #define SG_READ 0 #define SG_WRITE 1 #define SG_PIO 0 #define SG_DMA 1 #define SG_CHECK_CONDITION 0x02 #define SG_DRIVER_SENSE 0x08 #define SG_ATA_16 0x85 #define SG_ATA_16_LEN 16 #define SG_ATA_12 0xa1 #define SG_ATA_12_LEN 12 #define SG_ATA_LBA48 1 #define SG_ATA_PROTO_NON_DATA ( 3 << 1) #define SG_ATA_PROTO_PIO_IN ( 4 << 1) #define SG_ATA_PROTO_PIO_OUT ( 5 << 1) #define SG_ATA_PROTO_DMA ( 6 << 1) #define SG_ATA_PROTO_UDMA_IN (11 << 1) /* not yet supported in libata */ #define SG_ATA_PROTO_UDMA_OUT (12 << 1) /* not yet supported in libata */ void tf_init (struct ata_tf *tf, __u8 ata_op, __u64 lba, unsigned int nsect); __u64 tf_to_lba (struct ata_tf *tf); int sg16 (int fd, int rw, int dma, struct ata_tf *tf, void *data, unsigned int data_bytes, unsigned int timeout_secs); int do_drive_cmd (int fd, unsigned char *args, unsigned int timeout); int do_taskfile_cmd (int fd, struct hdio_taskfile *r, unsigned int timeout_secs); int dev_has_sgio (int fd); void init_hdio_taskfile (struct hdio_taskfile *r, __u8 ata_op, int rw, int force_lba48, __u64 lba, unsigned int nsect, int data_bytes); hdparm-9.43/dvdspeed.c0000644000000000000000000000261711234326447013400 0ustar rootroot#include #include #include #include #include #include #include #include "hdparm.h" /* * dvdspeed - use SET STREAMING command to set the speed of DVD-drives * * Copyright (c) 2004 Thomas Fritzsche * A bit mangled in 2006 and 2008 by Thomas Orgis * */ int set_dvdspeed(int fd, int speed) { struct cdrom_generic_command cgc; struct request_sense sense; unsigned char buffer[28]; unsigned long rwsize = 177 * speed; memset(&cgc, 0, sizeof(cgc)); memset(&sense, 0, sizeof(sense)); memset(&buffer, 0, sizeof(buffer)); cgc.cmd[0] = 0xb6; // SET_STREAMING cgc.cmd[10] = 28; // parameter list length (28 bytes) cgc.sense = &sense; cgc.buffer = buffer; cgc.buflen = sizeof(buffer); cgc.data_direction = CGC_DATA_WRITE; if (speed == 0) // reset to default speed? buffer[0] = 4; buffer[ 8] = 0xff; buffer[ 9] = 0xff; buffer[10] = 0xff; buffer[11] = 0xff; // read size: buffer[12] = rwsize >> 24; buffer[13] = rwsize >> 16; buffer[14] = rwsize >> 8; buffer[15] = rwsize; // read time = 1 second: buffer[18] = 0x03; buffer[19] = 0xE8; // write size: buffer[20] = rwsize >> 24; buffer[21] = rwsize >> 16; buffer[22] = rwsize >> 8; buffer[23] = rwsize; // write time = 1 second: buffer[26] = 0x03; buffer[27] = 0xE8; return ioctl(fd, CDROM_SEND_PACKET, &cgc); } hdparm-9.43/fallocate.c0000644000000000000000000000200111452426477013525 0ustar rootroot/* * This function is in a separate file here * so that it can locally define _FILE_OFFSET_BITS=64 * to automatically get 64-bit open/fstat/etc.. functions and types. * Eventually, all of hdparm should do that, but for now.. */ #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #include #include #include "hdparm.h" int do_fallocate_syscall (const char *path, __u64 bytecount) { int err; #ifndef SYS_fallocate bytecount = 0; fprintf(stderr, "Error: this copy of hdparm was built without %s support\n", path); err = EINVAL; #else int fd; loff_t offset = 0, len; int mode = 0; fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0600); if (fd == -1) { err = errno; } else { len = bytecount; err = syscall(SYS_fallocate, fd, mode, offset, len); if (err >= 0) { fsync(fd); exit(0); } err = errno; unlink(path); } perror(path); #endif return err; } hdparm-9.43/geom.c0000644000000000000000000001525611750753671012542 0ustar rootroot/* * Device geometry helpers for hdparm and friends. * Copyright (c) Mark Lord 2008 * * You may use/distribute this freely, under the terms of either * (your choice) the GNU General Public License version 2, * or a BSD style license. */ #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #include #include #include #include #include "hdparm.h" static int get_driver_major (const char *driver, unsigned int *major) { static const char proc_devices[] = "/proc/devices"; char buf[256]; int err = 0; FILE *fp = fopen(proc_devices, "r"); if (fp == NULL) { err = EIO; } else { while (fgets(buf, sizeof(buf) - 1, fp)) { int len = strlen(buf); if (len > 5 && buf[len - 1] == '\n') { buf[len - 1] = '\0'; if (buf[3] == ' ' && 0 == strcmp(buf + 4, driver)) { *major = atoi(buf); break; } } } } if (err) perror(proc_devices); if (fp) fclose(fp); return err; } static unsigned int md_major (void) { static unsigned int maj = 0; if (!maj) { unsigned int val; if (0 == get_driver_major("md", &val)) maj = val; } return maj; } int fd_is_raid (int fd) { struct stat st; if (!md_major()) return 0; /* not a RAID device */ if (fstat(fd, &st)) { perror("fstat()"); return 0; /* ugh.. shouldn't happen */ } return (major(st.st_rdev) == md_major()); } static int get_sector_count (int fd, __u64 *nsectors) { int err; unsigned int nsects32 = 0; __u64 nbytes64 = 0; if (0 == sysfs_get_attr(fd, "size", "%llu", nsectors, NULL, 0)) return 0; #ifdef BLKGETSIZE64 if (0 == ioctl(fd, BLKGETSIZE64, &nbytes64)) { // returns bytes *nsectors = nbytes64 / 512; return 0; } #endif err = ioctl(fd, BLKGETSIZE, &nsects32); // returns sectors if (err == 0) { *nsectors = nsects32; } else { err = errno; perror(" BLKGETSIZE failed"); } return err; } /* * "md" (RAID) devices have per-member "start" offsets. * Realistically, we can only support raid1 arrays here, * and only then when all members have the same "start" offsets. */ static int get_raid1_start_lba (int fd, __u64 *start_lba) { char buf[32]; unsigned int member, raid_disks; __u64 start = 0, offset = 0; if (sysfs_get_attr(fd, "md/level", "%s", buf, NULL, 0) || sysfs_get_attr(fd, "md/raid_disks", "%u", &raid_disks, NULL, 0)) return ENODEV; if (strcmp(buf, "raid1") || !raid_disks) return EINVAL; for (member = 0; member < raid_disks; ++member) { __u64 member_start, member_offset; char member_path[32]; sprintf(member_path, "md/rd%u/offset", member); if (sysfs_get_attr(fd, member_path, "%llu", &member_offset, NULL, 0)) member_offset = 0; sprintf(member_path, "md/rd%u/block/dev", member); if (sysfs_get_attr(fd, member_path, "%s", buf, NULL, 0)) return EINVAL; if (md_major() == (unsigned)atoi(buf)) /* disallow recursive RAIDs */ return EINVAL; sprintf(member_path, "md/rd%u/block/start", member); if (sysfs_get_attr(fd, member_path, "%llu", &member_start, NULL, 0)) return ENODEV; if (member == 0) { start = member_start; offset = member_offset; } else if (member_start != start || member_offset != offset) return EINVAL; /* FIXME? Should --fibmap should account for member_offset in calculations? */ } *start_lba = start; return 0; } int get_dev_geometry (int fd, __u32 *cyls, __u32 *heads, __u32 *sects, __u64 *start_lba, __u64 *nsectors) { static struct local_hd_geometry g; static struct local_hd_big_geometry bg; int err = 0, try_getgeo_big_first = 1; if (nsectors) { err = get_sector_count(fd, nsectors); if (err) return err; } if (start_lba) { /* * HDIO_GETGEO uses 32-bit fields on 32-bit architectures, * so it cannot be relied upon for start_lba with very large drives >= 2TB. */ __u64 result; if (0 == sysfs_get_attr(fd, "start", "%llu", &result, NULL, 0) || 0 == get_raid1_start_lba(fd, &result)) { *start_lba = result; start_lba = NULL; try_getgeo_big_first = 0; /* if kernel has sysfs, it probably lacks GETGEO_BIG */ } else if (fd_is_raid(fd)) { *start_lba = START_LBA_UNKNOWN; /* RAID: no such thing as a "start_lba" */ start_lba = NULL; try_getgeo_big_first = 0; /* no point even trying it on RAID */ } } if (cyls || heads || sects || start_lba) { /* Skip HDIO_GETGEO_BIG (doesn't exist) on kernels with sysfs (>= 2.6.xx) */ if (try_getgeo_big_first && !ioctl(fd, HDIO_GETGEO_BIG, &bg)) { if (cyls) *cyls = bg.cylinders; if (heads) *heads = bg.heads; if (sects) *sects = bg.sectors; if (start_lba) *start_lba = bg.start; } else if (!ioctl(fd, HDIO_GETGEO, &g)) { if (cyls) *cyls = g.cylinders; if (heads) *heads = g.heads; if (sects) *sects = g.sectors; if (start_lba) *start_lba = g.start; } else if (!try_getgeo_big_first && !ioctl(fd, HDIO_GETGEO_BIG, &bg)) { if (cyls) *cyls = bg.cylinders; if (heads) *heads = bg.heads; if (sects) *sects = bg.sectors; if (start_lba) *start_lba = bg.start; } else { err = errno; perror(" HDIO_GETGEO failed"); return err; } /* * On all (32 and 64 bit) systems, the cyls value is bit-limited. * So try and correct it using other info we have at hand. */ if (nsectors && cyls && heads && sects) { __u64 hs = (*heads) * (*sects); __u64 cyl = (*cyls); __u64 chs = cyl * hs; if (chs < (*nsectors)) *cyls = (*nsectors) / hs; } } return 0; } static int find_dev_in_directory (dev_t dev, const char *dir, char *path, int verbose) { DIR *dp; struct dirent *entry; unsigned int maj = major(dev), min = minor(dev); *path = '\0'; if (!(dp = opendir(dir))) { int err = errno; if (verbose) perror(dir); return err; } while ((entry = readdir(dp)) != NULL) { if (entry->d_type == DT_UNKNOWN || entry->d_type == DT_BLK) { struct stat st; sprintf(path, "%s/%s", dir, entry->d_name); if (stat(path, &st)) { if (verbose) perror(path); } else if (S_ISBLK(st.st_mode)) { if (maj == (unsigned)major(st.st_rdev) && min == (unsigned)minor(st.st_rdev)) { closedir(dp); return 0; } } } } closedir(dp); *path = '\0'; if (verbose) fprintf(stderr, "%d,%d: device not found in %s\n", major(dev), minor(dev), dir); return ENOENT; } int get_dev_t_geometry (dev_t dev, __u32 *cyls, __u32 *heads, __u32 *sects, __u64 *start_lba, __u64 *nsectors) { char path[PATH_MAX]; int fd, err; err = find_dev_in_directory (dev, "/dev", path, 1); if (err) return err; fd = open(path, O_RDONLY|O_NONBLOCK); if (fd == -1) { err = errno; perror(path); return err; } err = get_dev_geometry(fd, cyls, heads, sects, start_lba, nsectors); close(fd); return err; } hdparm-9.43/LICENSE.TXT0000644000000000000000000000037510325247632013116 0ustar rootrootBSD-Style Open Source License: You may freely use, modify, and redistribute the hdparm program, as either binary or source, or both. The only condition is that my name and copyright notice remain in the source code as-is. Mark Lord (mlord@pobox.com) hdparm-9.43/Makefile0000644000000000000000000000366211726211460013071 0ustar rootroot# Makefile for hdparm # DESTDIR is for non root installs (eg packages, NFS) only! DESTDIR = binprefix = manprefix = /usr exec_prefix = $(binprefix)/ sbindir = $(exec_prefix)sbin mandir = $(manprefix)/share/man oldmandir = $(manprefix)/man CC ?= gcc STRIP ?= strip CFLAGS := -O2 -W -Wall -Wbad-function-cast -Wcast-align -Wpointer-arith -Wcast-qual -Wshadow -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -fkeep-inline-functions -Wwrite-strings -Waggregate-return -Wnested-externs -Wtrigraphs $(CFLAGS) LDFLAGS = -s #LDFLAGS = -s -static INSTALL = install INSTALL_DATA = $(INSTALL) -m 644 INSTALL_DIR = $(INSTALL) -m 755 -d INSTALL_PROGRAM = $(INSTALL) OBJS = hdparm.o identify.o sgio.o sysfs.o geom.o fallocate.o fibmap.o fwdownload.o dvdspeed.o wdidle3.o all: hdparm hdparm: hdparm.h sgio.h $(OBJS) $(CC) $(LDFLAGS) -o hdparm $(OBJS) $(STRIP) hdparm hdparm.o: hdparm.h sgio.h identify.o: hdparm.h dvdspeed.o: dvdspeed.c sgio.o: sgio.c sgio.h hdparm.h fwdownload.o: fwdownload.c sgio.h hdparm.h install: all hdparm.8 if [ ! -z $(DESTDIR) ]; then $(INSTALL_DIR) $(DESTDIR) ; fi if [ ! -z $(DESTDIR)$(sbindir) ]; then $(INSTALL_DIR) $(DESTDIR)$(sbindir) ; fi if [ ! -z $(DESTDIR)$(mandir) ]; then $(INSTALL_DIR) $(DESTDIR)$(mandir) ; fi if [ ! -z $(DESTDIR)$(mandir)/man8/ ]; then $(INSTALL_DIR) $(DESTDIR)$(mandir)/man8/ ; fi if [ -f $(DESTDIR)$(sbindir)/hdparm ]; then rm -f $(DESTDIR)$(sbindir)/hdparm ; fi if [ -f $(DESTDIR)$(mandir)/man8/hdparm.8 ]; then rm -f $(DESTDIR)$(mandir)/man8/hdparm.8 ;\ elif [ -f $(DESTDIR)$(oldmandir)/man8/hdparm.8 ]; then rm -f $(DESTDIR)$(oldmandir)/man8/hdparm.8 ; fi $(INSTALL_PROGRAM) -D hdparm $(DESTDIR)$(sbindir)/hdparm if [ -d $(DESTDIR)$(mandir) ]; then $(INSTALL_DATA) -D hdparm.8 $(DESTDIR)$(mandir)/man8/hdparm.8 ;\ elif [ -d $(DESTDIR)$(oldmandir) ]; then $(INSTALL_DATA) -D hdparm.8 $(DESTDIR)$(oldmandir)/man8/hdparm.8 ; fi clean: -rm -f hdparm $(OBJS) core 2>/dev/null hdparm-9.43/README.acoustic0000644000000000000000000000310310614700736014114 0ustar rootrootAutomatic Acoustic Management ============================= Most modern harddisk drives have the ability to speed down the head movements to reduce their noise output. The possible values are between 0 and 254. 128 is the most quiet (and therefore slowest) setting and 254 the fastest (and loudest). Some drives have only two levels (quiet / fast), while others may have different levels realized between 128 and 254. To be able to use this with hdparm, you will need a current kernel with the -ac patches applied. Maybe the kernel of your favorite distribution will already include this (SuSE has it in their current kernel, for example). Just try to compile hdparm, type "hdparm" and have a look for "-M" in the output. If it doesn't appear, your kernel most likely doesn't support it. You can get the acoustic setting by typing hdparm -M /dev/hda To set the most quiet mode use hdparm -M 128 /dev/hda For the fastest setting use hdparm -M 254 /dev/hda Now test different values and try to hear the difference. :-) Not all disk drives support this setting - and the speed impacts may also vary between different manufacturers and models. If you see lines like kernel: hdb: task_no_data_intr: status=0x51 { DriveReady SeekComplete Error } kernel: hdb: task_no_data_intr: error=0x04 { DriveStatusError } in your syslog, then your harddisk will most likely not support Acoustic Management. Perhaps you also wanna have a look on the IBM Feature Tool, available at http://www.storage.ibm.com/hdd/support/download.htm. I would welcome any feedback to Gernot hdparm-9.43/identify.c0000644000000000000000000014773012031353165013414 0ustar rootroot/* identify.c - by Mark Lord (C) 2000-2007 -- freely distributable */ #include #include #include #include #include #include #if __BYTE_ORDER == __BIG_ENDIAN #define __USE_XOPEN #endif #include "hdparm.h" /* device types */ /* ------------ */ #define NO_DEV 0xffff #define ATA_DEV 0x0000 #define ATAPI_DEV 0x0001 /* word definitions */ /* ---------------- */ #define GEN_CONFIG 0 /* general configuration */ #define LCYLS 1 /* number of logical cylinders */ #define CONFIG 2 /* specific configuration */ #define LHEADS 3 /* number of logical heads */ #define TRACK_BYTES 4 /* number of bytes/track (ATA-1) */ #define SECT_BYTES 5 /* number of bytes/sector (ATA-1) */ #define LSECTS 6 /* number of logical sectors/track */ #define START_SERIAL 10 /* ASCII serial number */ #define LENGTH_SERIAL 10 /* 10 words (20 bytes or characters) */ #define BUF_TYPE 20 /* buffer type (ATA-1) */ #define BUF_SIZE 21 /* buffer size (ATA-1) */ #define RW_LONG 22 /* extra bytes in R/W LONG cmd ( < ATA-4)*/ #define START_FW_REV 23 /* ASCII firmware revision */ #define LENGTH_FW_REV 4 /* 4 words (8 bytes or characters) */ #define START_MODEL 27 /* ASCII model number */ #define LENGTH_MODEL 20 /* 20 words (40 bytes or characters) */ #define SECTOR_XFER_MAX 47 /* r/w multiple: max sectors xfered */ #define DWORD_IO 48 /* can do double-word IO (ATA-1 only) */ #define CAPAB_0 49 /* capabilities */ #define CAPAB_1 50 #define PIO_MODE 51 /* max PIO mode supported (obsolete)*/ #define DMA_MODE 52 /* max Singleword DMA mode supported (obs)*/ #define WHATS_VALID 53 /* what fields are valid */ #define LCYLS_CUR 54 /* current logical cylinders */ #define LHEADS_CUR 55 /* current logical heads */ #define LSECTS_CUR 56 /* current logical sectors/track */ #define CAPACITY_LSB 57 /* current capacity in sectors */ #define CAPACITY_MSB 58 #define SECTOR_XFER_CUR 59 /* r/w multiple: current sectors xfered */ #define LBA_SECTS_LSB 60 /* LBA: total number of user */ #define LBA_SECTS_MSB 61 /* addressable sectors */ #define SINGLE_DMA 62 /* singleword DMA modes */ #define MULTI_DMA 63 /* multiword DMA modes */ #define ADV_PIO_MODES 64 /* advanced PIO modes supported */ /* multiword DMA xfer cycle time: */ #define DMA_TIME_MIN 65 /* - minimum */ #define DMA_TIME_NORM 66 /* - manufacturer's recommended */ /* minimum PIO xfer cycle time: */ #define PIO_NO_FLOW 67 /* - without flow control */ #define PIO_FLOW 68 /* - with IORDY flow control */ #define PKT_REL 71 /* typical #ns from PKT cmd to bus rel */ #define SVC_NBSY 72 /* typical #ns from SERVICE cmd to !BSY */ #define CDR_MAJOR 73 /* CD ROM: major version number */ #define CDR_MINOR 74 /* CD ROM: minor version number */ #define QUEUE_DEPTH 75 /* queue depth */ #define SATA_CAP_0 76 /* Serial ATA Capabilities */ #define SATA_RESERVED_77 77 /* reserved for future Serial ATA definition */ #define SATA_SUPP_0 78 /* Serial ATA features supported */ #define SATA_EN_0 79 /* Serial ATA features enabled */ #define MAJOR 80 /* major version number */ #define MINOR 81 /* minor version number */ #define CMDS_SUPP_0 82 /* command/feature set(s) supported */ #define CMDS_SUPP_1 83 #define CMDS_SUPP_2 84 #define CMDS_EN_0 85 /* command/feature set(s) enabled */ #define CMDS_EN_1 86 #define CMDS_EN_2 87 #define ULTRA_DMA 88 /* ultra DMA modes */ /* time to complete security erase */ #define ERASE_TIME 89 /* - ordinary */ #define ENH_ERASE_TIME 90 /* - enhanced */ #define ADV_PWR 91 /* current advanced power management level in low byte, 0x40 in high byte. */ #define PSWD_CODE 92 /* master password revision code */ #define HWRST_RSLT 93 /* hardware reset result */ #define ACOUSTIC 94 /* acoustic mgmt values ( >= ATA-6) */ #define LBA_LSB 100 /* LBA: maximum. Currently only 48 */ #define LBA_MID 101 /* bits are used, but addr 103 */ #define LBA_48_MSB 102 /* has been reserved for LBA in */ #define LBA_64_MSB 103 /* the future. */ #define CMDS_SUPP_3 119 #define CMDS_EN_3 120 #define RM_STAT 127 /* removable media status notification feature set support */ #define SECU_STATUS 128 /* security status */ #define CFA_PWR_MODE 160 /* CFA power mode 1 */ #define START_MEDIA 176 /* media serial number */ #define LENGTH_MEDIA 20 /* 20 words (40 bytes or characters)*/ #define START_MANUF 196 /* media manufacturer I.D. */ #define LENGTH_MANUF 10 /* 10 words (20 bytes or characters) */ #define SCT_SUPP 206 /* SMART command transport (SCT) support */ #define TRANSPORT_MAJOR 222 /* PATA vs. SATA etc.. */ #define TRANSPORT_MINOR 223 /* minor revision number */ #define NMRR 217 /* nominal media rotation rate */ #define INTEGRITY 255 /* integrity word */ /* bit definitions within the words */ /* -------------------------------- */ /* many words are considered valid if bit 15 is 0 and bit 14 is 1 */ #define VALID 0xc000 #define VALID_VAL 0x4000 /* many words are considered invalid if they are either all-0 or all-1 */ /* word 0: gen_config */ #define NOT_ATA 0x8000 #define NOT_ATAPI 0x4000 /* (check only if bit 15 == 1) */ #define MEDIA_REMOVABLE 0x0080 #define DRIVE_NOT_REMOVABLE 0x0040 /* bit obsoleted in ATA 6 */ #define INCOMPLETE 0x0004 #define DRQ_RESPONSE_TIME 0x0060 #define DRQ_3MS_VAL 0x0000 #define DRQ_INTR_VAL 0x0020 #define DRQ_50US_VAL 0x0040 #define PKT_SIZE_SUPPORTED 0x0003 #define PKT_SIZE_12_VAL 0x0000 #define PKT_SIZE_16_VAL 0x0001 #define EQPT_TYPE 0x1f00 #define SHIFT_EQPT 8 #define CDROM 0x0005 const char *pkt_str[] = { "Direct-access device", /* word 0, bits 12-8 = 00 */ "Sequential-access device", /* word 0, bits 12-8 = 01 */ "Printer", /* word 0, bits 12-8 = 02 */ "Processor", /* word 0, bits 12-8 = 03 */ "Write-once device", /* word 0, bits 12-8 = 04 */ "CD-ROM", /* word 0, bits 12-8 = 05 */ "Scanner", /* word 0, bits 12-8 = 06 */ "Optical memory", /* word 0, bits 12-8 = 07 */ "Medium changer", /* word 0, bits 12-8 = 08 */ "Communications device", /* word 0, bits 12-8 = 09 */ "ACS-IT8 device", /* word 0, bits 12-8 = 0a */ "ACS-IT8 device", /* word 0, bits 12-8 = 0b */ "Array controller", /* word 0, bits 12-8 = 0c */ "Enclosure services", /* word 0, bits 12-8 = 0d */ "Reduced block command device", /* word 0, bits 12-8 = 0e */ "Optical card reader/writer", /* word 0, bits 12-8 = 0f */ "", /* word 0, bits 12-8 = 10 */ "", /* word 0, bits 12-8 = 11 */ "", /* word 0, bits 12-8 = 12 */ "", /* word 0, bits 12-8 = 13 */ "", /* word 0, bits 12-8 = 14 */ "", /* word 0, bits 12-8 = 15 */ "", /* word 0, bits 12-8 = 16 */ "", /* word 0, bits 12-8 = 17 */ "", /* word 0, bits 12-8 = 18 */ "", /* word 0, bits 12-8 = 19 */ "", /* word 0, bits 12-8 = 1a */ "", /* word 0, bits 12-8 = 1b */ "", /* word 0, bits 12-8 = 1c */ "", /* word 0, bits 12-8 = 1d */ "", /* word 0, bits 12-8 = 1e */ "Unknown", /* word 0, bits 12-8 = 1f */ }; const char *ata1_cfg_str[] = { /* word 0 in ATA-1 mode */ "reserved", /* bit 0 */ "hard sectored", /* bit 1 */ "soft sectored", /* bit 2 */ "not MFM encoded ", /* bit 3 */ "head switch time > 15us", /* bit 4 */ "spindle motor control option", /* bit 5 */ "fixed drive", /* bit 6 */ "removable drive", /* bit 7 */ "disk xfer rate <= 5Mbs", /* bit 8 */ "disk xfer rate > 5Mbs, <= 10Mbs", /* bit 9 */ "disk xfer rate > 5Mbs", /* bit 10 */ "rotational speed tol.", /* bit 11 */ "data strobe offset option", /* bit 12 */ "track offset option", /* bit 13 */ "format speed tolerance gap reqd", /* bit 14 */ "ATAPI" /* bit 14 */ }; /* word 1: number of logical cylinders */ #define LCYLS_MAX 0x3fff /* maximum allowable value */ /* word 2: specific configureation * (a) require SET FEATURES to spin-up * (b) require spin-up to fully reply to IDENTIFY DEVICE */ #define STBY_NID_VAL 0x37c8 /* (a) and (b) */ #define STBY_ID_VAL 0x738c /* (a) and not (b) */ #define PWRD_NID_VAL 0x8c73 /* not (a) and (b) */ #define PWRD_ID_VAL 0xc837 /* not (a) and not (b) */ /* words 47 & 59: sector_xfer_max & sector_xfer_cur */ #define SECTOR_XFER 0x00ff /* sectors xfered on r/w multiple cmds*/ #define MULTIPLE_SETTING_VALID 0x0100 /* 1=multiple sector setting is valid */ /* word 49: capabilities 0 */ #define STD_STBY 0x2000 /* 1=standard values supported (ATA); 0=vendor specific values */ #define IORDY_SUP 0x0800 /* 1=support; 0=may be supported */ #define IORDY_OFF 0x0400 /* 1=may be disabled */ #define LBA_SUP 0x0200 /* 1=Logical Block Address support */ #define DMA_SUP 0x0100 /* 1=Direct Memory Access support */ #define DMA_IL_SUP 0x8000 /* 1=interleaved DMA support (ATAPI) */ #define CMD_Q_SUP 0x4000 /* 1=command queuing support (ATAPI) */ #define OVLP_SUP 0x2000 /* 1=overlap operation support (ATAPI) */ #define SWRST_REQ 0x1000 /* 1=ATA SW reset required (ATAPI, obsolete */ /* word 50: capabilities 1 */ #define MIN_STANDBY_TIMER 0x0001 /* 1=device specific standby timer value minimum */ /* words 51 & 52: PIO & DMA cycle times */ #define MODE 0xff00 /* the mode is in the MSBs */ /* word 53: whats_valid */ #define OK_W88 0x0004 /* the ultra_dma info is valid */ #define OK_W64_70 0x0002 /* see above for word descriptions */ #define OK_W54_58 0x0001 /* current cyl, head, sector, cap. info valid */ /*word 63,88: dma_mode, ultra_dma_mode*/ #define MODE_MAX 7 /* bit definitions force udma <=7 (when * udma >=8 comes out it'll have to be * defined in a new dma_mode word!) */ /* word 64: PIO transfer modes */ #define PIO_SUP 0x00ff /* only bits 0 & 1 are used so far, */ #define PIO_MODE_MAX 8 /* but all 8 bits are defined */ /* word 75: queue_depth */ #define DEPTH_BITS 0x001f /* bits used for queue depth */ /* words 80-81: version numbers */ /* 0x0000 or 0xffff means device does not report version */ /* word 81: minor version number */ #define MINOR_MAX 0x22 const char *minor_str[MINOR_MAX+2] = { /* word 81 value: */ "Unspecified", /* 0x0000 */ "ATA-1 X3T9.2 781D prior to revision 4", /* 0x0001 */ "ATA-1 published, ANSI X3.221-1994", /* 0x0002 */ "ATA-1 X3T9.2 781D revision 4", /* 0x0003 */ "ATA-2 published, ANSI X3.279-1996", /* 0x0004 */ "ATA-2 X3T10 948D prior to revision 2k", /* 0x0005 */ "ATA-3 X3T10 2008D revision 1", /* 0x0006 */ "ATA-2 X3T10 948D revision 2k", /* 0x0007 */ "ATA-3 X3T10 2008D revision 0", /* 0x0008 */ "ATA-2 X3T10 948D revision 3", /* 0x0009 */ "ATA-3 published, ANSI X3.298-199x", /* 0x000a */ "ATA-3 X3T10 2008D revision 6", /* 0x000b */ "ATA-3 X3T13 2008D revision 7 and 7a", /* 0x000c */ "ATA/ATAPI-4 X3T13 1153D revision 6", /* 0x000d */ "ATA/ATAPI-4 T13 1153D revision 13", /* 0x000e */ "ATA/ATAPI-4 X3T13 1153D revision 7", /* 0x000f */ "ATA/ATAPI-4 T13 1153D revision 18", /* 0x0010 */ "ATA/ATAPI-4 T13 1153D revision 15", /* 0x0011 */ "ATA/ATAPI-4 published, ANSI INCITS 317-1998", /* 0x0012 */ "ATA/ATAPI-5 T13 1321D revision 3", "ATA/ATAPI-4 T13 1153D revision 14", /* 0x0014 */ "ATA/ATAPI-5 T13 1321D revision 1", /* 0x0015 */ "ATA/ATAPI-5 published, ANSI INCITS 340-2000", /* 0x0016 */ "ATA/ATAPI-4 T13 1153D revision 17", /* 0x0017 */ "ATA/ATAPI-6 T13 1410D revision 0", /* 0x0018 */ "ATA/ATAPI-6 T13 1410D revision 3a", /* 0x0019 */ "ATA/ATAPI-7 T13 1532D revision 1", /* 0x001a */ "ATA/ATAPI-6 T13 1410D revision 2", /* 0x001b */ "ATA/ATAPI-6 T13 1410D revision 1", /* 0x001c */ "ATA/ATAPI-7 published, ANSI INCITS 397-2005", /* 0x001d */ "ATA/ATAPI-7 T13 1532D revision 0", /* 0x001e */ "Reserved", /* 0x001f */ "Reserved", /* 0x0020 */ "ATA/ATAPI-7 T13 1532D revision 4a", /* 0x0021 */ "ATA/ATAPI-6 published, ANSI INCITS 361-2002", /* 0x0022 */ "Reserved", /* 0x0023-0xfffe*/ }; const char actual_ver[MINOR_MAX+2] = { /* word 81 value: */ 0, /* 0x0000 WARNING: */ 1, /* 0x0001 WARNING: */ 1, /* 0x0002 WARNING: */ 1, /* 0x0003 WARNING: */ 2, /* 0x0004 WARNING: This array */ 2, /* 0x0005 WARNING: corresponds */ 3, /* 0x0006 WARNING: *exactly* */ 2, /* 0x0007 WARNING: to the ATA/ */ 3, /* 0x0008 WARNING: ATAPI version */ 2, /* 0x0009 WARNING: listed in */ 3, /* 0x000a WARNING: the */ 3, /* 0x000b WARNING: minor_str */ 3, /* 0x000c WARNING: array */ 4, /* 0x000d WARNING: above. */ 4, /* 0x000e WARNING: */ 4, /* 0x000f WARNING: if you change */ 4, /* 0x0010 WARNING: that one, */ 4, /* 0x0011 WARNING: change this one */ 4, /* 0x0012 WARNING: too!!! */ 5, /* 0x0013 WARNING: */ 4, /* 0x0014 WARNING: */ 5, /* 0x0015 WARNING: */ 5, /* 0x0016 WARNING: */ 4, /* 0x0017 WARNING: */ 6, /* 0x0018 WARNING: */ 6, /* 0x0019 WARNING: */ 7, /* 0x001a WARNING: */ 6, /* 0x001b WARNING: */ 6, /* 0x001c WARNING: */ 7, /* 0x001d WARNING: */ 7, /* 0x001e WARNING: */ 0, /* 0x001f WARNING: */ 0, /* 0x0020 WARNING: */ 7, /* 0x0021 WARNING: */ 6, /* 0x0022 WARNING: */ 0 /* 0x0023-0xfffe */ }; /* words 82-84: cmds/feats supported */ #define CMDS_W82 0x77ff /* word 82: defined command locations*/ #define CMDS_W83 0x3fff /* word 83: defined command locations*/ #define CMDS_W84 0x27ff /* word 84: defined command locations*/ #define SUPPORT_48_BIT 0x0400 #define NUM_CMD_FEAT_STR 48 static const char unknown[8] = "obsolete"; //static const char unknown[8] = "unknown"; #define unknown "unknown-" static const char *feat_word69_str[16] = { "CFast specification support", /* word 69 bit 15 */ "Deterministic read data after TRIM", /* word 69 bit 14 */ "Long physical sector diagnostics", /* word 69 bit 13 */ "DEVICE CONFIGURATION SET/IDENTIFY DMA commands", /* word 69 bit 12 */ "READ BUFFER DMA command", /* word 69 bit 11 */ "WRITE BUFFER DMA command", /* word 69 bit 10 */ "SET MAX SETPASSWORD/UNLOCK DMA commands", /* word 69 bit 9 */ "DOWNLOAD MICROCODE DMA command", /* word 69 bit 8 */ "reserved 69[7]", /* word 69 bit 7 */ "reserved 69[6]", /* word 69 bit 6 */ "Deterministic read ZEROs after TRIM", /* word 69 bit 5 */ "reserved 69[4]", /* word 69 bit 4 */ "reserved 69[3]", /* word 69 bit 3 */ "reserved 69[2]", /* word 69 bit 2 */ "reserved 69[1]", /* word 69 bit 1 */ "reserved 69[0]", /* word 69 bit 0 */ }; static const char *feat_word82_str[16] = { "obsolete 82[15]", /* word 82 bit 15: obsolete */ "NOP cmd", /* word 82 bit 14 */ "READ_BUFFER command", /* word 82 bit 13 */ "WRITE_BUFFER command", /* word 82 bit 12 */ "WRITE_VERIFY command", /* word 82 bit 11: obsolete */ "Host Protected Area feature set", /* word 82 bit 10 */ "DEVICE_RESET command", /* word 82 bit 9 */ "SERVICE interrupt", /* word 82 bit 8 */ "Release interrupt", /* word 82 bit 7 */ "Look-ahead", /* word 82 bit 6 */ "Write cache", /* word 82 bit 5 */ "PACKET command feature set", /* word 82 bit 4 */ "Power Management feature set", /* word 82 bit 3 */ "Removable Media feature set", /* word 82 bit 2 */ "Security Mode feature set", /* word 82 bit 1 */ "SMART feature set" /* word 82 bit 0 */ }; static const char *feat_word83_str[16] = { NULL, /* word 83 bit 15: !valid bit */ NULL, /* word 83 bit 14: valid bit */ "FLUSH_CACHE_EXT", /* word 83 bit 13 */ "Mandatory FLUSH_CACHE", /* word 83 bit 12 */ "Device Configuration Overlay feature set", /* word 83 bit 11 */ "48-bit Address feature set", /* word 83 bit 10 */ "Automatic Acoustic Management feature set", /* word 83 bit 9 */ "SET_MAX security extension", /* word 83 bit 8 */ "Address Offset Reserved Area Boot", /* word 83 bit 7 */ "SET_FEATURES required to spinup after power up",/* word 83 bit 6 */ "Power-Up In Standby feature set", /* word 83 bit 5 */ "Removable Media Status Notification feature set",/* word 83 bit 4 */ "Advanced Power Management feature set", /* word 83 bit 3 */ "CFA feature set", /* word 83 bit 2 */ "READ/WRITE_DMA_QUEUED", /* word 83 bit 1 */ "DOWNLOAD_MICROCODE" /* word 83 bit 0 */ }; static const char *feat_word84_str[16] = { NULL, /* word 84 bit 15: !valid bit */ NULL, /* word 84 bit 14: valid bit */ "IDLE_IMMEDIATE with UNLOAD", /* word 84 bit 13 */ "Command Completion Time Limit (CCTL)", /* word 84 bit 12 (ref: dt1696) */ "Time Limited Commands (TLC) feature set", /* word 84 bit 11 (ref: dt1696) */ "URG for WRITE_STREAM[_DMA]_EXT", /* word 84 bit 10 */ "URG for READ_STREAM[_DMA]_EXT", /* word 84 bit 9 */ "64-bit World wide name", /* word 84 bit 8 */ "WRITE_DMA_QUEUED_FUA_EXT", /* word 84 bit 7 */ "WRITE_{DMA|MULTIPLE}_FUA_EXT", /* word 84 bit 6 */ "General Purpose Logging feature set", /* word 84 bit 5 */ "Media Card Pass-Through", /* word 84 bit 4 */ "Media Card Pass Through Command feature set", /* word 84 bit 3 */ "Media serial number", /* word 84 bit 2 */ "SMART self-test", /* word 84 bit 1 */ "SMART error logging" /* word 84 bit 0 */ }; static const char *feat_3_str[16] = { NULL, /* word 119 bit 15: !valid bit */ NULL, /* word 119 bit 14: valid bit */ "unknown 119[13]", /* word 119 bit 13 */ "unknown 119[12]", /* word 119 bit 12 */ "unknown 119[11]", /* word 119 bit 11 */ "unknown 119[10]", /* word 119 bit 10 */ "unknown 119[9]", /* word 119 bit 9 */ "unknown 119[8]", /* word 119 bit 8 */ "unknown 119[7]", /* word 119 bit 7 */ "unknown 119[6]", /* word 119 bit 6 */ "Free-fall Control feature set", /* word 119 bit 5 */ "Segmented DOWNLOAD_MICROCODE", /* word 119 bit 4 */ "{READ,WRITE}_DMA_EXT_GPL commands", /* word 119 bit 3 */ "WRITE_UNCORRECTABLE_EXT command", /* word 119 bit 2 */ "Write-Read-Verify feature set", /* word 119 bit 1 */ "Disable Data Transfer After Error Detection" /* word 119 bit 0 (ref: 2014DT)*/ }; static const char *cap_sata0_str[16] = { "unknown 76[15]", /* word 76 bit 15 */ "unknown 76[14]", /* word 76 bit 14 */ "unknown 76[13]", /* word 76 bit 13 */ "NCQ priority information", /* word 76 bit 12 */ "Idle-Unload when NCQ is active", /* word 76 bit 11 */ "Phy event counters", /* word 76 bit 10 */ "Host-initiated interface power management", /* word 76 bit 9 */ "Native Command Queueing (NCQ)", /* word 76 bit 8 */ "unknown 76[7]", /* word 76 bit 7 */ "unknown 76[6]", /* word 76 bit 6 */ "unknown 76[5]", /* word 76 bit 5 */ "unknown 76[4]", /* word 76 bit 4 */ "Gen3 signaling speed (6.0Gb/s)", /* word 76 bit 3 */ "Gen2 signaling speed (3.0Gb/s)", /* word 76 bit 2 */ "Gen1 signaling speed (1.5Gb/s)", /* word 76 bit 1 */ "unknown 76[0]" /* word 76 bit 0 */ }; static const char *feat_sata0_str[16] = { "unknown 78[15]", /* word 78 bit 15 */ "unknown 78[14]", /* word 78 bit 14 */ "unknown 78[13]", /* word 78 bit 13 */ "unknown 78[12]", /* word 78 bit 12 */ "unknown 78[11]", /* word 78 bit 11 */ "unknown 78[10]", /* word 78 bit 10 */ "unknown 78[9]", /* word 78 bit 9 */ "unknown 78[8]", /* word 78 bit 8 */ "unknown 78[7]", /* word 78 bit 7 */ "Software settings preservation", /* word 78 bit 6 */ "Asynchronous notification (eg. media change)", /* word 78 bit 5 */ "In-order data delivery", /* word 78 bit 4 */ "Device-initiated interface power management", /* word 78 bit 3 */ "DMA Setup Auto-Activate optimization", /* word 78 bit 2 */ "Non-Zero buffer offsets in DMA Setup FIS", /* word 78 bit 1 */ "unknown 78[0]" /* word 78 bit 0 */ }; /* words 85-87: cmds/feats enabled */ /* use cmd_feat_str[] to display what commands and features have * been enabled with words 85-87 */ #define WWN_SUP 0x100 /* 1=support; 0=not supported */ /* words 89, 90, SECU ERASE TIME */ #define ERASE_BITS 0x00ff /* word 92: master password revision */ /* 0x0000 or 0xffff means no support for master password revision */ /* word 93: hw reset result */ #define CBLID 0x2000 /* CBLID status */ #define RST0 0x0001 /* 1=reset to device #0 */ #define DEV_DET 0x0006 /* how device num determined */ #define JUMPER_VAL 0x0002 /* device num determined by jumper */ #define CSEL_VAL 0x0004 /* device num determined by CSEL_VAL */ /* word 127: removable media status notification feature set support */ #define RM_STAT_BITS 0x0003 #define RM_STAT_SUP 0x0001 /* word 128: security */ #define SECU_ENABLED 0x0002 #define SECU_LEVEL 0x0100 /* was 0x0010 */ #define NUM_SECU_STR 6 const char *secu_str[] = { "supported", /* word 128, bit 0 */ "enabled", /* word 128, bit 1 */ "locked", /* word 128, bit 2 */ "frozen", /* word 128, bit 3 */ "expired: security count", /* word 128, bit 4 */ "supported: enhanced erase" /* word 128, bit 5 */ }; /* word 160: CFA power mode */ #define VALID_W160 0x8000 /* 1=word valid */ #define PWR_MODE_REQ 0x2000 /* 1=CFA power level 1 is NOT supported */ #define PWR_MODE_OFF 0x1000 /* 1=CFA power level 1 commands are DISABLED */ #define MAX_AMPS 0x0fff /* value = max current in milli-amperes (mA) */ /* word 206: SMART command transport (SCT) */ static const char *feat_sct_str[16] = { "unknown 206[15] (vendor specific)", /* word 206 bit 15 */ "unknown 206[14] (vendor specific)", /* word 206 bit 14 */ "unknown 206[13] (vendor specific)", /* word 206 bit 13 */ "unknown 206[12] (vendor specific)", /* word 206 bit 12 */ "unknown 206[11]", /* word 206 bit 11 */ "unknown 206[10]", /* word 206 bit 10 */ "unknown 206[9]", /* word 206 bit 9 */ "unknown 206[8]", /* word 206 bit 8 */ "unknown 206[7]", /* word 206 bit 7 */ "unknown 206[6]", /* word 206 bit 6 */ "SCT Data Tables (AC5)", /* word 206 bit 5 */ "SCT Features Control (AC4)", /* word 206 bit 4 */ "SCT Error Recovery Control (AC3)", /* word 206 bit 3 */ "SCT Write Same (AC2)", /* word 206 bit 2 */ "SCT Read/Write Long (AC1), obsolete", /* word 206 bit 1: obsolete per T13/e08153r1 */ "SMART Command Transport (SCT) feature set" /* word 206 bit 0 */ }; /* word 255: integrity */ #define SIG 0x00ff /* signature location */ #define SIG_VAL 0x00A5 /* signature value */ __u8 mode_loop(__u16 mode_sup, __u16 mode_sel, int cc, __u8 *have_mode); static void print_ascii(__u16 *p, unsigned int length) { __u8 ii; char cl; /* find first non-space & print it */ for (ii = 0; ii< length; ii++) { if(((char) 0x00ff&((*p)>>8)) != ' ') break; if((cl = (char) 0x00ff&(*p)) != ' ') { if(cl != '\0') printf("%c",cl); p++; ii++; break; } p++; } /* print the rest */ for (; ii < length; ii++) { __u8 c; /* some older devices have NULLs */ c = (*p) >> 8; if (c) putchar(c); c = (*p); if (c) putchar(c); p++; } printf("\n"); } // Given a known-supported ATA major revision, // return the lowest possible supported ATA revision. // Each new revision seems to (sometimes) obsolete one // of the bits corresponding to an older revision. static __u16 min_ata_std (__u16 major) { if (major <= 4) // up to ata4, no obsolete bits return 1; if (major == 5) // ata5 obsoleted the ata1 bit return 2; if (major <= 7) // ata6,7 obsoleted the ata2 bit return 3; return 4; // ata8 obsoleted the ata3 bit } static void print_features (__u16 supported, __u16 enabled, const char *names[]) { int i; for (i = 0; i < 16; ++i) { __u16 mask = 1 << i; if ((supported & mask) && names[15 - i]) printf("\t %c\t%s\n", (enabled & mask) ? '*' : ' ', names[15 - i]); } } static int print_transport_type(__u16 val[]) { __u16 major = val[TRANSPORT_MAJOR], minor = val[TRANSPORT_MINOR]; unsigned int ttype, subtype, transport = 0; if (major == 0x0000 || major == 0xffff) { #if 0 printf("\t%-20snot reported","Transport:"); if ((val[SATA_CAP_0] && val[SATA_CAP_0] != 0xffff) || (val[SATA_SUPP_0] && val[SATA_SUPP_0] != 0xffff)) { printf(" (serial)"); } putchar('\n'); #endif return transport; } printf("\t%-20s","Transport:"); ttype = major >> 12; subtype = major & 0xfff; transport = ttype; switch (ttype) { case 0: printf("Parallel"); if (subtype & 1) printf(", ATA8-APT"); break; case 1: printf("Serial"); if (subtype & 0x2f) { if (subtype & (1<<0)) printf(", ATA8-AST"); if (subtype & (1<<1)) printf(", SATA 1.0a"); if (subtype & (1<<2)) printf(", SATA II Extensions"); if (subtype & (1<<3)) printf(", SATA Rev 2.5"); if (subtype & (1<<4)) printf(", SATA Rev 2.6"); if (subtype & (1<<5)) printf(", SATA Rev 3.0"); } break; default: printf("0x%04x", major); break; } if (minor != 0x0000 && minor != 0xffff) { printf("; Revision: "); switch (minor) { case 0x21: printf("ATA8-AST T13 Project D1697 Revision 0b"); break; default: printf("0x%04x", minor); } } putchar('\n'); return transport; } static int is_cfa_dev (__u16 *id) { /* * id[0] == 0x848a means "CFA compliant, not ATA-4 compliant". * id[0] == 0x044a is also allowed, but ISTR that some HDs use it too. * Also, bit 0x0004 of id[83] means "supports CFA feature set". */ return id[0] == 0x848a || id[0] == 0x844a || (id[83] & 0xc004) == 0x4004; } /* our main() routine: */ void identify (__u16 *id_supplied) { unsigned int sector_bytes = 512; __u16 val[256], ii, jj, kk; __u16 like_std = 1, std = 0, min_std = 0xffff; __u16 dev = NO_DEV, eqpt = NO_DEV; __u8 have_mode = 0, err_dma = 0; __u8 chksum = 0; __u32 ll, mm, nn; __u64 bb, bbbig; /* (:) */ int transport, is_cfa = 0, atapi_has_dmadir = 0, sdma_ok; memcpy(val, id_supplied, sizeof(val)); /* calculate checksum over all bytes */ for (ii = GEN_CONFIG; ii<=INTEGRITY; ii++) { chksum += val[ii] + (val[ii] >> 8); } /* check if we recognise the device type */ printf("\n"); //if(val[GEN_CONFIG] == 0x848a || val[GEN_CONFIG] == 0x844a) { if (is_cfa_dev(val)) { is_cfa = 1; dev = ATA_DEV; like_std = 4; printf("CompactFlash ATA device\n"); } else if(!(val[GEN_CONFIG] & NOT_ATA)) { dev = ATA_DEV; printf("ATA device, with "); } else if(!(val[GEN_CONFIG] & NOT_ATAPI)) { dev = ATAPI_DEV; eqpt = (val[GEN_CONFIG] & EQPT_TYPE) >> SHIFT_EQPT; printf("ATAPI %s, with ", pkt_str[eqpt]); like_std = 3; } else { printf("Unknown device type:\n\tbits 15&14 of general configuration word 0 both set to 1.\n"); exit(EINVAL); } if (!is_cfa) { if(!(val[GEN_CONFIG] & MEDIA_REMOVABLE)) printf("non-"); printf("removable media\n"); } /* Info from the specific configuration word says whether or not the * ID command completed correctly. It is only defined, however in * ATA/ATAPI-5 & 6; it is reserved (value theoretically 0) in prior * standards. Since the values allowed for this word are extremely * specific, it should be safe to check it now, even though we don't * know yet what standard this device is using. */ if((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==STBY_ID_VAL) || (val[CONFIG]==PWRD_NID_VAL) || (val[CONFIG]==PWRD_ID_VAL) ) { like_std = 5; if((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==STBY_ID_VAL)) printf("powers-up in standby; SET FEATURES subcmd spins-up.\n"); if(((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==PWRD_NID_VAL)) && (val[GEN_CONFIG] & INCOMPLETE)) printf("\n\tWARNING: ID response incomplete.\n\tWARNING: Following data may be incorrect.\n\n"); } /* output the model and serial numbers and the fw revision */ if(val[START_MODEL]) { printf("\t%-20s","Model Number:"); print_ascii(&val[START_MODEL], LENGTH_MODEL); } if(val[START_SERIAL]) { printf("\t%-20s","Serial Number:"); print_ascii( &val[START_SERIAL], LENGTH_SERIAL); } if(val[START_FW_REV]) { printf("\t%-20s","Firmware Revision:"); print_ascii(&val[START_FW_REV], LENGTH_FW_REV); } if(val[START_MEDIA]) { printf("\t%-20s","Media Serial Num:"); print_ascii(&val[START_MEDIA], LENGTH_MEDIA); } if(val[START_MANUF]) { printf("\t%-20s","Media Manufacturer:"); print_ascii(&val[START_MANUF], LENGTH_MANUF); } transport = print_transport_type(val); /* major & minor standards version number (Note: these words were not * defined until ATA-3 & the CDROM std uses different words.) */ printf("Standards:"); if(eqpt != CDROM) { //printf("major=%04x minor=%04x\n", val[MAJOR], val[MINOR]); const char * used = 0; if(val[MINOR] && (val[MINOR] <= MINOR_MAX)) { if(like_std < 3) like_std = 3; std = actual_ver[val[MINOR]]; if (std) used = minor_str[val[MINOR]]; } else { /* check for recent ATA-8 revision codes (not added to * actual_ver/minor_str to avoid large sparse tables) */ switch (val[MINOR]) { case 0x0027: used = "ATA-8-ACS revision 3c"; break; case 0x0033: used = "ATA-8-ACS revision 3e"; break; case 0x0042: used = "ATA-8-ACS revision 3f"; break; case 0x0052: used = "ATA-8-ACS revision 3b"; break; case 0x0107: used = "ATA-8-ACS revision 2d"; break; } if (used) std = 8; } if (used) printf("\n\tUsed: %s ", used); else if (val[MINOR] >= 0x001f) /* first "reserved" value possibly later used by ATA-8 */ printf("\n\tUsed: unknown (minor revision code 0x%04x) ", val[MINOR]); /* looks like when they up-issue the std, they obsolete one; * thus, only the newest 4 issues need be supported. * (That's what "kk" and "min_std" are all about) */ if(val[MAJOR] && (val[MAJOR] != 0xffff)) { printf("\n\tSupported: "); jj = val[MAJOR] << 1; kk = min_ata_std(like_std); for (ii = 14; ii > kk; ii--) { if(jj & 0x8000) { printf("%u ", ii); if (ii > like_std) { like_std = ii; kk = min_ata_std(like_std); } if (min_std > ii) min_std = ii; } jj <<= 1; } if(like_std < 3) like_std = 3; } /* Figure out what standard the device is using if it hasn't told * us. If we know the std, check if the device is using any of * the words from the next level up. It happens. */ if(like_std < std) like_std = std; if(((std == 7) || (!std && (like_std < 8))) && (val[SCT_SUPP] & 0x1)) { like_std = 8; } else if(((std == 5) || (!std && (like_std < 6))) && ( (((val[CMDS_SUPP_1] & VALID) == VALID_VAL) && ((val[CMDS_SUPP_1] & CMDS_W83) > 0x00ff)) || (((val[CMDS_SUPP_2] & VALID) == VALID_VAL) && (val[CMDS_SUPP_2] & CMDS_W84) ) ) ) { like_std = 6; } else if(((std == 4) || (!std && (like_std < 5))) && ((((val[INTEGRITY] & SIG) == SIG_VAL) && !chksum) || ((val[HWRST_RSLT] & VALID) == VALID_VAL) || (((val[CMDS_SUPP_1] & VALID) == VALID_VAL) && ((val[CMDS_SUPP_1] & CMDS_W83) > 0x001f)) ) ) { like_std = 5; } else if(((std == 3) || (!std && (like_std < 4))) && ((((val[CMDS_SUPP_1] & VALID) == VALID_VAL) && (((val[CMDS_SUPP_1] & CMDS_W83) > 0x0000) || ((val[CMDS_SUPP_0] & CMDS_W82) > 0x000f))) || ((val[CAPAB_1] & VALID) == VALID_VAL) || ((val[WHATS_VALID] & OK_W88) && val[ULTRA_DMA]) || ((val[RM_STAT] & RM_STAT_BITS) == RM_STAT_SUP) ) ) { like_std = 4; } else if(((std == 2) || (!std && (like_std < 3))) && ((val[CMDS_SUPP_1] & VALID) == VALID_VAL) ) { like_std = 3; } else if(((std == 1) || (!std && (like_std < 2))) && ((val[CAPAB_0] & (IORDY_SUP | IORDY_OFF)) || (val[WHATS_VALID] & OK_W64_70)) ) { like_std = 2; } if(!std) { printf("\n\tLikely used: %u\n",like_std); } else if(like_std > std) { printf("& some of %u\n",like_std); } else printf("\n"); } else { /* TBD: do CDROM stuff more thoroughly. For now... */ kk = 0; if(val[CDR_MINOR] == 9) { kk = 1; printf("\n\tUsed: ATAPI for CD-ROMs, SFF-8020i, r2.5"); } if(val[CDR_MAJOR] && (val[CDR_MAJOR] != 0xffff)) { kk = 1; printf("\n\tSupported: CD-ROM ATAPI"); jj = val[CDR_MAJOR] >> 1; for (ii = 1; ii <15; ii++) { if(jj & 0x0001) { printf("-%u ", ii); } jj >>= 1; } } if(!kk) printf("\n\tLikely used CD-ROM ATAPI-1\n"); else printf("\n"); /* the cdrom stuff is more like ATA-2 than anything else, so: */ like_std = 2; } if(min_std == 0xffff) min_std = like_std > 4 ? like_std - 3 : 1; printf("Configuration:\n"); /* more info from the general configuration word */ if((eqpt != CDROM) && (like_std == 1)) { jj = val[GEN_CONFIG] >> 1; for (ii = 1; ii < 15; ii++) { if(jj & 0x0001) printf("\t%s\n",ata1_cfg_str[ii]); jj >>=1; } } if(dev == ATAPI_DEV) { printf("\tDRQ response: "); /* Data Request (DRQ) */ switch(val[GEN_CONFIG] & DRQ_RESPONSE_TIME) { case DRQ_3MS_VAL : printf("3ms.\n"); break; case DRQ_INTR_VAL : printf("<=10ms with INTRQ\n"); break; case DRQ_50US_VAL : printf("50us.\n"); break; default : printf("unknown.\n"); break; } printf("\tPacket size: "); switch(val[GEN_CONFIG] & PKT_SIZE_SUPPORTED) { case PKT_SIZE_12_VAL : printf("12 bytes\n"); break; case PKT_SIZE_16_VAL : printf("16 bytes\n"); break; default : printf("Unknown\n"); break; } } else { /* addressing...CHS? See section 6.2 of ATA specs 4 or 5 */ ll = 0; mm = 0; bb = 0; bbbig = 0; if (val[CAPAB_0] & LBA_SUP) ll = (__u32)val[LBA_SECTS_MSB] << 16 | val[LBA_SECTS_LSB]; if ( (ll > 0x00FBFC10) && (!val[LCYLS])) { printf("\tCHS addressing not supported\n"); } else { jj = val[WHATS_VALID] & OK_W54_58; printf("\tLogical\t\tmax\tcurrent\n"); printf("\tcylinders\t%u\t%u\n",val[LCYLS],jj?val[LCYLS_CUR]:0); printf("\theads\t\t%u\t%u\n",val[LHEADS],jj?val[LHEADS_CUR]:0); printf("\tsectors/track\t%u\t%u\n",val[LSECTS],jj?val[LSECTS_CUR]:0); if(jj) bb = (__u64)val[LCYLS_CUR] * val[LHEADS_CUR] * val[LSECTS_CUR]; else bb = (__u64)val[LCYLS] * val[LHEADS] * val[LSECTS]; printf("\t--\n"); if((min_std == 1) && (val[TRACK_BYTES] || val[SECT_BYTES])) { printf("\tbytes/track: %u",val[TRACK_BYTES]); printf("\tbytes/sector: %u\n",val[SECT_BYTES]); } if(jj) { mm = (__u32)val[CAPACITY_MSB] << 16 | val[CAPACITY_LSB]; /* ATA-1 is ambiguous on ordering of words 57 & 58 */ if(like_std < 3) { nn = (__u32)val[CAPACITY_LSB] << 16 | val[CAPACITY_MSB]; /* check Endian of capacity bytes */ if(abs(mm - bb) > abs(nn - bb)) mm = nn; } printf("\tCHS current addressable sectors:%11u\n",mm); } } if (val[CAPAB_0] & LBA_SUP) { /* LBA addressing */ printf("\tLBA user addressable sectors:%11u\n",ll); if( ((val[CMDS_SUPP_1] & VALID) == VALID_VAL) && (val[CMDS_SUPP_1] & SUPPORT_48_BIT) ) { bbbig = (__u64)val[LBA_64_MSB] << 48 | (__u64)val[LBA_48_MSB] << 32 | (__u64)val[LBA_MID] << 16 | val[LBA_LSB] ; printf("\tLBA48 user addressable sectors:%11llu\n", (unsigned long long)bbbig); } } if((val[106] & 0xc000) != 0x4000) { printf("\t%-31s %11u bytes\n","Logical/Physical Sector size:", sector_bytes); } else { unsigned int lsize = 256, pfactor = 1; if (val[106] & (1<<13)) pfactor = (1 << (val[106] & 0xf)); if (val[106] & (1<<12)) lsize = (val[118] << 16) | val[117]; sector_bytes = 2 * lsize; printf("\t%-31s %11u bytes\n","Logical Sector size:", sector_bytes); printf("\t%-31s %11u bytes\n","Physical Sector size:", sector_bytes * pfactor); if ((val[209] & 0xc000) == 0x4000) { unsigned int offset = val[209] & 0x1fff; printf("\t%-31s %11u bytes\n", "Logical Sector-0 offset:", offset * sector_bytes); } } if (!bbbig) bbbig = (__u64)(ll>mm ? ll : mm); /* # 512 byte blocks */ if (!bbbig) bbbig = bb; bbbig *= (sector_bytes / 512); printf("\tdevice size with M = 1024*1024: %11llu MBytes\n", (unsigned long long)(bbbig>>11)); bbbig = (bbbig<<9)/1000000; printf("\tdevice size with M = 1000*1000: %11llu MBytes ", (unsigned long long)bbbig); if(bbbig > 1000) printf("(%llu GB)\n", (unsigned long long)(bbbig/1000)); else printf("\n"); } /* device cache/buffer size, if reported (obsolete field, but usually valid regardless) */ printf("\tcache/buffer size = "); if (val[20] <= 3 && val[BUF_SIZE] && val[BUF_SIZE] != 0xffff) { printf("%u KBytes", val[BUF_SIZE] / 2); if (val[20]) printf(" (type=%s)", BuffType[val[20]]); } else { printf("unknown"); } putchar('\n'); /* Form factor */ if(val[168] && (val[168] & 0xfff8) == 0) { printf("\tForm Factor: "); switch(val[168]) { case 1: printf("5.25 inch"); break; case 2: printf("3.5 inch"); break; case 3: printf("2.5 inch"); break; case 4: printf("1.8 inch"); break; case 5: printf("less than 1.8 inch"); break; default: printf("unknown (0x%04x]", val[168]); break; } printf("\n"); } /* Spinning disk or solid state? */ if(val[NMRR] == 1) printf("\tNominal Media Rotation Rate: Solid State Device\n"); else if(val[NMRR] > 0x401) printf("\tNominal Media Rotation Rate: %u\n", val[NMRR]); /* hw support of commands (capabilities) */ printf("Capabilities:\n"); printf("\t"); if(dev == ATAPI_DEV) { if(eqpt != CDROM) { if(val[CAPAB_0] & CMD_Q_SUP) printf("Cmd queuing, "); } if(val[CAPAB_0] & OVLP_SUP) printf("Cmd overlap, "); } if(val[CAPAB_0] & LBA_SUP) printf("LBA, "); if(like_std != 1) { printf("IORDY"); if(!(val[CAPAB_0] & IORDY_SUP)) printf("(may be)"); if(val[CAPAB_0] & IORDY_OFF) printf("(can"); else printf("(cannot"); printf(" be disabled)"); } else { printf("IORDY not likely"); } printf("\n"); if((like_std == 1) && val[BUF_TYPE]) { kk = val[BUF_TYPE]; printf("\tBuffer type: %04x: ",kk); if (kk < 2) printf("single port, single-sector"); else printf("dual port, multi-sector"); if (kk > 2) printf(" with read caching ability"); printf("\n"); } jj = 0; if((min_std == 1) && (val[BUF_SIZE] && (val[BUF_SIZE] != 0xffff))) { printf("\tBuffer size: %.1fkB",(float)val[BUF_SIZE]/2); jj = 1; } if((min_std < 4) && (val[RW_LONG])) { printf("\tbytes avail on r/w long: %u",val[RW_LONG]); jj = 1; } if((eqpt != CDROM) && (like_std > 3)) { int has_queuing = 0; if (transport == 1 || (val[SATA_CAP_0] && val[SATA_CAP_0] != 0xffff)) { if (val[SATA_CAP_0] & 0x0100) has_queuing = 1; // SATA NCQ } if ((val[CMDS_SUPP_1] & VALID) == VALID_VAL && val[CMDS_SUPP_1] & 2) { has_queuing = 1; // TCQ } if (has_queuing) { printf("\tQueue depth: %u",(val[QUEUE_DEPTH] & DEPTH_BITS)+1); jj = 1; } } if(jj) printf("\n"); if(dev == ATA_DEV) { if(like_std == 1) { printf("\tCan"); if(!val[DWORD_IO]) printf("not"); printf(" perform double-word IO\n"); } else { printf("\tStandby timer values: spec'd by "); if(val[CAPAB_0] & STD_STBY) printf("Standard"); else printf("Vendor"); if((like_std > 3) && ((val[CAPAB_1] & VALID) == VALID_VAL)) { if(val[CAPAB_1] & MIN_STANDBY_TIMER) printf(", with "); else printf(", no "); printf("device specific minimum\n"); } else printf("\n"); } printf("\tR/W multiple sector transfer: "); if((like_std < 3) && !(val[SECTOR_XFER_MAX] & SECTOR_XFER)) { printf("not supported\n"); } else { printf("Max = %u\t",val[SECTOR_XFER_MAX] & SECTOR_XFER); printf("Current = "); if(val[SECTOR_XFER_CUR] & MULTIPLE_SETTING_VALID) printf("%u\n",val[SECTOR_XFER_CUR] & SECTOR_XFER); else printf("?\n"); } if((like_std > 3) && (val[CMDS_SUPP_1] & 0xc008) == 0x4008) { printf("\tAdvanced power management level: "); if (val[CMDS_EN_1] & 0x0008) printf("%u\n", val[ADV_PWR] & 0xff); else printf("disabled\n"); } if(like_std > 5) { if(val[ACOUSTIC]) { printf("\tRecommended acoustic management value: %u, current value: %u\n", (val[ACOUSTIC] >> 8) & 0x00ff, val[ACOUSTIC] & 0x00ff); } } } else { /* ATAPI */ if(eqpt != CDROM) { if(val[CAPAB_0] & SWRST_REQ) printf("\tATA sw reset required\n"); } if(val[PKT_REL] || val[SVC_NBSY]) { printf("\tOverlap support:"); if(val[PKT_REL]) printf(" %uus to release bus.",val[PKT_REL]); if(val[SVC_NBSY]) printf(" %uus to clear BSY after SERVICE cmd.",val[SVC_NBSY]); printf("\n"); } } /* Some SATA-ATAPI devices use a different interpretation of IDENTIFY words for DMA modes */ if (dev == ATAPI_DEV && val[62] & 0x8000) { atapi_has_dmadir = 1; sdma_ok = 0; /* word 62 has been re-purposed for non-sdma mode reporting */ printf("\tDMADIR bit required in PACKET commands\n"); } else { __u16 w62 = val[62]; __u8 hi = w62 >> 8, lo = w62; if (!w62 || (lo & 0xf8)) sdma_ok = 0; else if (hi && hi != 1 && hi != 2 && hi != 4) sdma_ok = 0; else sdma_ok = 1; } printf("\tDMA: "); /* DMA stuff. Check that only one DMA mode is selected. */ if(!atapi_has_dmadir && !(val[CAPAB_0] & DMA_SUP)) { printf("not supported\n"); } else { if(val[DMA_MODE] && !val[62] && !val[MULTI_DMA]) { printf("sdma%u",(val[DMA_MODE] & MODE) >> 8); } else { if(sdma_ok) { kk = val[62] >> 8; jj = val[62]; err_dma += mode_loop(jj,kk,'s',&have_mode); } if(val[MULTI_DMA]) { kk = val[MULTI_DMA] >> 8; jj = atapi_has_dmadir ? (val[62] >> 7) & 7 : val[MULTI_DMA]; err_dma += mode_loop(jj,kk,'m',&have_mode); } if((val[WHATS_VALID] & OK_W88) && val[ULTRA_DMA]) { kk = val[ULTRA_DMA] >> 8; jj = atapi_has_dmadir ? val[62] & 0x7f : val[ULTRA_DMA]; err_dma += mode_loop(jj,kk,'u',&have_mode); } if(err_dma || !have_mode) printf("(?)"); } printf("\n"); if((dev == ATAPI_DEV) && (eqpt != CDROM) && (val[CAPAB_0] & DMA_IL_SUP)) printf("\t Interleaved DMA support\n"); if((val[WHATS_VALID] & OK_W64_70) && (val[DMA_TIME_MIN] || val[DMA_TIME_NORM])) { printf("\t Cycle time:"); if(val[DMA_TIME_MIN]) printf(" min=%uns",val[DMA_TIME_MIN]); if(val[DMA_TIME_NORM]) printf(" recommended=%uns",val[DMA_TIME_NORM]); printf("\n"); } } /* Programmed IO stuff */ printf("\tPIO: "); /* If a drive supports mode n (e.g. 3), it also supports all modes less * than n (e.g. 3, 2, 1 and 0). Print all the modes. */ if((val[WHATS_VALID] & OK_W64_70) && (val[ADV_PIO_MODES] & PIO_SUP)) { jj = ((val[ADV_PIO_MODES] & PIO_SUP) << 3) | 0x0007; for (ii = 0; ii <= PIO_MODE_MAX ; ii++) { if(jj & 0x0001) printf("pio%d ",ii); jj >>=1; } printf("\n"); } else if(((min_std < 5) || (eqpt == CDROM)) && ((val[PIO_MODE]>>8) <= 2)) { for (ii = 0; ii <= val[PIO_MODE]>>8; ii++) { printf("pio%d ",ii); } printf("\n"); } else printf("unknown\n"); if(val[WHATS_VALID] & OK_W64_70) { if(val[PIO_NO_FLOW] || val[PIO_FLOW]) { printf("\t Cycle time:"); if(val[PIO_NO_FLOW]) printf(" no flow control=%uns", val[PIO_NO_FLOW]); if(val[PIO_FLOW]) printf(" IORDY flow control=%uns", val[PIO_FLOW]); printf("\n"); } } if((val[CMDS_SUPP_1] & VALID) == VALID_VAL){ printf("Commands/features:\n\tEnabled\tSupported:\n"); print_features(val[CMDS_SUPP_0] & 0x7fff, val[CMDS_EN_0], feat_word82_str); if( (val[CMDS_SUPP_1] & VALID) == VALID_VAL) print_features(val[CMDS_SUPP_1] & 0x3fff, val[CMDS_EN_1], feat_word83_str); if( (val[CMDS_SUPP_2] & VALID) == VALID_VAL && (val[CMDS_EN_2] & VALID) == VALID_VAL) { print_features(val[CMDS_SUPP_2] & 0x3fff, val[CMDS_EN_2], feat_word84_str); if ((val[CMDS_SUPP_2] & 0x1800) == 0x1800 && val[116] && val[116] != 0xffff) printf(" (%u msec for TLC completion timer)\n", 10 * (unsigned int)(val[116])); } if( (val[CMDS_SUPP_1] & VALID) == VALID_VAL && (val[CMDS_EN_1] & 0x8000) == 0x8000 && (val[CMDS_SUPP_3] & VALID) == VALID_VAL && (val[CMDS_EN_3] & VALID) == VALID_VAL) print_features(val[CMDS_SUPP_3] & 0x3fff, val[CMDS_EN_3], feat_3_str); if (transport == 1 || (val[SATA_CAP_0] && val[SATA_CAP_0] != 0xffff)) print_features(val[SATA_CAP_0], val[SATA_CAP_0], cap_sata0_str); if (transport == 1 || (val[SATA_SUPP_0] && val[SATA_SUPP_0] != 0xffff)) print_features(val[SATA_SUPP_0], val[SATA_EN_0], feat_sata0_str); if (val[SCT_SUPP] & 0x1) print_features(val[SCT_SUPP], val[SCT_SUPP] & 0x3f, feat_sct_str); } if (like_std > 6) { const __u16 trimd = 1<<14; /* deterministic read data after TRIM */ const __u16 trimz = 1<<5; /* deterministic read ZEROs after TRIM */ __u16 word69 = val[69] & ~(trimz | trimd); /* TRIM bits require special interpretation */ print_features(word69, word69, feat_word69_str); if (val[169] & 1 && val[169] != 0xffff) { /* supports TRIM ? */ printf("\t *\tData Set Management TRIM supported"); if (val[105] && val[105] != 0xffff) printf(" (limit %u block%s)\n", val[105], val[105] > 1 ? "s" : ""); else printf(" (limit unknown)\n"); if (val[69] & trimd) { /* Deterministic TRIM support */ if (val[69] & trimz) print_features(trimz, trimz, feat_word69_str); else print_features(trimd, trimd, feat_word69_str); } } } if (is_cfa) { unsigned int mode, max, selected; char modes[256]; modes[0] = '\0'; // CFA pio5-6: max = val[163] & 7; if (max == 1 || max == 2) { selected = (val[163] >> 6) & 7; for (mode = 1; mode <= max; ++mode) { if (mode == selected) strcat(modes, "*"); sprintf(modes + strlen(modes), "pio%u ", mode + 4); } } // CFA mdma3-4: max = (val[163] >> 3) & 7; if (max == 1 || max == 2) { selected = (val[163] >> 9) & 7; for (mode = 1; mode <= max; ++mode) { if (mode == selected) strcat(modes, "*"); sprintf(modes + strlen(modes), "mdma%u ", mode + 2); } } if (val[164] & 0x8000) { static const unsigned char io_times [4] = {255,120,100,80}; static const unsigned char mem_times[4] = {250,120,100,80}; max = val[164] & 7; if (max <= 3) printf("\t\tCFA max advanced io_udma cycle time: %uns\n", io_times[max]); max = (val[164] >> 3) & 7; if (max <= 3) printf("\t\tCFA max advanced mem_udma cycle time: %uns\n", mem_times[max]); // CFA ioport dma0-6: max = (val[164] >> 6) & 7; if (max <= 6) { selected = (val[164] >> 12) & 7; for (mode = 0; mode <= max; ++mode) { if (mode == selected) strcat(modes, "*"); sprintf(modes + strlen(modes), "io_udma%u ", mode + 4); } } // CFA memory udma0-6: max = (val[164] >> 9) & 7; if (max <= 6) { selected = (val[164] >> 12) & 7; for (mode = 0; mode <= max; ++mode) { if (mode == selected) strcat(modes, "*"); sprintf(modes + strlen(modes), "mem_udma%u ", mode + 4); } } } if (modes[0]) printf("\t *\tCFA advanced modes: %s\n", modes); if(val[CFA_PWR_MODE] & VALID_W160) { putchar('\t'); if((val[CFA_PWR_MODE] & PWR_MODE_REQ) == 0) printf(" *"); printf("\tCFA Power Level 1 "); if(val[CFA_PWR_MODE] & PWR_MODE_REQ) printf(" not supported"); if(val[CFA_PWR_MODE] & MAX_AMPS) printf(" (max %umA)", val[CFA_PWR_MODE] & MAX_AMPS); printf("\n"); } //else printf("\t\tCFA Power modes not reported\n"); if (val[162] && val[162] != 0xffff) { if (val[162] & 1) printf("\t\tKey Management (CPRM) feature set\n"); } } if((val[RM_STAT] & RM_STAT_BITS) == RM_STAT_SUP) printf("\t\tRemovable Media Status Notification feature set supported\n"); /* security */ if((eqpt != CDROM) && (like_std > 3) && (val[SECU_STATUS] || val[ERASE_TIME] || val[ENH_ERASE_TIME])) { printf("Security: \n"); if(val[PSWD_CODE] && (val[PSWD_CODE] != 0xffff)) printf("\tMaster password revision code = %u\n",val[PSWD_CODE]); jj = val[SECU_STATUS]; if(jj) { for (ii = 0; ii < NUM_SECU_STR; ii++) { if(!(jj & 0x0001)) printf("\tnot\t"); else printf("\t\t"); printf("%s\n",secu_str[ii]); jj >>=1; } if(val[SECU_STATUS] & SECU_ENABLED) { printf("\tSecurity level "); if(val[SECU_STATUS] & SECU_LEVEL) printf("maximum\n"); else printf("high\n"); } } jj = val[ERASE_TIME]; kk = val[ENH_ERASE_TIME]; if((jj && jj <= 0x00ff) || (kk && kk <= 0x00ff)) { printf("\t"); if (jj) { if (jj == 0xff) printf("more than 508"); else printf("%u", jj * 2); printf("min for SECURITY ERASE UNIT. "); } if (kk) { if (kk == 0xff) printf("more than 508"); else printf("%u", kk * 2); printf("min for ENHANCED SECURITY ERASE UNIT. "); } printf("\n"); } } //printf("w84=0x%04x w87=0x%04x like_std=%d\n", val[84], val[87], like_std); if((eqpt != CDROM) && (like_std > 3) && (val[CMDS_SUPP_2] & WWN_SUP)) { printf("Logical Unit WWN Device Identifier: %04x%04x%04x%04x\n", val[108], val[109], val[110], val[111]); printf("\tNAA\t\t: %x\n", (val[108] & 0xf000) >> 12); printf("\tIEEE OUI\t: %06x\n", (((val[108] & 0x0fff) << 12) | ((val[109] & 0xfff0) >> 4))); printf("\tUnique ID\t: %x%08x\n", (val[109] & 0x000f), ((val[110] << 16) | val[111])); } /* reset result */ if((val[HWRST_RSLT] & VALID) == VALID_VAL) { printf("HW reset results:\n"); if(val[HWRST_RSLT] & CBLID) printf("\tCBLID- above Vih\n"); else printf("\tCBLID- below Vih\n"); if(val[HWRST_RSLT] & RST0) { printf("\tDevice num = 0"); jj = val[HWRST_RSLT]; } else { printf("\tDevice num = 1"); jj = val[HWRST_RSLT] >> 8; } if((jj & DEV_DET) == JUMPER_VAL) printf(" determined by the jumper"); else if((jj & DEV_DET) == CSEL_VAL) printf(" determined by CSEL"); printf("\n"); } /* more stuff from std 5 */ if ((like_std > 4) && (eqpt != CDROM)) { if ((val[INTEGRITY] & SIG) == SIG_VAL) { printf("Checksum: %scorrect", chksum ? "in" : ""); if (chksum) printf(" (0x%02x), expected 0x%02x\n", chksum, 0x100 - chksum); putchar('\n'); } else { printf("Integrity word not set (found 0x%04x, expected 0x%02x%02x)\n", val[INTEGRITY], 0x100 - chksum, SIG_VAL); } } } __u8 mode_loop(__u16 mode_sup, __u16 mode_sel, int cc, __u8 *have_mode) { __u16 ii; __u8 err_dma = 0; for (ii = 0; ii <= MODE_MAX; ii++) { if(mode_sel & 0x0001) { printf("*%cdma%u ",cc,ii); if(*have_mode) err_dma = 1; *have_mode = 1; } else if(mode_sup & 0x0001) { printf("%cdma%u ",cc,ii); } mode_sup >>=1; mode_sel >>=1; } return err_dma; } void dco_identify_print (__u16 *dco) { __u64 lba; printf("DCO Revision: 0x%04x", dco[0]); if (dco[0] == 0 || dco[0] > 2) printf(" -- unknown, treating as 0002"); printf("\nThe following features can be selectively disabled via DCO:\n"); printf("\tTransfer modes:\n\t\t"); if (dco[1] & 0x0007) { if (dco[1] & (1<<2)) printf(" mdma0 mdma1 mdma2"); else if (dco[1] & (1<<1)) printf(" mdma0 mdma1"); else if (dco[1] & (1<<0)) printf(" mdma0"); printf("\n\t\t"); } if (dco[2] & (1<<6)) { printf(" udma0 udma1 udma2 udma3 udma4 udma5 udma6"); if (dco[0] < 2) printf("(?)"); } else if (dco[2] & (1<<5)) printf(" udma0 udma1 udma2 udma3 udma4 udma5"); else if (dco[2] & (1<<4)) printf(" udma0 udma1 udma2 udma3 udma4"); else if (dco[2] & (1<<3)) printf(" udma0 udma1 udma2 udma3"); else if (dco[2] & (1<<2)) printf(" udma0 udma1 udma2"); else if (dco[2] & (1<<1)) printf(" udma0 udma1"); else if (dco[2] & (1<<0)) printf(" udma0"); putchar('\n'); lba = ((((__u64)dco[5]) << 32) | (dco[4] << 16) | dco[3]) + 1; printf("\tReal max sectors: %llu\n", lba); printf("\tATA command/feature sets:"); if (dco[7] & 0x01ff) { printf("\n\t\t"); if (dco[7] & (1<< 0)) printf(" SMART"); if (dco[7] & (1<< 1)) printf(" self_test"); if (dco[7] & (1<< 2)) printf(" error_log"); if (dco[7] & (1<< 3)) printf(" security"); if (dco[7] & (1<< 4)) printf(" PUIS"); if (dco[7] & (1<< 5)) printf(" TCQ"); if (dco[7] & (1<< 6)) printf(" AAM"); if (dco[7] & (1<< 7)) printf(" HPA"); if (dco[7] & (1<< 8)) printf(" 48_bit"); } if (dco[7] & 0xfe00) { printf("\n\t\t"); if (dco[0] < 2) printf(" (?):"); if (dco[7] & (1<< 9)) printf(" streaming"); if (dco[7] & (1<<10)) printf(" TLC_Reserved_7[10]"); if (dco[7] & (1<<11)) printf(" FUA"); if (dco[7] & (1<<12)) printf(" selective_test"); if (dco[7] & (1<<13)) printf(" conveyance_test"); if (dco[7] & (1<<14)) printf(" write_read_verify"); if (dco[7] & (1<<15)) printf(" reserved_7[15]"); } if (dco[21] & 0xf800) { printf("\n\t\t"); if (dco[0] < 2) printf(" (?):"); if (dco[21] & (1<<11)) printf(" free_fall"); if (dco[21] & (1<<12)) printf(" trusted_computing"); if (dco[21] & (1<<13)) printf(" WRITE_UNC_EXT"); if (dco[21] & (1<<14)) printf(" NV_cache_power_management"); if (dco[21] & (1<<15)) printf(" NV_cache"); } putchar('\n'); if (dco[8] & 0x1f) { printf("\tSATA command/feature sets:\n\t\t"); if (dco[0] < 2) printf(" (?):"); if (dco[8] & (1<<0)) printf(" NCQ"); if (dco[8] & (1<<1)) printf(" NZ_buffer_offsets"); if (dco[8] & (1<<2)) printf(" interface_power_management"); if (dco[8] & (1<<3)) printf(" async_notification"); if (dco[8] & (1<<4)) printf(" SSP"); putchar('\n'); } } hdparm-9.43/hdparm.lsm0000644000000000000000000001451412051264106013414 0ustar rootrootBegin4 Title: hdparm Version: 9.43 Entered-date: 2012-11-15 Description: hdparm - get/set hard disk parameters for Linux SATA/IDE drives. v9.43 rearrange flag execution so that the idle/standby/sleep "now" flags are executed last. v9.42 lots of fixes from the sourceforge queue v9.41 updated SCT identification, other small fixes. v9.40 internal release v9.39 Added -R, courtesy of Gordan Bobic v9.38 Added -J, fixed erase timeouts, updated wiper.sh v9.37 Enable --fibmap to work on RAID1; other tweaks v9.36 manpage updates, wiper.sh version 3.1 v9.35 Fixed CDB breakage from v9.34; -B works again now v9.34 Fixed CDB transfer length bug that affected some commands v9.33 Fixed AHCI issues; fixed compilation on older systems v9.32 Fixed various commands broken since 9.27. Eg. -B, -M, etc.. v9.31 Fixed security-erase issues; changed default of --user-master to user v9.30 Restrict LBA range counts for TRIM to what the drive reports it can handle v9.29 Assorted fixes, updated wiper.sh, made trim compatible with many more SSDs v9.28 Assorted fixes, updated wiper.sh v9.27 Fix compatibility with old IDE drivers; was broken for many versions now v9.26 Fix old -i model-name bug; fixed --security-erase-enhanced; other fixes v9.25 Limit --trim-sector-ranges-stdin to max_sectors_kb per TRIM command v9.24 Fixed nasty malloc() bug in --trim-sector-ranges code v9.23 Added --trim-sector-ranges-stdin flag v9.22 Workaround ext4 FEIMAP bug, revamped wiper.sh with xfs support v9.21 Fixes and speedups to wiper.sh script; no changes to hdparm itself v9.20 Reworked --trim-sector-ranges; replaced b0rked wiper scripts with wiper.sh v9.19 Fixed compile of fallocate.c on older systems; fixed manpage for --fallocate v9.18 Fixed -E (set streaming) for DVD drives v9.17 Lots of changes to support SSD TRIM functionality v9.16 Fixed/tested --fwdownload flags; fixed other bugs v9.15 Fix big-endian bugs v9.14 Show TRIM support in -I; use O_RDONLY when opening the device v9.13 Fix --direct for arch's other than x86 (eg. arm); strip -i strings v9.12 Lots of -I updates, -C updates; -B now reports current APM setting v9.11 Fixed -I for ATAPI; added --prefer-ata12 for some USB enclosures v9.10 Fixes for CF card detection/reporting v9.9 Recalculate cyls when kernel returns a truncated value v9.8 FIX -N for non-LBA48 drives v9.7 FIX LBA28/48 BUGS, favour ATA_12 over ATA_16 when possible (helps with USB) v9.6 fix -N for 1.5TB drives v9.5 byteswap ID strings in fwdownload workarounds v9.4 nuked --fwdownload80 in favour of model-specific workarounds v9.3 new --idle-immediate and --idle-unload commands v9.2 fix WWN (worldwide name) output from -I v9.1 tidy output of --dco-identify, update manpage v9.0 new --dco-* and --fwdownload flags, sg16 fixes, updated debian subdir v8.9 make compatible with /sys/block symlinks v8.8 bug fixes from v8.7, including -r, -a, -Q v8.7 new sysfs support, fibmap, misc fixes v8.6 add partition safeguards to r/w/b sector flags v8.5 fix broken --security-* commands (buggy passwd in all prior 8.x versions) v8.4 fix broken --write-sector from v8.3 v8.3 use exit(errno) on program completion; fix udma6 display for -i v8.2 fixed sector ops (and other stuff) to work with non-libata IDE driver again v8.1 fixed -U, updated -I info v8.0 some fixes, lots of new features (eg. --make-bad-sector and friends) v7.7 fixed bug with incorrect settings shown after -W0 (and others) v7.6 new -F flag; re-allow use of --security-freeze with other flags v7.5 beef up warnings for -s1: Joe User should never use this flag! v7.4 added CFA advanced timing info v7.3 fixed version number; much better SAT compliance v7.2 fixed breakage when used with old IDE driver v7.1 big-endian fixes for -I, --Istdin, --Istdout v7.0 major overhaul, proper SATA support, new features and tweaks v6.9 --Istdin fix, new -s flag, new SCT reporting, fixed -T x2 error.. v6.8 improve parsing/operation of --Istdin function v6.7 misc fixes, new -H flag, fixed -C flag v6.6 fix build on Redhat/Fedora v6.5 fix -I bugs introduced in v6.4 v6.4 major update for -I, bug fix for -C v6.3 report ATA revisions > 7 v6.2 major rework of ATA Security Commands v6.1 bug fix for BLKGETSIZE v6.0 bug fix for BLKGETSIZE64; new ATA Security Commands v5.9 bug fix: -W1/-W0 now work again v5.8 minor fixes v5.7 bug fixes, --direct flag (O_DIRECT), other enhancements v5.6 cleanups, new "-Istdout" flag, removed MAJOR-nr restrictions v5.5 added debian scripts, minor fixes v5.4 lots of fixes/updates, new timing measurement code v5.3 endian fixes, other stuff v5.2 compile fixes for 2.5.xx v5.1 fixed segfault in "-i" on older drives v5.0 lots of updates and new features v4.9 fixed compile error with 2.5.xx kernels v4.8 changed -Q to allow specifying queue depth v4.7 added -z, -Q, -M flags; expanded parm range for -p v4.6 manpage updates, version number corrections v4.5 cleanups, mostly courtesy of Maciej W. Rozycki v4.4 added -b option get/set bus state v4.3 use unsigned format for most stuff v4.2 lots of updates, rewritten -I option v4.0 no such version ever released v3.9 support for ide[6-9], more cosmetics v3.8 added -E, -R, and -U options; cosmetic fixes v3.7 added UDMA mode display v3.6 mostly cosmetic fixes, xt & ide4+ide5 support v3.5 fixed udma display/compile for older kernels v3.4 mostly cosmetic updates v3.3 add -C, -y, -Y flags for power management v3.2 flush buffer cache after -t or -T v3.1 add support for "-p[6789]" v3.0 move cache timings to new -T option v2.9 update author's email addr; document -I option v2.8 some fixes; removed "Estimating raw driver speed" from -t v2.7 fixed "hdparm -c" (broke in 2.6); fixed .lsm file v2.6 added "-p" flag to set IDE interface chipset PIO modes v2.5 cosmetic fixes, manpage clarifications v2.4 added support for -d (DMA) flag v2.3 added runtime flags for 32-bit mode; fixed -t for SCSI. v2.0 adds zillions of features for the new (E)IDE driver Keywords: ide eide ata atapi performance kernel cd cdrom disk device driver Author: mlord@pobox.com (Mark Lord) Maintained-by: mlord@pobox.com (Mark Lord) Primary-site: http://sourceforge.net/projects/hdparm/ Alternate-site: http://www.ibiblio.org/pub/Linux/system/hardware 127K hdparm-9.43.tar.gz 4K hdparm.lsm Platforms: Linux Copying-policy: BSD License End hdparm-9.43/wdidle3.c0000644000000000000000000001323511702135741013126 0ustar rootroot#include #include #include #include #include #include #include #include #include #include "sgio.h" #include "hdparm.h" extern int verbose; /* hdparm.c */ /* * The Western Digital (WD) "Green" drive IDLE3 timeout value is 8-bits. * Earlier models used a strict value from 8.0 to 25.5 seconds (0x50 to 0xff). * Later models use 8.0 to 12.7 secs (0x50 to 0x7f), and 30 to 300 secs (0x81 to 0x8a). * Other values are undefined, but have been observed on some drives. * * Older drives (from WDIDLE3.EXE documentation): * 0x00 timer disabled. * 0x50-0xff timeout in tenths of a second, from 8.0 to 25.5 seconds. * * * Some drives (found by observation): * 0x01-0x50 timeout in seconds, from 1 to 30 seconds (?). * * Newer drives (from WDIDLE3.EXE documentation): * 0x00 timer disabled. * 0x01-0x49 not permitted by WDIDLE3.EXE; reports as 0.1 to 7.9 seconds. * 0x50-0x7f timeout in tenths of a second, from 8.0 to 12.7 seconds. * 0x80 not permitted by WDIDLE3.EXE; reports as 12.8 seconds. * 0x81-0x8a timeout in 30s of seconds, from 30 to 300 seconds. * 0x90-0xff not permitted; reports as 330 to 3810 seconds. * * A WD whitepaper identified some models/versions of drives with the "older" firmware, * but no comprehensive list exists. Models with firmware 02.01B01 are "older", * and models with "02.01B02" are "newer". * * The real WDIDLE3 utility determines the correct value ranges * by interogating the drive somehow, or perhaps based on the reported firmware version. * * WDIDLE3.EXE also writes some scary looking full 512-byte sequences to the drives * in addition to what we do here. * * So this (hdparm) method may be somewhat risky, since it doesn't do everything WD does. */ enum { WDC_VSC_DISABLED = 'D', WDC_VSC_ENABLED = 'E', WDC_IDLE3_READ = 1, WDC_IDLE3_WRITE = 2, WDC_OP_TIMEOUT_SECS = 12, WDC_TIMEOUT_THRESHOLD = 128, }; static int wdidle3_issue (int fd, int rw, struct ata_tf *tf, void *data, const char *msg) { int ret = sg16(fd, rw, SG_PIO, tf, data, data ? 512 : 0, WDC_OP_TIMEOUT_SECS); if (ret != 0) { ret = errno; perror(msg); } return ret; } /* * Note: when WD vendor-specific-commands (vsc) are enabled, * the ATA_OP_SMART command is "enhanced" to support additional * functions to read/write specific data "registers" from the firmware. * This may (or not) also cause regular SMART commands to fail (?). */ static int wdidle3_vsc_enable_disable (int fd, int setting) { struct ata_tf tf; unsigned long long vendor_WD0 = ('W' << 16) | ('D' << 8) | 0; tf_init(&tf, ATA_OP_VENDOR_SPECIFIC_0x80, vendor_WD0, 0); tf.lob.feat = setting; tf.dev = 0xa0; return wdidle3_issue(fd, SG_WRITE, &tf, NULL, __func__); } /* * This sends a key (password? I2C address?) to the drive * in preparation for a data_in or data_out command. */ static int wdidle3_vsc_send_key (int fd, int rw) { char data[512]; struct ata_tf tf; memset(data, 0, sizeof(data)); tf_init(&tf, ATA_OP_SMART, 0xc24fbe, 1); tf.lob.feat = 0xd6; tf.dev = 0xa0; data[ 0] = 0x2a; data[ 2] = rw; data[ 4] = 0x02; data[ 6] = 0x0d; data[ 8] = 0x16; data[10] = 0x01; return wdidle3_issue(fd, SG_WRITE, &tf, data, __func__); } /* * This reads a data value from the drive. */ static int wdidle3_data_in (int fd, unsigned char *timeout) { char data[512]; int ret; struct ata_tf tf; memset(data, 0, sizeof(data)); tf_init(&tf, ATA_OP_SMART, 0xc24fbf, 1); tf.lob.feat = 0xd5; tf.dev = 0xa0; ret = wdidle3_issue(fd, SG_READ, &tf, data, __func__); if (!ret) *timeout = data[0]; return ret; } /* * This writes a data value to the drive. */ static int wdidle3_vsc_data_out (int fd, unsigned char timeout) { char data[512]; struct ata_tf tf; memset(data, 0, sizeof(data)); tf_init(&tf, ATA_OP_SMART, 0xc24fbf, 1); tf.lob.feat = 0xd6; tf.dev = 0xa0; data[0] = timeout; return wdidle3_issue(fd, SG_WRITE, &tf, data, __func__); } int wdidle3_set_timeout (int fd, unsigned char timeout) { int ret, ret2; ret = wdidle3_vsc_enable_disable(fd, WDC_VSC_ENABLED); if (!ret) { ret = wdidle3_vsc_send_key(fd, WDC_IDLE3_WRITE); if (!ret) ret = wdidle3_vsc_data_out(fd, timeout); ret2 = wdidle3_vsc_enable_disable(fd, WDC_VSC_DISABLED); if (!ret) ret = ret2; } return ret; } int wdidle3_get_timeout (int fd, unsigned char *timeout) { int ret, ret2; ret = wdidle3_vsc_enable_disable(fd, WDC_VSC_ENABLED); if (!ret) { ret = wdidle3_vsc_send_key(fd, WDC_IDLE3_READ); if (!ret) ret = wdidle3_data_in(fd, timeout); ret2 = wdidle3_vsc_enable_disable(fd, WDC_VSC_DISABLED); if (!ret) ret = ret2; } return ret; } unsigned char wdidle3_msecs_to_timeout (unsigned int secs) { unsigned char timeout; if (secs == 0) timeout = 0; /* disabled */ else if (secs < 8) timeout = 80; /* 8.0 seconds minimum */ else if (secs <= (WDC_TIMEOUT_THRESHOLD / 10)) timeout = secs * 10; /* 8.0 to 12.7 seconds */ else { secs += 29; /* round up to next multiple of 30 */ if (secs > 300) secs = 300; /* max timeout is 300 secs */ timeout = (secs / 30) + WDC_TIMEOUT_THRESHOLD; } return timeout; } void wdidle3_print_timeout (unsigned char timeout) { if (verbose) printf("[raw=0x%02x] ", timeout); //FIXME if (timeout == 0) printf("disabled"); else if (timeout < 0x50 || timeout == WDC_TIMEOUT_THRESHOLD) printf("%u ??", timeout); else if (timeout < WDC_TIMEOUT_THRESHOLD) printf("%u.%u secs", timeout / 10, timeout % 10); else { if (timeout > (WDC_TIMEOUT_THRESHOLD + 10)) printf("%u ??", timeout); else printf("%u secs", (timeout - WDC_TIMEOUT_THRESHOLD) * 30); printf(" (or %u.%u secs for older drives)", timeout / 10, timeout % 10); } } hdparm-9.43/hdparm-sysconfig0000644000000000000000000000246107376232132014632 0ustar rootroot# This file was adapted from Mandrake Linux 8.1 # # These options are used to tune the hard drives - # read the hdparm man page for more information # Set this to 1 to enable DMA. This might cause some # data corruption on certain chipset / hard drive # combinations. This is used with the "-d" option # USE_DMA=1 # Multiple sector I/O. a feature of most modern IDE hard drives, # permitting the transfer of multiple sectors per I/O interrupt, # rather than the usual one sector per interrupt. When this feature # is enabled, it typically reduces operating system overhead for disk # I/O by 30-50%. On many systems, it also provides increased non-DMA # data throughput of anywhere from 5% to 50%. Some drives, however # (most notably the older WD Caviar series), seem to run slower with # multiple mode enabled. Under rare circumstances, such failures can # result in # massive filesystem corruption. USE WITH CAUTION AND BACKUP. # This is the sector count for multiple sector I/O - the "-m" option # # MULTIPLE_IO=8 # (E)IDE 32-bit I/O support (to interface card) # # EIDE_32BIT=1 # Enable drive read-lookahead # # LOOKAHEAD=1 # Add extra parameters here if wanted # Other flags you might want to experiment with are -u1, -A1 and -W1 # See the hdparm manpage (man hdparm) for details and more options. # EXTRA_PARAMS= hdparm-9.43/sysfs.c0000644000000000000000000001040511452426550012741 0ustar rootroot/* * Access helpers for sysfs. * Copyright (c) Mark Lord 2008 * * You may use/distribute this freely, under the terms of either * (your choice) the GNU General Public License version 2, * or a BSD style license. */ #include #include #include #include #include #include #include #include #include #include "hdparm.h" static char *path_append (char *path, const char *new) { char *pathtail = path + strlen(path); *pathtail = '/'; strcpy(pathtail+1, new); return pathtail; } static int sysfs_write_attr (char *path, const char *attr, const char *fmt, void *val, int verbose) { FILE *fp; int count = -1, err = 0; char *pathtail = path_append(path, attr); fp = fopen(path, "w"); if (!fp) { err = errno; } else if (fmt[0] != '%') { err = EINVAL; } else { switch (fmt[1]) { case 's': count = fprintf(fp, fmt, val); break; case 'd': case 'u': count = fprintf(fp, fmt, *(unsigned int *)val); break; case 'l': if (fmt[2] == 'l') count = fprintf(fp, fmt, *(unsigned long long *)val); else count = fprintf(fp, fmt, *(unsigned long *)val); break; default: errno = EINVAL; } if (count < 0) err = errno; fclose(fp); } if (err && verbose) perror(path); *pathtail = '\0'; return err; } static int sysfs_read_attr (char *path, const char *attr, const char *fmt, void *val1, void *val2, int verbose) { FILE *fp; int count, err = 0; char *pathtail = path_append(path, attr); fp = fopen(path, "r"); if (!fp) { err = errno; } else { count = fscanf(fp, fmt, val1, val2); if (count != (val2 ? 2 : 1)) err = (count == EOF) ? errno : EINVAL; fclose(fp); } if (err && verbose) perror(path); *pathtail = '\0'; return err; } static int sysfs_find_dev2 (char *path, dev_t dev, int recurse, int verbose) { DIR *dp; struct dirent *entry; char *pathtail; if (!(dp = opendir(path))) { int err = errno; if (verbose) perror(path); return err; } pathtail = path + strlen(path); while ((entry = readdir(dp)) != NULL) { if ((entry->d_type == DT_DIR || entry->d_type == DT_LNK) && entry->d_name[0] != '.') { unsigned int maj, min; sprintf(pathtail, "/%s", entry->d_name); if (sysfs_read_attr(path, "/dev", "%u:%u", &maj, &min, verbose)) min = ~minor(dev); else if (maj != (unsigned)major(dev)) continue; if (min == (unsigned)minor(dev) || (recurse && sysfs_find_dev2(path, dev, recurse - 1, verbose) == 0)) { closedir(dp); return 0; } } } closedir(dp); *pathtail = '\0'; if (verbose) fprintf(stderr, "%u,%u: device not found in /sys\n", major(dev), minor(dev)); return ENOENT; } static int sysfs_find_dev (dev_t dev, char *path, int verbose) { int err, recurse = 1; strcpy(path, "/sys/block"); err = sysfs_find_dev2(path, dev, recurse, 0); if (err && verbose) fprintf(stderr, "%s(%u:%u): %s\n", __func__, major(dev), minor(dev), strerror(err)); return err; } static int get_dev_from_fd (int fd, dev_t *dev, int verbose) { struct stat st; if (0 != fstat(fd, &st)) { int err = errno; if (verbose) perror(" fstat() failed"); return err; } if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)) *dev = st.st_rdev; else *dev = st.st_dev; return 0; } static int sysfs_find_fd (int fd, char **path_p, int verbose) { static int have_prev = 0; static dev_t prev; static char path[PATH_MAX]; dev_t dev; int err; memset(&dev, 0, sizeof(dev)); err = get_dev_from_fd(fd, &dev, verbose); if (!err) { if (have_prev && 0 == memcmp(&dev, &prev, sizeof(dev))) { /*re-use previous path, since dev was unchanged from before */ } else { prev = dev; have_prev = 1; err = sysfs_find_dev(dev, path, verbose); } } if (err) have_prev = 0; else *path_p = path; return err; } int sysfs_get_attr (int fd, const char *attr, const char *fmt, void *val1, void *val2, int verbose) { char *path; int err; err = sysfs_find_fd(fd, &path, verbose); if (!err) err = sysfs_read_attr(path, attr, fmt, val1, val2, verbose); return err; } int sysfs_set_attr (int fd, const char *attr, const char *fmt, void *val_p, int verbose) { char *path; int err; err = sysfs_find_fd(fd, &path, verbose); if (!err) err = sysfs_write_attr(path, attr, fmt, val_p, verbose); return err; } hdparm-9.43/wiper/0000755000000000000000000000000012031363645012553 5ustar rootroothdparm-9.43/wiper/sil24_trim_protocol_fix.patch0000644000000000000000000000257611234400135020353 0ustar rootrootThe sil24 hardware has a built-in list of commands and associated protocols that gets used by default to decide how to handle a given command. However, if the command is not known to the controller then it presumably assumes it to be a non-data command which then causes protocol mismatch errors if the device ends up requesting data transfer. The new DATA SET MANAGEMENT - Trim command causes this issue since it's a DMA data-out command. Since we should always know best what protocol the command should be using, let's just set the override flag to inform the controller what protocol to use for all non-ATAPI commands with data transfer. Signed-off-by: Robert Hancock Tested-by: Mark Lord diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 77aa8d7..e6946fc 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -846,6 +846,17 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc) if (!ata_is_atapi(qc->tf.protocol)) { prb = &cb->ata.prb; sge = cb->ata.sge; + if (ata_is_data(qc->tf.protocol)) { + u16 prot = 0; + ctrl = PRB_CTRL_PROTOCOL; + if (ata_is_ncq(qc->tf.protocol)) + prot |= PRB_PROT_NCQ; + if (qc->tf.flags & ATA_TFLAG_WRITE) + prot |= PRB_PROT_WRITE; + else + prot |= PRB_PROT_READ; + prb->prot = cpu_to_le16(prot); + } } else { prb = &cb->atapi.prb; sge = cb->atapi.sge; hdparm-9.43/wiper/GPLv2.txt0000644000000000000000000004313411234143007014203 0ustar rootroot GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. hdparm-9.43/wiper/diffs-3.1plus.patch0000644000000000000000000000631211466775623016112 0ustar rootroot--- wiper.sh 2010-11-07 09:38:17.326668408 -0500 +++ wiper-31a.sh 2010-11-11 09:19:40.476974001 -0500 @@ -6,7 +6,8 @@ # Copyright (C) 2009-2010 Mark Lord. All rights reserved. # -# Contains hfsplus and ntfs code contributed by Heiko Wegeler . +# Contains hfsplus and ntfs code contributed by Heiko Wegeler . +# Package sleuthkit version >=3.1.1 is required for HFS+. Package ntfs-3g and ntfsprogs is required for NTFS. # # Requires gawk, a really-recent hdparm, and various other programs. # This needs to be redone entirely in C, for 64-bit math, someday. @@ -502,17 +503,38 @@ fi get_trimlist="$DEBUGREISERFS -m $fsdev" elif [ "$fstype" = "hfsplus" ]; then - FSSTAT=`find_prog /usr/local/bin/fsstat` || exit 1 - ICAT=`find_prog /usr/local/bin/icat` || exit 1 OD=`find_prog /usr/bin/od` || exit 1 - #get offset for hfsplus with wrapper/bootvolume - hfsoffset=`$FSSTAT -f hfs $fsdev | $GREP "File system is embedded in an HFS wrapper at offset "|tr -d "\t"` + TR=`find_prog /usr/bin/tr` || exit 1 + #check sleuthkit + FSSTAT=`find_prog /usr/local/bin/fsstat` + if [ "$?" = "1" ]; then + echo "fsstat and icat from package sleuthkit >= 3.1.1 is required for hfsplus." + exit 1 + fi + ICAT=`find_prog /usr/local/bin/icat` + if [ "`$ICAT -f list 2>/dev/stdout|$GREP HFS+`" = "" ]; then + echo "Wrong icat, version from package sleuthkit >= 3.1.1 is required for hfsplus." + exit 1 + fi + #check for unmounted properly + if [ "`$FSSTAT -f hfs $fsdev | $GREP "Volume Unmounted Properly"`" = "" ]; then + echo "Hfsplus volume unmounted improperly!" + exit 1 + fi + #check $AllocationFile inode + FFIND=`find_prog /usr/local/bin/ffind` + if [ "`$FFIND -f hfs $fsdev 6`" != "/\$AllocationFile" ]; then + echo "Hfsplus bitmap \$AllocationFile is not inode 6!" + exit 1 + fi + #get offset for hfsplus with a wrapper + hfsoffset=`$FSSTAT -f hfs $fsdev | $GREP "File system is embedded in an HFS wrapper at offset "|$TR -d "\t"` if [ -n "$hfsoffset" ]; then hfsoffset=${hfsoffset:52} ((fsoffset=fsoffset+hfsoffset)) echo "File system is embedded in an HFS wrapper at offset $hfsoffset" fi - blksize=`$FSSTAT -f hfs $fsdev | $GREP "Allocation Block Size: "|tr -d "\t"` + blksize=`$FSSTAT -f hfs $fsdev | $GREP "Allocation Block Size: "|$TR -d "\t"` blksize=${blksize:23} blksects=$((blksize / 512)) method="bitmap_offline" @@ -520,8 +542,20 @@ elif [ "$fstype" = "ntfs" ]; then NTFSINFO=`find_prog /usr/bin/ntfsinfo` || exit 1 NTFSCAT=`find_prog /usr/bin/ntfscat` || exit 1 + NTFSPROBE=`find_prog /usr/bin/ntfs-3g.probe` || exit 1 OD=`find_prog /usr/bin/od` || exit 1 TR=`find_prog /usr/bin/tr` || exit 1 + #check for unmounted properly + $NTFSPROBE -w $fsdev 2>/dev/null + if [ $? -ne 0 ]; then + echo "$fsdev contains an unclean file system!" + exit 1 + fi + #check for volume version + if [ "`$NTFSINFO -m -f $fsdev | $GREP "Volume Version: 3.1"`" = "" ]; then + echo "NTFS volume version must be 3.1!" + exit 1 + fi blksize=`$NTFSINFO -m -f $fsdev | $GREP "Cluster Size: " | $TR -d "\t"` blksize=${blksize:14} blksects=$((blksize / 512)) hdparm-9.43/wiper/fiemap_compat_ioctl.patch0000644000000000000000000000250611235056434017575 0ustar rootrootAdd support for the FIEMAP ioctl for 32-bit user on 64-bit kernel. When using a 32-bit runtime on top of a 64-bit kernel, programs like "filefrag" and "hdparm --fibmap" do not work correctly. This is because there's no compat ioctl entry for the FIEMAP call. FIEMAP returns file extent info, similar to FIBMAP (but better). Since FIBMAP itself is b0rked on ext4, this leaves no way for a 32-bit program to reliably get detailed block information for a file when run on top of a 64-bit kernel. This patch addresses the issue. Once upstream, this patch could also be a candidate for -stable. Signed-off-by: Mark Lord --- old/fs/compat_ioctl.c 2009-08-01 10:47:16.601066905 -0400 +++ linux/fs/compat_ioctl.c 2009-08-01 10:49:23.054387926 -0400 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -1907,6 +1908,7 @@ COMPATIBLE_IOCTL(FIONREAD) /* This is also TIOCINQ */ /* 0x00 */ COMPATIBLE_IOCTL(FIBMAP) +COMPATIBLE_IOCTL(FS_IOC_FIEMAP) COMPATIBLE_IOCTL(FIGETBSZ) /* 'X' - originally XFS but some now in the VFS */ COMPATIBLE_IOCTL(FIFREEZE) @@ -2805,6 +2807,7 @@ goto out_fput; #endif + case FS_IOC_FIEMAP: case FIBMAP: case FIGETBSZ: case FIONREAD: hdparm-9.43/wiper/wiper.sh0000755000000000000000000006641012031363645014247 0ustar rootroot#!/bin/bash # # SATA SSD free-space TRIM utility, by Mark Lord VERSION=3.5 # Copyright (C) 2009-2010 Mark Lord. All rights reserved. # # Contains hfsplus and ntfs code contributed by Heiko Wegeler . # Package sleuthkit version >=3.1.1 is required for HFS+. Package ntfs-3g and ntfsprogs is required for NTFS. # # Requires gawk, a really-recent hdparm, and various other programs. # This needs to be redone entirely in C, for 64-bit math, someday. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License Version 2, # as published by the Free Software Foundation. # # This program is distributed in the hope that it would be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Note for OCZ Vertex-LE users: the drive firmware will error when # attempting to trim the final sector of the drive. To avoid this, # partition the drive such that the final sector is not used. export LANG=C ## The usual terse usage information: ## function usage_error(){ echo >&2 echo "Linux tune-up (TRIM) utility for SATA SSDs" echo "Usage: $0 [--verbose] [--commit] " >&2 echo " Eg: $0 /dev/sda1" >&2 echo >&2 exit 1 } ## Parameter parsing for the main script. ## Yeah, we could use getopt here instead, but what fun would that be? ## echo echo "${0##*/}: Linux SATA SSD TRIM utility, version $VERSION, by Mark Lord." export verbose=0 commit="" destroy_me="" argc=$# arg="" while [ $argc -gt 0 ]; do if [ "$1" = "--commit" ]; then commit=yes elif [ "$1" = "--please-prematurely-wear-out-my-ssd" ]; then destroy_me=yes elif [ "$1" = "--verbose" ]; then verbose=$((verbose + 1)) elif [ "$1" = "" ]; then usage_error else if [ "$arg" != "" ]; then echo "$1: too many arguments, aborting." >&2 exit 1 fi arg="$1" fi argc=$((argc - 1)) shift done [ "$arg" = "" ] && usage_error ## Find a required program, or else give a nicer error message than we'd otherwise see: ## function find_prog(){ prog="$1" if [ ! -x "$prog" ]; then prog="${prog##*/}" p=`type -f -P "$prog" 2>/dev/null` if [ "$p" = "" ]; then [ "$2" != "quiet" ] && echo "$1: needed but not found, aborting." >&2 exit 1 fi prog="$p" [ $verbose -gt 0 ] && echo " --> using $prog instead of $1" >&2 fi echo "$prog" } ## Ensure we have most of the necessary utilities available before trying to proceed: ## hash -r ## Refresh bash's cached PATH entries HDPARM=`find_prog /sbin/hdparm` || exit 1 FIND=`find_prog /usr/bin/find` || exit 1 STAT=`find_prog /usr/bin/stat` || exit 1 GAWK=`find_prog /usr/bin/gawk` || exit 1 BLKID=`find_prog /sbin/blkid` || exit 1 GREP=`find_prog /bin/grep` || exit 1 ID=`find_prog /usr/bin/id` || exit 1 LS=`find_prog /bin/ls` || exit 1 DF=`find_prog /bin/df` || exit 1 RM=`find_prog /bin/rm` || exit 1 STAT=`find_prog /usr/bin/stat` || exit 1 [ $verbose -gt 1 ] && HDPARM="$HDPARM --verbose" ## I suppose this will confuse the three SELinux users out there: ## if [ `$ID -u` -ne 0 ]; then echo "Only the super-user can use this (try \"sudo $0\" instead), aborting." >&2 exit 1 fi ## We need a very modern hdparm, for its --fallocate and --trim-sector-ranges-stdin flags: ## Version 9.25 added automatic determination of safe max-size of TRIM commands. ## HDPVER=`$HDPARM -V | $GAWK '{gsub("[^0-9.]","",$2); if ($2 > 0) print ($2 * 100); else print 0; exit(0)}'` if [ $HDPVER -lt 925 ]; then echo "$HDPARM: version >= 9.25 is required, aborting." >&2 exit 1 fi ## Convert relative path "$1" into an absolute pathname, resolving all symlinks: ## function get_realpath(){ iter=0 p="$1" while [ -e "$p" -a $iter -lt 100 ]; do ## Strip trailing slashes: while [ "$p" != "/" -a "$p" != "${p%%/}" ]; do p="${p%%/}" done ## Split into directory:leaf portions: d="${p%/*}" t="${p##*/}" ## If the split worked, then cd into the directory portion: if [ "$d" != "" -a "$d" != "$p" ]; then cd -P "$d" || exit p="$t" fi ## If what we have left is a directory, then cd to it and print realpath: if [ -d "$p" ]; then cd -P "$p" || exit pwd -P exit ## Otherwise if it is a symlink, read the link and loop again: elif [ -h "$p" ]; then p="`$LS -ld "$p" | awk '{sub("^[^>]*-[>] *",""); print}'`" ## Otherwise, prefix $p with the cwd path and print it: elif [ -e "$p" ]; then [ "${p:0:1}" = "/" ] || p="`pwd -P`/$p" echo "$p" exit fi iter=$((iter + 1)) done } function get_devpath(){ dir="$1" kdev=`$STAT --format="%04D" "$dir" 2>/dev/null` [ "$kdev" = "" ] && exit 1 major=$((0x${kdev:0:2})) minor=$((0x${kdev:2:2})) $FIND /dev -xdev -type b -exec $LS -ln {} \; | $GAWK -v major="$major," -v minor="$minor" \ '($5 == major && $6 == minor){r=$NF}END{print r}' } ## Convert "$arg" into an absolute pathname target, with no symlinks or embedded blanks: target="`get_realpath "$arg"`" if [ "$target" = "" ]; then [ "$arg" = "/dev/root" ] && target="`get_devpath /`" if [ "$target" = "" ]; then echo "$arg: unable to determine full pathname, aborting." >&2 exit 1 fi fi if [ "$target" != "${target##* }" ]; then echo "\"$target\": pathname has embedded blanks, aborting." >&2 exit 1 fi ## Take a first cut at online/offline determination, based on the target: ## if [ -d "$target" ]; then method=online elif [ -b "$target" ]; then method=offline else echo "$target: not a block device or mount point, aborting." >&2 exit 1 fi ## Find the active mount-point (fsdir) associated with a device ($1: fsdev). ## This is complicated, and probably still buggy, because a single ## device can show up under *multiple* mount points in /proc/mounts. ## function get_fsdir(){ rw="" r="" while read -a m ; do pdev="${m[0]}" [ "$pdev" = "$1" ] || pdev="`get_realpath "$pdev"`" if [ "$pdev" = "$1" ]; then if [ "$rw" != "rw" ]; then rw="${m[3]:0:2}" r="${m[1]}" fi fi #echo "$pdev ${m[1]} ${m[2]} ${m[3]}" done echo -n "$r" } ## Find the device (fsdev) associated with a mount point ($1: fsdir). ## Since mounts can be stacked on top of each other, we return the ## one from the last occurance in the list from /proc/mounts. ## function get_fsdev(){ ## from fsdir get_realpath "`$GAWK -v p="$1" '{if ($2 == p) r=$1} END{print r}' < /proc/mounts`" } ## Find the r/w or r/o status (fsmode) of a filesystem mount point ($1: fsdir) ## We get it from the last occurance of the mount point in the list from /proc/mounts, ## and convert it to a longer human-readable string. ## function get_fsmode(){ ## from fsdir mode="`$GAWK -v p="$1" '{if ($2 == p) r=substr($4,1,2)} END{print r}' < /proc/mounts`" if [ "$mode" = "ro" ]; then echo "read-only" elif [ "$mode" = "rw" ]; then echo "read-write" else echo "$fsdir: unable to determine mount status, aborting." >&2 exit 1 fi } ## Try and determine the device name associated with the root filesystem. ## This is nearly impossible to do in any perfect fashion. ## ## Redhat/Fedora no longer have an rdev command. Silly them. ## So we now implement it internally, below. ## ## match_rootdev *should* work, but on some distros it may find only "/dev/root", ## and "/dev/root" is not usually a real device. We leave it like that for now, ## because that's the pattern such systems also use in /proc/mounts. ## Later, at time of use, we'll try harder to find the real rootdev. ## ## FIXME: apparently this doesn't work on SuSE Linux, though. ## So for there, we'll likely need to read /etc/mtab, ## or be a lot more clever and get it somehow from statfs or something. ## FIXME: or use target from /dev/root symlink for Gentoo as well. ## function match_rootdev() { rdev="" rdevno="$1" while read bdev ; do if [ "$rdev" = "" -o "$bdev" != "/dev/root" ]; then devno=$($STAT -c "0x%t%02T" "$bdev" 2>/dev/null) [ "$devno" = "$rdevno" ] && rdev="$bdev" fi done echo -n "$rdev" } rootdev=$($FIND /dev/ -type b 2>/dev/null | match_rootdev $($STAT -c "0x%D" '/')) [ $verbose -gt 0 ] && echo "rootdev=$rootdev" ## The user gave us a directory (mount point) to TRIM, ## which implies that we will be doing an online TRIM ## using --fallocate and --fibmap to find the free extents. ## Do some preliminary correctness/feasibility checks on fsdir: ## if [ "$method" = "online" ]; then ## Ensure fsdir exists and is accessible to us: fsdir="$target" cd "$fsdir" || exit 1 if [ "$fsdir" = "/" ]; then fsdev="$rootdev" else ## Figure out what device holds the filesystem. fsdev="`get_fsdev $fsdir`" if [ "$fsdev" = "" ]; then echo "$fsdir: not found in /proc/mounts, aborting." >&2 exit 1 fi fi ## The root filesystem may show up as the phoney "/dev/root" device ## in /proc/mounts (ugh). So if we see that, then substitute the rootdev ## that $DF gave us earlier. But $DF may have the same problem (double ugh). ## [ ! -e "$fsdev" -a "$fsdev" = "/dev/root" ] && fsdev="$rootdev" ## Ensure that fsdev exists and is a block device: if [ ! -e "$fsdev" ]; then if [ "$fsdev" != "/dev/root" ]; then echo "$fsdev: not found" >&2 exit 1 fi if [ "$rootdev" = "" ]; then echo "$fsdev: not found" >&2 exit 1 fi fsdev="$rootdev" fi if [ ! -b "$fsdev" ]; then echo "$fsdev: not a block device" >&2 exit 1 fi ## If it is mounted read-only, we must switch to doing an "offline" trim of fsdev: fsmode="`get_fsmode $fsdir`" || exit 1 [ $verbose -gt 0 ] && echo "fsmode1: fsmode=$fsmode" [ "$fsmode" = "read-only" ] && method=offline fi ## This is not an "else" clause from the above, because "method" may have changed. ## For offline TRIM, we need the block device, and it cannot be mounted read-write: ## if [ "$method" = "offline" ]; then ## We might already have fsdev/fsdir from above; if not, we need to find them. if [ "$fsdev" = "" -o "$fsdir" = "" ]; then fsdev="$target" fsdir="`get_fsdir "$fsdev" < /proc/mounts`" ## More weirdness for /dev/root in /proc/mounts: if [ "$fsdir" = "" -a "$fsdev" = "$rootdev" ]; then fsdir="`get_fsdir /dev/root < /proc/mounts`" if [ "$fsdir" = "" ]; then rdev="`get_devpath /`" [ "$rdev" != "" ] && fsdir="`get_fsdir "$rdev" < /proc/mounts`" fi fi fi ## If the filesystem is truly not-mounted, then fsdir will still be empty here. ## It could be mounted, though. Read-only is fine, but read-write means we need ## to switch gears and do an "online" TRIM instead of an "offline" TRIM. ## if [ "$fsdir" != "" ]; then fsmode="`get_fsmode $fsdir`" || exit 1 [ $verbose -gt 0 ] && echo "fsmode2: fsmode=$fsmode" if [ "$fsmode" = "read-write" ]; then method=online cd "$fsdir" || exit 1 fi fi fi ## Use $LS to find the major number of a block device: ## function get_major(){ $LS -ln "$1" | $GAWK '{print gensub(",","",1,$5)}' } ## At this point, we have finalized our selection of online vs. offline, ## and we definitely know the fsdev, as well as the fsdir (fsdir="" if not-mounted). ## ## Now guess at the underlying rawdev name, which could be exactly the same as fsdev. ## Then determine whether or not rawdev claims support for TRIM commands. ## Note that some devices lie about support, and later reject the TRIM commands. ## rawdev=`echo $fsdev | $GAWK '{print gensub("[0-9]*$","","g")}'` rawdev="`get_realpath "$rawdev"`" if [ ! -e "$rawdev" ]; then rawdev="" elif [ ! -b "$rawdev" ]; then rawdev="" elif [ "`get_major $fsdev`" -ne "`get_major $rawdev`" ]; then ## sanity check rawdev="" else ## "SCSI" drives only; no LVM confusion for now: maj="$(get_major $fsdev)" maj_ok=0 for scsi_major in 8 65 66 67 68 69 70 71 ; do [ "$maj" = "$scsi_major" ] && maj_ok=1 done if [ $maj_ok -eq 0 ]; then echo "$rawdev: does not appear to be a SCSI/SATA SSD, aborting." >&2 exit 1 fi if ! $HDPARM -I $rawdev | $GREP -i '[ ][*][ ]*Data Set Management TRIM supported' &>/dev/null ; then if [ "$commit" = "yes" ]; then echo "$rawdev: DSM/TRIM command not supported, aborting." >&2 exit 1 fi echo "$rawdev: DSM/TRIM command not supported (continuing with dry-run)." >&2 fi fi if [ "$rawdev" = "" ]; then echo "$fsdev: unable to reliably determine the underlying physical device name, aborting" >&2 exit 1 fi ## We also need to know the offset of fsdev from the beginning of rawdev, ## because TRIM requires absolute sector numbers within rawdev: ## fsoffset=`$HDPARM -g "$fsdev" | $GAWK 'END {print $NF}'` ## Next step is to determine what type of filesystem we are dealing with (fstype): ## if [ "$fsdir" = "" ]; then ## Not mounted: use $BLKID to determine the fstype of fsdev: fstype=`$BLKID -w /dev/null -c /dev/null $fsdev 2>/dev/null | \ $GAWK '/ TYPE=".*"/{sub("^.* TYPE=\"",""); sub("[\" ][\" ]*.*$",""); print}'` [ $verbose -gt 0 ] && echo "$fsdev: fstype=$fstype" else ## Mounted: we could just use $BLKID here, too, but it's safer to use /proc/mounts directly: fstype="`$GAWK -v p="$fsdir" '{if ($2 == p) r=$3} END{print r}' < /proc/mounts`" [ $verbose -gt 0 ] && echo "$fsdir: fstype=$fstype" fi if [ "$fstype" = "" ]; then echo "$fsdev: unable to determine filesystem type, aborting." >&2 exit 1 fi ## Some helper funcs and vars for use with the xfs filesystem tools: ## function xfs_abort(){ echo "$fsdev: unable to determine xfs filesystem ${1-parameters}, aborting." >&2 exit 1 } function xfs_trimlist(){ $XFS_DB -r -c "freesp -d" "$fsdev" ## couldn't get this to work inline } xfs_agoffsets="" xfs_blksects=0 ## We used to allow single-drive btrfs here, but it stopped working in linux-2.6.31, ## and Chris Mason says "unsafe at any speed" really. So it's been dropped now. ## if [ "$fstype" = "btrfs" ]; then ## hdparm --fibmap fails, due to fake 0:xx device nodes echo "$target: btrfs filesystem type not supported (cannot determine physical devices), aborting." >&2 exit 1 fi ## Now figure out whether we can actually do TRIM on this type of filesystem: ## if [ "$method" = "online" ]; then ## Print sensible error messages for some common situations, ## rather than failing with more confusing messages later on.. ## if [ "$fstype" = "ext2" -o "$fstype" = "ext3" ]; then ## No --fallocate support echo "$target: cannot TRIM $fstype filesystem when mounted read-write, aborting." >&2 exit 1 fi ## Figure out if we have enough free space to even attempt TRIM: ## freesize=`$DF -P -B 1024 . | $GAWK '{r=$4}END{print r}'` if [ "$freesize" = "" ]; then echo "$fsdev: unknown to '$DF'" exit 1 fi if [ $freesize -lt 15000 ]; then echo "$target: filesystem too full for TRIM, aborting." >&2 exit 1 fi ## Figure out how much space to --fallocate (later), keeping in mind ## that this is a live filesystem, and we need to leave some space for ## other concurrent activities, as well as for filesystem overhead (metadata). ## So, reserve at least 1% or 7500 KB, whichever is larger: ## reserved=$((freesize / 100)) [ $reserved -lt 7500 ] && reserved=7500 [ $verbose -gt 0 ] && echo "freesize = ${freesize} KB, reserved = ${reserved} KB" tmpsize=$((freesize - reserved)) tmpfile="WIPER_TMPFILE.$$" get_trimlist="$HDPARM --fibmap $tmpfile" else ## We can only do offline TRIM on filesystems that we "know" about here. ## Currently, this includes the ext2/3/4 family, xfs, and reiserfs. ## The first step for any of these is to ensure that the filesystem is "clean", ## and immediately abort if it is not. ## get_trimlist="" if [ "$fstype" = "ext2" -o "$fstype" = "ext3" -o "$fstype" = "ext4" ]; then DUMPE2FS=`find_prog /sbin/dumpe2fs` || exit 1 fstate="`$DUMPE2FS $fsdev 2>/dev/null | $GAWK '/^[Ff]ilesystem state:/{print $NF}' 2>/dev/null`" if [ "$fstate" != "clean" ]; then echo "$target: filesystem not clean, please run \"e2fsck $fsdev\" first, aborting." >&2 exit 1 fi get_trimlist="$DUMPE2FS $fsdev" elif [ "$fstype" = "xfs" ]; then XFS_DB=`find_prog /sbin/xfs_db` || exit 1 XFS_REPAIR=`find_prog /sbin/xfs_repair` || exit 1 if ! $XFS_REPAIR -n "$fsdev" &>/dev/null ; then echo "$fsdev: filesystem not clean, please run \"xfs_repair $fsdev\" first, aborting." >&2 exit 1 fi ## For xfs, life is more complex than with ext2/3/4 above. ## The $XFS_DB tool does not return absolute block numbers for freespace, ## but rather gives them as relative to it's allocation groups (ag's). ## So, we'll need to interogate it for the offset of each ag within the filesystem. ## The agoffsets are extracted from $XFS_DB as sector offsets within the fsdev. ## agcount=`$XFS_DB -r -c "sb" -c "print agcount" "$fsdev" | $GAWK '{print 0 + $NF}'` [ "$agcount" = "" -o "$agcount" = "0" ] && xfs_abort "agcount" xfs_agoffsets= i=0 while [ $i -lt $agcount ]; do agoffset=`$XFS_DB -r -c "sb" -c "convert agno $i daddr" "$fsdev" \ | $GAWK '{print 0 + gensub("[( )]","","g",$2)}'` [ "$agoffset" = "" ] && xfs_abort "agoffset-$i" [ $i -gt 0 ] && [ $agoffset -le ${xfs_agoffsets##* } ] && xfs_abort "agoffset[$i]" xfs_agoffsets="$xfs_agoffsets $agoffset" i=$((i + 1)) done xfs_agoffsets="${xfs_agoffsets:1}" ## strip leading space ## We also need xfs_blksects for later, because freespace gets listed as block numbers. ## blksize=`$XFS_DB -r -c "sb" -c "print blocksize" "$fsdev" | $GAWK '{print 0 + $NF}'` [ "$blksize" = "" -o "$blksize" = "0" ] && xfs_abort "block size" xfs_blksects=$((blksize/512)) get_trimlist="xfs_trimlist" elif [ "$fstype" = "reiserfs" ]; then DEBUGREISERFS=`find_prog /sbin/debugreiserfs` || exit 1 ( $DEBUGREISERFS $fsdev | $GREP '^Filesystem state:.consistent' ) &> /dev/null if [ $? -ne 0 ]; then echo "Please run fsck.reiserfs first, aborting." >&2 exit 1 fi get_trimlist="$DEBUGREISERFS -m $fsdev" elif [ "$fstype" = "hfsplus" ]; then OD=`find_prog /usr/bin/od` || exit 1 TR=`find_prog /usr/bin/tr` || exit 1 #check sleuthkit FSSTAT=`find_prog /usr/local/bin/fsstat` if [ "$?" = "1" ]; then echo "fsstat and icat from package sleuthkit >= 3.1.1 is required for hfsplus." exit 1 fi ICAT=`find_prog /usr/local/bin/icat` if [ "`$ICAT -f list 2>/dev/stdout|$GREP HFS+`" = "" ]; then echo "Wrong icat, version from package sleuthkit >= 3.1.1 is required for hfsplus." exit 1 fi #check for unmounted properly if [ "`$FSSTAT -f hfs $fsdev | $GREP "Volume Unmounted Properly"`" = "" ]; then echo "Hfsplus volume unmounted improperly!" exit 1 fi #check $AllocationFile inode FFIND=`find_prog /usr/local/bin/ffind` if [ "`$FFIND -f hfs $fsdev 6`" != "/\$AllocationFile" ]; then echo "Hfsplus bitmap \$AllocationFile is not inode 6!" exit 1 fi #get offset for hfsplus with a wrapper hfsoffset=`$FSSTAT -f hfs $fsdev | $GREP "File system is embedded in an HFS wrapper at offset "|$TR -d "\t"` if [ -n "$hfsoffset" ]; then hfsoffset=${hfsoffset:52} ((fsoffset=fsoffset+hfsoffset)) echo "File system is embedded in an HFS wrapper at offset $hfsoffset" fi blksize=`$FSSTAT -f hfs $fsdev | $GREP "Allocation Block Size: "|$TR -d "\t"` blksize=${blksize:23} blksects=$((blksize / 512)) #get count of used bytes in $AllocationFile blkcount=`$FSSTAT -f hfs $fsdev | $GREP "Block Range: 0 - "` blkcount=${blkcount:17} bytecount=$((blkcount/blksects)) method="bitmap_offline" get_trimlist="echo $blksects hfsplus `$ICAT -f hfs $fsdev 6 | $OD -N $bytecount -An -vtu1 -j0 -w1`" elif [ "$fstype" = "ntfs" ]; then NTFSINFO=`find_prog /usr/bin/ntfsinfo` || exit 1 NTFSCAT=`find_prog /usr/bin/ntfscat` || exit 1 NTFSPROBE=`find_prog /usr/bin/ntfs-3g.probe` || exit 1 OD=`find_prog /usr/bin/od` || exit 1 TR=`find_prog /usr/bin/tr` || exit 1 #check for unmounted properly $NTFSPROBE -w $fsdev 2>/dev/null if [ $? -ne 0 ]; then echo "$fsdev contains an unclean file system!" exit 1 fi #check for volume version if [ "`$NTFSINFO -m -f $fsdev | $GREP "Volume Version: 3.1"`" = "" ]; then echo "NTFS volume version must be 3.1!" exit 1 fi blksize=`$NTFSINFO -m -f $fsdev | $GREP "Cluster Size: " | $TR -d "\t"` blksize=${blksize:14} blksects=$((blksize / 512)) #get count of used bytes in $Bitmap blkcount=`$NTFSINFO -m -f $fsdev | $GREP "Volume Size in Clusters: " | $TR -d "\t"` blkcount=${blkcount:25} bytecount=$((blkcount/blksects)) method="bitmap_offline" get_trimlist="echo $blksects ntfs `$NTFSCAT $fsdev \\\$Bitmap | $OD -N $bytecount -An -vtu1 -j0 -w1`" fi if [ "$get_trimlist" = "" ]; then echo "$target: offline TRIM not supported for $fstype filesystems, aborting." >&2 exit 1 fi fi ## All ready. Now let the user know exactly what we intend to do: ## mountstatus="$fstype non-mounted" [ "$fsdir" = "" ] || mountstatus="$fstype mounted $fsmode at $fsdir" echo "Preparing for $method TRIM of free space on $fsdev ($mountstatus)." ## If they specified "--commit" on the command line, then prompt for confirmation first: ## if [ "$commit" = "yes" ]; then if [ "$destroy_me" = "" ]; then echo >/dev/tty echo -n "This operation could silently destroy your data. Are you sure (y/N)? " >/dev/tty read yn < /dev/tty if [ "$yn" != "y" -a "$yn" != "Y" ]; then echo "Aborting." >&2 exit 1 fi fi TRIM="$HDPARM --please-destroy-my-drive --trim-sector-ranges-stdin $rawdev" else echo "This will be a DRY-RUN only. Use --commit to do it for real." TRIM="$GAWK {}" fi ## Useful in a few places later on: ## function sync_disks(){ echo -n "Syncing disks.. " sync echo } ## Clean up tmpfile (if any) and exit: ## function do_cleanup(){ if [ "$method" = "online" ]; then if [ -e $tmpfile ]; then echo "Removing temporary file.." $RM -f $tmpfile fi sync_disks fi [ $1 -eq 0 ] && echo "Done." [ $1 -eq 0 ] || echo "Aborted." >&2 exit $1 } ## Prepare signal handling, in case we get interrupted while $tmpfile exists: ## function do_abort(){ echo do_cleanup 1 } trap do_abort SIGTERM trap do_abort SIGQUIT trap do_abort SIGINT trap do_abort SIGHUP trap do_abort SIGPIPE ## For online TRIM, go ahead and create the huge temporary file. ## This is where we finally discover whether the filesystem actually ## supports --fallocate or not. Some folks will be disappointed here. ## ## Note that --fallocate does not actually write any file data to fsdev, ## but rather simply allocates formerly-free space to the tmpfile. ## if [ "$method" = "online" ]; then if [ -e "$tmpfile" ]; then if ! $RM -f "$tmpfile" ; then echo "$tmpfile: already exists and could not be removed, aborting." >&2 exit 1 fi fi echo -n "Creating temporary file (${tmpsize} KB).. " if ! $HDPARM --fallocate "${tmpsize}" $tmpfile ; then echo "$target: this kernel may not support 'fallocate' on a $fstype filesystem, aborting." >&2 exit 1 fi echo fi ## Finally, we are now ready to TRIM something! ## ## Feed the "get_trimlist" output into a gawk program which will ## extract the trimable lba-ranges (extents) and batch them together ## into huge --trim-sector-ranges calls. ## ## We are limited by at least one thing when doing this: ## 1. Some device drivers may not support more than 255 sectors ## full of lba:count range data per TRIM command. ## The latest hdparm versions now take care of that automatically. ## sync_disks if [ "$commit" = "yes" ]; then echo "Beginning TRIM operations.." else echo "Simulating TRIM operations.." fi [ $verbose -gt 0 ] && echo "get_trimlist=$get_trimlist" ## Begin gawk program GAWKPROG=' BEGIN { if (xfs_agoffsets != "") { method = "xfs_offline" agcount = split(xfs_agoffsets,agoffset," "); } } function append_range (lba,count ,this_count){ nsectors += count; while (count > 0) { this_count = (count > 65535) ? 65535 : count printf "%u:%u ", lba, this_count if (verbose > 1) printf "%u:%u ", lba, this_count > "/dev/stderr" lba += this_count count -= this_count nranges++; } } (method == "online") { ## Output from "hdparm --fibmap", in absolute sectors: if (NF == 4 && $2 ~ "^[1-9][0-9]*$") append_range($2,$4) next } (method == "xfs_offline") { ## Output from xfs_db: if (NF == 3 && gensub("[0-9 ]","","g",$0) == "" && $1 < agcount) { lba = agoffset[1 + $1] + ($2 * xfs_blksects) + fsoffset count = $3 * xfs_blksects append_range(lba,count) } next } (method == "bitmap_offline") { n = split($0,f) blksects = f[1] fstype = f[2] bitmap_start = 3 range_first = -1 #clusters range_last = -1 for (i = bitmap_start; i <= n-1; i++) { if (f[i] == 0) { if (range_first == -1) range_first = (i-bitmap_start) * 8 range_last = (i-bitmap_start) * 8 + 7 } else if (f[i] == 255 && range_first > -1){ #printf range_first "-" range_last "\n" > "/dev/stderr" lba = (range_first * blksects) + fsoffset count = (range_last - range_first + 1) * blksects append_range(lba,count) range_first = -1 range_last = -1 } else { for (b = 0; b < 8; b++) { if (fstype == "ntfs") bit = and(f[i], lshift(1, b)) ? 1 : 0 else #hfsplus bit = and(f[i], lshift(1, 7-b)) ? 1 : 0 if (bit == 0) { if (range_first == -1) { range_first = (i-bitmap_start) * 8 + b range_last = (i-bitmap_start) * 8 + b } else range_last += 1 } else if (range_first > -1) { #printf range_first "-" range_last " " > "/dev/stderr" lba = (range_first * blksects) + fsoffset count = (range_last - range_first + 1) * blksects if (fstype == "ntfs") append_range(lba,count) else if (count > (2 * blksects)) #faster for hfsplus append_range(lba,count) range_first = -1 range_last = -1 } } } } if (range_first > -1){ #printf range_first "-" range_last " " > "/dev/stderr" lba = (range_first * blksects) + fsoffset count = (range_last - range_first + 1) * blksects append_range(lba,count) } next } /^Block size: *[1-9]/ { ## First stage output from dumpe2fs: blksects = $NF / 512 next } /^Group [0-9][0-9]*:/ { ## Second stage output from dumpe2fs: in_groups = 1 next } /^ *Free blocks: [0-9]/ { ## Bulk of output from dumpe2fs: if (blksects && in_groups) { n = split(substr($0,16),f,",* *") for (i = 1; i <= n; ++i) { if (f[i] ~ "^[1-9][0-9]*-[1-9][0-9]*$") { split(f[i],b,"-") lba = (b[1] * blksects) + fsoffset count = (b[2] - b[1] + 1) * blksects append_range(lba,count) } else if (f[i] ~ "^[1-9][0-9]*$") { lba = (f[i] * blksects) + fsoffset count = blksects append_range(lba,count) } } next } } /^Reiserfs super block/ { method = "reiserfs" next } /^Blocksize: / { if (method == "reiserfs") { blksects = $2 / 512 next } } /^#[0-9][0-9]*:.*Free[(]/ { ## debugreiserfs if (method == "reiserfs" && blksects > 0) { n = split($0,f) for (i = 4; i <= n; ++i) { if (f[i] ~ "^ *Free[(]") { if (2 == split(gensub("[^-0-9]","","g",f[i]),b,"-")) { lba = (b[1] * blksects) + fsoffset count = (b[2] - b[1] + 1) * blksects append_range(lba, count) } } } next } } END { if (err == 0 && commit != "yes") printf "(dry-run) trimming %u sectors from %u ranges\n", nsectors, nranges > "/dev/stderr" exit err }' ## End gawk program $get_trimlist 2>/dev/null | $GAWK \ -v commit="$commit" \ -v method="$method" \ -v rawdev="$rawdev" \ -v fsoffset="$fsoffset" \ -v verbose="$verbose" \ -v xfs_blksects="$xfs_blksects" \ -v xfs_agoffsets="$xfs_agoffsets" \ "$GAWKPROG" | $TRIM do_cleanup $? hdparm-9.43/wiper/contrib/0000755000000000000000000000000012031352226014204 5ustar rootroothdparm-9.43/wiper/contrib/README.contrib0000644000000000000000000000042412031352226016523 0ustar rootrootContributed scripts and notes from others (untested by me). =========================================================== raid1ext4trim.sh-1.5 Similar to wiper.sh, but for ext4/RAID1 mirrors. By Chris Caputo . Adapted from wiper.sh (ver 2.6 by Mark Lord). hdparm-9.43/wiper/contrib/raid1ext4trim.sh-1.50000755000000000000000000002607312031352135017554 0ustar rootroot#!/bin/bash # # SSD TRIM utility for live RAID1 mirrored ext4 drives. # # By Chris Caputo. Adapted from wiper.sh (ver 2.6) by Mark Lord. VERSION=1.5 # Copyright (C) 2010-2012 Chris Caputo. All rights reserved. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License Version 2, # as published by the Free Software Foundation. # # This program is distributed in the hope that it would be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA function usage_error(){ echo "Usage:" echo " ${0##*/} [--verbose] [--commit] [--reserve=#megs] [--max-ranges=#ranges] " echo "Examples:" echo " ${0##*/} --verbose --commit --reserve=100 --max-ranges=512 md0 /" echo " ${0##*/} --verbose --verbose md1 /boot" echo echo "Note: For best results, this script should be run on each ext4-based filesystem present on a RAID1 array." echo exit 1 } echo "${0##*/}: TRIM utility for live RAID1 ext4 SATA SSDs, version $VERSION, by Chris Caputo, based on Mark Lord's wiper.sh." echo ## Parameter parsing for the main script. ## export verbose=0 commit="" reservemegs=0 max_ranges=0 argc=$# raiddev="" fsdir="" while [ $argc -gt 0 ]; do if [ "$1" = "--commit" ]; then commit=yes elif [ "$1" = "--verbose" ]; then verbose=$((verbose + 1)) elif [[ "$1" =~ --reserve= ]]; then reservemegs=${1##--reserve=} elif [[ "$1" =~ --max-ranges= ]]; then max_ranges=${1##--max-ranges=} elif [ "$1" = "" ]; then usage_error else if [ "$raiddev" = "" ]; then raiddev=${1##*/} elif [ "$fsdir" = "" ]; then fsdir=$1 else echo "$1: too many arguments, aborting." exit 1 fi fi argc=$((argc - 1)) shift done [ "$raiddev" = "" ] && usage_error [ "$fsdir" = "" ] && usage_error ## Check --reserve number. ## isdigit () # Tests whether *entire string* is numerical. { # In other words, tests for integer variable. [ $# -eq 1 ] || return 1 case $1 in *[!0-9]*|"") return 1;; *) return 0;; esac } if ! isdigit "$reservemegs" ; then echo "'$reservemegs' is not numerical" exit 1 fi if ! isdigit "$max_ranges" ; then echo "'$max_ranges' is not numerical" exit 1 fi if [ $reservemegs -eq 0 ]; then echo "Reserve defaulting to 10 megabytes." reservemegs=10 fi reservekilos=$((reservemegs * 1024)) ## Find a required program, or else give a nicer error message than we'd otherwise see: ## function find_prog(){ prog="$1" if [ ! -x "$prog" ]; then prog="${prog##*/}" p=`type -f -P "$prog" 2>/dev/null` if [ "$p" = "" ]; then echo "$1: needed but not found, aborting." exit 1 fi prog="$p" [ $verbose -gt 0 ] && echo " --> using $prog instead of $1" fi echo "$prog" } ## Ensure we have most of the necessary utilities available before trying to proceed: ## hash -r ## Refresh bash's cached PATH entries HDPARM=`find_prog /sbin/hdparm` || exit 1 GAWK=`find_prog /usr/bin/gawk` || exit 1 GREP=`find_prog /bin/grep` || exit 1 ID=`find_prog /usr/bin/id` || exit 1 LS=`find_prog /bin/ls` || exit 1 DF=`find_prog /bin/df` || exit 1 RM=`find_prog /bin/rm` || exit 1 [ $verbose -gt 1 ] && HDPARM="$HDPARM --verbose" ## I suppose this will confuse the three SELinux users out there: ## if [ `$ID -u` -ne 0 ]; then echo "Only the super-user can use this (try \"sudo $0\" instead), aborting." exit 1 fi ## We need a very modern hdparm, for its --fallocate and --trim-sector-ranges-stdin flags: ## Version 9.25 added automatic determination of safe max-size of TRIM commands. ## HDPVER=`$HDPARM -V | $GAWK '{gsub("[^0-9.]","",$2); if ($2 > 0) print ($2 * 100); else print 0; exit(0)}'` if [ $HDPVER -lt 925 ]; then echo "$HDPARM: version >= 9.25 is required, aborting." exit 1 fi ## Check that this is a RAID1 device. ## if ! $GREP raid1 /sys/block/$raiddev/md/level 1>/dev/null ; then echo "$raiddev is not a RAID1 array." exit 1 fi ## Get list of slave devices in the RAID1 mirror. ## slaves=(`$LS /sys/block/$raiddev/slaves`) #slaves=(sda sdb sdc) #slaves=(md0) ## Check for DEVTYPE disk and TRIM support on each slave. ## index=0 for slave in "${slaves[@]}" do # Check that slave is of DEVTYPE disk. if ! $GREP "DEVTYPE=disk" /sys/block/$slave/uevent 1>/dev/null ; then echo "$slave is not a whole disk. This program only works with full-disk RAID1, not RAID1 partitions." exit 1 fi # Check that slave has TRIM support. Exclude if not. if ! $HDPARM -I /dev/$slave | $GREP -i '[ ][*][ ]*Data Set Management TRIM supported' &>/dev/null ; then echo "$slave doesn't appear to support TRIM, per $HDPARM. Excluding." unset slaves[index] fi let "index = $index + 1" done if [ "${slaves[0]}" = "" ]; then echo "No constituent of $raiddev array supports TRIM. Aborting." exit 1 fi ## Check that fsdir is on an ext4 volume. ## lines=`$DF --type=ext4 $fsdir 2>/dev/null | $GREP -v ^Filesystem | wc -l` if [ $lines -ne 1 ]; then echo "'$fsdir' does not appear to be on an ext4 filesystem. Aborting." exit 1 fi ## Check that fsdir is a directory. ## if [ ! -d $fsdir ]; then echo "'$fsdir' is not a directory. Aborting." exit 1 fi ## Check free space & calculate tmpfile size. ## freesize=`$DF -P -B 1024 $fsdir | $GAWK '{r=$4}END{print r}'` if [ "$freesize" = "" ]; then echo "'$fsdir' is unknown to '$DF'. Aborting." exit 1 fi if [ $freesize -lt $reservekilos ]; then echo "'$fsdir' available space of $freesize KB is less than the $reservekilos KB to be reserved for the TRIM operation. Aborting." >&2 exit 1 fi tmpsize=$((freesize - reservekilos)) tmpfile="$fsdir/${0##*/}_TMPFILE.$$" ## Clean up tmpfile (if any) and exit: ## function do_cleanup(){ if [ -e $tmpfile ]; then echo "Removing temporary file '$tmpfile'..." $RM -f $tmpfile if [ -e $tmpfile ]; then echo "Failed to remove '$tmpfile'!!!" fi fi [ $1 -eq 0 ] && echo "Done." [ $1 -eq 0 ] || echo "Aborted." >&2 exit $1 } ## Prepare signal handling, in case we get interrupted while $tmpfile exists: ## function do_abort(){ echo do_cleanup 1 } trap do_abort SIGTERM trap do_abort SIGQUIT trap do_abort SIGINT trap do_abort SIGHUP trap do_abort SIGPIPE ## Do the fallocate. ## This is where we finally discover whether the filesystem actually ## supports --fallocate or not. Some folks will be disappointed here. ## ## Note that --fallocate does not actually write any file data to fsdev, ## but rather simply allocates formerly-free space to the tmpfile. ## echo -n "Creating temporary file (${tmpsize} KB '$tmpfile') ... " if ! $HDPARM --fallocate "${tmpsize}" $tmpfile ; then echo "This kernel may not support 'fallocate'. Aborting." exit 1 fi echo ## Verify that slaves and RAID1 mirror have same base LBA. First add a test ## string to the tmpfile. "date" is used since it is ever changing. ## TESTSTR=`date` echo "$TESTSTR" >> $tmpfile sync # this is critical SECTOR_BYTES=`$HDPARM --fibmap $tmpfile | \ $GREP "byte sectors" | \ $GAWK '{print $9}'` LAST_EXTENT_SECTOR_COUNT=`$HDPARM --fibmap $tmpfile | \ tail -1 | \ $GAWK '{print $4}'` LAST_EXTENT_LBA=`$HDPARM --fibmap $tmpfile | tail -1 | $GAWK '{print $2}'` ## Verify the test string is in the extent read. if ! dd iflag=direct status=noxfer bs=$SECTOR_BYTES count=$LAST_EXTENT_SECTOR_COUNT skip=$LAST_EXTENT_LBA if=/dev/$raiddev 2>/dev/null | $GREP "$TESTSTR" &>/dev/null ; then echo "Test string was not found in last extent of tmpfile, as it should have been. Aborting." do_cleanup 1 fi ## Now compare the mirror and the slaves to make sure they have the same data at the same LBA. ## refchksum=`dd iflag=direct status=noxfer bs=$SECTOR_BYTES count=$LAST_EXTENT_SECTOR_COUNT skip=$LAST_EXTENT_LBA if=/dev/$raiddev 2>/dev/null | sha1sum` index=0 for slave in "${slaves[@]}" do chksum=`dd iflag=direct status=noxfer bs=$SECTOR_BYTES count=$LAST_EXTENT_SECTOR_COUNT skip=$LAST_EXTENT_LBA if=/dev/$slave 2>/dev/null | sha1sum` if [ "$chksum" != "$refchksum" ]; then echo "Direct I/O of last extent of tmpfile on $slave doesn't match that of $raiddev. Excluding." unset slaves[index] fi let "index = $index + 1" done if [ "${slaves[0]}" = "" ]; then echo "No constituent of $raiddev array has a matching checksum. Aborting." do_cleanup 1 fi echo "TRIMable constituents of $raiddev: ${slaves[@]}" ## If they specified "--commit" on the command line, then prompt for confirmation first: ## if [ "$commit" = "yes" ]; then echo "Beginning TRIM operations..." else echo "This will be a DRY-RUN only. Use --commit to do it for real." echo "Simulating TRIM operations..." fi get_trimlist="$HDPARM --fibmap $tmpfile" [ $verbose -gt 0 ] && echo "get_trimlist=$get_trimlist" ## Begin gawk program GAWKPROG=' function append_range (lba,count ,this_count){ nsectors += count; while (count > 0) { this_count = (count > 65535) ? 65535 : count printf "%u:%u \n", lba, this_count if (verbose > 1) printf "%u:%u ", lba, this_count > "/dev/stderr" lba += this_count count -= this_count nranges++; } } { ## Output from "hdparm --fibmap", in absolute sectors: if (NF == 4 && $2 ~ "^[1-9][0-9]*$") append_range($2,$4) next } END { if (verbose > 1) printf "\n" > "/dev/stderr" if (err == 0 && commit != "yes") printf "(dry-run) trimming %u sectors from %u ranges\n", nsectors, nranges > "/dev/stderr" exit err }' ## End gawk program ## Run TRIM on each slave. Batch as requested. sync index=0 for slave in "${slaves[@]}" do echo "TRIM beginning on $slave..." if [ "$commit" = "yes" ]; then TRIM="$HDPARM --please-destroy-my-drive \ --trim-sector-ranges-stdin /dev/$slave" else TRIM="$GAWK {}" fi ## Different SSD's have a different maximum number of ranges they'll ## accept in a single TRIM command. if [ $max_ranges -eq 0 ] ; then model=`$HDPARM -I /dev/$slave | $GAWK '/Model Number/ { print $NF }'` case "$model" in SSDSA[12]*) slave_max_range=512 ;; # Intel X18-M/X25-M OCZ-VERTEX2) slave_max_range=64 ;; # OCZ Vertex2 *) slave_max_range=65535 esac else slave_max_range=$max_ranges fi [ $verbose -gt 0 ] && echo "$slave: max-ranges = $slave_max_range" $get_trimlist 2>/dev/null | $GAWK \ -v commit="$commit" \ -v verbose="$verbose" \ "$GAWKPROG" | \ if true; then i=0 while read range; do (( i++ )) if (( i <= $slave_max_range )); then ranges=$ranges" "$range else [ $verbose -gt 0 ] && echo -e "Trim ranges:" $ranges echo $ranges | $TRIM ret=$? if [ $ret -ne 0 ] ; then do_cleanup $ret fi ranges=$range i=1 fi done [ $verbose -gt 0 ] && echo -e "Trim ranges:" $ranges echo $ranges | $TRIM ret=$? if [ $ret -ne 0 ] ; then do_cleanup $ret fi ranges="" fi ret=$? if [ $ret -ne 0 ] ; then echo "TRIM failed on $slave. Aborting." do_cleanup $ret else echo "TRIM finished successfully on $slave." fi done do_cleanup 0 hdparm-9.43/wiper/Changelog0000644000000000000000000000342212031357533014365 0ustar rootrootwiper.sh-3.5 - don't skip Group 0 on ext* filesystems wiper.sh-3.4 - updated to allow all SCSI_DISK_MAJOR numbers, not just "8" wiper.sh-3.3 - remove need for external "rdev" utility, to keep Suse/Redhat/Fedora users happy wiper.sh-3.2 -limits the trimmed blocks to the size of the hfsplus/ntfs filesystem wiper.sh-3.1 - updated contrib/raid1ext4trim.sh script to v1.4, courtesy of Chris Caputo - new flag to enable unattended operation, and handle SIGPIPE - basic compatibility with latest Redhat/Fedora systems that lack the rdev command - support hfsplus and ntfs filesystem types, courtesy of Heiko Wegeler - hfsplus/ntfs notes from Heiko Wegeler: Icat and fsstat from package sleuthkit version >=3.1.1 is required for hfsplus. A outdated icat is in Debian package tct, the right icat is a link in package sleuthkit to ->/etc/alternatives/icat->/usr/bin/icat-sleuthkit. Sleuthkit from Ubuntu 10.4 LTS is too old, you need a local build in /usr/local/bin. Fedora 14 works. Fedora13+updates should work. Win-7 tests from a kvm installation: ok: "ntfs" compiletest and win-7 checkdsk after trim ok: "ntfs 8k cluster" same test ok: "ntfs with compressed files" same test ok: "ntfs with encrypted files" same test after decrypt Win-XP: ok: Systemdrive boots after trim and chkdsk. MacOS 10.4.5 tests from the MacOS-installer: ok: "mac os extended (journaled)" compiletest and macos-verify after trim ok: "mac os extended" same test ok: "mac os extended (case sensitive, journaled)" same test ok: "mac os extended (case sensitive)" same test ok: "mac os standard" wiper says:offline TRIM not supported for hfs filesystems, aborting. ok: "unix file system" wiper says: offline TRIM not supported for ufs filesystems, aborting. not tested: "msdos filesystem" and raids hdparm-9.43/wiper/README.txt0000644000000000000000000001033511465535145014261 0ustar rootrootTRIM / wiper script for SATA SSDs (June 2010) ================================================= The wiper.sh script is for tuning up SATA SSDs (Solid-State-Drives). It calculates a list of free (unallocated) blocks within a filesystem, and informs the SSD firmware of those blocks, so that it can better manage the underlying media for wear-leveling and garbage-collection purposes. In some cases, this can restore a sluggish SSD to nearly-new speeds again. This script may be EXTREMELY HAZARDOUS TO YOUR DATA. It does work for me here, but it has not yet been exhaustively tested by others. Please back-up your data to a *different* physical drive before trying it. And if you are at all worried, then DO NOT USE THIS SCRIPT!! DO NOT USE THIS SCRIPT if you cannot afford losing your data!! This script works for read-write mounted ext4 and xfs filesystems, and for read-only mounted/unmounted ext2, ext3, ext4, reiser3 and xfs filesystems. As of Version 3.1, hfsplus and ntfs filesystem types are also supported, but this code has not been widely tested yet. BE CAREFUL! Invoke the script with the pathname to the mounted filesystem or the block device path for the filesystem. Eg. ./wiper.sh /boot ./wiper.sh / ./wiper.sh /dev/sda1 Note that the most comprehensive results are achieved when wiping a filesystem that is not currently mounted read-write, though the difference is small. ================================================== btrfs -- DO NOT USE !!! Chris Mason, the primary author/maintainer of btrfs, believes that the FIEMAP/FIBMAP ioctl() calls are completely unsafe when used on a btrfs filesystem. Even when only a single device is involved. This seems rather strange. If true, those ioctls() should be removed from btrfs. But there are other issues, as well. btrfs breaks the Linux filesystem model in many ways, making it rather dangerous to your data to try and TRIM it. It implements it's own internal multiple-device layer, similar to DM/MD/VFS, but without any indication to external utilities like wiper.sh. As a result, detection of the underlying device for the filesystem is haphazard at best, and this could cause wiper.sh to destroy data on whatever device it thinks is the correct one. Also, because of the built-in duplication of multiple-device support, the FIBMAP and FIEMAP ioctl()s will work incorrectly on btrfs when more than a single device is involved. This means that btrfs will mislead the wiper.sh script, causing it to TRIM the WRONG sectors, destroying valuable data, programs, and filesystem metadata. You will lose everything. Finally, due to the non-standard internal volume/device remapping done by btrfs, it is very difficult for standard Linux tools like hdparm and wiper.sh to actually determine the device that lies underneath a given file. Odd, but true. So support for btrfs has been dropped as of wiper-2.5. It used to work for single drives, but as of the Linux-2.6.31 kernel even hdparm is now failing for simple operations like obtaining drive geometries from /sys on btrfs. btrfs is an experimental beta with serious issues; use ext4 or xfs instead. ================================================== The sil24_trim_protocol_fix.patch file in this directory is a kernel patch for all recent Linux kernel versions up to and including 2.6.31. This fixes the kernel device driver for the Silicon Image SiI-3132 SATA controller to correctly pass DSM/TRIM commands to the drives. If you use this hardware in your system, then you will need to apply the patch to your kernel before using the wiper scripts. ================================================== The fiemap_compat_ioctl.patch file in this directory is a kernel patch to speed up "hdparm --fibmap" when run as a 32-bit program on top of a 64-bit Linux kernel. Kernels versions up to and including 2.6.31 are missing support for this, so hdparm will fall back to the older and slower FIBMAP call, causing wiper.sh to take much longer to run. The older call has other limitations, such as failing on really large files or huge disks, so use of FIEMAP really is preferred. As of August 16, a similar patch has now been backported to the -stable streams of most recent Linux kernel versions. So update your kernel and this functionality will already be included. hdparm-9.43/sgio.h0000644000000000000000000001306112031356632012536 0ustar rootroot/* prototypes and stuff for ATA command ioctls */ #include enum { ATA_OP_DSM = 0x06, // Data Set Management (TRIM) ATA_OP_READ_PIO = 0x20, ATA_OP_READ_PIO_ONCE = 0x21, ATA_OP_READ_LONG = 0x22, ATA_OP_READ_LONG_ONCE = 0x23, ATA_OP_READ_PIO_EXT = 0x24, ATA_OP_READ_DMA_EXT = 0x25, ATA_OP_READ_FPDMA = 0x60, // NCQ ATA_OP_WRITE_PIO = 0x30, ATA_OP_WRITE_LONG = 0x32, ATA_OP_WRITE_LONG_ONCE = 0x33, ATA_OP_WRITE_PIO_EXT = 0x34, ATA_OP_WRITE_DMA_EXT = 0x35, ATA_OP_WRITE_FPDMA = 0x61, // NCQ ATA_OP_READ_VERIFY = 0x40, ATA_OP_READ_VERIFY_ONCE = 0x41, ATA_OP_READ_VERIFY_EXT = 0x42, ATA_OP_WRITE_UNC_EXT = 0x45, // lba48, no data, uses feat reg ATA_OP_FORMAT_TRACK = 0x50, ATA_OP_DOWNLOAD_MICROCODE = 0x92, ATA_OP_STANDBYNOW2 = 0x94, ATA_OP_CHECKPOWERMODE2 = 0x98, ATA_OP_SLEEPNOW2 = 0x99, ATA_OP_PIDENTIFY = 0xa1, ATA_OP_READ_NATIVE_MAX = 0xf8, ATA_OP_READ_NATIVE_MAX_EXT = 0x27, ATA_OP_SMART = 0xb0, ATA_OP_DCO = 0xb1, ATA_OP_ERASE_SECTORS = 0xc0, ATA_OP_READ_DMA = 0xc8, ATA_OP_WRITE_DMA = 0xca, ATA_OP_DOORLOCK = 0xde, ATA_OP_DOORUNLOCK = 0xdf, ATA_OP_STANDBYNOW1 = 0xe0, ATA_OP_IDLEIMMEDIATE = 0xe1, ATA_OP_SETIDLE = 0xe3, ATA_OP_SET_MAX = 0xf9, ATA_OP_SET_MAX_EXT = 0x37, ATA_OP_SET_MULTIPLE = 0xc6, ATA_OP_CHECKPOWERMODE1 = 0xe5, ATA_OP_SLEEPNOW1 = 0xe6, ATA_OP_FLUSHCACHE = 0xe7, ATA_OP_FLUSHCACHE_EXT = 0xea, ATA_OP_IDENTIFY = 0xec, ATA_OP_SETFEATURES = 0xef, ATA_OP_SECURITY_SET_PASS = 0xf1, ATA_OP_SECURITY_UNLOCK = 0xf2, ATA_OP_SECURITY_ERASE_PREPARE = 0xf3, ATA_OP_SECURITY_ERASE_UNIT = 0xf4, ATA_OP_SECURITY_FREEZE_LOCK = 0xf5, ATA_OP_SECURITY_DISABLE = 0xf6, ATA_OP_VENDOR_SPECIFIC_0x80 = 0x80, }; /* * Some useful ATA register bits */ enum { ATA_USING_LBA = (1 << 6), ATA_STAT_DRQ = (1 << 3), ATA_STAT_ERR = (1 << 0), }; /* * Useful parameters for init_hdio_taskfile(): */ enum { RW_READ = 0, RW_WRITE = 1, LBA28_OK = 0, LBA48_FORCE = 1, }; /* * Definitions and structures for use with SG_IO + ATA_16: */ struct ata_lba_regs { __u8 feat; __u8 nsect; __u8 lbal; __u8 lbam; __u8 lbah; }; struct ata_tf { __u8 dev; __u8 command; __u8 error; __u8 status; __u8 is_lba48; struct ata_lba_regs lob; struct ata_lba_regs hob; }; /* * Definitions and structures for use with HDIO_DRIVE_TASKFILE: */ enum { /* * These (redundantly) specify the category of the request */ TASKFILE_CMD_REQ_NODATA = 0, /* ide: IDE_DRIVE_TASK_NO_DATA */ TASKFILE_CMD_REQ_IN = 2, /* ide: IDE_DRIVE_TASK_IN */ TASKFILE_CMD_REQ_OUT = 3, /* ide: IDE_DRIVE_TASK_OUT */ TASKFILE_CMD_REQ_RAW_OUT= 4, /* ide: IDE_DRIVE_TASK_RAW_WRITE */ /* * These specify the method of transfer (pio, dma, multi, ..) */ TASKFILE_DPHASE_NONE = 0, /* ide: TASKFILE_IN */ TASKFILE_DPHASE_PIO_IN = 1, /* ide: TASKFILE_IN */ TASKFILE_DPHASE_PIO_OUT = 4, /* ide: TASKFILE_OUT */ }; union reg_flags { unsigned all :16; union { unsigned lob_all : 8; struct { unsigned data : 1; unsigned feat : 1; unsigned lbal : 1; unsigned nsect : 1; unsigned lbam : 1; unsigned lbah : 1; unsigned dev : 1; unsigned command : 1; } lob; }; union { unsigned hob_all : 8; struct { unsigned data : 1; unsigned feat : 1; unsigned lbal : 1; unsigned nsect : 1; unsigned lbam : 1; unsigned lbah : 1; unsigned dev : 1; unsigned command : 1; } hob; }; } __attribute__((packed)); struct taskfile_regs { __u8 data; __u8 feat; __u8 nsect; __u8 lbal; __u8 lbam; __u8 lbah; __u8 dev; __u8 command; }; struct hdio_taskfile { struct taskfile_regs lob; struct taskfile_regs hob; union reg_flags oflags; union reg_flags iflags; int dphase; int cmd_req; /* IDE command_type */ unsigned long obytes; unsigned long ibytes; __u16 data[0]; }; struct scsi_sg_io_hdr { int interface_id; int dxfer_direction; unsigned char cmd_len; unsigned char mx_sb_len; unsigned short iovec_count; unsigned int dxfer_len; void * dxferp; unsigned char * cmdp; void * sbp; unsigned int timeout; unsigned int flags; int pack_id; void * usr_ptr; unsigned char status; unsigned char masked_status; unsigned char msg_status; unsigned char sb_len_wr; unsigned short host_status; unsigned short driver_status; int resid; unsigned int duration; unsigned int info; }; #ifndef SG_DXFER_NONE #define SG_DXFER_NONE -1 #define SG_DXFER_TO_DEV -2 #define SG_DXFER_FROM_DEV -3 #define SG_DXFER_TO_FROM_DEV -4 #endif #define SG_READ 0 #define SG_WRITE 1 #define SG_PIO 0 #define SG_DMA 1 #define SG_CHECK_CONDITION 0x02 #define SG_DRIVER_SENSE 0x08 #define SG_ATA_16 0x85 #define SG_ATA_16_LEN 16 #define SG_ATA_12 0xa1 #define SG_ATA_12_LEN 12 #define SG_ATA_LBA48 1 #define SG_ATA_PROTO_NON_DATA ( 3 << 1) #define SG_ATA_PROTO_PIO_IN ( 4 << 1) #define SG_ATA_PROTO_PIO_OUT ( 5 << 1) #define SG_ATA_PROTO_DMA ( 6 << 1) #define SG_ATA_PROTO_UDMA_IN (11 << 1) /* not yet supported in libata */ #define SG_ATA_PROTO_UDMA_OUT (12 << 1) /* not yet supported in libata */ void tf_init (struct ata_tf *tf, __u8 ata_op, __u64 lba, unsigned int nsect); __u64 tf_to_lba (struct ata_tf *tf); int sg16 (int fd, int rw, int dma, struct ata_tf *tf, void *data, unsigned int data_bytes, unsigned int timeout_secs); int do_drive_cmd (int fd, unsigned char *args, unsigned int timeout); int do_taskfile_cmd (int fd, struct hdio_taskfile *r, unsigned int timeout_secs); int dev_has_sgio (int fd); void init_hdio_taskfile (struct hdio_taskfile *r, __u8 ata_op, int rw, int force_lba48, __u64 lba, unsigned int nsect, int data_bytes); hdparm-9.43/contrib/0000755000000000000000000000000011702131533013056 5ustar rootroothdparm-9.43/contrib/buildit.empeg0000755000000000000000000000015510776427373015561 0ustar rootroot#!/bin/bash export PATH="/usr/local/armtools-empeg/cbin:/usr/local/armtools-empeg/bin:$PATH" make clean make hdparm-9.43/contrib/idectl0000755000000000000000000000144710010437072014254 0ustar rootroot#!/bin/sh HDPARM=/sbin/hdparm MAX_IDE_NR=1 IDE_IO_0=0x1f0 IDE_IO_1=0x170 USE_IDE_DEV_0=/dev/hda USE_IDE_DEV_1=/dev/hdc usage () { if [ $# -gt 0 ]; then echo $* >&2 echo fi echo "usage: $0 ide-channel-nr [off|on|rescan]" 2>&1 exit 1 } IDE_NR=$1 MODE=$2 do_register=0 do_unregister=0 if [ ! "$IDE_NR" ] || [ $IDE_NR -lt 0 ] || [ $IDE_NR -gt $MAX_IDE_NR ]; then usage "Unrecognized IDE-channel number" fi case "$MODE" in on ) do_register=1 ;; off ) do_unregister=1 ;; rescan ) do_unregister=1; do_register=1 ;; * ) usage "Unrecognized command" ;; esac eval "IDE_IO=\$IDE_IO_$IDE_NR" eval "USE_IDE_DEV=\$USE_IDE_DEV_$IDE_NR" [ $do_unregister -eq 1 ] && eval "$HDPARM -U $IDE_NR $USE_IDE_DEV > /dev/null" [ $do_register -eq 1 ] && eval "$HDPARM -R $IDE_IO 0 0 $USE_IDE_DEV > /dev/null" hdparm-9.43/contrib/fix_standby0000755000000000000000000002477210574112401015331 0ustar rootrootELF4p4 (# 444444 4HHH hhhQtd/lib/ld-linux.so.2GNUSuSESuSE    M?@$.R39MoA9`<Y{ H7 _Jv_RegisterClasses__gmon_start__libc.so.6putssleepstrtolfprintfsyncioplstderrfwrite_IO_stdin_used__libc_start_mainGLIBC_2.0$ii Т    U< 5آ%ܢ%h%h%h%h%h %h(%h0%h8p%h@`%hHP1^PTRhhQVhuUS[tX[ÐU=t ҡuÐUtt $ÐU$$B$$2$$"$$$$UEfEUEEU$D$$@$/D$$Xa$D$$pB$D$$#$D$$$D$$$D$$Џ$uD$$$$UD$$U‹E$UEfEUffEEU‹E$gU(EU EUEi@BE$EE E"E:EE}t m}u˃}t UE}t EEEU(EU EUEUMED$ ED$T$ $Ct4ED$ ED$D$$E}t UEEUD$9D$ D$D$$@Gt EeE¸ D$$ED$JD$ D$D$$@t EEEUEE‹E UD$$UEU EfUEUUS4EED$[D$ D$D$$@Kt EED$$WD$oD$ (ED$D$$@t EwEtN$0EUEMT$D$ L$D$$EED$$EE4[]U(EU EUD$ҐD$ D$D$$@1t E7ED$$@ED$$,$lEEUD$$4|Q$f=4u4D$$!CQ&$f=!Cu E,D$ D$ D$$EEUEfE‹E UD$$UEU fEfUEUfU(D$$=w EEE  $$$E}t}u1D$ D$-D$$$)E!E%t1D$ D$'D$$TE $t E& D$$)|D$$qt ED$$Mt Ec$t EJ$ D$$$$|EEÍL$qUQ4ME8EUBD$ED$$tE8&t=wEt Et.D$ D$,D$$LE:N$$$iEUUE4Y]aU]U]ÐU]Ít&'UWVSQ9+ )Et%1֋ED$E D$E$9}u߃[^_]Ë$USt1Ћu[]ÐUS[ìY[ide_data = 0x%04x ide_error = 0x%02x ide_nsectors = 0x%02x ide_lbal = 0x%02x ide_lbam = 0x%02x ide_lbah = 0x%02x ide_select = 0x%02x ide_status = 0x%02x ide_altstatus = 0x%02x status timeout: %s, stat=0x%02x do_drive_select1do_drive_select2do_nondata_command1do_nondata_command2command 0x%02x failed, status=0x%02x, error=0x%02x command 0x%02x succeeded do_setfeatures1register read/write test failed Trying with ide_base=0x%x: No drive detected, try a different ide_base? IDE interface is busy, try again later Done; the drive may take another 30 seconds to come to life now.Bad argument; expected ide_base, Eg: 0x1f0 $ ԃ ́ ԢPtoToo8"2BRbrGCC: (GNU) 4.1.0 (SUSE Linux)GCC: (GNU) 4.1.0 (SUSE Linux)GCC: (GNU) 4.1.0 (SUSE Linux)GCC: (GNU) 4.1.0 (SUSE Linux)GCC: (GNU) 4.1.0 (SUSE Linux)GCC: (GNU) 4.1.0 (SUSE Linux)GCC: (GNU) 4.1.0 (SUSE Linux),ԃ Ą&$4!y_IO_stdin_usedĄĄpP8]K:intFPA<O|B'/usr/src/packages/BUILD/glibc-2.4/cc-nptl/csu/crti.S/usr/src/packages/BUILD/glibc-2.4/csuGNU AS 2.16.91.0.5|R/usr/src/packages/BUILD/glibc-2.4/cc-nptl/csu/crtn.S/usr/src/packages/BUILD/glibc-2.4/csuGNU AS 2.16.91.0.5% $ > $ > 4: ; I?  &I%%# init.cK /usr/src/packages/BUILD/glibc-2.4/cc-nptl/csucrti.S3!/!=Z!ԃ#!/=Ą !/!=Z!gg//Z!!!sK /usr/src/packages/BUILD/glibc-2.4/cc-nptl/csucrtn.S4!!! !init.cshort intlong long intGNU C 4.1.0 (SUSE Linux)unsigned charlong long unsigned intshort unsigned int/usr/src/packages/BUILD/glibc-2.4/csu_IO_stdin_used.symtab.strtab.shstrtab.interp.note.ABI-tag.note.SuSE.hash.dynsym.dynstr.gnu.version.gnu.version_r.rel.dyn.rel.plt.init.text.fini.rodata.eh_frame.ctors.dtors.jcr.dynamic.got.got.plt.data.bss.comment.debug_aranges.debug_pubnames.debug_info.debug_abbrev.debug_line.debug_str44#HH 1hh<LB ́JRo88_oTT n ttw P ԃ{| 88ТԢ4 XH%m b`7'0<2"U %4Hh́8Tt  ԃ   8ТԢ !" 4;F{Ą   + ;AvDX $   ׆# #  :  C .  8 M Ԋ &j/ +  0 = Io Mu QZkԢ?8$  ԃ  M-\ =Iu Nk v9 (<{ 7 abi-note.Ssuse-note.S../sysdeps/i386/elf/start.Sinit.cinitfini.c/usr/src/packages/BUILD/glibc-2.4/cc-nptl/csu/crti.Scall_gmon_startcrtstuff.c__CTOR_LIST____DTOR_LIST____JCR_LIST__completed.5751p.5749__do_global_dtors_auxframe_dummy__CTOR_END____DTOR_END____FRAME_END____JCR_END____do_global_ctors_aux/usr/src/packages/BUILD/glibc-2.4/cc-nptl/csu/crtn.Sfix_standby.cwait_400nside_altstatusinbdump_regsINWINBide_baseinwwait_for_statusrequire_statusdo_drive_selectOUTBoutbdo_nondata_commanddo_setfeaturesdo_rw_testOUTWoutwdo_fix_driveide_controlclisti_DYNAMIC__init_array_end_GLOBAL_OFFSET_TABLE___init_array_startiopl@@GLIBC_2.0_fp_hwfprintf@@GLIBC_2.0__dso_handle__libc_csu_finiputs@@GLIBC_2.0_initstderr@@GLIBC_2.0_startsleep@@GLIBC_2.0strtol@@GLIBC_2.0__libc_csu_init__bss_startmain__libc_start_main@@GLIBC_2.0data_startprintf@@GLIBC_2.0_fini_edata__i686.get_pc_thunk.bx_end_IO_stdin_usedfwrite@@GLIBC_2.0__data_start_Jv_RegisterClassessync@@GLIBC_2.0__gmon_start__hdparm-9.43/contrib/ultrabayd0000755000000000000000000000154007046633346015012 0ustar rootroot#!/bin/sh VERSION="0.1.000" TPCTL="/usr/bin/tpctl" IDECTL="/sbin/idectl" INTERVAL=5 case "$1" in -V ) echo "$0: Version $VERSION" exit 0 ;; -daemon ) o_d_type="" o_d_id="" while true; do d_type="" d_type_n="" d_id="" d_id_n="" while read w1 w2 w3 wn; do case "$w1" in device ) case "$w2" in type: ) d_type=$w3; d_type_n="$wn";; ID: ) d_id=$w3; d_id_n="$wn";; esac ;; esac if [ "$d_type" ] && [ "$d_id" ]; then break; fi done <<- END `eval $TPCTL -iU` END if [ "$d_type" != "$o_d_type" ] || [ "$d_id" != "$o_d_id" ]; then echo -n "\07" > /dev/tty1 o_d_type="$d_type" o_d_id="$d_id" case "$d_type" in 0x10 ) eval "$IDECTL 1 rescan" ;; * ) eval "$IDECTL 1 off" ;; esac fi sleep $INTERVAL done ;; * ) exec nohup $0 -daemon 2>&1 > /dev/null & ;; esac hdparm-9.43/contrib/make_bad_sector.c0000644000000000000000000001043110755421775016344 0ustar rootroot/* make_bad_sector.c v3.03 by Mark Lord */ #include #include #include #include #include #include #include #include #include #include #include #include #include "hdparm.h" #include "sgio.h" #define READ 0 #define WRITE 1 int verbose = 0; // used by sgio.c #if 0 static void init_hdio_taskfile (struct hdio_taskfile *r, __u8 ata_op, int rw, int force_lba48, __u64 lba, unsigned int nsect, int data_bytes) { const __u64 lba28_mask = 0x0fffffff; memset(r, 0, sizeof(struct hdio_taskfile) + data_bytes); r->xfer_method = TASKFILE_XFER_METHOD_PIO_OUT; if (!data_bytes) { r->cmd_req = TASKFILE_CMD_REQ_NODATA; } else { r->cmd_req = rw ? TASKFILE_CMD_REQ_OUT : TASKFILE_CMD_REQ_IN; if (rw) r->out_bytes = data_bytes; else r->in_bytes = data_bytes; } r->lob.command = ata_op; r->out_flags.lob.b.command = 1; r->out_flags.lob.b.dev = 1; r->out_flags.lob.b.lbal = 1; r->out_flags.lob.b.lbam = 1; r->out_flags.lob.b.lbah = 1; r->out_flags.lob.b.nsect = 1; r->lob.nsect = nsect; r->lob.lbal = lba; r->lob.lbam = lba >> 8; r->lob.lbah = lba >> 16; r->lob.dev = ATA_USING_LBA; if ((lba & ~lba28_mask) == 0 && nsect <= 256 && !force_lba48) { r->lob.dev |= lba >> 24; } else { r->hob.nsect = nsect >> 8; r->hob.lbal = lba >> 24; r->hob.lbam = lba >> 32; r->hob.lbah = lba >> 40; r->out_flags.hob.b.nsect = 1; r->out_flags.hob.b.lbal = 1; r->out_flags.hob.b.lbam = 1; r->out_flags.hob.b.lbah = 1; } } #endif int main (int argc, char *argv[]) { /* * Note: the extra bytes are transfered ONE-PER_WORD after the sector data, * so for 4 extra bytes, we must transfer 4 extra WORDs. */ const char *devpath, *myname = argv[0];; int rc = 0, fd, do_rewrite = 0, do_readback = 0; __u8 ata_op; __u64 lba; unsigned char bad_pattern = 0x00; struct hdio_taskfile *r; const int ten_seconds = 10; r = malloc(sizeof(struct hdio_taskfile) + 520); if (!r) { perror("malloc()"); exit(1); } while (argc-- > 1 && **++argv == '-') { if (!strcmp("--readback", argv[0])) { do_readback = 1; } else if (!strcmp("--rewrite", argv[0])) { do_rewrite = 1; } else { fprintf(stderr, "%s: unknown flag: %s\n", myname, argv[0]); exit(1); } } if (argc != 2) { fprintf(stderr, "%s: bad/missing parms: expected [--rewrite|--readback] \n", myname); exit(1); } devpath = argv[0]; lba = strtol(argv[1], NULL, 0); fd = open(devpath, O_RDWR); if (fd == -1) { perror(devpath); exit(1); } // Try and ensure that the system doesn't have our sector in cache: (void) ioctl(fd, BLKFLSBUF, NULL); if (do_rewrite) { fprintf(stderr, "%s: overwriting LBA=%llu (this should succeed!)\n", devpath, (unsigned long long)lba); ata_op = (lba >> 28) ? ATA_OP_WRITE_PIO_EXT : ATA_OP_WRITE_PIO; init_hdio_taskfile(r, ata_op, WRITE, 0, lba, 1, 512); rc = do_taskfile_cmd(fd, r, ten_seconds); fprintf(stderr, "%s: %s\n", devpath, rc ? "error" : "success"); } if (rc == 0 || do_readback) { fprintf(stderr, "%s: readback test LBA=%llu%s\n", devpath, (unsigned long long)lba, do_rewrite ? " (this should succeed!)" : ""); ata_op = (lba >> 28) ? ATA_OP_READ_PIO_EXT : ATA_OP_READ_PIO; init_hdio_taskfile(r, ata_op, READ, 0, lba, 1, 512); rc = do_taskfile_cmd(fd, r, ten_seconds); fprintf(stderr, "%s: %s\n", devpath, rc ? "error" : "success"); } if (do_rewrite || do_readback) exit(rc); do { int i; init_hdio_taskfile(r, ATA_OP_WRITE_LONG_ONCE, WRITE, 0, lba, 1, 520); --bad_pattern; // Corrupt and rewrite the sector: for (i = 0; i < 520; ++i) r->data[i] = bad_pattern; fprintf(stderr, "%s: writing LBA=%llu\n", devpath, (unsigned long long)lba); rc = do_taskfile_cmd(fd, r, ten_seconds); if (rc) { fprintf(stderr, "%s: WRITE_LONG failed\n", devpath); } else { fprintf(stderr, "%s: readback test LBA=%llu (this should fail!)\n", devpath, (unsigned long long)lba); //init_hdio_taskfile(r, ATA_OP_READ_VERIFY_ONCE, READ, 0, lba, 1, 0); init_hdio_taskfile(r, ATA_OP_READ_PIO_EXT, READ, 1, lba, 1, 512); rc = do_taskfile_cmd(fd, r, ten_seconds); if (rc) fprintf(stderr, "%s: readback failed\n", devpath); } } while (rc == 0); exit (0); } hdparm-9.43/contrib/README0000644000000000000000000000116007046633515013751 0ustar rootrootThese files were contributed by various users. ===================================================================== Dear Mark, attached I send you a small patch for hdparm-3.5 to make use of the ioctls HDIO_UNREGISTER_HWIF and HDIO_SCAN_HWIF found in newer kernels. With this patched version I can make my IBM ThinkPad 600E recognize 'hot-swapped' ide-devices in its UltraBay II - slot. Together with tpctl-0.7.0 and the two scripts 'idectl' and 'ultrabayd' it works really nice. Christian Lademann Attached: idectl, ultrabayd ===================================================================== hdparm-9.43/contrib/fix_standby.c0000644000000000000000000001311010574112377015543 0ustar rootroot/* * fix_standby.c by Mark Lord, March 2006. * * This frees a drive from the "power up in standby" condition. * It tries to be safe, but is still quite risky when run * on a preemptive kernel, because it could preempt something * that was in the middle of issuing an IDE/SATA command. * * Hardcoded to work only on the first (master) drive * on the first (primary) IDE/SATA interface. */ #include #include #include #include #include typedef unsigned char u8; typedef unsigned short u16; enum { BUSY_STAT = 0x80, READY_STAT = 0x40, WRERR_STAT = 0x20, SEEK_STAT = 0x10, DRQ_STAT = 0x08, ECC_STAT = 0x04, INDEX_STAT = 0x02, ERR_STAT = 0x01, }; enum { CHECKPOWERMODE = 0xE5, SETFEATURES = 0xEF, SF_SPINUP_NOW = 0x07, SF_NO_STANDBY = 0x86, }; static unsigned int ide_base, ide_control, ide_altstatus; enum { ide_data = 0, ide_feature = 1, ide_error = ide_feature, ide_nsectors = 2, ide_lbal = 3, ide_lbam = 4, ide_lbah = 5, ide_select = 6, ide_command = 7, ide_status = ide_command, }; static inline void cli (void) { __asm__ __volatile__("cli" : : : "memory"); } static inline void sti (void) { __asm__ __volatile__("sti" : : : "memory"); } static void wait_400ns (void) { inb(ide_altstatus); inb(ide_altstatus); inb(ide_altstatus); inb(ide_altstatus); inb(ide_altstatus); } static inline void OUTB (u8 val, unsigned int reg) { outb(val, ide_base + reg); } static inline u8 INB (unsigned int reg) { return inb(ide_base + reg); } static inline u16 INW (unsigned int reg) { return inw(ide_base + reg); } static inline void OUTW (u16 val, unsigned int reg) { outw(val, ide_base + reg); } static void dump_regs (void) { printf("ide_data = 0x%04x\n", INW(ide_data)); printf("ide_error = 0x%02x\n", INB(ide_error)); printf("ide_nsectors = 0x%02x\n", INB(ide_nsectors)); printf("ide_lbal = 0x%02x\n", INB(ide_lbal)); printf("ide_lbam = 0x%02x\n", INB(ide_lbam)); printf("ide_lbah = 0x%02x\n", INB(ide_lbah)); printf("ide_select = 0x%02x\n", INB(ide_select)); printf("ide_status = 0x%02x\n", INB(ide_status)); printf("ide_altstatus = 0x%02x\n", INB(ide_altstatus)); } static int wait_for_status (u8 ones, u8 zeros, u8 *stat_r, unsigned int timeout) { u8 stat; int result; wait_400ns(); timeout *= 1000000; do { stat = INB(ide_status); result = (stat & (ones|zeros)) != ones; } while (result && --timeout); if (stat_r) *stat_r = stat; return result ? EIO : 0; } static int require_status (u8 ones, u8 zeros, u8 *stat_r, unsigned int timeout, const char *msg) { int result = 0; u8 stat; if (wait_for_status(ones, zeros, &stat, timeout)) { fprintf(stderr, "status timeout: %s, stat=0x%02x\n", msg, stat); dump_regs(); result = EIO; } if (stat_r) *stat_r = stat; return result; } static int do_drive_select (int master_slave) { if (require_status(READY_STAT, BUSY_STAT|DRQ_STAT, NULL, 1, "do_drive_select1")) return EIO; OUTB(0xe0 | ((master_slave & 1) << 4), ide_select); if (require_status(READY_STAT, BUSY_STAT|DRQ_STAT, NULL, 1, "do_drive_select2")) return EIO; return 0; } static int do_nondata_command (u8 command) { u8 stat, err; if (require_status(READY_STAT, BUSY_STAT|DRQ_STAT, NULL, 1, "do_nondata_command1")) return EIO; OUTB(command, ide_command); if (require_status(READY_STAT, BUSY_STAT|DRQ_STAT, &stat, 40, "do_nondata_command2")) return EIO; if ((stat & ERR_STAT)) { err = INB(ide_error); fprintf(stderr, "command 0x%02x failed, status=0x%02x, error=0x%02x\n", command, stat, err); dump_regs(); return EIO; } printf("command 0x%02x succeeded\n", command); return 0; } static int do_setfeatures (u8 subcommand, u8 parameter) { if (require_status(READY_STAT, BUSY_STAT|DRQ_STAT, NULL, 1, "do_setfeatures1")) return EIO; OUTB(subcommand, ide_feature); OUTB(parameter, ide_nsectors); return do_nondata_command(SETFEATURES); } static int do_rw_test (void) { OUTW(0x1234, ide_data); wait_400ns(); if (INW(ide_data) == 0x1234) { OUTW(0x4321, ide_data); wait_400ns(); if (INW(ide_data) == 0x4321) return 0; /* success */ } fprintf(stderr, "register read/write test failed\n"); return EIO; } static int do_fix_drive (void) { u8 stat; printf("\nTrying with ide_base=0x%x:\n", ide_base); ide_control = (ide_base < 0x1000) ? 0x206 : 0x102; ide_altstatus = ide_control; stat = INB(ide_altstatus); if (stat == 0xff || stat == 0x00) { fprintf(stderr, "No drive detected, try a different ide_base?\n"); return ENODEV; } if ((stat & (BUSY_STAT|DRQ_STAT))) { fprintf(stderr, "IDE interface is busy, try again later\n"); return EAGAIN; } if (do_drive_select(0)) return EIO; do_rw_test(); OUTB(0x02, ide_control); /* set NIEN */ wait_400ns(); if (do_setfeatures(SF_SPINUP_NOW, 0)) /* spin-up the drive */ return EIO; if (do_setfeatures(SF_NO_STANDBY, 0)) /* disable powerup-in-standby feature */ return EIO; if (do_nondata_command(CHECKPOWERMODE)) /* clear any leftover errors */ return EIO; dump_regs(); INB(ide_status); /* clear IRQ */ OUTB(0x00, ide_control); /* reeanble NIEN */ wait_400ns(); INB(ide_status); /* clear IRQ */ printf("Done; the drive may take another 30 seconds to come to life now.\n"); return 0; } int main (int argc, char **argv) { int result; ide_base = 0x1f0; if (argc > 1) { char *end = NULL; ide_base = strtol(argv[1], &end, 0); if (argc > 2 || !ide_base || ide_base > 0xffff || !end || *end) { fprintf(stderr, "Bad argument; expected ide_base, Eg: 0x1f0\n"); return EINVAL; } } sync(); sleep(2); iopl(3); cli(); result = do_fix_drive(); sti(); sync(); return result; } hdparm-9.43/contrib/wdidle3_trace.txt0000644000000000000000000003761411702130245016342 0ustar rootrootThese are FIS (SATA Frame Information Structures) traces captured with a SATA analyser when using the WDIDLE3-1.03 program under DOS. I do not know the sequence that these four traces were done in, which may affect the exact actions/values used. ---------------------------------------------------------------------------------------------------------------------------------------------------- wdidle3-report.sata: report state of the idle3 timer: RESET_DEVICE: fis: 27 00 80 44 01 00 00 00 00 00 00 d5 01 00 00 06 00 00 00 00 fis: 27 00 80 44 01 00 00 00 00 00 00 d5 01 00 00 02 00 00 00 00 IDENTIFY_DEVICE: fis: 27 80 ec 44 01 00 00 a0 00 00 00 d5 01 00 00 02 00 00 00 00 data_in: 0: 7a 42 ff 3f 37 c8 10 00 00 00 00 00 3f 00 00 00 00 00 00 00 20 20 20 20 57 20 2d 44 4d 57 56 41 30 35 32 33 35 36 36 38 00 00 ff ff 32 00 31 30 48: 30 2e 41 30 31 30 44 57 20 43 44 57 30 35 30 30 41 41 53 44 30 2d 4d 30 42 32 20 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 10 80 96: 00 00 00 2f 01 40 00 00 00 00 07 00 ff 3f 10 00 3f 00 10 fc fb 00 00 01 ff ff ff 0f 00 00 07 00 03 00 78 00 78 00 78 00 78 00 00 00 00 00 00 00 144: 00 00 00 00 00 00 1f 00 06 17 00 00 44 00 40 00 fe 01 00 00 6b 74 61 7f 23 41 69 74 41 bc 23 41 7f 40 4a 00 4a 00 00 00 fe ff 00 00 fe 80 00 00 192: 00 00 00 00 00 00 00 00 30 60 38 3a 00 00 00 00 00 00 00 00 00 00 00 00 01 50 e0 4e 81 ac a1 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1c 40 240: 1c 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 21 00 00 00 00 00 00 00 00 00 ce 16 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 288: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 336: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 384: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 37 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 432: 00 00 00 00 00 00 00 00 00 00 00 00 1e 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 10 00 00 00 00 00 00 00 00 480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a5 60 VSC_ENABLE: fis: 27 80 80 45 01 44 57 a0 00 00 00 44 00 00 00 02 00 00 00 00 SMART_WRITE_LOG: fis: 27 80 b0 d6 be 4f c2 a0 01 44 57 45 01 00 00 02 00 00 00 00 data_out: 57 00 1a 00.. SMART_READ_LOG: fis: 27 80 b0 d5 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00 data_in: 40 1f 00 00.. SMART_WRITE_LOG: fis: 27 80 b0 d6 be 4f c2 a0 bf 00 00 d5 01 00 00 02 00 00 00 00 data_out: 2a 00 01 00 02 00 0d 00 16 00 01 00.. SMART_READ_LOG: fis: 27 80 b0 d5 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00 data_in: 50 00.. VSC_DISABLE: fis: 27 80 80 44 bf 44 57 a0 00 00 00 d5 00 00 00 02 00 00 00 00 ---------------------------------------------------------------------------------------------------------------------------------------------------- wdidle3-disable.sata: completely disable the idle3 timer: RESET, IDENTIFY: fis: 27 80 ec 44 01 00 00 a0 00 00 00 d5 01 00 00 02 00 00 00 00 data_in: 0: 7a 42 ff 3f 37 c8 10 00 00 00 00 00 3f 00 00 00 00 00 00 00 20 20 20 20 57 20 2d 44 4d 57 56 41 30 35 32 33 35 36 36 38 00 00 ff ff 32 00 31 30 48: 30 2e 41 30 31 30 44 57 20 43 44 57 30 35 30 30 41 41 53 44 30 2d 4d 30 42 32 20 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 10 80 96: 00 00 00 2f 01 40 00 00 00 00 07 00 ff 3f 10 00 3f 00 10 fc fb 00 00 01 ff ff ff 0f 00 00 07 00 03 00 78 00 78 00 78 00 78 00 00 00 00 00 00 00 144: 00 00 00 00 00 00 1f 00 06 17 00 00 44 00 40 00 fe 01 00 00 6b 74 61 7f 23 41 69 74 41 bc 23 41 7f 40 4a 00 4a 00 00 00 fe ff 00 00 fe 80 00 00 192: 00 00 00 00 00 00 00 00 30 60 38 3a 00 00 00 00 00 00 00 00 00 00 00 00 01 50 e0 4e 81 ac a1 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1c 40 240: 1c 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 21 00 00 00 00 00 00 00 00 00 ce 16 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 288: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 336: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 384: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 37 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 432: 00 00 00 00 00 00 00 00 00 00 00 00 1e 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 10 00 00 00 00 00 00 00 00 480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a5 60 vSC_ENABLE: fis: 27 80 80 45 01 44 57 a0 00 00 00 44 00 00 00 02 00 00 00 00 SMART: fis: 27 80 b0 d6 be 4f c2 a0 01 44 57 45 01 00 00 02 00 00 00 00 data_out: 57 00 1b 00.. SMART: fis: 27 80 b0 d6 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00 data_out: 0: 00 00 00 00 f2 0b 00 00 d3 de 43 00 ff ff ff ff 00 00 00 00 78 57 55 00 3c 2d 4c 00 60 70 4b 00 63 70 4b 00 00 00 00 00 00 00 00 00 f2 0b 00 00 48: d4 2e 4c 00 60 70 4b 00 d0 67 4c 00 08 60 4c 00 6e 4f 44 00 63 70 4b 00 14 00 00 00 14 00 00 00 f2 0b 00 00 b2 80 43 00 64 00 00 00 a0 00 00 00 96: 50 40 55 00 73 00 83 00 73 00 63 00 e8 06 00 00 d4 33 03 00 00 00 00 00 00 00 00 00 00 00 00 00 b7 01 87 01 83 00 83 00 e8 06 00 00 38 00 00 00 144: d4 2d 4c 00 a4 2d 4c 00 21 00 00 00 19 00 00 00 00 00 00 00 00 03 00 00 46 32 21 00 00 00 6e 0d 15 00 c3 00 22 04 00 00 00 00 00 00 73 00 af 01 192: 73 00 63 00 0c 2e 4c 00 d4 33 03 00 00 00 00 00 00 00 00 00 00 00 00 00 b7 01 00 00 af 01 d3 00 0c 2e 4c 00 00 00 00 00 0c 2e 4c 00 fc 2d 4c 00 240: 21 00 00 00 21 00 00 00 00 00 4b 00 00 30 00 00 02 30 21 00 c2 55 6a 0d 08 00 c3 00 8a 3e 00 00 69 61 4c 00 00 00 00 00 00 00 00 00 e4 23 00 00 288: 01 00 00 00 19 00 00 00 c2 55 4b 00 01 68 00 00 02 30 4c 00 00 00 00 00 00 00 00 00 4c 2e 00 24 01 31 00 00 b7 01 00 00 00 00 00 00 af 01 00 00 336: af 01 00 00 00 32 00 00 00 00 00 00 12 2b 00 00 58 18 48 00 a7 01 00 00 5d 18 48 00 01 00 00 00 f0 a9 47 00 19 00 00 00 69 61 4c 00 86 00 00 00 384: c2 55 4b 00 00 06 00 00 0a 00 00 00 05 9a 47 00 d7 80 4a 00 70 5c 47 00 44 2f 4c 00 00 0a 00 00 ac 2e 4c 00 7c 5c 47 00 73 2e 4c 00 05 9b 47 00 432: c2 55 4b 00 f1 ff ff ff ff ff ff ff d0 67 4c 00 18 00 00 00 d0 73 20 00 d0 67 4c 00 64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 480: 00 00 00 00 00 00 00 00 00 51 43 00 ef 20 46 00 cd 01 00 00 f7 20 46 00 14 00 00 00 14 00 00 00 SMART: fis: 27 80 b0 d6 be 4f c2 a0 bf 00 00 d6 01 01 00 02 00 00 00 00 data_out: 57 00 1a 00.. SMART: fis: 27 80 b0 d5 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00 data_in: 01 00.. SMART: fis: 27 80 b0 d6 be 4f c2 a0 bf 00 00 d5 01 00 00 02 00 00 00 00 data_out: 2a 00 02 00 02 00 0d 00 16 00 01 00.. SMART: fis: 27 80 b0 d6 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00 data_out: fc 2c 4c 00 01 SMART: fis: 27 80 b0 d6 be 4f c2 a0 bf 00 00 d6 01 01 00 02 00 00 00 00 data_out: 2a 00 01 00 02 00 0d 00 16 00 01 00.. SMART: fis: 27 80 b0 d5 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00 data_in: fc 00.. VSC_DISABLE: fis: 27 80 80 44 bf 44 57 a0 00 00 00 d5 00 00 00 02 00 00 00 00 ---------------------------------------------------------------------------------------------------------------------------------------------------- wdidle3-300.sata: set idle3 timeout to 300 seconds. IDENTIFY: data_in: 0: 7a 42 ff 3f 37 c8 10 00 00 00 00 00 3f 00 00 00 00 00 00 00 20 20 20 20 57 20 2d 44 4d 57 56 41 30 35 32 33 35 36 36 38 00 00 ff ff 32 00 31 30 48: 30 2e 41 30 31 30 44 57 20 43 44 57 30 35 30 30 41 41 53 44 30 2d 4d 30 42 32 20 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 10 80 96: 00 00 00 2f 01 40 00 00 00 00 07 00 ff 3f 10 00 3f 00 10 fc fb 00 00 01 ff ff ff 0f 00 00 07 00 03 00 78 00 78 00 78 00 78 00 00 00 00 00 00 00 144: 00 00 00 00 00 00 1f 00 06 17 00 00 44 00 40 00 fe 01 00 00 6b 74 61 7f 23 41 69 74 41 bc 23 41 7f 40 4a 00 4a 00 00 00 fe ff 00 00 fe 80 00 00 192: 00 00 00 00 00 00 00 00 30 60 38 3a 00 00 00 00 00 00 00 00 00 00 00 00 01 50 e0 4e 81 ac a1 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1c 40 240: 1c 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 21 00 00 00 00 00 00 00 00 00 ce 16 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 288: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 336: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 384: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 37 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 432: 00 00 00 00 00 00 00 00 00 00 00 00 1e 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 10 00 00 00 00 00 00 00 00 480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a5 60 VSC_ENABLE: fis: 27 80 80 45 01 44 57 a0 00 00 00 44 00 00 00 02 00 00 00 00 SMART: fis: 27 80 b0 d6 be 4f c2 a0 01 44 57 45 01 00 00 02 00 00 00 00 data_out: 57 00 1b 00.. SMART: fis: 27 80 b0 d6 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00 data_out: 0: e0 93 04 00 f2 0b 00 00 d3 de 43 00 ff ff ff ff 00 00 00 00 78 57 55 00 3c 2d 4c 00 60 70 4b 00 66 70 4b 00 00 00 00 00 00 00 00 00 f2 0b 00 00 48: d4 2e 4c 00 60 70 4b 00 d8 67 4c 00 08 60 4c 00 6e 4f 44 00 66 70 4b 00 14 00 00 00 14 00 00 00 f2 0b 00 00 b2 80 43 00 64 00 00 00 a0 00 00 00 96: 50 40 55 00 73 00 83 00 73 00 63 00 e8 06 00 00 d4 33 03 00 00 00 00 00 00 00 00 00 00 00 00 00 b7 01 87 01 83 00 83 00 e8 06 00 00 38 00 00 00 144: d4 2d 4c 00 a4 2d 4c 00 21 00 00 00 19 00 00 00 00 00 00 00 00 03 00 00 46 32 21 00 00 00 6e 0d 15 00 c3 00 22 04 00 00 00 00 00 00 00 00 46 32 192: d8 2d 46 32 00 02 00 00 00 03 00 00 46 32 00 00 46 32 00 00 00 03 00 00 81 00 00 00 e8 06 00 00 71 61 4c 00 1c 2e 4c 00 f8 2d 4c 00 21 00 00 00 240: 19 00 00 00 19 00 00 00 01 ff 00 00 b7 01 00 00 87 01 00 00 83 00 00 00 af 01 00 00 b6 05 00 00 37 01 00 00 00 32 00 00 c3 05 00 00 60 00 00 00 288: 19 00 00 00 01 00 00 00 58 61 4c 00 3c 2e 4c 00 01 00 00 00 58 61 4c 00 19 00 00 00 19 00 00 00 b7 01 00 00 00 00 00 00 af 01 00 00 af 01 00 00 336: 1f 01 48 00 a7 01 00 00 44 32 00 00 19 00 00 00 00 00 00 00 58 61 4c 00 19 00 00 00 c2 55 4b 00 59 a9 47 00 19 00 00 00 71 61 4c 00 86 00 00 00 384: c2 55 4b 00 00 06 00 00 0a 00 00 00 05 9a 47 00 d7 80 4a 00 70 5c 47 00 44 2f 4c 00 00 0a 00 00 ac 2e 4c 00 7c 5c 47 00 73 2e 4c 00 05 9b 47 00 432: c2 55 4b 00 f1 ff ff ff ff ff ff ff d8 67 4c 00 18 00 00 00 d8 73 20 00 d8 67 4c 00 64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 480: 00 00 00 00 00 00 00 00 00 51 43 00 ef 20 46 00 17 02 00 00 f7 20 46 00 14 00 00 00 14 00 00 00 SMART: fis: 27 80 b0 d6 be 4f c2 a0 bf 00 00 d6 01 01 00 02 00 00 00 00 data_out: 57 00 1a 00.. SMART: fis: 27 80 b0 d5 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00 data_in: e0 93 04 00.. SMART: fis: 27 80 b0 d6 be 4f c2 a0 bf 00 00 d5 01 00 00 02 00 00 00 00 data_out: 2a 00 02 00 02 00 0d 00 16 00 01 00.. SMART: fis: 27 80 b0 d6 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00 data: 8a 2c 4c 00 e0 93 04 00.. SMART: fis: 27 80 b0 d6 be 4f c2 a0 bf 00 00 d6 01 01 00 02 00 00 00 00 data_out: 2a 00 01 00 02 00 0d 00 16 00 01 00 SMART: fis: 27 80 b0 d5 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00 data_in: 8a 00.. VSC_DISABLE: fis: 27 80 80 44 bf 44 57 a0 00 00 00 d5 00 00 00 02 00 00 00 00 ---------------------------------------------------------------------------------------------------------------------------------------------------- wdidle3-30.5.sata: change idle3 timeout to 30.5(?) seconds. IDENTIFY: fis: 27 80 ec 44 01 00 00 a0 00 00 00 d5 01 00 00 02 00 00 00 00 data_in: 0: 7a 42 ff 3f 37 c8 10 00 00 00 00 00 3f 00 00 00 00 00 00 00 20 20 20 20 57 20 2d 44 4d 57 56 41 30 35 32 33 35 36 36 38 00 00 ff ff 32 00 31 30 48: 30 2e 41 30 31 30 44 57 20 43 44 57 30 35 30 30 41 41 53 44 30 2d 4d 30 42 32 20 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 10 80 96: 00 00 00 2f 01 40 00 00 00 00 07 00 ff 3f 10 00 3f 00 10 fc fb 00 00 01 ff ff ff 0f 00 00 07 00 03 00 78 00 78 00 78 00 78 00 00 00 00 00 00 00 144: 00 00 00 00 00 00 1f 00 06 17 00 00 44 00 40 00 fe 01 00 00 6b 74 61 7f 23 41 69 74 41 bc 23 41 7f 40 4a 00 4a 00 00 00 fe ff 00 00 fe 80 00 00 192: 00 00 00 00 00 00 00 00 30 60 38 3a 00 00 00 00 00 00 00 00 00 00 00 00 01 50 e0 4e 81 ac a1 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1c 40 240: 1c 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 21 00 00 00 00 00 00 00 00 00 ce 16 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 288: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 336: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 384: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 37 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 432: 00 00 00 00 00 00 00 00 00 00 00 00 1e 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 10 00 00 00 00 00 00 00 00 480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a5 60 VSC_ENABLE: fis: 27 80 80 45 01 44 57 a0 00 00 00 44 00 00 00 02 00 00 00 00 SMART: fis: 27 80 b0 d6 be 4f c2 a0 01 44 57 45 01 00 00 02 00 00 00 00 data_out: 57 00 1b 00.. SMART: fis: 27 80 b0 d6 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00 data_out: 0: 24 77 00 00 f2 0b 00 00 d3 de 43 00 ff ff ff ff 00 00 00 00 78 57 55 00 3c 2d 4c 00 60 70 4b 00 67 70 4b 00 00 00 00 00 00 00 00 00 f2 0b 00 00 48: d4 2e 4c 00 60 70 4b 00 d8 67 4c 00 08 60 4c 00 6e 4f 44 00 67 70 4b 00 14 00 00 00 14 00 00 00 f2 0b 00 00 b2 80 43 00 64 00 00 00 a0 00 00 00 96: 50 40 55 00 73 00 83 00 73 00 63 00 e8 06 00 00 d4 33 03 00 00 00 00 00 00 00 00 00 00 00 00 00 b7 01 87 01 83 00 83 00 e8 06 00 00 38 00 00 00 144: d4 2d 4c 00 a4 2d 4c 00 21 00 00 00 19 00 00 00 00 00 00 00 00 03 00 00 46 32 21 00 00 00 6e 0d 15 00 c3 00 22 04 00 00 00 00 00 00 00 00 46 32 192: d8 2d 46 32 00 02 00 00 00 03 00 00 46 32 00 00 46 32 00 00 00 03 00 00 81 00 00 00 e8 06 00 00 71 61 4c 00 1c 2e 4c 00 f8 2d 4c 00 21 00 00 00 240: 19 00 00 00 19 00 00 00 01 ff 00 00 b7 01 00 00 87 01 00 00 83 00 00 00 af 01 00 00 b6 05 00 00 37 01 00 00 00 32 00 00 c3 05 00 00 60 00 00 00 288: 19 00 00 00 01 00 00 00 58 61 4c 00 3c 2e 4c 00 01 00 00 00 58 61 4c 00 19 00 00 00 19 00 00 00 b7 01 00 00 00 00 00 00 af 01 00 00 af 01 00 00 336: 1f 01 48 00 a7 01 00 00 44 32 00 00 19 00 00 00 00 00 00 00 58 61 4c 00 19 00 00 00 c2 55 4b 00 59 a9 47 00 19 00 00 00 71 61 4c 00 86 00 00 00 384: c2 55 4b 00 00 06 00 00 0a 00 00 00 05 9a 47 00 d7 80 4a 00 70 5c 47 00 44 2f 4c 00 00 0a 00 00 ac 2e 4c 00 7c 5c 47 00 73 2e 4c 00 05 9b 47 00 432: c2 55 4b 00 f1 ff ff ff ff ff ff ff d8 67 4c 00 18 00 00 00 d8 73 20 00 d8 67 4c 00 64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 480: 00 00 00 00 00 00 00 00 00 51 43 00 ef 20 46 00 4c 02 00 00 f7 20 46 00 14 00 00 00 14 00 00 00 SMART: fis: 27 80 b0 d6 be 4f c2 a0 bf 00 00 d6 01 01 00 02 00 00 00 00 data_out: 57 00 1a 00.. SMART: fis: 27 80 b0 d5 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00 data_in: 24 77 00.. SMART: fis: 27 80 b0 d6 be 4f c2 a0 bf 00 00 d5 01 00 00 02 00 00 00 00 data_out: 2A 00 02 00 02 00 0D 00 16 00 01 00.. SMART: fis: 27 80 b0 d6 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00 data_out: 81 2c 4c 00 24 77 00 SMART: fis: 27 80 b0 d6 be 4f c2 a0 bf 00 00 d6 01 01 00 02 00 00 00 00 data_out: 2a 00 01 00 02 00 0d 00 16 00 01 00.. SMART: fis: 27 80 b0 d5 bf 4f c2 a0 00 01 00 d6 01 00 00 02 00 00 00 00 data_in: 81 00.. VSC_DISABLE: fis: 27 80 80 44 bf 44 57 a0 00 00 00 d5 00 00 00 02 ---------------------------------------------------------------------------------------------------------------------------------------------------- hdparm-9.43/hdparm.h0000644000000000000000000000565111701621643013056 0ustar rootroot/* Some prototypes for extern functions. */ //#undef __KERNEL_STRICT_NAMES #include #if !defined(__GNUC__) && !defined(__attribute__) #define __attribute__(x) #endif #define lba28_limit ((__u64)(1<<28) - 1) void identify (__u16 *id_supplied); void usage_error(int out) __attribute__((noreturn)); void no_scsi (void); void no_xt (void); void process_dev (char *devname); int sysfs_get_attr (int fd, const char *attr, const char *fmt, void *val1, void *val2, int verbose); int sysfs_set_attr (int fd, const char *attr, const char *fmt, void *val_p, int verbose); int get_dev_geometry (int fd, __u32 *cyls, __u32 *heads, __u32 *sects, __u64 *start_lba, __u64 *nsectors); int get_dev_t_geometry (dev_t dev, __u32 *cyls, __u32 *heads, __u32 *sects, __u64 *start_lba, __u64 *nsectors); int do_filemap(const char *file_name); int do_fallocate_syscall (const char *name, __u64 bytecount); int fwdownload(int fd, __u16 *id, const char *fwpath, int xfer_mode); void dco_identify_print (__u16 *dco); int set_dvdspeed(int fd, int speed); int fd_is_raid (int fd); int wdidle3_set_timeout (int fd, unsigned char timeout); int wdidle3_get_timeout (int fd, unsigned char *timeout); void wdidle3_print_timeout (unsigned char timeout); unsigned char wdidle3_msecs_to_timeout (unsigned int msecs); extern const char *BuffType[4]; struct local_hd_big_geometry { unsigned char heads; unsigned char sectors; unsigned int cylinders; unsigned long start; }; struct local_hd_geometry { unsigned char heads; unsigned char sectors; unsigned short cylinders; unsigned long start; /* mmm.. on 32-bit, this limits us to LBA32, 2TB max offset */ }; enum { /* ioctl() numbers */ HDIO_DRIVE_CMD = 0x031f, HDIO_DRIVE_RESET = 0x031c, HDIO_DRIVE_TASK = 0x031e, HDIO_DRIVE_TASKFILE = 0x031d, HDIO_GETGEO = 0x0301, HDIO_GETGEO_BIG = 0x0330, HDIO_GET_32BIT = 0x0309, HDIO_GET_ACOUSTIC = 0x030f, HDIO_GET_BUSSTATE = 0x031a, HDIO_GET_DMA = 0x030b, HDIO_GET_IDENTITY = 0x030d, HDIO_GET_KEEPSETTINGS = 0x0308, HDIO_GET_MULTCOUNT = 0x0304, HDIO_GET_NOWERR = 0x030a, HDIO_GET_QDMA = 0x0305, HDIO_GET_UNMASKINTR = 0x0302, HDIO_OBSOLETE_IDENTITY = 0x0307, HDIO_SCAN_HWIF = 0x0328, HDIO_SET_32BIT = 0x0324, HDIO_SET_ACOUSTIC = 0x032c, HDIO_SET_BUSSTATE = 0x032d, HDIO_SET_DMA = 0x0326, HDIO_SET_KEEPSETTINGS = 0x0323, HDIO_SET_MULTCOUNT = 0x0321, HDIO_SET_NOWERR = 0x0325, HDIO_SET_PIO_MODE = 0x0327, HDIO_SET_QDMA = 0x032e, HDIO_SET_UNMASKINTR = 0x0322, HDIO_SET_WCACHE = 0x032b, HDIO_TRISTATE_HWIF = 0x031b, HDIO_UNREGISTER_HWIF = 0x032a, CDROM__SPEED = 0x5322, }; #define START_LBA_UNKNOWN (~0ull) /* Some systems define BLKGETSIZE64 with a "u64" arg, * but without supplying a typedef for u64. * The only real workaround here is to define it locally, * instead of using the system def from */ #ifdef BLKGETSIZE64 #undef BLKGETSIZE64 #endif #define BLKGETSIZE64 _IOR(0x12,114,__u64) hdparm-9.43/Changelog0000644000000000000000000005577312051264032013250 0ustar rootroothdparm-9.43 - rearrange flag execution so that the idle/standby/sleep "now" flags are executed last. hdparm-9.42 - fix ordering of -S -y flags - spelling, typo, and formatting fixes for manpage and others - set block-count to 1 for Security commands sent via SAT (sgio) - use FIGETBSZ to determine filesystem block size for fibmap -- needed for FAT - fix master password revcode handling - try and fix reg_flags (again!) for old IDE taskfile ioctls - fixed '&&' bug in dco_identify code - force sector dumps (read-sector, identify, ..) to use le16 output format hdparm-9.41 - proper SCT identify info courtesy of Leonid Evdokimov - updated raid1ext4trim.sh-1.5 script hdparm-9.40 - avoid HDIO_GETGEO_BIG when possible (doesn't exist in linux-2.6.xx and beyond) - pad secure erase timeouts by 30minutes rather than 5minutes. hdparm-9.39 - added -R flag to control Read-Write-Verify feature, courtesy of Gordan Bobic - nuked leftover sgio.c.orig file hdparm-9.38 - updated wiper.sh to allow all SCSI_DISK major numbers - updated handing for very long SECURITY-ERASE times - added -J flag for wdidle3 set/get hdparm-9.37 - handle raid1 start_lba values, and show -1 for indeterminte raid start_lba values - abort --fibmap when start_lba is indeterminate - updated wiper.sh to fix a kink with hfsplus filesystems - updated wiper.sh to no longer rely on the obsolete "rdev" command hdparm-9.36 - udpated raid1ext4trim.sh script to version 1.4 - updated wiper.sh to support hfsplus and ntfs filesystem types, courtesy of Heiko Wegeler - updated wiper.sh with new flag to enable unattended operation, and handle SIGPIPE - updated manpage to indicate max sector range of 65335 for TRIM hdparm-9.35 - third go at fixing cdb issues, fixing -B flag. Got it this time (finally). hdparm-9.34 - fix bad/missing cdb transfer length field for IDENTIFY and some other commands hdparm-9.33 - fix AHCI issues in sg16(): don't ask for sense_data on DATA-xfer commands - fix compiler warnings on old systems - fixed compilation on old systems lacking __be16 hdparm-9.32 - fix b0rked (since 9.27?) SET_FEATURES commands; eg. -B, -M, etc.. hdparm-9.31 - fix oflags bug in do_taskfile_cmd(). - change --user-master to default to "user" instead of "master", for better drive compatibility. - use drive-supplied timeout (plus a little) for security-erase commands - use 15 secs as default general timeout (instead of 5) - ensure timeouts get passed through to sg16 correctly - increment revision-code when setting master-password, rather than always using 0xff11 - update HPA description in manpage hdparm-9.30 - report word[105] in -I : max 512-byte blocks of range-data per DSM/Trim command - fix wiper.sh/hdparm to use only as many LBA ranges per TRIM as the drive can handle - manpage / help-text cleanups from Benno Schulenberg hdparm-9.29 - add --offset for use with -t, to get timings from middle/end of drive, courtesy of Sergei Kirjanov - restrict --trim-sector-ranges-stdin to small TRIM commands on most drives - fix w62 bug in -I - dump all data bytes with --verbose - warn about bad/missing sense data, but continue regardless - show in/out data[] separately with --verbose - Add reporting to -I for sata3 signaling speed. - force use of ATA_16 for all commands to ATAPI devices. - supply a sector count of "1" for IDENTIFY commands, to satisfy buggy USB3 bridges. hdparm-9.28 - check for EBADE for IDE/ATAPI compatibility with recent kernels - always issue both methods when setting DVD speed with -E - use /usr/sbin/rdev to find rootdev in wiper.sh - fix reporting of Sector-0 offset, from Martin Petersen - first crack at decoding the "WD Idle3" vendor-unique command (disabled by default) hdparm-9.27 - wiper.sh updated to wiper-2.3 - fix definition of reg_flags in sgio.h to work with old IDE drivers again hdparm-9.26 - wiper.sh updated to wiper-2.2 - zero-day bugfix for "hdparm -i" on model names with embedded blanks - bugfix for --security-erase-enhanced, courtesy of Cyril.Guyot@hitachigst.com - set _FILE_OFFSET_BITS in geom.c (still need to do this in hdparm.c someday) - added reporting for "Deterministic read ZEROs after TRIM" feature hdparm-9.25 - slightly tidier output from --trim-* commands - restrict --trim-sector-ranges-stdin to limit from /sys/block/sd?/queue/max_sectors_kb - updated wiper.sh to use --trim-sector-ranges-stdin rather than --trim-sector-ranges hdparm-9.24 - fixed malloc() bug in --trim-sector-ranges: it was allocating half the required size (oops). hdparm-9.23 - minor cosmetic changes in fibmap.c - added --trim-sector-ranges-stdin for wiper.sh-2.0 - tightened up excess-args checking on a number of flags - added name to version line hdparm-9.22 - added fsync() call inside --fallocate - fixed fibmap.c to work around an observed ext4 bug with FIEMAP's "LAST" flag - added detailed comments to wiper.sh - more rework of wiper.sh, added xfs support, added generic online support - twiddled the code in geom.c slightly - cosmetic changes in fibmap.c and the manpage description of --fibmap - added kernel patch for compat_ioctl::fiemap support hdparm-9.21 - fixes and (big) speedups to wiper.sh (v1.2) script hdparm-9.20 - unified the online/offline wiper scripts into a single wiper.sh script - fixed bug whereby the wiper scripts generated command-lines too long for bash - fixed non-zero exit status from successful --trim-sector-ranges - reimplemented --trim-sector-ranges to use sg16() directly, with aligned data - allow wiper scripts to issue TRIM with up to 255 sectors of LBA-range data - added kernel patch file for sil24 protocol fix, needed for wiper/TRIM - cosmetic updates to the wiper scripts - fixed confirmation prompt text for --trim-sector-ranges - fixed manpage example for --trim-sector-ranges - removed some dead code (previously #if 0'd) hdparm-9.19 - fixed compile of fallocate.c on older systems - fixed man page description of --fallocate (parameters were reversed) hdparm-9.18 - fixed -E (set cd/dvd streaming speed) - updated man page for --fallocate, indicating ext4/xfs only - bumped max_sectors to 8000000 per TRIM in wiper scripts - s/awk/$GAWK/ in wiper.sh.online script - fixed Changelog for 9.17 hdparm-9.17 - added wiper/ subdirectory with preliminary SSD-wiper (TRIM) scripts - nuked kernel_patches/ subdirectory - Capitalize first word of each line of help output - added ioctl(FIEMAP) support to --fibmap - added --fallocate flag - added --trim-sector-ranges flag - removed --trim-sectors flag - removed --fibmap-sector flag - first cut at wiper.sh script, to trim unused space on a non-rw ext[234] filesystem - embed VERSION string for easier digging out with strings(1) hdparm-9.16 - new protocol-specific forms of --fwdownload flags - added --trim-sectors flag - prevent segfaults when get_identify_data() fails - added full word69 features reporting for -I - added BuffSize=unknown to -i hdparm-9.15 - fix sgio.c LBA48 bugs on big-endian machines - fix -m to work with libata - added development snapshot of --erase-sectors (256) command (do not use) - added development snapshot of --format-track (256) command (do not use) hdparm-9.14 - display DSM determinate/indeterminate TRIM support in -I output - tidy output of CFA features from -I - switch back to O_RDONLY for everything, to keep Debian/udevd happy http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=522091 Note that the kernel returns EFAULT rather than EPERM from SG_IO for non-root users, and *no* SG_IO functions work for non-root users now. hdparm-9.13 - fix O_DIRECT (--direct) for arch's other than x86 - strip leading/trailing spaces from -i model/fwrev/serno strings hdparm-9.12 - added logical/physical sector size reporting - updated -I output with SATA-2.6 additions - support APM level retrieval with -B flag - updated -C output to match ATA8 - added "form factor" and "rotation" display to -I, courtesy of Martin K.Petersen. hdparm-9.11 - switch back to ATA_16 by default: required by libata for ATAPI devices - add --prefer-ata12 to force use of ATA_12 when needed (some USB enclosures) hdparm-9.10 - try and improve CF card detection - fix display of mwdma modes 3,4 for CF cards hdparm-9.9 - recalculate cyls when kernel returns a truncated value hdparm-9.8 - fix -N to correctly use top 4 LBA bits on non-LBA48 drives hdparm-9.7 - FIX RATHER NASTY LBA48/LBA28 CONFUSION BUGS - use ATA_12 by default (helps USB), ATA_16 only when needed for LBA48 hdparm-9.6 - fix -N for 1.5TB drives (from Justin Maggard) hdparm-9.5 - byteswap ID strings for fwdownload workarounds - Makefile fixes for $(STRIP) from Wolfram Sang hdparm-9.4 - nuked --fwdownload80 in favour of model-specific workarounds - use mlock() instead of MAP_POPULATE in fwdownload.c - issue SET_STREAMING command as part of -E (for newer CD/DVD drives) courtesy of Thomas Orgis and Thomas Fritzsche" . hdparm-9.3 - new --idle-immediate and --idle-unload commands hdparm-9.2 - fix WWN output from -I hdparm-9.1 - tidy up output from --dco-identify, add more info to manpage - add kernel (device driver) bug detection/warning to -N output hdparm-9.0 - update debian directory contents - add --dco-freeze, --dco-identify, --dco-restore flags - fix sgio.c to be more clever around the lba28 boundary - add supposedly obsolete "cache/buffer size" reporting to -I - new --fwdownload flag - fix error reporting from sg16(). - dump entire returned sense desc[] in sgio.c with --verbose hdparm-8.9 - support /sys/block symlinks (some kernels seem to have those). hdparm-8.8 - fix -r, -a so that they display their values again (duh). - define BLKGETSIZE64 locally to avoid broken system headers that use u64 with it. - update man page to indicate that --security-* flags must be standalone - fix -Q to permit querying queue_depth (was broken in v8.7). hdparm-8.7 - fixes to permit building against older kernels which lack SG_IO - added build script for empeg systems - removed -R, -U flags: kernel support is broken and being removed - fixed IO_support output - prevent error messages from default flags - added sysfs.c, geom.c, fibmap.c - use sysfs for device start_lba/nsectors values whereever possible (for >= 2TB drives) - new standalone --fibmap and --fibmap-sector flags - converted -Q to access the queue_depth attribute from sysfs (now works for SATA!) - fixed readonly issue with optical drives that some people noticed hdparm-8.6 - add partition safeguards to r/w sector and make_bad_sector hdparm-8.5 - fix u8->u16 bug in security commands for all of 8.x series, Christian Franke - try and quiet errors from flush_buffer_cache() hdparm-8.4 - oops: v8.3 broke --write-sector. Fix it again. hdparm-8.3 - fixed -i display for udma6 - try and exit with errno on fail paths, from Ladislav Michnovic hdparm-8.2 - clear feat register for safety with SET_MAX_ADDRESS command - add note to manpage regarding possible -N transient failures - IDE_TASKFILE bug fixes and cleanups: works with old IDE driver now - fix misreporting of dma modes on some SATA-ATAPI bridged drives hdparm-8.1 - fixed -U parameter bug - added ATA8 minor revision info to -I, courtesy of chrfranke - added WorldWideNumber to -I, courtesy of Raksac hdparm-8.0 - added --make-bad-sector to deliberately create a media error - added --write-sector (aka. --repair-sector) to repair a media error - added --read-sector to test for a media error - Makefile dependency tweaks - added -N (get/set max address/HPA) flag, courtesy of Jakub Bogusz - fixed LBAsects output from -i to use LBA48 values when available - fixed alternate opcode for SLEEPNOW - lots of changes/fixes to sgio.c to support more commands - add detection of buggy Sandisk 16MB CF card - fixed tf_to_lba() bug, courtesy of Jakub Bogusz hdparm-7.7 - fixed bug whereby old data was shown after settings changed (eg. with -W0) - removed old notes about a "correction factor" from man page -tT descriptions - retry open with O_RDONLY if O_RDWR fails with errno==EROFS hdparm-7.6 - added -F flag to flush on-drive write cache buffer - replaced use of shm* functions with of mmap()/mlock() - removed gcc -Wextra flag --> unsupported on Debian Sarge - re-allow use of --security-freeze in combination with other flags hdparm-7.5 - beef up warnings for -s1 flag, as people seem to be ignoring them hdparm-7.4 - ignore ENOTTY response from DRIVE_CMD(NULL) - decode CFA advanced timing information hdparm-7.3 - fixed spelling of --drq-hsm-error in -h output - fixed SG_IO CDB[2] bits for better SAT compliance - fixed version number (v7.2 has "7.1" as version, doh!) - added #ifdef around use of BLKGETSIZE64 - manpage updated - flush_cache before/after -W0 action - use O_RDWR instead of O_RDONLY for better SG_IO compatibility hdparm-7.2 - tweak -C - added more debug info from --verbose - added --drq-hsm-error to test libata EH (VERY DANGEROUS, do not use) - fixed breakage when used with old IDE driver hdparm-7.1 - big-endian fixes for -I, --Istdin, --Istdout - cody tidying in sgio.c - updated help/manpage for -v - marked -s1 as (DANGEROUS) hdparm-7.0 - new command-line parser - allow any chars (except 0x00) in security passwords - fixed -s manpage format error - updated -W manpage description - major internal rework in hdparm.c - added SET_FEATURES subcommand 0x07 to the -s0 sequence (the kernel will eventually have to do this automatically) - fixed duplicate display of udma modes 3,4,5 with -i - added Timed-Command-Completion (TLC) data for -I - added support for SG_IO (SAT) ATA_16 command transport - ignore case for longargs (eg. --istdout or --Istdout) - remove dependencies on - added query wcache (-W) - enhanced query acoustic (-M) - added kernel_patches directory with patches for ATAPI support hdparm-6.9 - added -s flag to control power-up in standby (thanks to chrfranke) - make --Istdin more robust - added -I recognition of SMART Command Transport (SCT) (thanks to chrfranke). - fix X2 over-reporting of -T results - add udma 3/4/5 modes to the -i results hdparm-6.8 - improve parsing/operation of --Istdin function hdparm-6.7 - don't default to "-v" when only new "--" longopts are used. - calculate integrity word if not correct - remove used code/parameter from identify() - fix "(null)" strings from the "Drive conforms to" line of -I - tidied up usage of prefix vars in Makefile - fix bug in -C implementation - new -H flag for (Hitachi) drive temperature hdparm-6.6 - fix build for Redhat/Fedora systems. - disable security commands when building on Redhat/Fedora, as they lack the required data structures in the system headers. hdparm-6.5 - fix -I bugs from version 6.4. hdparm-6.4 - Makefile updates from Mikkel Krautz. - manpage updates / corrections. - fixed bug in -C code. - major updates to bring -I information up to current specs. hdparm-6.3 - added reporting of ATA revision numbers > 7 hdparm-6.2 - eliminated short form (-F) of --security-freeze flag - completely revamped ATA Security Commands (now they actually work sometimes) courtesy of Leonard den Ottolander (a BIG thank-you!) hdparm-6.1 - fix BLKGETSIZE bug introduced in 6.0 - man page clarification for -M (courtesy Stephen Gran) hdparm-6.0 - correct usage of BLKGETSIZE64 (returns bytes instead of sectors) - Added ATA Security switches (Benjamin Benz bbe[AT]heise[DOT]de) hdparm-5.9 - fix security-mode display (Franz Lehner) - fixed -W bug (Stephan Gran) hdparm-5.8 - added HDIO_SET_WCACHE support to -W - fixed double byteswap for big endian - fixed %lld warnings on 64-bit architectures - "hdparm -h" now goes to stdout instead of stderr hdparm-5.7 - fixed output of NULs in -I string fields - fixed big-endian -I crashes from 5.6 - removed remains of defunct major-number checks - added support for BLKGETSIZE64 ioctl internally - added --direct flag to use O_DIRECT on device open - renamed -Istdin to --Istdin - renamed -Istdout to --Istdout - allow other flags to follow any of: -I, --Istdin, --Istdout hdparm-5.6 - fixed reversed device names in idectl script - renamed readahead variables to avoid new glibc conflicts - added -Istdout flag to dump IDENTIFY data as hex - removed MAJOR number checks to open up hdpar for SATA-SCSI drivers hdparm-5.5 - added limited support for SCSI(-controlled) CDROM/optical drives - incorporated various -I clean-up patches from Maciej W. Rozycki - removed wordswap from capacity calculation: latest kenels already do it - fixed slight issues with ATA Revision display - added debian scripts from Stephan Gran hdparm-5.4 - fixed 2.5.67 compile error (LVM_BLK_MAJOR) - first attempt to support BIG_ENDIAN in identify.c - converted -T and -t to use minimum timing intervals (2 and 3 seconds) - fix device size overflow issue with -t - hdparm -I: fixed device size output for devices with reversed endian. - hdparm -i: added explanation for "*" - slight formatting change for -Tt outputs - fixed "(illegal value)" formatting - added CCISS_MAJOR - incorporated RedHat-8.0 and other patches hdparm-5.3 - get rid of malloc() - fix(?) BIG_ENDIAN problems - fix -tT to work on very small drives - fix -p output for parameters >= 100 hdparm-5.2 - compile fixes for latest 2.5.xx kernels - moved -s from CFLAGS to LDFLAGS - fixed manpage formatting error from 5.1 - -i was broken due to non-compatible changes in 2.5.xx - the fix for -i now breaks hdparm -i for really old kernels hdparm-5.1 - fixed segfault from -i on older drives hdparm-5.0 - updated -I to most recent ATA6 draft standard - added -Istdin to process input from /proc/ide/hd*/identify - CFLAGS Makefile fix from Kevin P. Fleming - -X mode names from Martin - tweaked #include's for Slackware - eliminate bogus "udma10" from -I output - formatting fixes for -I from various people - clean compile fixes from Steven Augart - allow -d parameters other than 0/1 for special uses - removed busstate, acoustic, and nowerr from "-v" subset - support for Pacific Digital ADMA-100i hdparm-4.9 - fixed compile error with some kernels hdparm-4.8 - updated -Q to take queue depth as parameter value hdparm-4.7 - add -z option for BLKRRPART ("re-read partition table") - add -Q option to turn on/off tagged queuing - add -M option for acoustic feature set - allow ANY value for the parameter to '-p' (user beware!) - applied APM fixes from Gildas Bazin hdparm-4.6 - fix version numbers, update DMA notes in manpage hdparm-4.5 - ENDIAN tidyup, GETGEO fixes, Makefile fixes, mostly courtesy of Maciej W. Rozycki hdparm-4.4 - add -b option, courtesy of Tim Hockin hdparm-4.3 - display most fields as unsigned rather than signed values hdparm-4.2 - completely new format/implementation of "-I" with much more detail - code cleanups for newer libs/compilers hdparm-4.1 - merge some changes from Andre - code cleanups from Neil Macvicar and others - improved output from -i for newer features - incorporate RedHat-7.0 patches hdparm-4.0 - no such release hdparm-3.9 - added IDE_MAJOR[6-9] - nuked the LBAsects display (again!) hdparm-3.8 - fix display of drive capacity (Stephane Eranian ) - new -E "set cdrom speed" option (Matthias Oster ) - new -R and -U "(un)register hwif" options (Christian Lademann ) - new contrib subdirectory with contributed scripts from users. - support for display of newer PIO and DMA/UDMA modes hdparm-3.7 - use O_NONBLOCK for open(), to handle drives with media removed - make "HDIO_DRIVE_CMD failed" messages slightly more verbose - get rid of "HDIO_GET_MULTCOUNT failed" from -i on non-disks hdparm-3.6 - added new -V (version) option - removed confusing LBA "remapping" geometry calculation - small fix to "-I" - Courtesy of Andrzej Krzysztofowicz : - added support for old XT drives - transfer display in kB/s rather than in MB/s for slow disks - fixed -v for SCSI disks - added -L to lock/unlock door of removeable harddisks - added udma modes 3,4,5.. - updated Makefile to use "destdir" prefix -- Ytiddo hdparm-3.5 - fixed compilation under older kernels - fixed udma mode info under older kernels hdparm-3.4 - added udma mode info - added support for SCSI_DISK_MAJOR{0-7} - fix -h (help) to show -y instead of -Y for "standby" - fix display of drive SerialNo: 20 chars instead of just 8 - modify -C -y -Y to each try both possible command codes - add interpretations for use of -X to set UltraDMA modes - add -D for enable/disable drive defect-mgmt hdparm-3.3 - add -C, -y, and -Y flags for IDE power management hdparm-3.2 - force BLKFLSBUF after -T or -t -- kmg@barco.com - fix minor -T/-t mixup in manpage -- hankedr@mail.auburn.edu hdparm-3.1 - permit "-p" with values larger than 5 (for cmd640 readahead) - updated version number on manpage (was way out of date!) hdparm-3.0 - always touch each sector in read_big_block() -- Jon Burgess - move cache timings to new -T option -- piercarl@sabi.demon.co.uk hdparm-2.9: - updated author's email address hdparm-2.8: - fixed compilation against older kernels - changed "KB" to "kB" - support for "-t" on "md" devices (from boris@xtalk.msk.su) - removed "Estimating raw driver speed" message from "-t" because it is likely very incorrect on faster systems - added "-I" to re-issue IDENTIFY command to drive hdparm-2.7: - fixed .lsm file - fixed "hdparm -c" (broken in 2.6) (kudos to clive@epos.demon.co.uk) hdparm-2.6: - tidied up manpage - added support for HDIO_SET_PIO_MODE (kernel 1.3.61+) - reduced codesize by combining fprintf's in help hdparm-2.5: - fixed -i display of eight character fwrev field - rearranged output of -v hdparm-2.4: - added flag to turn on/off "using_dma" flag (kernel 1.3.22+) - added warnings about CMD-640B and RZ1000 bugs to manpage ("-u1") - cleaned up output from -c, added text interpretations - added -c functionality to -v - removed -a functionality from -v for scsi drives - added -n flag for ignoring the "write error" bit from a drive - moved binary from /usr/local/bin to /usr/local/sbin - added support for 3rd/4th IDE interfaces hdparm-2.3: - added -c flag for controlling 32-bit chipset features with 1.2.9+ - fixed error messages when -t used on SCSI drives - fixed date on man page to read 1995 rather than 1994 (late change) hdparm-2.2: - fixed a memory problem in my PC, and now BLKFLSBUF seems safe again - fixed "help" line for "-v" hdparm-2.1: - fixed formatting of DMA info line - added "(DANGEROUS)" to -u,-X,-W options in "hdparm -h" - changed order in which settings are applied: placed standby last hdparm-2.0: - added this file to the distribution - added -f and -q flags to hdparm.c and hdparm.8 - added -N to gcc in makefile - changed installation paths to /usr/local/* in makefile - removed meaningless CPU% measures - removed -s and -x flags - added new -AKPSWXZ flags using new HDIO_DRIVE_CMD ioctl - removed BLKFLSBUF ioctl from everywhere except -t (there may be a kernel bug in the implementation of BLKFLSBUF when used on an active (mounted rw) filesystem). - most features now require (E)IDE driver v2.6 or higher (ide-2.6.patch.65+.gz) hdparm-9.43/fwdownload.c0000644000000000000000000001220211232056517013731 0ustar rootroot/* * Copyright (c) EMC Corporation 2008 * Copyright (c) Mark Lord 2008 * * You may use/distribute this freely, under the terms of either * (your choice) the GNU General Public License version 2, * or a BSD style license. */ #include #include #include #include #include #include #include #include #include #include #include #include "hdparm.h" #include "sgio.h" /* glibc-2.2 / linux-2.4 don't have MAP_POPULATE */ #ifndef MAP_POPULATE #define MAP_POPULATE 0 #endif extern int verbose; /* Download a firmware segment to the drive */ static int send_firmware (int fd, unsigned int xfer_mode, unsigned int offset, const void *data, unsigned int bytecount) { int err = 0; struct hdio_taskfile *r; unsigned int blockcount = bytecount / 512; unsigned int timeout_secs = 20; __u64 lba; lba = ((offset / 512) << 8) | ((blockcount >> 8) & 0xff); r = malloc(sizeof(struct hdio_taskfile) + bytecount); if (!r) { if (xfer_mode == 3) { putchar('\n'); fflush(stdout); } err = errno; perror("malloc()"); return err; } init_hdio_taskfile(r, ATA_OP_DOWNLOAD_MICROCODE, RW_WRITE, LBA28_OK, lba, blockcount & 0xff, bytecount); r->lob.feat = xfer_mode; r->oflags.lob.feat = 1; r->iflags.lob.nsect = 1; if (data && bytecount) memcpy(r->data, data, bytecount); if (do_taskfile_cmd(fd, r, timeout_secs)) { err = errno; if (xfer_mode == 3) { putchar('\n'); fflush(stdout); } perror("FAILED"); } else { if (xfer_mode == 3) { if (!verbose) { putchar('.'); fflush(stdout); } switch (r->lob.nsect) { case 1: // drive wants more data case 2: // drive thinks it is all done err = - r->lob.nsect; break; default: // no status indication err = 0; break; } } } free(r); return err; } int fwdownload (int fd, __u16 *id, const char *fwpath, int xfer_mode) { int fwfd, err = 0; struct stat st; const char *fw = NULL; const int max_bytes = 0xffff * 512; int xfer_min = 1, xfer_max = 0xffff, xfer_size; ssize_t offset; if ((fwfd = open(fwpath, O_RDONLY)) == -1 || fstat(fwfd, &st) == -1) { err = errno; perror(fwpath); return err; } if (!S_ISREG(st.st_mode)) { fprintf(stderr, "%s: not a regular file\n", fwpath); err = EINVAL; goto done; } if (st.st_size > max_bytes) { fprintf(stderr, "%s: file size too large, max=%u bytes\n", fwpath, max_bytes); err = EINVAL; goto done; } if (st.st_size == 0 || st.st_size % 512) { fprintf(stderr, "%s: file size (%llu) not a multiple of 512\n", fwpath, (unsigned long long) st.st_size); err = EINVAL; goto done; } if (verbose) printf("%s: %llu bytes\n", fwpath, (unsigned long long)st.st_size); fw = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED|MAP_POPULATE|MAP_LOCKED, fwfd, 0); if (fw == MAP_FAILED) { err = errno; perror(fwpath); goto done; } /* Check drive for fwdownload support */ if (!((id[83] & 1) && (id[86] & 1))) { fprintf(stderr, "DOWNLOAD_MICROCODE: not supported by device\n"); err = ENOTSUP; goto done; } if (xfer_mode == 0) { if ((id[119] & 0x10) && (id[120] & 0x10)) xfer_mode = 3; else xfer_mode = 7; } if (xfer_mode == 3 || xfer_mode == 30) { /* the newer, segmented transfer mode */ xfer_min = id[234]; if (xfer_min == 0 || xfer_min == 0xffff) xfer_min = 1; xfer_max = id[235]; if (xfer_max == 0 || xfer_max == 0xffff) xfer_max = xfer_min; } if (xfer_mode == 30) { // mode-3, using xfer_max xfer_mode = 3; xfer_size = xfer_max; } else if (xfer_mode == 3) { xfer_size = xfer_min; } else { xfer_size = st.st_size / 512; if (xfer_size > 0xffff) { fprintf(stderr, "Error: file size (%llu) too large for mode7 transfers\n", (__u64)st.st_size); err = EINVAL; goto done; } } xfer_size *= 512; /* bytecount */ fprintf(stderr, "%s: xfer_mode=%d min=%u max=%u size=%u\n", __func__, xfer_mode, xfer_min, xfer_max, xfer_size); /* Perform the fwdownload, in segments if appropriate */ for (offset = 0; !err && offset < st.st_size;) { if ((offset + xfer_size) >= st.st_size) xfer_size = st.st_size - offset; err = send_firmware(fd, xfer_mode, offset, fw + offset, xfer_size); offset += xfer_size; if (err == -2) { // drive has had enough? if (offset >= st.st_size) { // transfer complete? err = 0; } else { if (xfer_mode == 3) { putchar('\n'); fflush(stdout); } fprintf(stderr, "Error: drive completed transfer at %llu/%llu bytes\n", (unsigned long long)offset, (unsigned long long)st.st_size); err = EIO; } } else if (err == -1) { if (offset >= st.st_size) { // no more data? #if 0 /* Try sending an empty segment before complaining */ err = send_firmware(fd, xfer_mode, offset, NULL, 0); if (err == 0 || err == -2) { err = 0; break; } #endif if (xfer_mode == 3) { putchar('\n'); fflush(stdout); } fprintf(stderr, "Error: drive expects more data than provided,\n"); fprintf(stderr, "but the transfer may have worked regardless.\n"); err = EIO; } else { err = 0; } } } if (!err) printf(" Done.\n"); done: munlock(fw, st.st_size); close (fwfd); return err; } hdparm-9.43/fibmap.c0000644000000000000000000001706312031360407013027 0ustar rootroot/* * Based upon original code by Ric Wheeler and Mark Lord. * * Copyright (c) EMC Corporation 2008 * Copyright (c) Mark Lord 2008 * * You may use/distribute this freely, under the terms of either * (your choice) the GNU General Public License version 2, * or a BSD style license. */ #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #include #include #include #include "hdparm.h" static const unsigned int sector_bytes = 512; // FIXME someday struct file_extent { __u64 byte_offset; __u64 first_block; __u64 last_block; __u64 block_count; }; static void handle_extent (struct file_extent ext, unsigned int sectors_per_block, __u64 start_lba) { char lba_info[64], len_info[32]; __u64 begin_lba, end_lba; __u64 nsectors = ext.block_count * sectors_per_block; if (ext.first_block) { begin_lba = start_lba + ( ext.first_block * sectors_per_block); end_lba = start_lba + ((ext.last_block + 1) * sectors_per_block) - 1; } else { begin_lba = end_lba = 0; } if (ext.first_block) sprintf(lba_info, "%10llu %10llu", begin_lba, end_lba); else strcpy(lba_info, " - - "); if (!ext.first_block && !nsectors) strcpy(len_info, " - "); else sprintf(len_info, "%10llu", nsectors); printf("%12llu %s %s\n", ext.byte_offset, lba_info, len_info); } static int walk_fibmap (int fd, struct stat *st, unsigned int sectors_per_block, __u64 start_lba) { struct file_extent ext; unsigned long num_blocks; __u64 blk_idx, hole = ~0ULL; /* * How many calls to FIBMAP do we need? * FIBMAP returns a filesystem block number (counted from the start of the device) * for each file block. This can be converted to a disk LBA using the filesystem * blocksize and LBA offset obtained earlier. */ num_blocks = (st->st_size + st->st_blksize - 1) / st->st_blksize; memset(&ext, 0, sizeof(ext)); /* * Loop through the file, building a map of the extents. * All of this is done in filesystem blocks size (fs_blksize) units. * * Assumptions: * Throughout the file, there can be any number of blocks backed by holes * or by allocated blocks. Tail-packed files are special - if we find a file * that has a size and has no allocated blocks, we could flag it as a "tail-packed" * file if we cared: data is packed into the tail space of the inode block. */ for (blk_idx = 0; blk_idx < num_blocks; blk_idx++) { unsigned int blknum = blk_idx; __u64 blknum64; /* * FIBMAP takes a block index as input and on return replaces it with a * block number relative to the beginning of the filesystem/partition. * An output value of zero means "unallocated", or a "hole" in a sparse file. * Note that this is a 32-bit value, so it will not work properly on * files/filesystems with more than 4 billion blocks (~16TB), */ if (ioctl(fd, FIBMAP, &blknum) == -1) { int err = errno; perror("ioctl(FIBMAP)"); return err; } blknum64 = blknum; /* work in 64-bits as much as possible */ if (blk_idx && blknum64 == (ext.last_block + 1)) { /* * Continuation of extent: Bump last_block and block_count. */ ext.last_block = blknum64 ? blknum64 : hole; ext.block_count++; } else { /* * New extent: print previous extent (if any), and re-init the extent record. */ if (blk_idx) handle_extent(ext, sectors_per_block, start_lba); ext.first_block = blknum64; ext.last_block = blknum64 ? blknum64 : hole; ext.block_count = 1; ext.byte_offset = blk_idx * st->st_blksize; } } handle_extent(ext, sectors_per_block, start_lba); return 0; } #define FE_COUNT 8000 #define FE_FLAG_LAST (1 << 0) #define FE_FLAG_UNKNOWN (1 << 1) #define FE_FLAG_UNALLOC (1 << 2) #define FE_FLAG_NOALIGN (1 << 8) #define EXTENT_UNKNOWN (FE_FLAG_UNKNOWN | FE_FLAG_UNALLOC | FE_FLAG_NOALIGN) struct fe_s { __u64 logical; __u64 physical; __u64 length; __u64 reserved64[2]; __u32 flags; __u32 reserved32[3]; }; struct fm_s { __u64 start; __u64 length; __u32 flags; __u32 mapped_extents; __u32 extent_count; __u32 reserved; }; struct fs_s { struct fm_s fm; struct fe_s fe[FE_COUNT]; }; #define FIEMAP _IOWR('f', 11, struct fm_s) static int walk_fiemap (int fd, unsigned int sectors_per_block, __u64 start_lba) { unsigned int i, done = 0; unsigned int blksize = sectors_per_block * sector_bytes; struct fs_s fs; memset(&fs, 0, sizeof(fs)); do { fs.fm.length = ~0ULL; fs.fm.flags = 0; fs.fm.extent_count = FE_COUNT; if (-1 == ioctl(fd, FIEMAP, &fs)) { int err = errno; //perror("ioctl(FIEMAP)"); return err; } if (0) fprintf(stderr, "ioctl(FIEMAP) returned %llu extents\n", (__u64)fs.fm.mapped_extents); if (!fs.fm.mapped_extents) { done = 1; } else { struct file_extent ext; memset(&ext, 0, sizeof(ext)); for (i = 0; i < fs.fm.mapped_extents; i++) { __u64 phy_blk, ext_len; ext.byte_offset = fs.fe[i].logical; if (0) fprintf(stderr, "log=%llu phy=%llu len=%llu flags=0x%x\n", fs.fe[i].logical, fs.fe[i].physical, fs.fe[i].length, fs.fe[i].flags); if (fs.fe[i].flags & EXTENT_UNKNOWN) { ext.first_block = 0; ext.last_block = 0; ext.block_count = 0; /* FIEMAP returns garbage for this. Ugh. */ } else { phy_blk = fs.fe[i].physical / blksize; ext_len = fs.fe[i].length / blksize; ext.first_block = phy_blk; ext.last_block = phy_blk + ext_len - 1; ext.block_count = ext_len; } handle_extent(ext, sectors_per_block, start_lba); if (fs.fe[i].flags & FE_FLAG_LAST) { /* * Hit an ext4 bug in 2.6.29.4, where some FIEMAP calls * had the LAST flag set in the final returned extent, * even though there were *plenty* more extents to be had * from continued FIEMAP calls. * * So, we'll ignore it here, and instead rely on getting * a zero count back from fs.fm.mapped_extents at the end. */ if (0) fprintf(stderr, "%s: ignoring LAST bit\n", __func__); //done = 1; } } fs.fm.start = (fs.fe[i-1].logical + fs.fe[i-1].length); } } while (!done); return 0; } int do_filemap (const char *file_name) { int fd, err; struct stat st; __u64 start_lba = 0; unsigned int sectors_per_block, blksize; if ((fd = open(file_name, O_RDONLY)) == -1) { err = errno; perror(file_name); return err; } if (fstat(fd, &st) == -1) { err = errno; perror(file_name); return err; } if (!S_ISREG(st.st_mode)) { fprintf(stderr, "%s: not a regular file\n", file_name); close(fd); return EINVAL; } /* * Get the filesystem starting LBA: */ err = get_dev_t_geometry(st.st_dev, NULL, NULL, NULL, &start_lba, NULL); if (err) { close(fd); return err; } if (start_lba == START_LBA_UNKNOWN) { fprintf(stderr, "Unable to determine start offset LBA for device, aborting.\n"); close(fd); return EIO; } if((err=ioctl(fd,FIGETBSZ,&blksize))){ fprintf(stderr, "Unable to determine block size, aborting.\n"); close(fd); return err; }; sectors_per_block = blksize / sector_bytes; printf("\n%s:\n filesystem blocksize %u, begins at LBA %llu;" " assuming %u byte sectors.\n", file_name, blksize, start_lba, sector_bytes); printf("%12s %10s %10s %10s\n", "byte_offset", "begin_LBA", "end_LBA", "sectors"); if (st.st_size == 0) { struct file_extent ext; memset(&ext, 0, sizeof(ext)); handle_extent(ext, sectors_per_block, start_lba); close(fd); return 0; } err = walk_fiemap(fd, sectors_per_block, start_lba); if (err) err = walk_fibmap(fd, &st, sectors_per_block, start_lba); close (fd); return 0; } hdparm-9.43/sgio.c0000644000000000000000000003656512031357164012550 0ustar rootroot/* sgio.c - by Mark Lord (C) 2007 -- freely distributable */ #include #include #include #include #include #include #include #include #include #include #include #include "sgio.h" #include "hdparm.h" #include extern int verbose; extern int prefer_ata12; static const unsigned int default_timeout_secs = 15; /* * Taskfile layout for SG_ATA_16 cdb: * * LBA48: * cdb[ 3] = hob_feat * cdb[ 5] = hob_nsect * cdb[ 7] = hob_lbal * cdb[ 9] = hob_lbam * cdb[11] = hob_lbah * * LBA28/LBA48: * cdb[ 4] = feat * cdb[ 6] = nsect * cdb[ 8] = lbal * cdb[10] = lbam * cdb[12] = lbah * cdb[13] = device * cdb[14] = command * * Taskfile layout for SG_ATA_12 cdb: * * cdb[ 3] = feat * cdb[ 4] = nsect * cdb[ 5] = lbal * cdb[ 6] = lbam * cdb[ 7] = lbah * cdb[ 8] = device * cdb[ 9] = command * * dxfer_direction choices: * SG_DXFER_TO_DEV, SG_DXFER_FROM_DEV, SG_DXFER_NONE */ #if 0 /* maybe use this in sg16 later.. ? */ static inline int get_rw (__u8 ata_op) { switch (ata_op) { case ATA_OP_DSM: case ATA_OP_WRITE_PIO: case ATA_OP_WRITE_LONG: case ATA_OP_WRITE_LONG_ONCE: case ATA_OP_WRITE_PIO_EXT: case ATA_OP_WRITE_DMA_EXT: case ATA_OP_WRITE_FPDMA: case ATA_OP_WRITE_UNC_EXT: case ATA_OP_WRITE_DMA: case ATA_OP_SECURITY_UNLOCK: case ATA_OP_SECURITY_DISABLE: case ATA_OP_SECURITY_ERASE_UNIT: case ATA_OP_SECURITY_SET_PASS: return SG_WRITE; default: return SG_READ; } } #endif static inline int needs_lba48 (__u8 ata_op, __u64 lba, unsigned int nsect) { switch (ata_op) { case ATA_OP_DSM: case ATA_OP_READ_PIO_EXT: case ATA_OP_READ_DMA_EXT: case ATA_OP_WRITE_PIO_EXT: case ATA_OP_WRITE_DMA_EXT: case ATA_OP_READ_VERIFY_EXT: case ATA_OP_WRITE_UNC_EXT: case ATA_OP_READ_NATIVE_MAX_EXT: case ATA_OP_SET_MAX_EXT: case ATA_OP_FLUSHCACHE_EXT: return 1; case ATA_OP_SECURITY_ERASE_PREPARE: case ATA_OP_SECURITY_ERASE_UNIT: case ATA_OP_VENDOR_SPECIFIC_0x80: case ATA_OP_SMART: return 0; } if (lba >= lba28_limit) return 1; if (nsect) { if (nsect > 0xff) return 1; if ((lba + nsect - 1) >= lba28_limit) return 1; } return 0; } static inline int is_dma (__u8 ata_op) { switch (ata_op) { case ATA_OP_DSM: case ATA_OP_READ_DMA_EXT: case ATA_OP_READ_FPDMA: case ATA_OP_WRITE_DMA_EXT: case ATA_OP_WRITE_FPDMA: case ATA_OP_READ_DMA: case ATA_OP_WRITE_DMA: return SG_DMA; default: return SG_PIO; } } void tf_init (struct ata_tf *tf, __u8 ata_op, __u64 lba, unsigned int nsect) { memset(tf, 0, sizeof(*tf)); tf->command = ata_op; tf->dev = ATA_USING_LBA; tf->lob.lbal = lba; tf->lob.lbam = lba >> 8; tf->lob.lbah = lba >> 16; tf->lob.nsect = nsect; if (needs_lba48(ata_op, lba, nsect)) { tf->is_lba48 = 1; tf->hob.nsect = nsect >> 8; tf->hob.lbal = lba >> 24; tf->hob.lbam = lba >> 32; tf->hob.lbah = lba >> 40; } else { tf->dev |= (lba >> 24) & 0x0f; } } #ifdef SG_IO __u64 tf_to_lba (struct ata_tf *tf) { __u32 lba24, lbah; __u64 lba64; lba24 = (tf->lob.lbah << 16) | (tf->lob.lbam << 8) | (tf->lob.lbal); if (tf->is_lba48) lbah = (tf->hob.lbah << 16) | (tf->hob.lbam << 8) | (tf->hob.lbal); else lbah = (tf->dev & 0x0f); lba64 = (((__u64)lbah) << 24) | (__u64)lba24; return lba64; } enum { SG_CDB2_TLEN_NODATA = 0 << 0, SG_CDB2_TLEN_FEAT = 1 << 0, SG_CDB2_TLEN_NSECT = 2 << 0, SG_CDB2_TLEN_BYTES = 0 << 2, SG_CDB2_TLEN_SECTORS = 1 << 2, SG_CDB2_TDIR_TO_DEV = 0 << 3, SG_CDB2_TDIR_FROM_DEV = 1 << 3, SG_CDB2_CHECK_COND = 1 << 5, }; static void dump_bytes (const char *prefix, unsigned char *p, int len) { int i; if (prefix) fprintf(stderr, "%s: ", prefix); for (i = 0; i < len; ++i) fprintf(stderr, " %02x", p[i]); fprintf(stderr, "\n"); } int sg16 (int fd, int rw, int dma, struct ata_tf *tf, void *data, unsigned int data_bytes, unsigned int timeout_secs) { unsigned char cdb[SG_ATA_16_LEN]; unsigned char sb[32], *desc; struct scsi_sg_io_hdr io_hdr; int prefer12 = prefer_ata12, demanded_sense = 0; if (tf->command == ATA_OP_PIDENTIFY) prefer12 = 0; memset(&cdb, 0, sizeof(cdb)); memset(&sb, 0, sizeof(sb)); memset(&io_hdr, 0, sizeof(struct scsi_sg_io_hdr)); if (data && data_bytes && !rw) memset(data, 0, data_bytes); if (dma) { //cdb[1] = data ? (rw ? SG_ATA_PROTO_UDMA_OUT : SG_ATA_PROTO_UDMA_IN) : SG_ATA_PROTO_NON_DATA; cdb[1] = data ? SG_ATA_PROTO_DMA : SG_ATA_PROTO_NON_DATA; } else { cdb[1] = data ? (rw ? SG_ATA_PROTO_PIO_OUT : SG_ATA_PROTO_PIO_IN) : SG_ATA_PROTO_NON_DATA; } /* libata/AHCI workaround: don't demand sense data for IDENTIFY commands */ if (data) { cdb[2] |= SG_CDB2_TLEN_NSECT | SG_CDB2_TLEN_SECTORS; cdb[2] |= rw ? SG_CDB2_TDIR_TO_DEV : SG_CDB2_TDIR_FROM_DEV; } else { cdb[2] = SG_CDB2_CHECK_COND; } if (!prefer12 || tf->is_lba48) { cdb[ 0] = SG_ATA_16; cdb[ 4] = tf->lob.feat; cdb[ 6] = tf->lob.nsect; cdb[ 8] = tf->lob.lbal; cdb[10] = tf->lob.lbam; cdb[12] = tf->lob.lbah; cdb[13] = tf->dev; cdb[14] = tf->command; if (tf->is_lba48) { cdb[ 1] |= SG_ATA_LBA48; cdb[ 3] = tf->hob.feat; cdb[ 5] = tf->hob.nsect; cdb[ 7] = tf->hob.lbal; cdb[ 9] = tf->hob.lbam; cdb[11] = tf->hob.lbah; } io_hdr.cmd_len = SG_ATA_16_LEN; } else { cdb[ 0] = SG_ATA_12; cdb[ 3] = tf->lob.feat; cdb[ 4] = tf->lob.nsect; cdb[ 5] = tf->lob.lbal; cdb[ 6] = tf->lob.lbam; cdb[ 7] = tf->lob.lbah; cdb[ 8] = tf->dev; cdb[ 9] = tf->command; io_hdr.cmd_len = SG_ATA_12_LEN; } io_hdr.interface_id = 'S'; io_hdr.mx_sb_len = sizeof(sb); io_hdr.dxfer_direction = data ? (rw ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV) : SG_DXFER_NONE; io_hdr.dxfer_len = data ? data_bytes : 0; io_hdr.dxferp = data; io_hdr.cmdp = cdb; io_hdr.sbp = sb; io_hdr.pack_id = tf_to_lba(tf); io_hdr.timeout = (timeout_secs ? timeout_secs : default_timeout_secs) * 1000; /* msecs */ if (verbose) { dump_bytes("outgoing cdb", cdb, sizeof(cdb)); if (rw && data) dump_bytes("outgoing_data", data, data_bytes); } if (ioctl(fd, SG_IO, &io_hdr) == -1) { if (verbose) perror("ioctl(fd,SG_IO)"); return -1; /* SG_IO not supported */ } if (verbose) fprintf(stderr, "SG_IO: ATA_%u status=0x%x, host_status=0x%x, driver_status=0x%x\n", io_hdr.cmd_len, io_hdr.status, io_hdr.host_status, io_hdr.driver_status); if (io_hdr.status && io_hdr.status != SG_CHECK_CONDITION) { if (verbose) fprintf(stderr, "SG_IO: bad status: 0x%x\n", io_hdr.status); errno = EBADE; return -1; } if (io_hdr.host_status) { if (verbose) fprintf(stderr, "SG_IO: bad host status: 0x%x\n", io_hdr.host_status); errno = EBADE; return -1; } if (verbose) { dump_bytes("SG_IO: sb[]", sb, sizeof(sb)); if (!rw && data) dump_bytes("incoming_data", data, data_bytes); } if (io_hdr.driver_status && (io_hdr.driver_status != SG_DRIVER_SENSE)) { if (verbose) fprintf(stderr, "SG_IO: bad driver status: 0x%x\n", io_hdr.driver_status); errno = EBADE; return -1; } desc = sb + 8; if (io_hdr.driver_status != SG_DRIVER_SENSE) { if (sb[0] | sb[1] | sb[2] | sb[3] | sb[4] | sb[5] | sb[6] | sb[7] | sb[8] | sb[9]) { static int second_try = 0; if (!second_try++) fprintf(stderr, "SG_IO: questionable sense data, results may be incorrect\n"); } else if (demanded_sense) { static int second_try = 0; if (!second_try++) fprintf(stderr, "SG_IO: missing sense data, results may be incorrect\n"); } } else if (sb[0] != 0x72 || sb[7] < 14 || desc[0] != 0x09 || desc[1] < 0x0c) { dump_bytes("SG_IO: bad/missing sense data, sb[]", sb, sizeof(sb)); } if (verbose) { unsigned int len = desc[1] + 2, maxlen = sizeof(sb) - 8 - 2; if (len > maxlen) len = maxlen; dump_bytes("SG_IO: desc[]", desc, len); } tf->is_lba48 = desc[ 2] & 1; tf->error = desc[ 3]; tf->lob.nsect = desc[ 5]; tf->lob.lbal = desc[ 7]; tf->lob.lbam = desc[ 9]; tf->lob.lbah = desc[11]; tf->dev = desc[12]; tf->status = desc[13]; tf->hob.feat = 0; if (tf->is_lba48) { tf->hob.nsect = desc[ 4]; tf->hob.lbal = desc[ 6]; tf->hob.lbam = desc[ 8]; tf->hob.lbah = desc[10]; } else { tf->hob.nsect = 0; tf->hob.lbal = 0; tf->hob.lbam = 0; tf->hob.lbah = 0; } if (verbose) fprintf(stderr, " ATA_%u stat=%02x err=%02x nsect=%02x lbal=%02x lbam=%02x lbah=%02x dev=%02x\n", io_hdr.cmd_len, tf->status, tf->error, tf->lob.nsect, tf->lob.lbal, tf->lob.lbam, tf->lob.lbah, tf->dev); if (tf->status & (ATA_STAT_ERR | ATA_STAT_DRQ)) { if (verbose) { fprintf(stderr, "I/O error, ata_op=0x%02x ata_status=0x%02x ata_error=0x%02x\n", tf->command, tf->status, tf->error); } errno = EIO; return -1; } return 0; } #endif /* SG_IO */ int do_drive_cmd (int fd, unsigned char *args, unsigned int timeout_secs) { #ifdef SG_IO struct ata_tf tf; void *data = NULL; unsigned int data_bytes = 0; int rc; if (args == NULL) goto use_legacy_ioctl; /* * Reformat and try to issue via SG_IO: * args[0]: command in; status out. * args[1]: lbal for SMART, nsect for all others; error out * args[2]: feat in; nsect out. * args[3]: data-count (512 multiple) for all cmds. */ tf_init(&tf, args[0], 0, 0); tf.lob.nsect = args[1]; tf.lob.feat = args[2]; if (args[3]) { data_bytes = args[3] * 512; data = args + 4; if (!tf.lob.nsect) tf.lob.nsect = args[3]; } if (tf.command == ATA_OP_SMART) { tf.lob.nsect = args[3]; tf.lob.lbal = args[1]; tf.lob.lbam = 0x4f; tf.lob.lbah = 0xc2; } rc = sg16(fd, SG_READ, is_dma(tf.command), &tf, data, data_bytes, timeout_secs); if (rc == -1) { if (errno == EINVAL || errno == ENODEV || errno == EBADE) goto use_legacy_ioctl; } if (rc == 0 || errno == EIO) { args[0] = tf.status; args[1] = tf.error; args[2] = tf.lob.nsect; } return rc; use_legacy_ioctl: #endif /* SG_IO */ if (verbose) { if (args) fprintf(stderr, "Trying legacy HDIO_DRIVE_CMD\n"); } return ioctl(fd, HDIO_DRIVE_CMD, args); } int do_taskfile_cmd (int fd, struct hdio_taskfile *r, unsigned int timeout_secs) { int rc; #ifdef SG_IO struct ata_tf tf; void *data = NULL; unsigned int data_bytes = 0; int rw = SG_READ; /* * Reformat and try to issue via SG_IO: */ tf_init(&tf, 0, 0, 0); #if 1 /* debugging */ if (verbose) { printf("oflags.lob_all=0x%02x, flags={", r->oflags.lob_all); if (r->oflags.lob.feat) printf(" feat"); if (r->oflags.lob.nsect)printf(" nsect"); if (r->oflags.lob.lbal) printf(" lbal"); if (r->oflags.lob.lbam) printf(" lbam"); if (r->oflags.lob.lbah) printf(" lbah"); if (r->oflags.lob.dev) printf(" dev"); if (r->oflags.lob.command) printf(" command"); printf(" }\n"); printf("oflags.hob_all=0x%02x, flags={", r->oflags.hob_all); if (r->oflags.hob.feat) printf(" feat"); if (r->oflags.hob.nsect)printf(" nsect"); if (r->oflags.hob.lbal) printf(" lbal"); if (r->oflags.hob.lbam) printf(" lbam"); if (r->oflags.hob.lbah) printf(" lbah"); printf(" }\n"); } #endif if (r->oflags.lob.feat) tf.lob.feat = r->lob.feat; if (r->oflags.lob.lbal) tf.lob.lbal = r->lob.lbal; if (r->oflags.lob.nsect) tf.lob.nsect = r->lob.nsect; if (r->oflags.lob.lbam) tf.lob.lbam = r->lob.lbam; if (r->oflags.lob.lbah) tf.lob.lbah = r->lob.lbah; if (r->oflags.lob.dev) tf.dev = r->lob.dev; if (r->oflags.lob.command) tf.command = r->lob.command; if (needs_lba48(tf.command,0,0) || r->oflags.hob_all || r->iflags.hob_all) { tf.is_lba48 = 1; if (r->oflags.hob.feat) tf.hob.feat = r->hob.feat; if (r->oflags.hob.lbal) tf.hob.lbal = r->hob.lbal; if (r->oflags.hob.nsect)tf.hob.nsect = r->hob.nsect; if (r->oflags.hob.lbam) tf.hob.lbam = r->hob.lbam; if (r->oflags.hob.lbah) tf.hob.lbah = r->hob.lbah; if (verbose) fprintf(stderr, "using LBA48 taskfile\n"); } switch (r->cmd_req) { case TASKFILE_CMD_REQ_OUT: case TASKFILE_CMD_REQ_RAW_OUT: data_bytes = r->obytes; data = r->data; rw = SG_WRITE; break; case TASKFILE_CMD_REQ_IN: data_bytes = r->ibytes; data = r->data; break; } rc = sg16(fd, rw, is_dma(tf.command), &tf, data, data_bytes, timeout_secs); if (rc == -1) { if (errno == EINVAL || errno == ENODEV || errno == EBADE) goto use_legacy_ioctl; } if (rc == 0 || errno == EIO) { if (r->iflags.lob.feat) r->lob.feat = tf.error; if (r->iflags.lob.lbal) r->lob.lbal = tf.lob.lbal; if (r->iflags.lob.nsect) r->lob.nsect = tf.lob.nsect; if (r->iflags.lob.lbam) r->lob.lbam = tf.lob.lbam; if (r->iflags.lob.lbah) r->lob.lbah = tf.lob.lbah; if (r->iflags.lob.dev) r->lob.dev = tf.dev; if (r->iflags.lob.command) r->lob.command = tf.status; if (r->iflags.hob.feat) r->hob.feat = tf.hob.feat; if (r->iflags.hob.lbal) r->hob.lbal = tf.hob.lbal; if (r->iflags.hob.nsect) r->hob.nsect = tf.hob.nsect; if (r->iflags.hob.lbam) r->hob.lbam = tf.hob.lbam; if (r->iflags.hob.lbah) r->hob.lbah = tf.hob.lbah; } return rc; use_legacy_ioctl: #else timeout_secs = 0; /* keep compiler happy */ #endif /* SG_IO */ if (verbose) fprintf(stderr, "trying legacy HDIO_DRIVE_TASKFILE\n"); errno = 0; rc = ioctl(fd, HDIO_DRIVE_TASKFILE, r); if (verbose) { int err = errno; fprintf(stderr, "rc=%d, errno=%d, returned ATA registers: ", rc, err); if (r->iflags.lob.feat) fprintf(stderr, " er=%02x", r->lob.feat); if (r->iflags.lob.nsect) fprintf(stderr, " ns=%02x", r->lob.nsect); if (r->iflags.lob.lbal) fprintf(stderr, " ll=%02x", r->lob.lbal); if (r->iflags.lob.lbam) fprintf(stderr, " lm=%02x", r->lob.lbam); if (r->iflags.lob.lbah) fprintf(stderr, " lh=%02x", r->lob.lbah); if (r->iflags.lob.dev) fprintf(stderr, " dh=%02x", r->lob.dev); if (r->iflags.lob.command) fprintf(stderr, " st=%02x", r->lob.command); if (r->iflags.hob.feat) fprintf(stderr, " err=%02x", r->hob.feat); if (r->iflags.hob.nsect) fprintf(stderr, " err=%02x", r->hob.nsect); if (r->iflags.hob.lbal) fprintf(stderr, " err=%02x", r->hob.lbal); if (r->iflags.hob.lbam) fprintf(stderr, " err=%02x", r->hob.lbam); if (r->iflags.hob.lbah) fprintf(stderr, " err=%02x", r->hob.lbah); fprintf(stderr, "\n"); errno = err; } if (rc == -1 && errno == EINVAL) { fprintf(stderr, "The running kernel lacks CONFIG_IDE_TASK_IOCTL support for this device.\n"); errno = EINVAL; } return rc; } void init_hdio_taskfile (struct hdio_taskfile *r, __u8 ata_op, int rw, int force_lba48, __u64 lba, unsigned int nsect, int data_bytes) { memset(r, 0, sizeof(struct hdio_taskfile) + data_bytes); if (!data_bytes) { r->dphase = TASKFILE_DPHASE_NONE; r->cmd_req = TASKFILE_CMD_REQ_NODATA; } else if (rw == RW_WRITE) { r->dphase = TASKFILE_DPHASE_PIO_OUT; r->cmd_req = TASKFILE_CMD_REQ_RAW_OUT; r->obytes = data_bytes; } else { /* rw == RW_READ */ r->dphase = TASKFILE_DPHASE_PIO_IN; r->cmd_req = TASKFILE_CMD_REQ_IN; r->ibytes = data_bytes; } r->lob.command = ata_op; r->oflags.lob.command = 1; r->oflags.lob.dev = 1; r->oflags.lob.lbal = 1; r->oflags.lob.lbam = 1; r->oflags.lob.lbah = 1; r->oflags.lob.nsect = 1; r->iflags.lob.command = 1; r->iflags.lob.feat = 1; r->lob.nsect = nsect; r->lob.lbal = lba; r->lob.lbam = lba >> 8; r->lob.lbah = lba >> 16; r->lob.dev = 0xa0 | ATA_USING_LBA; if (needs_lba48(ata_op, lba, nsect) || force_lba48) { r->hob.nsect = nsect >> 8; r->hob.lbal = lba >> 24; r->hob.lbam = lba >> 32; r->hob.lbah = lba >> 40; r->oflags.hob.nsect = 1; r->oflags.hob.lbal = 1; r->oflags.hob.lbam = 1; r->oflags.hob.lbah = 1; } else { r->lob.dev |= (lba >> 24) & 0x0f; } } hdparm-9.43/hdparm.c0000644000000000000000000024002212051263763013046 0ustar rootroot/* * hdparm.c - Command line interface to get/set hard disk parameters. * - by Mark Lord (C) 1994-2012 -- freely distributable. */ #define _LARGEFILE64_SOURCE /*for lseek64*/ #define _BSD_SOURCE /* for strtoll() */ #include #include #include #define __USE_GNU /* for O_DIRECT */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "hdparm.h" #include "sgio.h" static int argc; static char **argv; static char *argp; static int num_flags_processed = 0; extern const char *minor_str[]; #define VERSION "v9.43" #ifndef O_DIRECT #define O_DIRECT 040000 /* direct disk access, not easily obtained from headers */ #endif #ifndef CDROM_SELECT_SPEED /* already defined in 2.3.xx kernels and above */ #define CDROM_SELECT_SPEED 0x5322 #endif #define TIMING_BUF_MB 2 #define TIMING_BUF_BYTES (TIMING_BUF_MB * 1024 * 1024) char *progname; int verbose = 0; int prefer_ata12 = 0; static int do_defaults = 0, do_flush = 0, do_ctimings, do_timings = 0; static int do_identity = 0, get_geom = 0, noisy = 1, quiet = 0; static int do_flush_wcache = 0; static int set_wdidle3 = 0, get_wdidle3 = 0, wdidle3 = 0; static int set_timings_offset = 0; static __u64 timings_offset = 0; static int set_fsreadahead= 0, get_fsreadahead= 0, fsreadahead= 0; static int set_readonly = 0, get_readonly = 0, readonly = 0; static int set_unmask = 0, get_unmask = 0, unmask = 0; static int set_mult = 0, get_mult = 0, mult = 0; static int set_dma = 0, get_dma = 0, dma = 0; static int set_dma_q = 0, get_dma_q = 0, dma_q = 0; static int set_nowerr = 0, get_nowerr = 0, nowerr = 0; static int set_keep = 0, get_keep = 0, keep = 0; static int set_io32bit = 0, get_io32bit = 0, io32bit = 0; static int set_piomode = 0, get_piomode= 0, piomode = 0; static int set_dkeep = 0, get_dkeep = 0, dkeep = 0; static int set_standby = 0, get_standby = 0, standby= 0; static int set_xfermode = 0, get_xfermode = 0; static int xfermode_requested= 0; static int set_lookahead= 0, get_lookahead= 0, lookahead= 0; static int set_prefetch = 0, get_prefetch = 0, prefetch = 0; static int set_defects = 0, get_defects = 0, defects = 0; static int set_wcache = 0, get_wcache = 0, wcache = 0; static int set_doorlock = 0, get_doorlock = 0, doorlock = 0; static int set_seagate = 0, get_seagate = 0; static int get_idleimmediate = 0, set_idleimmediate = 0; static int get_idleunload = 0, set_idleunload = 0; static int set_standbynow = 0, get_standbynow = 0; static int set_sleepnow = 0, get_sleepnow = 0; static int set_powerup_in_standby = 0, get_powerup_in_standby = 0, powerup_in_standby = 0; static int get_hitachi_temp = 0, set_hitachi_temp = 0; static int security_freeze = 0; static int security_master = 0, security_mode = 0; static int enhanced_erase = 0; static int set_security = 0; static int do_dco_freeze = 0, do_dco_restore = 0, do_dco_identify = 0; static unsigned int security_command = ATA_OP_SECURITY_UNLOCK; static char security_password[33], *fwpath; static int get_powermode = 0, set_powermode = 0; static int set_apmmode = 0, get_apmmode= 0, apmmode = 0; static int get_cdromspeed = 0, set_cdromspeed = 0, cdromspeed = 0; static int do_IDentity = 0, drq_hsm_error = 0; static int do_fwdownload = 0, xfer_mode = 0; static int set_busstate = 0, get_busstate = 0, busstate = 0; static int set_reread_partn = 0, get_reread_partn; static int set_acoustic = 0, get_acoustic = 0, acoustic = 0; static int write_read_verify = 0, get_write_read_verify = 0, set_write_read_verify = 0; static int make_bad_sector = 0, make_bad_sector_flagged; static __u64 make_bad_sector_addr = ~0ULL; #ifdef FORMAT_AND_ERASE static int format_track = 0; static __u64 format_track_addr = ~0ULL; static int erase_sectors = 0; static __u64 erase_sectors_addr = ~0ULL; #endif static struct sector_range_s *trim_sector_ranges = NULL; static int trim_sector_ranges_count = 0; static int trim_from_stdin = 0; static int write_sector = 0; static __u64 write_sector_addr = ~0ULL; static int read_sector = 0; static __u64 read_sector_addr = ~0ULL; static int set_max_sectors = 0, set_max_permanent, get_native_max_sectors = 0; static __u64 set_max_addr = 0; static int get_doreset = 0, set_doreset = 0; static int i_know_what_i_am_doing = 0; static int please_destroy_my_drive = 0; const int timeout_15secs = 15; const int timeout_60secs = 60; const int timeout_5mins = (5 * 60); const int timeout_2hrs = (2 * 60 * 60); static int open_flags = O_RDONLY|O_NONBLOCK; // Historically, if there was no HDIO_OBSOLETE_IDENTITY, then // then the HDIO_GET_IDENTITY only returned 142 bytes. // Otherwise, HDIO_OBSOLETE_IDENTITY returns 142 bytes, // and HDIO_GET_IDENTITY returns 512 bytes. But the latest // 2.5.xx kernels no longer define HDIO_OBSOLETE_IDENTITY // (which they should, but they should just return -EINVAL). // // So.. we must now assume that HDIO_GET_IDENTITY returns 512 bytes. // On a really old system, it will not, and we will be confused. // Too bad, really. const char *cfg_str[] = { "", " HardSect", " SoftSect", " NotMFM", " HdSw>15uSec", " SpinMotCtl", " Fixed", " Removeable", " DTR<=5Mbs", " DTR>5Mbs", " DTR>10Mbs", " RotSpdTol>.5%", " dStbOff", " TrkOff", " FmtGapReq", " nonMagnetic" }; const char *SlowMedFast[] = {"slow", "medium", "fast", "eide", "ata"}; const char *BuffType[4] = {"unknown", "1Sect", "DualPort", "DualPortCache"}; #define YN(b) (((b)==0)?"no":"yes") static void on_off (unsigned int value) { printf(value ? " (on)\n" : " (off)\n"); } #ifndef ENOIOCTLCMD #define ENOIOCTLCMD ENOTTY #endif static void flush_buffer_cache (int fd) { sync(); fsync(fd); /* flush buffers */ fdatasync(fd); /* flush buffers */ sync(); if (ioctl(fd, BLKFLSBUF, NULL)) /* do it again, big time */ perror("BLKFLSBUF failed"); else do_drive_cmd(fd, NULL, 0); /* IDE: await completion */ sync(); } static int seek_to_zero (int fd) { if (lseek(fd, (off_t) 0, SEEK_SET)) { perror("lseek() failed"); return 1; } return 0; } static int read_big_block (int fd, char *buf) { int i, rc; if ((rc = read(fd, buf, TIMING_BUF_BYTES)) != TIMING_BUF_BYTES) { if (rc) { if (rc == -1) perror("read() failed"); else fprintf(stderr, "read(%u) returned %u bytes\n", TIMING_BUF_BYTES, rc); } else { fputs ("read() hit EOF - device too small\n", stderr); } return 1; } /* access all sectors of buf to ensure the read fully completed */ for (i = 0; i < TIMING_BUF_BYTES; i += 512) buf[i] &= 1; return 0; } static void *prepare_timing_buf (unsigned int len) { unsigned int i; __u8 *buf; buf = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); if (buf == MAP_FAILED) { perror("could not allocate timing buf"); return NULL; } for (i = 0; i < len; i += 4096) buf[i] = 0; /* guarantee memory is present/assigned */ if (-1 == mlock(buf, len)) { perror("mlock() failed on timing buf"); munmap(buf, len); return NULL; } mlockall(MCL_CURRENT|MCL_FUTURE); // don't care if this fails on low-memory machines sync(); /* give time for I/O to settle */ sleep(3); return buf; } static void time_cache (int fd) { char *buf; struct itimerval e1, e2; double elapsed, elapsed2; unsigned int iterations, total_MB; buf = prepare_timing_buf(TIMING_BUF_BYTES); if (!buf) return; /* * getitimer() is used rather than gettimeofday() because * it is much more consistent (on my machine, at least). */ setitimer(ITIMER_REAL, &(struct itimerval){{1000,0},{1000,0}}, NULL); if (seek_to_zero (fd)) return; if (read_big_block (fd, buf)) return; printf(" Timing %scached reads: ", (open_flags & O_DIRECT) ? "O_DIRECT " : ""); fflush(stdout); /* Clear out the device request queues & give them time to complete */ flush_buffer_cache(fd); sleep(1); /* Now do the timing */ iterations = 0; getitimer(ITIMER_REAL, &e1); do { ++iterations; if (seek_to_zero (fd) || read_big_block (fd, buf)) goto quit; getitimer(ITIMER_REAL, &e2); elapsed = (e1.it_value.tv_sec - e2.it_value.tv_sec) + ((e1.it_value.tv_usec - e2.it_value.tv_usec) / 1000000.0); } while (elapsed < 2.0); total_MB = iterations * TIMING_BUF_MB; elapsed = (e1.it_value.tv_sec - e2.it_value.tv_sec) + ((e1.it_value.tv_usec - e2.it_value.tv_usec) / 1000000.0); /* Now remove the lseek() and getitimer() overheads from the elapsed time */ getitimer(ITIMER_REAL, &e1); do { if (seek_to_zero (fd)) goto quit; getitimer(ITIMER_REAL, &e2); elapsed2 = (e1.it_value.tv_sec - e2.it_value.tv_sec) + ((e1.it_value.tv_usec - e2.it_value.tv_usec) / 1000000.0); } while (--iterations); elapsed -= elapsed2; if (total_MB >= elapsed) /* more than 1MB/s */ printf("%3u MB in %5.2f seconds = %6.2f MB/sec\n", total_MB, elapsed, total_MB / elapsed); else printf("%3u MB in %5.2f seconds = %6.2f kB/sec\n", total_MB, elapsed, total_MB / elapsed * 1024); flush_buffer_cache(fd); sleep(1); quit: munlockall(); munmap(buf, TIMING_BUF_BYTES); } static int time_device (int fd) { char *buf; double elapsed; struct itimerval e1, e2; int err = 0; unsigned int max_iterations = 1024, total_MB, iterations; /* * get device size */ if (do_ctimings || do_timings) { __u64 nsectors; do_flush = 1; err = get_dev_geometry(fd, NULL, NULL, NULL, NULL, &nsectors); if (!err) max_iterations = nsectors / (2 * 1024) / TIMING_BUF_MB; } buf = prepare_timing_buf(TIMING_BUF_BYTES); if (!buf) err = ENOMEM; if (err) goto quit; printf(" Timing %s disk reads", (open_flags & O_DIRECT) ? "O_DIRECT" : "buffered"); if (set_timings_offset) printf(" (offset %llu GB)", timings_offset / 0x40000000ULL); printf(": "); fflush(stdout); if (set_timings_offset && lseek64(fd, timings_offset, SEEK_SET) == (off64_t)-1) { err = errno; perror("lseek() failed"); goto quit; } /* * getitimer() is used rather than gettimeofday() because * it is much more consistent (on my machine, at least). */ setitimer(ITIMER_REAL, &(struct itimerval){{1000,0},{1000,0}}, NULL); /* Now do the timings for real */ iterations = 0; getitimer(ITIMER_REAL, &e1); do { ++iterations; if (read_big_block (fd, buf)) goto quit; getitimer(ITIMER_REAL, &e2); elapsed = (e1.it_value.tv_sec - e2.it_value.tv_sec) + ((e1.it_value.tv_usec - e2.it_value.tv_usec) / 1000000.0); } while (elapsed < 3.0 && iterations < max_iterations); total_MB = iterations * TIMING_BUF_MB; if ((total_MB / elapsed) > 1.0) /* more than 1MB/s */ printf("%3u MB in %5.2f seconds = %6.2f MB/sec\n", total_MB, elapsed, total_MB / elapsed); else printf("%3u MB in %5.2f seconds = %6.2f kB/sec\n", total_MB, elapsed, total_MB / elapsed * 1024); quit: munlockall(); if (buf) munmap(buf, TIMING_BUF_BYTES); return err; } static void dmpstr (const char *prefix, unsigned int i, const char *s[], unsigned int maxi) { if (i > maxi) printf("%s%u", prefix, i); else printf("%s%s", prefix, s[i]); } static __u16 *id; static void get_identify_data (int fd); static __u64 get_lba_capacity (__u16 *idw) { __u64 nsects = ((__u32)idw[58] << 16) | idw[57]; if (idw[49] & 0x200) { nsects = ((__u32)idw[61] << 16) | idw[60]; if ((idw[83] & 0xc000) == 0x4000 && (idw[86] & 0x0400)) { nsects = (__u64)idw[103] << 48 | (__u64)idw[102] << 32 | (__u64)idw[101] << 16 | idw[100]; } } return nsects; } static char *strip (char *s) { char *e; while (*s == ' ') ++s; if (*s) for (e = s + strlen(s); *--e == ' '; *e = '\0'); return s; } static void dump_identity (__u16 *idw) { int i; char pmodes[64] = {0,}, dmodes[128]={0,}, umodes[128]={0,}; char *model = strip(strndup((char *)&idw[27], 40)); char *fwrev = strip(strndup((char *)&idw[23], 8)); char *serno = strip(strndup((char *)&idw[10], 20)); __u8 tPIO; printf("\n Model=%.40s, FwRev=%.8s, SerialNo=%.20s", model, fwrev, serno); printf("\n Config={"); for (i = 0; i <= 15; i++) { if (idw[0] & (1<> 8; if (tPIO <= 5) { strcat(pmodes, "pio0 "); if (tPIO >= 1) strcat(pmodes, "pio1 "); if (tPIO >= 2) strcat(pmodes, "pio2 "); } if (!(idw[53] & 1)) printf(" (maybe):"); printf(" CurCHS=%u/%u/%u, CurSects=%u", idw[54], idw[55], idw[56], idw[57] | (idw[58] << 16)); printf(", LBA=%s", YN(idw[49] & 0x200)); if (idw[49] & 0x200) printf(", LBAsects=%llu", get_lba_capacity(idw)); if (idw[49] & 0x100) { if (idw[62] | idw[63]) { if (idw[62] & 0x100) strcat(dmodes,"*"); if (idw[62] & 1) strcat(dmodes,"sdma0 "); if (idw[62] & 0x200) strcat(dmodes,"*"); if (idw[62] & 2) strcat(dmodes,"sdma1 "); if (idw[62] & 0x400) strcat(dmodes,"*"); if (idw[62] & 4) strcat(dmodes,"sdma2 "); if (idw[62] & 0xf800) strcat(dmodes,"*"); if (idw[62] & 0xf8) strcat(dmodes,"sdma? "); if (idw[63] & 0x100) strcat(dmodes,"*"); if (idw[63] & 1) strcat(dmodes,"mdma0 "); if (idw[63] & 0x200) strcat(dmodes,"*"); if (idw[63] & 2) strcat(dmodes,"mdma1 "); if (idw[63] & 0x400) strcat(dmodes,"*"); if (idw[63] & 4) strcat(dmodes,"mdma2 "); if (idw[63] & 0xf800) strcat(dmodes,"*"); if (idw[63] & 0xf8) strcat(dmodes,"mdma? "); } } printf("\n IORDY="); if (idw[49] & 0x800) printf((idw[49] & 0x400) ? "on/off" : "yes"); else printf("no"); if ((idw[49] & 0x800) || (idw[53] & 2)) { if ((idw[53] & 2)) { printf(", tPIO={min:%u,w/IORDY:%u}", idw[67], idw[68]); if (idw[64] & 1) strcat(pmodes, "pio3 "); if (idw[64] & 2) strcat(pmodes, "pio4 "); if (idw[64] &~3) strcat(pmodes, "pio? "); } if (idw[53] & 4) { if (idw[88] & 0x100) strcat(umodes,"*"); if (idw[88] & 0x001) strcat(umodes,"udma0 "); if (idw[88] & 0x200) strcat(umodes,"*"); if (idw[88] & 0x002) strcat(umodes,"udma1 "); if (idw[88] & 0x400) strcat(umodes,"*"); if (idw[88] & 0x004) strcat(umodes,"udma2 "); if (idw[88] & 0x800) strcat(umodes,"*"); if (idw[88] & 0x008) strcat(umodes,"udma3 "); if (idw[88] & 0x1000) strcat(umodes,"*"); if (idw[88] & 0x010) strcat(umodes,"udma4 "); if (idw[88] & 0x2000) strcat(umodes,"*"); if (idw[88] & 0x020) strcat(umodes,"udma5 "); if (idw[88] & 0x4000) strcat(umodes,"*"); if (idw[88] & 0x040) strcat(umodes,"udma6 "); } } if ((idw[49] & 0x100) && (idw[53] & 2)) printf(", tDMA={min:%u,rec:%u}", idw[65], idw[66]); printf("\n PIO modes: %s", pmodes); if (*dmodes) printf("\n DMA modes: %s", dmodes); if (*umodes) printf("\n UDMA modes: %s", umodes); printf("\n AdvancedPM=%s",YN(idw[83]&8)); if (idw[83] & 8) { if (!(idw[86]&8)) printf(": disabled (255)"); else if ((idw[91]&0xFF00)!=0x4000) printf(": unknown setting"); else printf(": mode=0x%02X (%u)",idw[91]&0xFF,idw[91]&0xFF); } if (idw[82]&0x20) printf(" WriteCache=%s",(idw[85]&0x20) ? "enabled" : "disabled"); if (idw[81] || idw[80]) { printf("\n Drive conforms to: "); if (idw[81] <= 31) printf("%s: ", minor_str[idw[81]]); else printf("unknown: "); if (idw[80] != 0x0000 && /* NOVAL_0 */ idw[80] != 0xFFFF) { /* NOVAL_1 */ int count = 0; for (i=0; i <= 7; i++) { if (idw[80] & (1< 3) value = 3; return states[value]; } static void interpret_standby (void) { printf(" ("); switch(standby) { case 0: printf("off"); break; case 252: printf("21 minutes"); break; case 253: printf("vendor-specific"); break; case 254: printf("?reserved"); break; case 255: printf("21 minutes + 15 seconds"); break; default: if (standby <= 240) { unsigned int secs = standby * 5; unsigned int mins = secs / 60; secs %= 60; if (mins) printf("%u minutes", mins); if (mins && secs) printf(" + "); if (secs) printf("%u seconds", secs); } else if (standby <= 251) { unsigned int mins = (standby - 240) * 30; unsigned int hrs = mins / 60; mins %= 60; if (hrs) printf("%u hours", hrs); if (hrs && mins) printf(" + "); if (mins) printf("%u minutes", mins); } else { printf("illegal value"); } break; } printf(")\n"); } struct xfermode_entry { int val; const char *name; }; static const struct xfermode_entry xfermode_table[] = { { 8, "pio0" }, { 9, "pio1" }, { 10, "pio2" }, { 11, "pio3" }, { 12, "pio4" }, { 13, "pio5" }, { 14, "pio6" }, { 15, "pio7" }, { 16, "sdma0" }, { 17, "sdma1" }, { 18, "sdma2" }, { 19, "sdma3" }, { 20, "sdma4" }, { 21, "sdma5" }, { 22, "sdma6" }, { 23, "sdma7" }, { 32, "mdma0" }, { 33, "mdma1" }, { 34, "mdma2" }, { 35, "mdma3" }, { 36, "mdma4" }, { 37, "mdma5" }, { 38, "mdma6" }, { 39, "mdma7" }, { 64, "udma0" }, { 65, "udma1" }, { 66, "udma2" }, { 67, "udma3" }, { 68, "udma4" }, { 69, "udma5" }, { 70, "udma6" }, { 71, "udma7" }, { 0, NULL } }; static int translate_xfermode(char * name) { const struct xfermode_entry *tmp; char *endptr; int val = -1; for (tmp = xfermode_table; tmp->name != NULL; ++tmp) { if (!strcmp(name, tmp->name)) return tmp->val; } val = strtol(name, &endptr, 10); if (*endptr == '\0') return val; return -1; } static void interpret_xfermode (unsigned int xfermode) { printf(" ("); switch(xfermode) { case 0: printf("default PIO mode"); break; case 1: printf("default PIO mode, disable IORDY"); break; case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: printf("PIO flow control mode%u", xfermode-8); break; case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: printf("singleword DMA mode%u", xfermode-16); break; case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: printf("multiword DMA mode%u", xfermode-32); break; case 64: case 65: case 66: case 67: case 68: case 69: case 70: case 71: printf("UltraDMA mode%u", xfermode-64); break; default: printf("unknown, probably not valid"); break; } printf(")\n"); } static unsigned int get_erase_timeout_secs (int fd, int enhanced) { unsigned int timeout = 0; unsigned int idx = 89 + enhanced; get_identify_data(fd); if (id) { timeout = id[idx]; if (timeout && timeout <= 0xff) { /* * 0xff means "more than 254 2-minute intervals (508+ minutes), * but we really want a better idea than that. * Norman Diamond suggests allowing 1sec per 30MB of capacity. */ if (timeout == 0xff) { __u64 lba_limit = get_lba_capacity(id); __u64 estimate = (lba_limit / 2048ULL) / 30ULL / 60; timeout = 508 + 60; /* spec says > 508 minutes */ if (timeout < estimate) timeout = estimate; } else { timeout = (timeout * 2) + 30; /* Add on a 30min margin */ } } } if (!timeout) timeout = 2 * 60; /* default: two hours */ timeout *= 60; /* convert minutes to seconds */ return timeout; } static void do_set_security (int fd) { int err = 0; const char *description; struct hdio_taskfile *r; __u8 *data; r = malloc(sizeof(struct hdio_taskfile) + 512); if (!r) { err = errno; perror("malloc()"); exit(err); } memset(r, 0, sizeof(struct hdio_taskfile) + 512); r->cmd_req = TASKFILE_CMD_REQ_OUT; r->dphase = TASKFILE_DPHASE_PIO_OUT; r->obytes = 512; r->lob.command = security_command; r->oflags.lob.nsect = 1; r->lob.nsect = 1; data = (__u8*)r->data; data[0] = security_master & 0x01; memcpy(data+2, security_password, 32); r->oflags.lob.command = 1; r->oflags.lob.feat = 1; switch (security_command) { case ATA_OP_SECURITY_ERASE_UNIT: description = "SECURITY_ERASE"; data[0] |= enhanced_erase ? 0x02 : 0; break; case ATA_OP_SECURITY_DISABLE: description = "SECURITY_DISABLE"; break; case ATA_OP_SECURITY_UNLOCK: description = "SECURITY_UNLOCK"; break; case ATA_OP_SECURITY_SET_PASS: description = "SECURITY_SET_PASS"; data[1] = (security_mode & 0x01); if (security_master) { /* increment master-password revision-code */ __u16 revcode; get_identify_data(fd); if (!id) exit(EIO); revcode = id[92]; if (revcode == 0xfffe) revcode = 0; revcode += 1; data[34] = revcode; data[35] = revcode >> 8; } break; default: fprintf(stderr, "BUG in do_set_security(), command1=0x%x\n", security_command); exit(EINVAL); } printf(" Issuing %s command, password=\"%s\", user=%s", description, security_password, (data[0] & 1) ? "master" : "user"); if (security_command == ATA_OP_SECURITY_SET_PASS) printf(", mode=%s", data[1] ? "max" : "high"); printf("\n"); /* * The Linux kernel IDE driver (until at least 2.6.12) segfaults on the first * command when issued on a locked drive, and the actual erase is never issued. * One could patch the code to issue separate commands for erase prepare and * erase to erase a locked drive. * * We would like to issue these commands consecutively, but since the Linux * kernel until at least 2.6.12 segfaults on each command issued the second will * never be executed. * * One is at least able to issue the commands consecutively in two hdparm invocations, * assuming the segfault isn't followed by an oops. */ if (security_command == ATA_OP_SECURITY_ERASE_UNIT) { unsigned int timeout = get_erase_timeout_secs(fd, enhanced_erase); __u8 args[4] = {ATA_OP_SECURITY_ERASE_PREPARE,0,0,0}; if (do_drive_cmd(fd, args, 0)) { err = errno; perror("ERASE_PREPARE"); } else { if ((do_taskfile_cmd(fd, r, timeout))) { err = errno; perror("SECURITY_ERASE"); } } } else if (security_command == ATA_OP_SECURITY_DISABLE) { /* First attempt an unlock */ r->lob.command = ATA_OP_SECURITY_UNLOCK; if ((do_taskfile_cmd(fd, r, timeout_15secs))) { err = errno; perror("SECURITY_UNLOCK"); } else { /* Then the security disable */ r->lob.command = security_command; if ((do_taskfile_cmd(fd, r, timeout_15secs))) { err = errno; perror("SECURITY_DISABLE"); } } } else if (security_command == ATA_OP_SECURITY_UNLOCK) { if ((do_taskfile_cmd(fd, r, timeout_15secs))) { err = errno; perror("SECURITY_UNLOCK"); } } else if (security_command == ATA_OP_SECURITY_SET_PASS) { if ((do_taskfile_cmd(fd, r, timeout_15secs))) { err = errno; perror("SECURITY_SET_PASS"); } } else { fprintf(stderr, "BUG in do_set_security(), command2=0x%x\n", security_command); err = EINVAL; } free(r); if (err) exit(err); } static __u8 last_identify_op = 0; static void get_identify_data (int fd) { static __u8 args[4+512]; int i; if (id) return; memset(args, 0, sizeof(args)); last_identify_op = ATA_OP_IDENTIFY; args[0] = last_identify_op; args[3] = 1; /* sector count */ if (do_drive_cmd(fd, args, 0)) { prefer_ata12 = 0; memset(args, 0, sizeof(args)); last_identify_op = ATA_OP_PIDENTIFY; args[0] = last_identify_op; args[3] = 1; /* sector count */ if (do_drive_cmd(fd, args, 0)) { perror(" HDIO_DRIVE_CMD(identify) failed"); return; } } /* byte-swap the little-endian IDENTIFY data to match byte-order on host CPU */ id = (void *)(args + 4); for (i = 0; i < 0x100; ++i) __le16_to_cpus(&id[i]); } static void confirm_i_know_what_i_am_doing (const char *opt, const char *explanation) { if (!i_know_what_i_am_doing) { fprintf(stderr, "Use of %s is VERY DANGEROUS.\n%s\n" "Please supply the --yes-i-know-what-i-am-doing flag if you really want this.\n" "Program aborted.\n", opt, explanation); exit(EPERM); } } static void confirm_please_destroy_my_drive (const char *opt, const char *explanation) { if (!please_destroy_my_drive) { fprintf(stderr, "Use of %s is EXTREMELY DANGEROUS.\n%s\n" "Please also supply the --please-destroy-my-drive flag if you really want this.\n" "Program aborted.\n", opt, explanation); exit(EPERM); } } static int flush_wcache (int fd) { __u8 args[4] = {ATA_OP_FLUSHCACHE,0,0,0}; int err = 0; get_identify_data(fd); if (id && (id[83] & 0xe000) == 0x6000) args[0] = ATA_OP_FLUSHCACHE_EXT; if (do_drive_cmd(fd, args, timeout_60secs)) { err = errno; perror (" HDIO_DRIVE_CMD(flushcache) failed"); } return err; } static void dump_sectors (__u16 *w, unsigned int count) { unsigned int i; for (i = 0; i < (count*256/8); ++i) { #if 0 printf("%04x %04x %04x %04x %04x %04x %04x %04x\n", w[0], w[1], w[2], w[3], w[4], w[5], w[6], w[7]); w += 8; #else int word; for (word = 0; word < 8; ++word) { printf("%04x", le16toh(w[0])); ++w; putchar(word == 7 ? '\n' : ' '); } #endif } } static int abort_if_not_full_device (int fd, __u64 lba, const char *devname, const char *msg) { __u64 start_lba; int i, err, shortened = 0; char *fdevname = strdup(devname); err = get_dev_geometry(fd, NULL, NULL, NULL, &start_lba, NULL); if (err) exit(err); for (i = strlen(fdevname); --i > 2 && (fdevname[i] >= '0' && fdevname[i] <= '9');) { fdevname[i] = '\0'; shortened = 1; } if (!shortened) fdevname = strdup("the full disk"); if (start_lba == 0ULL) return 0; if (start_lba == START_LBA_UNKNOWN || fd_is_raid(fd)) { fprintf(stderr, "%s is a RAID device: please specify an absolute LBA of a raw member device instead (raid1 only)\n", devname); } else if (msg) { fprintf(stderr, "%s\n", msg); } else { fprintf(stderr, "Device %s has non-zero LBA starting offset of %llu.\n", devname, start_lba); fprintf(stderr, "Please use an absolute LBA with the /dev/ entry for the raw device, rather than a partition or raid name.\n"); fprintf(stderr, "%s is probably a partition of %s (?)\n", devname, fdevname); fprintf(stderr, "The absolute LBA of sector %llu from %s should be %llu\n", lba, devname, start_lba + lba); } fprintf(stderr, "Aborting.\n"); exit(EINVAL); } static __u16 *get_dco_identify_data (int fd, int quietly) { static __u8 args[4+512]; __u16 *dco = (void *)(args + 4); int i; memset(args, 0, sizeof(args)); args[0] = ATA_OP_DCO; args[2] = 0xc2; args[3] = 1; if (do_drive_cmd(fd, args, 0)) { if (!quietly) perror(" HDIO_DRIVE_CMD(dco_identify) failed"); return NULL; } else { /* byte-swap the little-endian DCO data to match byte-order on host CPU */ for (i = 0; i < 0x100; ++i) __le16_to_cpus(&dco[i]); //dump_sectors(dco, 1); return dco; } } static __u64 do_get_native_max_sectors (int fd) { int err = 0; __u64 max = 0; struct hdio_taskfile r; get_identify_data(fd); if (!id) exit(EIO); memset(&r, 0, sizeof(r)); r.cmd_req = TASKFILE_CMD_REQ_NODATA; r.dphase = TASKFILE_DPHASE_NONE; r.oflags.lob.dev = 1; r.oflags.lob.command = 1; r.iflags.lob.command = 1; r.iflags.lob.lbal = 1; r.iflags.lob.lbam = 1; r.iflags.lob.lbah = 1; r.lob.dev = 0x40; if (((id[83] & 0xc400) == 0x4400) && (id[86] & 0x0400)) { r.iflags.hob.lbal = 1; r.iflags.hob.lbam = 1; r.iflags.hob.lbah = 1; r.lob.command = ATA_OP_READ_NATIVE_MAX_EXT; if (do_taskfile_cmd(fd, &r, 10)) { err = errno; perror (" READ_NATIVE_MAX_ADDRESS_EXT failed"); } else { if (verbose) printf("READ_NATIVE_MAX_ADDRESS_EXT response: hob={%02x %02x %02x} lob={%02x %02x %02x}\n", r.hob.lbah, r.hob.lbam, r.hob.lbal, r.lob.lbah, r.lob.lbam, r.lob.lbal); max = (((__u64)((r.hob.lbah << 16) | (r.hob.lbam << 8) | r.hob.lbal) << 24) | ((r.lob.lbah << 16) | (r.lob.lbam << 8) | r.lob.lbal)) + 1; } } else { r.iflags.lob.dev = 1; r.lob.command = ATA_OP_READ_NATIVE_MAX; if (do_taskfile_cmd(fd, &r, 0)) { err = errno; perror (" READ_NATIVE_MAX_ADDRESS failed"); } else { max = (((r.lob.dev & 0x0f) << 24) | (r.lob.lbah << 16) | (r.lob.lbam << 8) | r.lob.lbal) + 1; } } errno = err; return max; } static int do_make_bad_sector (int fd, __u64 lba, const char *devname) { int err = 0, has_write_unc = 0; struct hdio_taskfile *r; const char *flagged; abort_if_not_full_device(fd, lba, devname, NULL); r = malloc(sizeof(struct hdio_taskfile) + 520); if (!r) { err = errno; perror("malloc()"); return err; } get_identify_data(fd); if (id) has_write_unc = (id[ 83] & 0xc000) == 0x4000 && (id[ 86] & 0x8000) == 0x8000 && (id[119] & 0xc004) == 0x4004 && (id[120] & 0xc000) == 0x4000; if (has_write_unc || make_bad_sector_flagged || lba >= lba28_limit) { if (!has_write_unc) { printf("Device does not claim to implement the required WRITE_UNC_EXT command\n" "This operation will probably fail (continuing regardless).\n"); } init_hdio_taskfile(r, ATA_OP_WRITE_UNC_EXT, RW_READ, LBA48_FORCE, lba, 1, 0); r->oflags.lob.feat = 1; r->lob.feat = make_bad_sector_flagged ? 0xaa : 0x55; flagged = make_bad_sector_flagged ? "flagged" : "pseudo"; printf("Corrupting sector %llu (WRITE_UNC_EXT as %s): ", lba, flagged); } else { init_hdio_taskfile(r, ATA_OP_WRITE_LONG_ONCE, RW_WRITE, LBA28_OK, lba, 1, 520); memset(r->data, 0xa5, 520); printf("Corrupting sector %llu (WRITE_LONG): ", lba); } fflush(stdout); /* Try and ensure that the system doesn't have our sector in cache */ flush_buffer_cache(fd); if (do_taskfile_cmd(fd, r, timeout_60secs)) { err = errno; perror("FAILED"); } else { printf("succeeded\n"); } free(r); return err; } #ifdef FORMAT_AND_ERASE static int do_format_track (int fd, __u64 lba, const char *devname) { int err = 0; struct hdio_taskfile *r; abort_if_not_full_device(fd, lba, devname, NULL); r = malloc(sizeof(struct hdio_taskfile) + 512); if (!r) { err = errno; perror("malloc()"); return err; } init_hdio_taskfile(r, ATA_OP_FORMAT_TRACK, RW_WRITE, LBA28_OK, lba, 1, 512); r->lob.nsect = 0; printf("re-formatting lba %llu: ", lba); fflush(stdout); if (do_taskfile_cmd(fd, r, timeout_60secs)) { err = errno; perror("FAILED"); } else { printf("succeeded\n"); } // Try and ensure that the system doesn't have our sector in cache: flush_buffer_cache(fd); free(r); return err; } static int do_erase_sectors (int fd, __u64 lba, const char *devname) { int err = 0; struct hdio_taskfile *r; abort_if_not_full_device(fd, lba, devname, NULL); r = malloc(sizeof(struct hdio_taskfile) + 0); if (!r) { err = errno; perror("malloc()"); return err; } init_hdio_taskfile(r, ATA_OP_ERASE_SECTORS, RW_READ, LBA28_OK, lba, 256, 0); printf("erasing sectors %llu-%llu: ", lba, lba + 255); fflush(stdout); if (do_taskfile_cmd(fd, r, timeout_60secs)) { err = errno; perror("FAILED"); } else { printf("succeeded\n"); } free(r); return err; } #endif /* FORMAT_AND_ERASE */ struct sector_range_s { __u64 lba; __u64 nsectors; }; static int trim_sectors (int fd, const char *devname, int nranges, void *data, __u64 nsectors) { struct ata_tf tf; int err = 0; unsigned int data_bytes = nranges * sizeof(__u64); unsigned int data_sects = (data_bytes + 511) / 512; data_bytes = data_sects * 512; abort_if_not_full_device(fd, 0, devname, NULL); printf("trimming %llu sectors from %d ranges\n", nsectors, nranges); fflush(stdout); // Try and ensure that the system doesn't have the to-be-trimmed sectors in cache: flush_buffer_cache(fd); tf_init(&tf, ATA_OP_DSM, 0, data_sects); tf.lob.feat = 0x01; /* DSM/TRIM */ if (sg16(fd, SG_WRITE, SG_DMA, &tf, data, data_bytes, 300 /* seconds */)) { err = errno; perror("FAILED"); } else { printf("succeeded\n"); } return err; } static void do_trim_sector_ranges (int fd, const char *devname, int nranges, struct sector_range_s *sr) { __u64 range, *data, nsectors = 0; unsigned int data_sects, data_bytes; int i, err = 0; abort_if_not_full_device(fd, 0, devname, NULL); data_sects = ((nranges * sizeof(range)) + 511) / 512; data_bytes = data_sects * 512; data = mmap(NULL, data_bytes, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); if (data == MAP_FAILED) { err = errno; perror("mmap(MAP_ANONYMOUS)"); exit(err); } // FIXME: handle counts > 65535 here! for (i = 0; i < nranges; ++i) { nsectors += sr->nsectors; range = sr->nsectors; range = (range << 48) | sr->lba; data[i] = __cpu_to_le64(range); ++sr; } err = trim_sectors(fd, devname, nranges, data, nsectors); munmap(data, data_bytes); exit(err); } static void extract_id_string (__u16 *idw, int words, char *dst) { char *e; int i, max = words * 2; for (i = 0; i < words; ++i) { __u16 w = idw[i]; w = __be16_to_cpu(w); dst[i*2 ] = w >> 8; dst[i*2+1] = w; } dst[max] = '\0'; for (e = dst + max; --e != dst;) { if (*e && *e != ' ') break; *e = '\0'; } } static int get_trim_dev_limit (void) { char model[41]; if (id[105] && id[105] != 0xffff) return id[105]; extract_id_string(id + 27, 20, model); if (0 == strcmp(model, "OCZ VERTEX-LE")) return 8; if (0 == strcmp(model, "OCZ-VERTEX")) return 64; return 1; /* all other drives, including Intel SSDs */ } static int do_trim_from_stdin (int fd, const char *devname) { __u64 *data, range, nsectors = 0, lba_limit; unsigned int max_kb, data_sects, data_bytes; unsigned int total_ranges = 0, nranges = 0, max_ranges, dev_limit; int err = 0; get_identify_data(fd); if (!id) exit(EIO); lba_limit = get_lba_capacity(id); dev_limit = get_trim_dev_limit(); err = sysfs_get_attr(fd, "queue/max_sectors_kb", "%u", &max_kb, NULL, 0); if (err || max_kb == 0) data_sects = 128; /* "safe" default for most controllers */ else data_sects = max_kb * 2; if (data_sects > dev_limit) data_sects = dev_limit; data_bytes = data_sects * 512; data = mmap(NULL, data_bytes, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); if (data == MAP_FAILED) { err = errno; perror("mmap(MAP_ANONYMOUS)"); exit(err); } memset(data, 0, data_bytes); max_ranges = data_bytes / sizeof(range); do { __u64 lba, nsect; int args; if (nranges == 0) memset(data, 0, data_bytes); errno = EINVAL; args = scanf("%llu:%llu", &lba, &nsect); if (args == EOF) break; if (args != 2 || nsect > 0xffff || lba >= lba_limit) { if (args == 2) errno = ERANGE; err = errno; fprintf(stderr, "stdin: error at lba:count pair #%d: %s\n", (total_ranges + 1), strerror(err)); } else { range = (nsect << 48) | lba; nsectors += nsect; data[nranges++] = __cpu_to_le64(range); if (nranges == max_ranges) { err = trim_sectors(fd, devname, nranges, data, nsectors); memset(data, 0, data_bytes); nranges = 0; nsectors = 0; } ++total_ranges; } } while (!err); if (!err && nranges) err = trim_sectors(fd, devname, nranges, data, nsectors); munmap(data, data_bytes); return err; } static int do_write_sector (int fd, __u64 lba, const char *devname) { int err = 0; __u8 ata_op; struct hdio_taskfile *r; abort_if_not_full_device(fd, lba, devname, NULL); r = malloc(sizeof(struct hdio_taskfile) + 512); if (!r) { err = errno; perror("malloc()"); return err; } ata_op = (lba >= lba28_limit) ? ATA_OP_WRITE_PIO_EXT : ATA_OP_WRITE_PIO; init_hdio_taskfile(r, ata_op, RW_WRITE, LBA28_OK, lba, 1, 512); printf("re-writing sector %llu: ", lba); fflush(stdout); // Try and ensure that the system doesn't have our sector in cache: flush_buffer_cache(fd); if (do_taskfile_cmd(fd, r, timeout_60secs)) { err = errno; perror("FAILED"); } else { printf("succeeded\n"); } free(r); return err; } static int do_read_sector (int fd, __u64 lba, const char *devname) { int err = 0; __u8 ata_op; struct hdio_taskfile *r; abort_if_not_full_device(fd, lba, devname, NULL); r = malloc(sizeof(struct hdio_taskfile) + 512); if (!r) { err = errno; perror("malloc()"); return err; } ata_op = (lba >= lba28_limit) ? ATA_OP_READ_PIO_EXT : ATA_OP_READ_PIO; init_hdio_taskfile(r, ata_op, RW_READ, LBA28_OK, lba, 1, 512); printf("reading sector %llu: ", lba); fflush(stdout); if (do_taskfile_cmd(fd, r, timeout_60secs)) { err = errno; perror("FAILED"); } else { printf("succeeded\n"); dump_sectors(r->data, 1); } free(r); return err; } static int do_idleunload (int fd, const char *devname) { int err = 0; struct hdio_taskfile r; abort_if_not_full_device(fd, 0, devname, NULL); init_hdio_taskfile(&r, ATA_OP_IDLEIMMEDIATE, RW_READ, LBA28_OK, 0x0554e4c, 0, 0); r.oflags.lob.feat = 1; r.lob.feat = 0x44; if (do_taskfile_cmd(fd, &r, 0)) { err = errno; perror("TASKFILE(idle_immediate_unload) failed"); } return err; } static int do_set_max_sectors (int fd, __u64 max_lba, int permanent) { int err = 0; struct hdio_taskfile r; __u8 nsect = permanent ? 1 : 0; get_identify_data(fd); if (!id) exit(EIO); if ((max_lba >= lba28_limit) || (id && ((id[83] & 0xc400) == 0x4400) && (id[86] & 0x0400))) { init_hdio_taskfile(&r, ATA_OP_SET_MAX_EXT, RW_READ, LBA48_FORCE, max_lba, nsect, 0); } else { init_hdio_taskfile(&r, ATA_OP_SET_MAX, RW_READ, LBA28_OK, max_lba, nsect, 0); r.oflags.lob.feat = 1; /* this ATA op requires feat==0 */ } /* spec requires that we do this immediately in front.. racey */ if (!do_get_native_max_sectors(fd)) return errno; /* now set the new value */ if (do_taskfile_cmd(fd, &r, 0)) { err = errno; perror(" SET_MAX_ADDRESS failed"); } return err; } static void usage_help (int clue, int rc) { FILE *desc = rc ? stderr : stdout; fprintf(desc,"\n%s - get/set hard disk parameters - version " VERSION ", by Mark Lord.\n\n", progname); if (0) if (rc) fprintf(desc, "clue=%d\n", clue); fprintf(desc,"Usage: %s [options] [device ...]\n\n", progname); fprintf(desc,"Options:\n" " -a Get/set fs readahead\n" " -A Get/set the drive look-ahead flag (0/1)\n" " -b Get/set bus state (0 == off, 1 == on, 2 == tristate)\n" " -B Set Advanced Power Management setting (1-255)\n" " -c Get/set IDE 32-bit IO setting\n" " -C Check drive power mode status\n" " -d Get/set using_dma flag\n" " -D Enable/disable drive defect management\n" " -E Set cd/dvd drive speed\n" " -f Flush buffer cache for device on exit\n" " -F Flush drive write cache\n" " -g Display drive geometry\n" " -h Display terse usage information\n" " -H Read temperature from drive (Hitachi only)\n" " -i Display drive identification\n" " -I Detailed/current information directly from drive\n" " -J Get/set Western DIgital \"Idle3\" timeout for a WDC \"Green\" drive (DANGEROUS)\n" " -k Get/set keep_settings_over_reset flag (0/1)\n" " -K Set drive keep_features_over_reset flag (0/1)\n" " -L Set drive doorlock (0/1) (removable harddisks only)\n" " -m Get/set multiple sector count\n" " -M Get/set acoustic management (0-254, 128: quiet, 254: fast)\n" " -n Get/set ignore-write-errors flag (0/1)\n" " -N Get/set max visible number of sectors (HPA) (VERY DANGEROUS)\n" " -p Set PIO mode on IDE interface chipset (0,1,2,3,4,...)\n" " -P Set drive prefetch count\n" " -q Change next setting quietly\n" " -Q Get/set DMA queue_depth (if supported)\n" " -r Get/set device readonly flag (DANGEROUS to set)\n" " -R Get/set device write-read-verify flag\n" " -s Set power-up in standby flag (0/1) (DANGEROUS)\n" " -S Set standby (spindown) timeout\n" " -t Perform device read timings\n" " -T Perform cache read timings\n" " -u Get/set unmaskirq flag (0/1)\n" " -U Obsolete\n" " -v Use defaults; same as -acdgkmur for IDE drives\n" " -V Display program version and exit immediately\n" " -w Perform device reset (DANGEROUS)\n" " -W Get/set drive write-caching flag (0/1)\n" " -x Obsolete\n" " -X Set IDE xfer mode (DANGEROUS)\n" " -y Put drive in standby mode\n" " -Y Put drive to sleep\n" " -z Re-read partition table\n" " -Z Disable Seagate auto-powersaving mode\n" " --dco-freeze Freeze/lock current device configuration until next power cycle\n" " --dco-identify Read/dump device configuration identify data\n" " --dco-restore Reset device configuration back to factory defaults\n" " --direct Use O_DIRECT to bypass page cache for timings\n" " --drq-hsm-error Crash system with a \"stuck DRQ\" error (VERY DANGEROUS)\n" " --fallocate Create a file without writing data to disk\n" " --fibmap Show device extents (and fragmentation) for a file\n" " --fwdownload Download firmware file to drive (EXTREMELY DANGEROUS)\n" " --fwdownload-mode3 Download firmware using min-size segments (EXTREMELY DANGEROUS)\n" " --fwdownload-mode3-max Download firmware using max-size segments (EXTREMELY DANGEROUS)\n" " --fwdownload-mode7 Download firmware using a single segment (EXTREMELY DANGEROUS)\n" " --idle-immediate Idle drive immediately\n" " --idle-unload Idle immediately and unload heads\n" " --Istdin Read identify data from stdin as ASCII hex\n" " --Istdout Write identify data to stdout as ASCII hex\n" " --make-bad-sector Deliberately corrupt a sector directly on the media (VERY DANGEROUS)\n" " --offset use with -t, to begin timings at given offset (in GiB) from start of drive\n" " --prefer-ata12 Use 12-byte (instead of 16-byte) SAT commands when possible\n" " --read-sector Read and dump (in hex) a sector directly from the media\n" " --security-help Display help for ATA security commands\n" " --trim-sector-ranges Tell SSD firmware to discard unneeded data sectors: lba:count ..\n" " --trim-sector-ranges-stdin Same as above, but reads lba:count pairs from stdin\n" " --verbose Display extra diagnostics from some commands\n" " --write-sector Repair/overwrite a (possibly bad) sector directly on the media (VERY DANGEROUS)\n" "\n"); exit(rc); } static void security_help (int rc) { FILE *desc = rc ? stderr : stdout; fprintf(desc, "\n" "ATA Security Commands:\n" " Most of these are VERY DANGEROUS and can destroy all of your data!\n" " Due to bugs in older Linux kernels, use of these commands may even\n" " trigger kernel segfaults or worse. EXPERIMENT AT YOUR OWN RISK!\n" "\n" " --security-freeze Freeze security settings until reset.\n" "\n" " --security-set-pass PASSWD Lock drive, using password PASSWD:\n" " Use 'NULL' to set empty password.\n" " Drive gets locked if user-passwd is selected.\n" " --security-unlock PASSWD Unlock drive.\n" " --security-disable PASSWD Disable drive locking.\n" " --security-erase PASSWD Erase a (locked) drive.\n" " --security-erase-enhanced PASSWD Enhanced-erase a (locked) drive.\n" "\n" " The above four commands may optionally be preceded by these options:\n" " --security-mode LEVEL Use LEVEL to select security level:\n" " h high security (default).\n" " m maximum security.\n" " --user-master WHICH Use WHICH to choose password type:\n" " u user-password (default).\n" " m master-password\n" ); exit(rc); } void process_dev (char *devname) { int fd; int err = 0; static long parm, multcount; id = NULL; fd = open(devname, open_flags); if (fd < 0) { err = errno; perror(devname); exit(err); } if (!quiet) printf("\n%s:\n", devname); if (trim_from_stdin) { if (num_flags_processed > 1 || argc) usage_help(12,EINVAL); confirm_please_destroy_my_drive("--trim-sector-ranges-stdin", "This might destroy the drive and/or all data on it."); exit(do_trim_from_stdin(fd, devname)); } if (set_wdidle3) { unsigned char timeout = wdidle3_msecs_to_timeout(wdidle3); confirm_please_destroy_my_drive("-J", "This implementation is not as thorough as the official WDIDLE3.EXE. Use at your own risk!"); if (get_wdidle3) { printf(" setting wdidle3 to "); wdidle3_print_timeout(timeout); putchar('\n'); } err = wdidle3_set_timeout(fd, timeout); } if (set_fsreadahead) { if (get_fsreadahead) printf(" setting fs readahead to %d\n", fsreadahead); if (ioctl(fd, BLKRASET, fsreadahead)) { err = errno; perror(" BLKRASET failed"); } } if (set_piomode) { if (get_piomode) { if (piomode == 255) printf(" attempting to auto-tune PIO mode\n"); else if (piomode < 100) printf(" attempting to set PIO mode to %d\n", piomode); else if (piomode < 200) printf(" attempting to set MDMA mode to %d\n", (piomode-100)); else printf(" attempting to set UDMA mode to %d\n", (piomode-200)); } if (ioctl(fd, HDIO_SET_PIO_MODE, piomode)) { err = errno; perror(" HDIO_SET_PIO_MODE failed"); } } if (set_io32bit) { if (get_io32bit) printf(" setting 32-bit IO_support flag to %d\n", io32bit); if (ioctl(fd, HDIO_SET_32BIT, io32bit)) { err = errno; perror(" HDIO_SET_32BIT failed"); } } if (set_mult) { if (get_mult) printf(" setting multcount to %d\n", mult); if (ioctl(fd, HDIO_SET_MULTCOUNT, mult)) #if 0 perror(" HDIO_SET_MULTCOUNT failed"); #else /* for libata */ { if (errno != ENOTTY) { perror(" HDIO_SET_MULTCOUNT failed"); } else { __u8 args[4] = {ATA_OP_SET_MULTIPLE,mult,0,0}; confirm_i_know_what_i_am_doing("-m", "Only the old IDE drivers work correctly with -m with kernels up to at least 2.6.29.\nlibata drives may fail and get hung if you set this flag."); if (do_drive_cmd(fd, args, 0)) { err = errno; perror(" HDIO_DRIVE_CMD(set_multi_count) failed"); } } } #endif } if (set_readonly) { if (get_readonly) { printf(" setting readonly to %d", readonly); on_off(readonly); } if (ioctl(fd, BLKROSET, &readonly)) { err = errno; perror(" BLKROSET failed"); } } if (set_unmask) { if (get_unmask) { printf(" setting unmaskirq to %d", unmask); on_off(unmask); } if (ioctl(fd, HDIO_SET_UNMASKINTR, unmask)) { err = errno; perror(" HDIO_SET_UNMASKINTR failed"); } } if (set_dma) { if (get_dma) { printf(" setting using_dma to %d", dma); on_off(dma); } if (ioctl(fd, HDIO_SET_DMA, dma)) { err = errno; perror(" HDIO_SET_DMA failed"); } } if (set_dma_q) { if (get_dma_q) printf(" setting queue_depth to %d\n", dma_q); err = sysfs_set_attr(fd, "device/queue_depth", "%u", &dma_q, 1); } if (set_nowerr) { if (get_nowerr) { printf(" setting nowerr to %d", nowerr); on_off(nowerr); } if (ioctl(fd, HDIO_SET_NOWERR, nowerr)) { err = errno; perror(" HDIO_SET_NOWERR failed"); } } if (set_keep) { if (get_keep) { printf(" setting keep_settings to %d", keep); on_off(keep); } if (ioctl(fd, HDIO_SET_KEEPSETTINGS, keep)) { err = errno; perror(" HDIO_SET_KEEPSETTINGS failed"); } } if (set_doorlock) { __u8 args[4] = {0,0,0,0}; args[0] = doorlock ? ATA_OP_DOORLOCK : ATA_OP_DOORUNLOCK; if (get_doorlock) { printf(" setting drive doorlock to %d", doorlock); on_off(doorlock); } if (do_drive_cmd(fd, args, timeout_15secs)) { err = errno; perror(" HDIO_DRIVE_CMD(doorlock) failed"); } } if (set_dkeep) { /* lock/unlock the drive's "feature" settings */ __u8 args[4] = {ATA_OP_SETFEATURES,0,0,0}; if (get_dkeep) { printf(" setting drive keep features to %d", dkeep); on_off(dkeep); } args[2] = dkeep ? 0x66 : 0xcc; if (do_drive_cmd(fd, args, 0)) { err = errno; perror(" HDIO_DRIVE_CMD(keepsettings) failed"); } } if (set_defects) { __u8 args[4] = {ATA_OP_SETFEATURES,0,0,0}; args[2] = defects ? 0x04 : 0x84; if (get_defects) printf(" setting drive defect management to %d\n", defects); if (do_drive_cmd(fd, args, 0)) { err = errno; perror(" HDIO_DRIVE_CMD(defectmgmt) failed"); } } if (set_prefetch) { __u8 args[4] = {ATA_OP_SETFEATURES,0,0xab,0}; args[1] = prefetch; if (get_prefetch) printf(" setting drive prefetch to %d\n", prefetch); if (do_drive_cmd(fd, args, 0)) { err = errno; perror(" HDIO_DRIVE_CMD(setprefetch) failed"); } } if (set_xfermode) { __u8 args[4] = {ATA_OP_SETFEATURES,0,3,0}; args[1] = xfermode_requested; if (get_xfermode) { printf(" setting xfermode to %d", xfermode_requested); interpret_xfermode(xfermode_requested); } if (do_drive_cmd(fd, args, 0)) { err = errno; perror(" HDIO_DRIVE_CMD(setxfermode) failed"); } } if (set_lookahead) { __u8 args[4] = {ATA_OP_SETFEATURES,0,0,0}; args[2] = lookahead ? 0xaa : 0x55; if (get_lookahead) { printf(" setting drive read-lookahead to %d", lookahead); on_off(lookahead); } if (do_drive_cmd(fd, args, 0)) { err = errno; perror(" HDIO_DRIVE_CMD(setreadahead) failed"); } } if (set_powerup_in_standby) { __u8 args[4] = {ATA_OP_SETFEATURES,0,0,0}; if (powerup_in_standby == 0) { __u8 args1[4] = {ATA_OP_SETFEATURES,0,0x07,0}; /* spinup from standby */ printf(" spin-up:"); fflush(stdout); (void) do_drive_cmd(fd, args1, 0); } else { confirm_i_know_what_i_am_doing("-s1", "This requires BIOS and kernel support to recognize/boot the drive."); } if (get_powerup_in_standby) { printf(" setting power-up in standby to %d", powerup_in_standby); fflush(stdout); on_off(powerup_in_standby); } args[0] = ATA_OP_SETFEATURES; args[2] = powerup_in_standby ? 0x06 : 0x86; if (do_drive_cmd(fd, args, 0)) { err = errno; perror(" HDIO_DRIVE_CMD(powerup_in_standby) failed"); } } if (set_apmmode) { __u8 args[4] = {ATA_OP_SETFEATURES,0,0,0}; if (get_apmmode) printf(" setting Advanced Power Management level to"); if (apmmode==255) { /* disable Advanced Power Management */ args[2] = 0x85; /* feature register */ if (get_apmmode) printf(" disabled\n"); } else { /* set Advanced Power Management mode */ args[2] = 0x05; /* feature register */ args[1] = apmmode; /* sector count register */ if (get_apmmode) printf(" 0x%02x (%d)\n",apmmode,apmmode); } if (do_drive_cmd(fd, args, 0)) { err = errno; perror(" HDIO_DRIVE_CMD failed"); } } if (set_cdromspeed) { int err1, err2; /* The CDROM_SELECT_SPEED ioctl * actually issues GPCMD_SET_SPEED to the drive. * But many newer DVD drives want GPCMD_SET_STREAMING instead, * which we now do afterwards. */ if (get_cdromspeed) printf ("setting cd/dvd speed to %d\n", cdromspeed); err1 = set_dvdspeed(fd, cdromspeed); err2 = ioctl(fd, CDROM_SELECT_SPEED, cdromspeed); if (err1 && err2) { err = errno; perror(" SET_STREAMING/CDROM_SELECT_SPEED both failed"); } } if (set_acoustic) { __u8 args[4]; if (get_acoustic) printf(" setting acoustic management to %d\n", acoustic); args[0] = ATA_OP_SETFEATURES; args[1] = acoustic; args[2] = acoustic ? 0x42 : 0xc2; args[3] = 0; if (do_drive_cmd(fd, args, 0)) { err = errno; perror(" HDIO_DRIVE_CMD:ACOUSTIC failed"); } } if (set_write_read_verify) { __u8 args[4]; if (get_write_read_verify) printf(" setting write-read-verify to %d\n", write_read_verify); args[0] = ATA_OP_SETFEATURES; args[1] = write_read_verify; args[2] = write_read_verify ? 0x0b : 0x8b; args[3] = 0; if (do_drive_cmd(fd, args, 0)) { err = errno; perror(" HDIO_DRIVE_CMD:WRV failed"); } } if (set_wcache) { if (get_wcache) { printf(" setting drive write-caching to %d", wcache); on_off(wcache); } if (!wcache) err = flush_wcache(fd); if (ioctl(fd, HDIO_SET_WCACHE, wcache)) { __u8 setcache[4] = {ATA_OP_SETFEATURES,0,0,0}; setcache[2] = wcache ? 0x02 : 0x82; if (do_drive_cmd(fd, setcache, 0)) { err = errno; perror(" HDIO_DRIVE_CMD(setcache) failed"); } } if (!wcache) err = flush_wcache(fd); } if (set_standby) { __u8 args[4] = {ATA_OP_SETIDLE,standby,0,0}; if (get_standby) { printf(" setting standby to %u", standby); interpret_standby(); } if (do_drive_cmd(fd, args, 0)) { err = errno; perror(" HDIO_DRIVE_CMD(setidle) failed"); } } if (set_security) { do_set_security(fd); } if (do_dco_identify) { __u16 *dco = get_dco_identify_data(fd, 0); if (dco) dco_identify_print(dco); } if (do_dco_restore) { __u8 args[4] = {ATA_OP_DCO,0,0xc0,0}; confirm_i_know_what_i_am_doing("--dco-restore", "You are trying to deliberately reset your drive configuration back to the factory defaults.\nThis may change the apparent capacity and feature set of the drive, making all data on it inaccessible.\nYou could lose *everything*."); printf(" issuing DCO restore command\n"); if (do_drive_cmd(fd, args, 0)) { err = errno; perror(" HDIO_DRIVE_CMD(dco_restore) failed"); } } if (do_dco_freeze) { __u8 args[4] = {ATA_OP_DCO,0,0xc1,0}; printf(" issuing DCO freeze command\n"); if (do_drive_cmd(fd, args, 0)) { err = errno; perror(" HDIO_DRIVE_CMD(dco_freeze) failed"); } } if (security_freeze) { __u8 args[4] = {ATA_OP_SECURITY_FREEZE_LOCK,0,0,0}; printf(" issuing security freeze command\n"); if (do_drive_cmd(fd, args, 0)) { err = errno; perror(" HDIO_DRIVE_CMD(security_freeze) failed"); } } if (set_seagate) { __u8 args[4] = {0xfb,0,0,0}; if (get_seagate) printf(" disabling Seagate auto powersaving mode\n"); if (do_drive_cmd(fd, args, 0)) { err = errno; perror(" HDIO_DRIVE_CMD(seagatepwrsave) failed"); } } if (set_busstate) { if (get_busstate) printf(" setting bus state to %d (%s)\n", busstate, busstate_str(busstate)); if (ioctl(fd, HDIO_SET_BUSSTATE, busstate)) { err = errno; perror(" HDIO_SET_BUSSTATE failed"); } } if (set_max_sectors) { if (get_native_max_sectors) printf(" setting max visible sectors to %llu (%s)\n", set_max_addr, set_max_permanent ? "permanent" : "temporary"); get_identify_data(fd); if (id) { if (set_max_addr < get_lba_capacity(id)) confirm_i_know_what_i_am_doing("-Nnnnnn", "You have requested reducing the apparent size of the drive.\nThis is a BAD idea, and can easily destroy all of the drive's contents."); err = do_set_max_sectors(fd, set_max_addr - 1, set_max_permanent); id = NULL; /* invalidate existing identify data */ } } if (make_bad_sector) { get_identify_data(fd); if (id) { confirm_i_know_what_i_am_doing("--make-bad-sector", "You are trying to deliberately corrupt a low-level sector on the media.\nThis is a BAD idea, and can easily result in total data loss."); err = do_make_bad_sector(fd, make_bad_sector_addr, devname); } } #ifdef FORMAT_AND_ERASE if (format_track) { confirm_i_know_what_i_am_doing("--format-track", "This flag is still under development and probably does not work correctly yet.\nYou are trying to deliberately destroy your device.\nThis is a BAD idea, and can easily result in total data loss."); confirm_please_destroy_my_drive("--format-track", "This might destroy the drive and/or all data on it."); err = do_format_track(fd, format_track_addr, devname); } if (erase_sectors) { confirm_i_know_what_i_am_doing("--erase-sectors", "This flag is still under development and probably does not work correctly yet.\nYou are trying to deliberately destroy your device.\nThis is a BAD idea, and can easily result in total data loss."); confirm_please_destroy_my_drive("--erase-sectors", "This might destroy the drive and/or all data on it."); err = do_erase_sectors(fd, erase_sectors_addr, devname); } #endif /* FORMAT_AND_ERASE */ if (trim_sector_ranges_count) { if (num_flags_processed > 1 || argc) usage_help(13,EINVAL); confirm_please_destroy_my_drive("--trim-sector-ranges", "This might destroy the drive and/or all data on it."); do_trim_sector_ranges(fd, devname, trim_sector_ranges_count, trim_sector_ranges); } if (write_sector) { if (num_flags_processed > 1 || argc) usage_help(14,EINVAL); confirm_i_know_what_i_am_doing("--write-sector", "You are trying to deliberately overwrite a low-level sector on the media.\nThis is a BAD idea, and can easily result in total data loss."); err = do_write_sector(fd, write_sector_addr, devname); } if (do_fwdownload) { if (num_flags_processed > 1 || argc) usage_help(15,EINVAL); abort_if_not_full_device (fd, 0, devname, "--fwdownload requires the raw device, not a partition."); confirm_i_know_what_i_am_doing("--fwdownload", "This flag has not been tested with many drives to date.\nYou are trying to deliberately overwrite the drive firmware with the contents of the specified file.\nIf this fails, your drive could be toast."); confirm_please_destroy_my_drive("--fwdownload", "This might destroy the drive and well as all of the data on it."); get_identify_data(fd); if (id) { err = fwdownload(fd, id, fwpath, xfer_mode); if (err) exit(err); } } if (read_sector) err = do_read_sector(fd, read_sector_addr, devname); if (drq_hsm_error) { get_identify_data(fd); if (id) { __u8 args[4] = {0,0,0,0}; args[0] = last_identify_op; printf(" triggering \"stuck DRQ\" host state machine error\n"); flush_buffer_cache(fd); sleep(1); do_drive_cmd(fd, args, timeout_60secs); err = errno; perror("drq_hsm_error"); fprintf(stderr, "ata status=0x%02x ata error=0x%02x\n", args[0], args[1]); } } id = NULL; /* force re-IDENTIFY in case something above modified settings */ if (get_hitachi_temp) { __u8 args[4] = {0xf0,0,0x01,0}; /* "Sense Condition", vendor-specific */ if (do_drive_cmd(fd, args, 0)) { err = errno; perror(" HDIO_DRIVE_CMD(hitachisensecondition) failed"); } else { printf(" drive temperature (celsius) is: "); if (args[2]==0) printf("under -20"); else if (args[2]==0xFF) printf("over 107"); else printf("%d", args[2]/2-20); printf("\n drive temperature in range: %s\n", YN(!(args[1]&0x10)) ); } } if (do_defaults || get_mult || do_identity) { multcount = -1; err = 0; if (ioctl(fd, HDIO_GET_MULTCOUNT, &multcount)) { err = errno; get_identify_data(fd); if (id) { err = 0; if ((id[59] & 0xff00) == 0x100) multcount = id[59] & 0xff; else multcount = 0; } if (err && get_mult) { errno = err; perror(" HDIO_GET_MULTCOUNT failed"); } } if (!err && (do_defaults || get_mult)) { printf(" multcount = %2ld", multcount); on_off(multcount); } } if (do_defaults || get_io32bit) { if (0 == ioctl(fd, HDIO_GET_32BIT, &parm)) { printf(" IO_support =%3ld (", parm); switch (parm) { case 0: printf("default) \n"); break; case 2: printf("16-bit)\n"); break; case 1: printf("32-bit)\n"); break; case 3: printf("32-bit w/sync)\n"); break; case 8: printf("Request-Queue-Bypass)\n"); break; default:printf("\?\?\?)\n"); } } else if (get_io32bit) { err = errno; perror(" HDIO_GET_32BIT failed"); } } if (do_defaults || get_unmask) { if (0 == ioctl(fd, HDIO_GET_UNMASKINTR, &parm)) { printf(" unmaskirq = %2ld", parm); on_off(parm); } else if (get_unmask) { err = errno; perror(" HDIO_GET_UNMASKINTR failed"); } } if (do_defaults || get_dma) { if (0 == ioctl(fd, HDIO_GET_DMA, &parm)) { printf(" using_dma = %2ld", parm); if (parm == 8) printf(" (DMA-Assisted-PIO)\n"); else on_off(parm); } else if (get_dma) { err = errno; perror(" HDIO_GET_DMA failed"); } } if (get_dma_q) { err = sysfs_get_attr(fd, "device/queue_depth", "%u", &dma_q, NULL, 1); if (!err) printf(" queue_depth = %2u\n", dma_q); } if (do_defaults || get_keep) { if (0 == ioctl(fd, HDIO_GET_KEEPSETTINGS, &parm)) { printf(" keepsettings = %2ld", parm); on_off(parm); } else if (get_keep) { err = errno; perror(" HDIO_GET_KEEPSETTINGS failed"); } } if (get_nowerr) { if (ioctl(fd, HDIO_GET_NOWERR, &parm)) { err = errno; perror(" HDIO_GET_NOWERR failed"); } else { printf(" nowerr = %2ld", parm); on_off(parm); } } if (do_defaults || get_readonly) { if (ioctl(fd, BLKROGET, &parm)) { err = errno; perror(" BLKROGET failed"); } else { printf(" readonly = %2ld", parm); on_off(parm); } } if (do_defaults || get_fsreadahead) { if (ioctl(fd, BLKRAGET, &parm)) { err = errno; perror(" BLKRAGET failed"); } else { printf(" readahead = %2ld", parm); on_off(parm); } } if (do_defaults || get_geom) { __u32 cyls = 0, heads = 0, sects = 0; __u64 start_lba = 0, nsectors = 0; err = get_dev_geometry (fd, &cyls, &heads, §s, &start_lba, &nsectors); if (!err) { printf(" geometry = %u/%u/%u, sectors = %lld, start = ", cyls, heads, sects, nsectors); if (start_lba == START_LBA_UNKNOWN) printf("unknown\n"); else printf("%lld\n", start_lba); } } if (get_wdidle3) { unsigned char timeout = 0; err = wdidle3_get_timeout(fd, &timeout); if (!err) { printf(" wdidle3 = "); wdidle3_print_timeout(timeout); putchar('\n'); } } if (get_powermode) { __u8 args[4] = {ATA_OP_CHECKPOWERMODE1,0,0,0}; const char *state = "unknown"; if (do_drive_cmd(fd, args, 0) && (args[0] = ATA_OP_CHECKPOWERMODE2) /* (single =) try again with 0x98 */ && do_drive_cmd(fd, args, 0)) { err = errno; } else { switch (args[2]) { case 0x00: state = "standby"; break; case 0x40: state = "NVcache_spindown"; break; case 0x41: state = "NVcache_spinup"; break; case 0x80: state = "idle"; break; case 0xff: state = "active/idle"; break; } } printf(" drive state is: %s\n", state); } if (do_identity) { __u16 id2[256]; if (!ioctl(fd, HDIO_GET_IDENTITY, id2)) { if (multcount != -1) { id2[59] = multcount | 0x100; } else { id2[59] &= ~0x100; } dump_identity(id2); } else if (errno == -ENOMSG) { printf(" no identification info available\n"); } else { err = errno; perror(" HDIO_GET_IDENTITY failed"); } } if (do_IDentity) { get_identify_data(fd); if (id) { if (do_IDentity == 2) dump_sectors(id, 1); else identify((void *)id); } } if (get_lookahead) { get_identify_data(fd); if (id) { int supported = id[82] & 0x0040; if (supported) { lookahead = !!(id[85] & 0x0040); printf(" look-ahead = %2d", lookahead); on_off(lookahead); } else { printf(" look-ahead = not supported\n"); } } } if (get_wcache) { get_identify_data(fd); if (id) { int supported = id[82] & 0x0020; if (supported) { wcache = !!(id[85] & 0x0020); printf(" write-caching = %2d", wcache); on_off(wcache); } else { printf(" write-caching = not supported\n"); } } } if (get_apmmode) { get_identify_data(fd); if (id) { printf(" APM_level = "); if ((id[83] & 0xc008) == 0x4008) { if (id[86] & 0x0008) printf("%u\n", id[91] & 0xff); else printf("off\n"); } else printf("not supported\n"); } } if (get_acoustic) { get_identify_data(fd); if (id) { int supported = id[83] & 0x200; if (supported) printf(" acoustic = %2u (128=quiet ... 254=fast)\n", id[94] & 0xff); else printf(" acoustic = not supported\n"); } } if (get_write_read_verify) { get_identify_data(fd); if (id) { int supported = id[119] & 0x2; if (supported) printf(" write-read-verify = %2u\n", id[120] & 0x2); else printf(" write-read-verify = not supported\n"); } } if (get_busstate) { if (ioctl(fd, HDIO_GET_BUSSTATE, &parm)) { err = errno; perror(" HDIO_GET_BUSSTATE failed"); } else { printf(" busstate = %2ld (%s)\n", parm, busstate_str(parm)); } } if (get_native_max_sectors) { __u64 visible, native; get_identify_data(fd); if (id) { visible = get_lba_capacity(id); native = do_get_native_max_sectors(fd); if (!native) { err = errno; } else { printf(" max sectors = %llu/%llu", visible, native); if (visible < native) printf(", HPA is enabled\n"); else if (visible == native) printf(", HPA is disabled\n"); else { __u16 *dco = get_dco_identify_data(fd, 1); if (dco) { __u64 dco_max = dco[5]; dco_max = ((((__u64)dco[5]) << 32) | (dco[4] << 16) | dco[3]) + 1; printf("(%llu?)", dco_max); } printf(", HPA setting seems invalid"); if ((native & 0xffffff000000ull) == 0) printf(" (buggy kernel device driver?)"); putchar('\n'); } } } } if (do_ctimings) time_cache(fd); if (do_flush_wcache) err = flush_wcache(fd); if (do_timings) err = time_device(fd); if (do_flush) flush_buffer_cache(fd); if (set_reread_partn) { if (get_reread_partn) printf(" re-reading partition table\n"); if (ioctl(fd, BLKRRPART, NULL)) { err = errno; perror(" BLKRRPART failed"); } } if (set_idleimmediate) { __u8 args[4] = {ATA_OP_IDLEIMMEDIATE,0,0,0}; if (get_idleimmediate) printf(" issuing idle_immediate command\n"); if (do_drive_cmd(fd, args, 0)) { err = errno; perror(" HDIO_DRIVE_CMD(idle_immediate) failed"); } } if (set_standbynow) { __u8 args1[4] = {ATA_OP_STANDBYNOW1,0,0,0}; __u8 args2[4] = {ATA_OP_STANDBYNOW2,0,0,0}; if (get_standbynow) printf(" issuing standby command\n"); if (do_drive_cmd(fd, args1, 0) && do_drive_cmd(fd, args2, 0)) { err = errno; perror(" HDIO_DRIVE_CMD(standby) failed"); } } if (set_idleunload) { if (get_idleunload) printf(" issuing idle_immediate_unload command\n"); err = do_idleunload(fd, devname); } if (set_sleepnow) { __u8 args1[4] = {ATA_OP_SLEEPNOW1,0,0,0}; __u8 args2[4] = {ATA_OP_SLEEPNOW2,0,0,0}; if (get_sleepnow) printf(" issuing sleep command\n"); if (do_drive_cmd(fd, args1, 0) && do_drive_cmd(fd, args2, 0)) { err = errno; perror(" HDIO_DRIVE_CMD(sleep) failed"); } } if (set_doreset) { if (get_doreset) printf(" resetting drive\n"); if (ioctl(fd, HDIO_DRIVE_RESET, NULL)) { err = errno; perror(" HDIO_DRIVE_RESET failed"); } } close (fd); if (err) exit (err); } #define GET_XFERMODE(flag, num) \ do { \ char *tmpstr = name; \ tmpstr[0] = '\0'; \ if (!*argp && argc && isalnum(**argv)) \ argp = *argv++, --argc; \ while (isalnum(*argp) && (tmpstr - name) < 31) {\ tmpstr[0] = *argp++; \ tmpstr[1] = '\0'; \ ++tmpstr; \ } \ num = translate_xfermode(name); \ if (num == -1) \ flag = 0; \ else \ flag = 1; \ } while (0) static int fromhex (__u8 c) { if (c >= '0' && c <= '9') return (c - '0'); if (c >= 'a' && c <= 'f') return 10 + (c - 'a'); if (c >= 'A' && c <= 'F') return 10 + (c - 'A'); fprintf(stderr, "bad char: '%c' 0x%02x\n", c, c); exit(EINVAL); } static int ishex (char c) { return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); } static void identify_from_stdin (void) { __u16 sbuf[512]; int err, wc = 0; do { int digit; int d[4]; if (ishex(d[digit=0] = getchar()) && ishex(d[++digit] = getchar()) && ishex(d[++digit] = getchar()) && ishex(d[++digit] = getchar())) { sbuf[wc] = (fromhex(d[0]) << 12) | (fromhex(d[1]) << 8) | (fromhex(d[2]) << 4) | fromhex(d[3]); ++wc; } else if (d[digit] == EOF) { goto eof; } else if (wc == 0) { /* skip over leading lines of cruft */ while (d[digit] != '\n') { if (d[digit] == EOF) goto eof; d[digit=0] = getchar(); }; } } while (wc < 256); putchar('\n'); identify(sbuf); return; eof: err = errno; fprintf(stderr, "read only %u/256 IDENTIFY words from stdin: %s\n", wc, strerror(err)); exit(err); } static void numeric_parm (char c, const char *name, int *val, int *setparm, int *getparm, int min, int max, int set_only) { int got_digit = 0; *val = 0; *getparm = noisy; noisy = 1; if (!*argp && argc && isdigit(**argv)) argp = *argv++, --argc; while (isdigit(*argp)) { *setparm = 1; *val = (*val * 10) + (*argp++ - '0'); got_digit = 1; } if ((set_only && !got_digit) || *val < min || *val > max) { fprintf(stderr, " -%c: bad/missing %s value (%d..%d)\n", c, name, min, max); exit(EINVAL); } } #define NUMERIC_PARM(CH,NAME,VAR,MIN,MAX,GETSET) numeric_parm(CH,NAME,&VAR,&set_##VAR,&get_##VAR,MIN,MAX,GETSET) #define GET_SET_PARM(CH,NAME,VAR,MIN,MAX) CH:NUMERIC_PARM(CH,NAME,VAR,MIN,MAX,0);break #define SET_PARM(CH,NAME,VAR,MIN,MAX) CH:NUMERIC_PARM(CH,NAME,VAR,MIN,MAX,1);break #define SET_FLAG1(VAR) get_##VAR=noisy;noisy=1;set_##VAR=1 #define SET_FLAG(CH,VAR) CH:SET_FLAG1(VAR);break #define DO_FLAG(CH,VAR) CH:VAR=1;noisy=1;break #define INCR_FLAG(CH,VAR) CH:VAR++;noisy=1;break static void get_security_password (int handle_NULL) { unsigned int maxlen = sizeof(security_password) - 1; if (argc < 2) { fprintf(stderr, "missing PASSWD\n"); exit(EINVAL); } argp = *argv++, --argc; if (!argp) { fprintf(stderr, "missing PASSWD\n"); exit(EINVAL); } if (strlen(argp) > maxlen) { fprintf(stderr, "PASSWD too long (must be %d chars max)\n", maxlen); exit(EINVAL); } memset(security_password, 0, maxlen + 1); if (!handle_NULL || strcmp(argp, "NULL")) strcpy(security_password, argp); printf("security_password=\"%s\"\n", security_password); while (*argp) ++argp; } static const char *lba_emsg = "bad/missing sector value"; static const char *count_emsg = "bad/missing sector count"; static const __u64 lba_limit = (1ULL << 48) - 1; static int get_u64_parm (int optional, const char flag_c, int *flag_p, __u64 *value_p, unsigned int min_value, __u64 limit, const char *eprefix, const char *emsg) { int got_value = 0; __u64 value = *value_p; char *endp = NULL; if (!*argp && argc && (isdigit(**argv) || (flag_p && flag_c == **argv))) argp = *argv++, --argc; if (flag_p) { *flag_p = 0; if (*argp == flag_c) { *flag_p = 1; argp++; } } errno = 0; value = strtoll(argp, &endp, 0); if (errno != 0 || (endp != argp && ((__s64)value < (__s64)min_value || value > limit))) { fprintf(stderr, " %s: %s\n", eprefix, emsg); exit(EINVAL); } if (endp != argp) { got_value = 1; *value_p = value; argp = endp; } if (!optional && !got_value) { fprintf(stderr, " %s: %s\n", eprefix, emsg); exit(EINVAL); } return got_value; } static void get_set_max_sectors_parms (void) { get_native_max_sectors = noisy; noisy = 1; set_max_sectors = get_u64_parm(1, 'p', &set_max_permanent, &set_max_addr, 1, lba_limit, "-N", lba_emsg); } static void handle_standalone_longarg (char *name) { if (num_flags_processed) { if (verbose) fprintf(stderr, "handle_standalone_longarg: num_flags_processed == %d\n", num_flags_processed); usage_help(1,EINVAL); } /* --Istdin is special: no filename arg(s) wanted here */ if (0 == strcasecmp(name, "Istdin")) { if (argc > 0) { if (verbose) fprintf(stderr, "handle_standalone_longarg: argc(%d) > 0\n", argc); usage_help(2,EINVAL); } identify_from_stdin(); exit(0); } if (0 == strcasecmp(name, "dco-restore")) { do_dco_restore = 1; } else if (0 == strcasecmp(name, "security-help")) { security_help(0); exit(0); } else if (0 == strcasecmp(name, "security-unlock")) { set_security = 1; security_command = ATA_OP_SECURITY_UNLOCK; get_security_password(0); } else if (0 == strcasecmp(name, "security-set-pass")) { set_security = 1; security_command = ATA_OP_SECURITY_SET_PASS; get_security_password(1); } else if (0 == strcasecmp(name, "security-disable")) { set_security = 1; security_command = ATA_OP_SECURITY_DISABLE; get_security_password(1); } else if (0 == strcasecmp(name, "security-erase")) { set_security = 1; security_command = ATA_OP_SECURITY_ERASE_UNIT; get_security_password(1); } else if (0 == strcasecmp(name, "security-erase-enhanced")) { set_security = 1; enhanced_erase = 1; security_command = ATA_OP_SECURITY_ERASE_UNIT; get_security_password(1); } else { usage_help(3,EINVAL); } } static void get_filename_parm (char **result, const char *emsg) { if (!*argp && argc) argp = *argv++, --argc; if (!argp || !*argp) { fprintf(stderr, " %s: bad/missing filename parameter\n", emsg); exit(EINVAL); } *result = argp; argp += strlen(argp); // if (argc) argp = *argv++, --argc; } static void do_fallocate (const char *name) { char *path; __u64 blkcount; get_u64_parm(0, 0, NULL, &blkcount, 0, (1ULL << 53), name, "bad/missing block-count"); get_filename_parm(&path, name); if (num_flags_processed || argc) usage_help(4,EINVAL); exit(do_fallocate_syscall(path, blkcount * 1024)); } static void do_fibmap_file (const char *name) { int err; char *path; get_filename_parm(&path, name); if (num_flags_processed || argc) usage_help(5,EINVAL); err = do_filemap(path); exit(err); } static int get_longarg (void) { char *name = argp; while (*argp) ++argp; if (0 == strcasecmp(name, "verbose")) { verbose = 1; --num_flags_processed; /* doesn't count as an action flag */ } else if (0 == strcasecmp(name, "prefer-ata12")) { prefer_ata12 = 1; --num_flags_processed; /* doesn't count as an action flag */ } else if (0 == strcasecmp(name, "offset")) { set_timings_offset = 1; get_u64_parm(0, 0, NULL, &timings_offset, 0, ~0, name, "GB offset for -t flag"); timings_offset *= 0x40000000ULL; } else if (0 == strcasecmp(name, "yes-i-know-what-i-am-doing")) { i_know_what_i_am_doing = 1; --num_flags_processed; /* doesn't count as an action flag */ } else if (0 == strcasecmp(name, "please-destroy-my-drive")) { please_destroy_my_drive = 1; --num_flags_processed; /* doesn't count as an action flag */ } else if (0 == strcasecmp(name, "direct")) { open_flags |= O_DIRECT; --num_flags_processed; /* doesn't count as an action flag */ } else if (0 == strcasecmp(name, "drq-hsm-error")) { drq_hsm_error = 1; } else if (0 == strcasecmp(name, "dco-freeze")) { do_dco_freeze = 1; } else if (0 == strcasecmp(name, "dco-identify")) { do_dco_identify = 1; } else if (0 == strcasecmp(name, "fallocate")) { do_fallocate(name); } else if (0 == strcasecmp(name, "fibmap")) { do_fibmap_file(name); } else if (0 == strcasecmp(name, "fwdownload-mode3")) { get_filename_parm(&fwpath, name); do_fwdownload = 1; xfer_mode = 3; } else if (0 == strcasecmp(name, "fwdownload-mode3-max")) { get_filename_parm(&fwpath, name); do_fwdownload = 1; xfer_mode = 30; } else if (0 == strcasecmp(name, "fwdownload-mode7")) { get_filename_parm(&fwpath, name); do_fwdownload = 1; xfer_mode = 7; } else if (0 == strcasecmp(name, "fwdownload")) { get_filename_parm(&fwpath, name); do_fwdownload = 1; xfer_mode = 0; } else if (0 == strcasecmp(name, "idle-immediate")) { SET_FLAG1(idleimmediate); } else if (0 == strcasecmp(name, "idle-unload")) { SET_FLAG1(idleunload); } else if (0 == strcasecmp(name, "make-bad-sector")) { make_bad_sector = 1; get_u64_parm(0, 'f', &make_bad_sector_flagged, &make_bad_sector_addr, 0, lba_limit, name, lba_emsg); #ifdef FORMAT_AND_ERASE } else if (0 == strcasecmp(name, "format-track")) { format_track = 1; get_u64_parm(0, 0, NULL, &format_track_addr, 0, lba_limit, name, lba_emsg); } else if (0 == strcasecmp(name, "erase-sectors")) { erase_sectors = 1; get_u64_parm(0, 0, NULL, &erase_sectors_addr, 0, lba_limit, name, lba_emsg); #endif } else if (0 == strcasecmp(name, "trim-sector-ranges-stdin")) { trim_from_stdin = 1; } else if (0 == strcasecmp(name, "trim-sector-ranges")) { int i, optional = 0, max_ranges = argc; trim_sector_ranges = malloc(sizeof(struct sector_range_s) * max_ranges); if (!trim_sector_ranges) { int err = errno; perror("malloc()"); exit(err); } open_flags |= O_RDWR; for (i = 0; i < max_ranges; ++i) { char err_prefix[64]; struct sector_range_s *p = &trim_sector_ranges[i]; sprintf(err_prefix, "%s[%u]", name, i); if (!get_u64_parm(optional, 0, NULL, &(p->lba), 0, lba_limit, err_prefix, lba_emsg)) break; if (*argp++ != ':' || !isdigit(*argp)) { fprintf(stderr, "%s: %s\n", err_prefix, count_emsg); exit(EINVAL); } get_u64_parm(0, 0, NULL, &(p->nsectors), 1, 0xffff, err_prefix, count_emsg); optional = 1; trim_sector_ranges_count = i + 1; } } else if (0 == strcasecmp(name, "write-sector") || 0 == strcasecmp(name, "repair-sector")) { write_sector = 1; get_u64_parm(0, 0, NULL, &write_sector_addr, 0, lba_limit, name, lba_emsg); } else if (0 == strcasecmp(name, "read-sector")) { read_sector = 1; get_u64_parm(0, 0, NULL, &read_sector_addr, 0, lba_limit, name, lba_emsg); } else if (0 == strcasecmp(name, "Istdout")) { do_IDentity = 2; } else if (0 == strcasecmp(name, "security-mode")) { if (argc && isalpha(**argv)) { argp = *argv++, --argc; if (*argp == 'm') /* max */ security_mode = 1; else if (*argp == 'h') /* high */ security_mode = 0; else security_help(EINVAL); while (*argp) ++argp; } --num_flags_processed; /* doesn't count as an action flag */ } else if (0 == strcasecmp(name, "user-master")) { if (argc && isalpha(**argv)) { argp = *argv++, --argc; if (*argp == 'u') /* user */ security_master = 0; else if (*argp == 'm') /* master */ security_master = 1; else security_help(EINVAL); while (*argp) ++argp; } --num_flags_processed; /* doesn't count as an action flag */ } else if (0 == strcasecmp(name, "security-freeze")) { security_freeze = 1; } else { handle_standalone_longarg(name); return 1; /* 1 == no more flags allowed */ } return 0; /* additional flags allowed */ } int main (int _argc, char **_argv) { int no_more_flags = 0, disallow_flags = 0; char c; char name[32]; argc = _argc; argv = _argv; argp = NULL; if ((progname = (char *) strrchr(*argv, '/')) == NULL) progname = *argv; else progname++; ++argv; if (!--argc) usage_help(6,EINVAL); while (argc--) { argp = *argv++; if (no_more_flags || argp[0] != '-') { if (!num_flags_processed) do_defaults = 1; process_dev(argp); continue; } if (0 == strcmp(argp, "--")) { no_more_flags = 1; continue; } if (disallow_flags) usage_help(7,EINVAL); if (!*++argp) usage_help(8,EINVAL); while (argp && (c = *argp++)) { switch (c) { case GET_SET_PARM('a',"filesystem-read-ahead",fsreadahead,0,2048); case GET_SET_PARM('A',"look-ahead",lookahead,0,1); case GET_SET_PARM('b',"bus-state",busstate,0,2); case GET_SET_PARM('B',"power-management-mode",apmmode,0,255); case GET_SET_PARM('c',"32-bit-IO",io32bit,0,3); case SET_FLAG('C',powermode); case GET_SET_PARM('d',"dma-enable",dma,0,1); case SET_PARM('D',"defects-management",defects,0,1); case SET_PARM('E',"CDROM/DVD-speed",cdromspeed,0,255); case DO_FLAG('f',do_flush); case DO_FLAG('F',do_flush_wcache); case DO_FLAG('g',get_geom); case 'h': usage_help(9,0); break; case SET_FLAG('H',hitachi_temp); case DO_FLAG('i',do_identity); case DO_FLAG('I',do_IDentity); case GET_SET_PARM('J',"WDC-idle3-timeout",wdidle3,0,300); case GET_SET_PARM('k',"kernel-keep-settings",keep,0,1); case SET_PARM('K',"drive-keep-settings",dkeep,0,1); case SET_PARM('L',"door-lock",doorlock,0,1); case GET_SET_PARM('m',"multmode-count",mult,0,64); case GET_SET_PARM('M',"acoustic-management",acoustic,0,255); case GET_SET_PARM('n',"ignore-write-errors",nowerr,0,1); case 'N': get_set_max_sectors_parms(); break; case SET_PARM('P',"prefetch",prefetch,0,255); case 'q': quiet = 1; noisy = 0; break; case GET_SET_PARM('Q',"queue-depth",dma_q,0,1024); case SET_PARM('s',"powerup-in-standby",powerup_in_standby,0,1); case SET_PARM('S',"standby-interval",standby,0,255); case GET_SET_PARM('r',"read-only",readonly,0,1); case GET_SET_PARM('R',"write-read-verify",write_read_verify,0,3); case DO_FLAG('t',do_timings); case DO_FLAG('T',do_ctimings); case GET_SET_PARM('u',"unmask-irq",unmask,0,1); case DO_FLAG('v',do_defaults); case 'V': fprintf(stdout, "%s %s\n", progname, VERSION); exit(0); case SET_FLAG('w',doreset); case GET_SET_PARM('W',"write-cache",wcache,0,1); case SET_FLAG('y',standbynow); case SET_FLAG('Y',sleepnow); case SET_FLAG('z',reread_partn); case SET_FLAG('Z',seagate); case '-': if (get_longarg()) disallow_flags = 1; break; case 'p': get_piomode = noisy; noisy = 1; GET_XFERMODE(set_piomode,piomode); break; case 'X': get_xfermode = noisy; noisy = 1; GET_XFERMODE(set_xfermode,xfermode_requested); if (!set_xfermode) fprintf(stderr, "-X: missing value\n"); break; default: usage_help(10,EINVAL); } num_flags_processed++; } if (!argc) usage_help(11,EINVAL); } return 0; } hdparm-9.43/sysfs.h0000644000000000000000000000006711020776444012752 0ustar rootrootint sysfs_get_start_lba (dev_t dev, __u64 *start_lba); hdparm-9.43/hdparm.80000644000000000000000000010734712051264123012776 0ustar rootroot.TH HDPARM 8 "November 2012" "Version 9.43" .SH NAME hdparm \- get/set SATA/IDE device parameters .SH SYNOPSIS .B hdparm [options] [device ...] .SH DESCRIPTION .BI hdparm provides a command line interface to various kernel interfaces supported by the Linux SATA/PATA/SAS "libata" subsystem and the older IDE driver subsystem. Many newer (2008 and later) USB drive enclosures now also support "SAT" (SCSI-ATA Command Translation) and therefore may also work with hdparm. E.g. recent WD "Passport" models and recent NexStar-3 enclosures. Some options may work correctly only with the latest kernels. .SH OPTIONS When no options are given, .B -acdgkmur is assumed. For "Get/set" options, a query without the optional parameter (e.g. \-d) will query (get) the device state, and with a parameter (e.g., \-d0) will set the device state. .TP .I -a Get/set sector count for filesystem (software) read-ahead. This is used to improve performance in sequential reads of large files, by prefetching additional blocks in anticipation of them being needed by the running task. Many IDE drives also have a separate built-in read-ahead function, which augments this filesystem (software) read-ahead function. .TP .I -A Get/set the IDE drive\'s read-lookahead feature (usually ON by default). Usage: .B -A0 (disable) or .B -A1 (enable). .TP .I -b Get/set bus state. .TP .I -B Get/set Advanced Power Management feature, if the drive supports it. A low value means aggressive power management and a high value means better performance. Possible settings range from values 1 through 127 (which permit spin-down), and values 128 through 254 (which do not permit spin-down). The highest degree of power management is attained with a setting of 1, and the highest I/O performance with a setting of 254. A value of 255 tells hdparm to disable Advanced Power Management altogether on the drive (not all drives support disabling it, but most do). .TP .I -c Get/set (E)IDE 32-bit I/O support. A numeric parameter can be used to enable/disable 32-bit I/O support. Currently supported values include .B 0 to disable 32-bit I/O support, .B 1 to enable 32-bit data transfers, and .B 3 to enable 32-bit data transfers with a special .B sync sequence required by many chipsets. The value .B 3 works with nearly all 32-bit IDE chipsets, but incurs slightly more overhead. Note that "32-bit" refers to data transfers across a PCI or VLB bus to the interface card only; all (E)IDE drives still have only a 16-bit connection over the ribbon cable from the interface card. .TP .I -C Check the current IDE power mode status, which will always be one of .B unknown (drive does not support this command), .B active/idle (normal operation), .B standby (low power mode, drive has spun down), or .B sleeping (lowest power mode, drive is completely shut down). The .B -S, -y, -Y, and .B -Z options can be used to manipulate the IDE power modes. .TP .I -d Get/set the "using_dma" flag for this drive. This option now works with most combinations of drives and PCI interfaces which support DMA and which are known to the kernel IDE driver. It is also a good idea to use the appropriate .B -X option in combination with .B -d1 to ensure that the drive itself is programmed for the correct DMA mode, although most BIOSs should do this for you at boot time. Using DMA nearly always gives the best performance, with fast I/O throughput and low CPU usage. But there are at least a few configurations of chipsets and drives for which DMA does not make much of a difference, or may even slow things down (on really messed up hardware!). Your mileage may vary. .TP .I --dco-freeze DCO stands for Device Configuration Overlay, a way for vendors to selectively disable certain features of a drive. The .B --dco-freeze option will freeze/lock the current drive configuration, thereby preventing software (or malware) from changing any DCO settings until after the next power-on reset. .TP .I --dco-identify Query and dump information regarding drive configuration settings which can be disabled by the vendor or OEM installer. These settings show capabilities of the drive which might be disabled by the vendor for "enhanced compatibility". When disabled, they are otherwise hidden and will not show in the .B -I identify output. For example, system vendors sometimes disable 48_bit addressing on large drives, for compatibility (and loss of capacity) with a specific BIOS. In such cases, .B --dco-identify will show that the drive is 48_bit capable, but .B -I will not show it, and nor will the drive accept 48_bit commands. .TP .I --dco-restore Reset all drive settings, features, and accessible capacities back to factory defaults and full capabilities. This command will fail if DCO is frozen/locked, or if a .B -Np maximum size restriction has also been set. This is .B EXTREMELY DANGEROUS and will very likely cause massive loss of data. .B DO NOT USE THIS COMMAND. .TP .I --direct Use the kernel\'s "O_DIRECT" flag when performing a .B -t timing test. This bypasses the page cache, causing the reads to go directly from the drive into hdparm's buffers, using so-called "raw" I/O. In many cases, this can produce results that appear much faster than the usual page cache method, giving a better indication of raw device and driver performance. .TP .I --drq-hsm-error .B VERY DANGEROUS, DON'T EVEN THINK ABOUT USING IT. This option causes hdparm to issue an IDENTIFY command to the kernel, but incorrectly marked as a "non-data" command. This results in the drive being left with its DataReQust(DRQ) line "stuck" high. This confuses the kernel drivers, and may crash the system immediately with massive data loss. The option exists to help in testing and fortifying the kernel against similar real-world drive malfunctions. .B VERY DANGEROUS, DO NOT USE!! .TP .I -D Enable/disable the on-drive defect management feature, whereby the drive firmware tries to automatically manage defective sectors by relocating them to "spare" sectors reserved by the factory for such. Control of this feature via the .B -D option is not supported for most modern drives since ATA-4; thus this command may fail. .TP .I -E Set cd/dvd drive speed. This is NOT necessary for regular operation, as the drive will automatically switch speeds on its own. But if you want to play with it, just supply a speed number after the option, usually a number like 2 or 4. This can be useful in some cases, though, to smooth out DVD video playback. .TP .I -f Sync and flush the buffer cache for the device on exit. This operation is also performed internally as part of the .B -t and .B -T timings and other options. .TP .I --fallocate This option currently works only on ext4 and xfs filesystem types. When used, this must be the only option given. It requires two parameters: the desired file size in kilo-bytes (byte count divided by 1024), followed by the pathname for the new file. It will create a new file of the specified size, but without actually having to write any data to the file. This will normally complete very quickly, and without thrashing the storage device. .IP E.g. Create a 10KByte file: .B hdparm --fallocate 10 temp_file .TP .I --fibmap When used, this must be the only option given. It requires a file path as a parameter, and will print out a list of the block extents (sector ranges) occupied by that file on disk. Sector numbers are given as absolute LBA numbers, referenced from sector 0 of the physical device rather than from the partition or filesystem. This information can then be used for a variety of purposes, such as examining the degree of fragmenation of larger files, or determining appropriate sectors to deliberately corrupt during fault-injection testing procedures. .IP This option uses the new FIEMAP (file extent map) ioctl() when available, and falls back to the older FIBMAP (file block map) ioctl() otherwise. Note that FIBMAP suffers from a 32-bit block-number interface, and thus not work beyond 8TB or 16TB. FIBMAP is also very slow, and does not deal well with preallocated uncommitted extents in ext4/xfs filesystems, unless a sync() is done before using this option. .TP .I --fwdownload When used, this should be the only option given. It requires a file path immediately after the option, indicating where the new drive firmware should be read from. The contents of this file will be sent to the drive using the (S)ATA .B DOWNLOAD MICROCODE command, using either transfer protocol 7 (entire file at once), or, if the drive supports it, transfer protocol 3 (segmented download). This command is .B EXTREMELY DANGEROUS and could destroy both the drive and all data on it. .B DO NOT USE THIS COMMAND. The .B --fwdownload-mode3 , .B --fwdownload-mode3-max , and .B --fwdownload-mode7 variations on basic .B --fwdownload allow overriding automatic protocol detection in favour of forcing hdparm to use a specific transfer protocol, for testing purposes only. .TP .I -F Flush the on-drive write cache buffer (older drives may not implement this). .TP .I -g Display the drive geometry (cylinders, heads, sectors), the size (in sectors) of the device, and the starting offset (in sectors) of the device from the beginning of the drive. .TP .I -h Display terse usage information (help). .TP .I -H Read the temperature from some (mostly Hitachi) drives. Also reports if the temperature is within operating condition range (this may not be reliable). Does not cause the drive to spin up if idle. .TP .I -i Display the identification info which the kernel drivers (IDE, libata) have stored from boot/configuration time. This may differ from the current information obtainable directly from the drive itself with the .B -I option. The data returned may or may not be current, depending on activity since booting the system. For a more detailed interpretation of the identification info, refer to .I AT Attachment Interface for Disk Drives, ANSI ASC X3T9.2 working draft, revision 4a, April 19/93, and later editions. .TP .I --idle-immediate Issue an ATA IDLE_IMMEDIATE command, to put the drive into a lower power state. Usually the device remains spun-up. .TP .I --idle-unload Issue an ATA IDLE_IMMEDIATE_WITH_UNLOAD command, to unload or park the heads and put the drive into a lower power state. Usually the device remains spun-up. .TP .I -I Request identification info directly from the drive, which is displayed in a new expanded format with considerably more detail than with the older .B -i option. .TP .I --Istdin This is a special variation on the .B -I option, which accepts a drive identification block as standard input instead of using a /dev/hd* parameter. The format of this block must be .B exactly the same as that found in the /proc/ide/*/hd*/identify "files", or that produced by the .B --Istdout option described below. This variation is designed for use with collected "libraries" of drive identification information, and can also be used on ATAPI drives which may give media errors with the standard mechanism. When .B --Istdin is used, it must be the *only* parameter given. .TP .I --Istdout This option dumps the drive's identify data in hex to stdout, in a format similar to that from /proc/ide/*/identify, and suitable for later use with the .B --Istdin option. .TP .I -J Get/set the Western Digital (WD) Green Drive's "idle3" timeout value. This timeout controls how often the drive parks its heads and enters a low power consumption state. The factory default is eight (8) seconds, which is a very poor choice for use with Linux. Leaving it at the default will result in hundreds of thousands of head load/unload cycles in a very short period of time. The drive mechanism is only rated for 300,000 to 1,000,000 cycles, so leaving it at the default could result in premature failure, not to mention the performance impact of the drive often having to wake-up before doing routine I/O. .IP WD supply a WDIDLE3.EXE DOS utility for tweaking this setting, and you should use that program instead of hdparm if at all possible. The reverse-engineered implementation in hdparm is not as complete as the original official program, even though it does seem to work on at a least a few drives. A full power cycle is required for any change in setting to take effect, regardless of which program is used to tweak things. .IP A setting of 30 seconds is recommended for Linux use. Permitted values are from 8 to 12 seconds, and from 30 to 300 seconds in 30-second increments. Specify a value of zero (0) to disable the WD idle3 timer completely (NOT RECOMMENDED!). .TP .I -k Get/set the "keep_settings_over_reset" flag for the drive. When this flag is set, the drive will preserve the .B -dmu settings over a soft reset, (as done during the error recovery sequence). This option defaults to off, to prevent drive reset loops which could be caused by combinations of .B -dmu settings. The .B -k option should therefore only be set after one has achieved confidence in correct system operation with a chosen set of configuration settings. In practice, all that is typically necessary to test a configuration (prior to using \-k) is to verify that the drive can be read/written, and that no error logs (kernel messages) are generated in the process (look in /var/log/messages on most systems). .TP .I -K Set the drive\'s "keep_features_over_reset" flag. Setting this enables the drive to retain the settings for .B -APSWXZ over a soft reset (as done during the error recovery sequence). Not all drives support this feature. .TP .I -L Set the drive\'s doorlock flag. Setting this to .B 1 will lock the door mechanism of some removable hard drives (e.g. Syquest, ZIP, Jazz..), and setting it to .B 0 will unlock the door mechanism. Normally, Linux maintains the door locking mechanism automatically, depending on drive usage (locked whenever a filesystem is mounted). But on system shutdown, this can be a nuisance if the root partition is on a removable disk, since the root partition is left mounted (read-only) after shutdown. So, by using this command to unlock the door .B after the root filesystem is remounted read-only, one can then remove the cartridge from the drive after shutdown. .TP .I -m Get/set sector count for multiple sector I/O on the drive. A setting of .B 0 disables this feature. Multiple sector mode (aka IDE Block Mode), is a feature of most modern IDE hard drives, permitting the transfer of multiple sectors per I/O interrupt, rather than the usual one sector per interrupt. When this feature is enabled, it typically reduces operating system overhead for disk I/O by 30-50%. On many systems, it also provides increased data throughput of anywhere from 5% to 50%. Some drives, however (most notably the WD Caviar series), seem to run slower with multiple mode enabled. Your mileage may vary. Most drives support the minimum settings of 2, 4, 8, or 16 (sectors). Larger settings may also be possible, depending on the drive. A setting of 16 or 32 seems optimal on many systems. Western Digital recommends lower settings of 4 to 8 on many of their drives, due tiny (32kB) drive buffers and non-optimized buffering algorithms. The .B -i option can be used to find the maximum setting supported by an installed drive (look for MaxMultSect in the output). Some drives claim to support multiple mode, but lose data at some settings. Under rare circumstances, such failures can result in .B massive filesystem corruption. .TP .I --make-bad-sector Deliberately create a bad sector (aka. "media error") on the disk. .B EXCEPTIONALLY DANGEROUS. DO NOT USE THIS OPTION!! This can be useful for testing of device/RAID error recovery mechanisms. The sector number is given as a (base10) parameter after the option. Depending on the device, hdparm will choose one of two possible ATA commands for corrupting the sector. The WRITE_LONG works on most drives, but only up to the 28-bit sector boundary. Some very recent drives (2008) may support the new WRITE_UNCORRECTABLE_EXT command, which works for any LBA48 sector. If available, hdparm will use that in preference to WRITE_LONG. The WRITE_UNCORRECTABLE_EXT command itself presents a choice of how the new bad sector should behave. By default, it will look like any other bad sector, and the drive may take some time to retry and fail on subsequent READs of the sector. However, if a single letter .B f is prepended immediately in front of the first digit of the sector number parameter, then hdparm will issue a "flagged" WRITE_UNCORRECTABLE_EXT, which causes the drive to merely flag the sector as bad (rather than genuinely corrupt it), and subsequent READs of the sector will fail immediately (rather than after several retries). Note also that the .B --repair-sector option can be used to restore (any) bad sectors when they are no longer needed, including sectors that were genuinely bad (the drive will likely remap those to a fresh area on the media). .TP .I -M Get/set Automatic Acoustic Management (AAM) setting. Most modern harddisk drives have the ability to speed down the head movements to reduce their noise output. The possible values are between 0 and 254. 128 is the most quiet (and therefore slowest) setting and 254 the fastest (and loudest). Some drives have only two levels (quiet / fast), while others may have different levels between 128 and 254. At the moment, most drives only support 3 options, off, quiet, and fast. These have been assigned the values 0, 128, and 254 at present, respectively, but integer space has been incorporated for future expansion, should this change. .TP .I -n Get or set the "ignore_write_errors" flag in the driver. Do NOT play with this without grokking the driver source code first. .TP .I -N Get/set max visible number of sectors, also known as the .B Host Protected Area setting. Without a parameter, .B -N displays the current setting, which is reported as two values: the first gives the current max sectors setting, and the second shows the native (real) hardware limit for the disk. The difference between these two values indicates how many sectors of the disk are currently hidden from the operating system, in the form of a .B Host Protected Area (HPA). This area is often used by computer makers to hold diagnostic software, and/or a copy of the originally provided operating system for recovery purposes. Another possible use is to hide the true capacity of a very large disk from a BIOS/system that cannot normally cope with drives of that size (eg. most current {2010} BIOSs cannot deal with drives larger than 2TB, so an HPA could be used to cause a 3TB drive to report itself as a 2TB drive). To change the current max (VERY DANGEROUS, DATA LOSS IS EXTREMELY LIKELY), a new value should be provided (in base10) immediately following the .B -N option. This value is specified as a count of sectors, rather than the "max sector address" of the drive. Drives have the concept of a temporary (volatile) setting which is lost on the next hardware reset, as well as a more permanent (non-volatile) value which survives resets and power cycles. By default, .B -N affects only the temporary (volatile) setting. To change the permanent (non-volatile) value, prepend a leading .B p character immediately before the first digit of the value. Drives are supposed to allow only a single permanent change per session. A hardware reset (or power cycle) is required before another permanent .B -N operation can succeed. Note that any attempt to set this value may fail if the disk is being accessed by other software at the same time. This is because setting the value requires a pair of back-to-back drive commands, but there is no way to prevent some other command from being inserted between them by the kernel. So if it fails initially, just try again. Kernel support for .B -N is buggy for many adapter types across many kernel versions, in that an incorrect (too small) max size value is sometimes reported. As of the 2.6.27 kernel, this does finally seem to be working on most hardware. .TP .I --offset Offsets to given number of GiB (1024*1024*1024) when performing .B -t timings of device reads. Speed changes (about twice) along many mechanical drives. Usually the maximum is at the beginning, but not always. Solid-state drives (SSDs) should show similar timings regardless of offset. .TP .I -p Attempt to reprogram the IDE interface chipset for the specified PIO mode, or attempt to auto-tune for the "best" PIO mode supported by the drive. This feature is supported in the kernel for only a few "known" chipsets, and even then the support is iffy at best. Some IDE chipsets are unable to alter the PIO mode for a single drive, in which case this option may cause the PIO mode for .I both drives to be set. Many IDE chipsets support either fewer or more than the standard six (0 to 5) PIO modes, so the exact speed setting that is actually implemented will vary by chipset/driver sophistication. .I Use with extreme caution! This feature includes zero protection for the unwary, and an unsuccessful outcome may result in .I severe filesystem corruption! .TP .I -P Set the maximum sector count for the drive\'s internal prefetch mechanism. Not all drives support this feature, and it was dropped from the offical spec as of ATA-4. .TP .I --prefer-ata12 When using the SAT (SCSI ATA Translation) protocol, hdparm normally prefers to use the 16-byte command format whenever possible. But some USB drive enclosures don't work correctly with 16-byte commands. This option can be used to force use of the smaller 12-byte command format with such drives. hdparm will still revert to 16-byte commands for things that cannot be done with the 12-byte format (e.g. sector accesses beyond 28-bits). .TP .I -q Handle the next option quietly, suppressing normal output (but not error messages). This is useful for reducing screen clutter when running from system startup scripts. Not applicable to the .B -i or .B -v or .B -t or .B -T options. .TP .I -Q Get or set the device's command queue_depth, if supported by the hardware. This only works with 2.6.xx (or later) kernels, and only with device and driver combinations which support changing the queue_depth. For SATA disks, this is the Native Command Queuing (NCQ) queue depth. .TP .I -r Get/set read-only flag for the device. When set, Linux disallows write operations on the device. .TP .I -R Get/set Write-Read-Verify feature, if the drive supports it. Usage: .B -R0 (disable) or .B -R1 (enable). This feature is intended to have the drive firmware automatically read-back any data that is written by software, to verify that the data was successfully written. This is generally overkill, and can slow down disk writes by as much as a factor of two (or more). .TP .I --read-sector Reads from the specified sector number, and dumps the contents in hex to standard output. The sector number must be given (base10) after this option. hdparm will issue a low-level read (completely bypassing the usual block layer read/write mechanisms) for the specified sector. This can be used to definitively check whether a given sector is bad (media error) or not (doing so through the usual mechanisms can sometimes give false positives). .TP .I --repair-sector This is an alias for the .B --write-sector option. VERY DANGEROUS. .TP .I -s Enable/disable the power-on in standby feature, if supported by the drive. .B VERY DANGEROUS. Do not use unless you are absolutely certain that both the system BIOS (or firmware) and the operating system kernel (Linux >= 2.6.22) support probing for drives that use this feature. When enabled, the drive is powered-up in the .B standby mode to allow the controller to sequence the spin-up of devices, reducing the instantaneous current draw burden when many drives share a power supply. Primarily for use in large RAID setups. This feature is usually disabled and the drive is powered-up in the .B active mode (see \-C above). Note that a drive may also allow enabling this feature by a jumper. Some SATA drives support the control of this feature by pin 11 of the SATA power connector. In these cases, this command may be unsupported or may have no effect. .TP .I -S Put the drive into idle (low-power) mode, and also set the standby (spindown) timeout for the drive. This timeout value is used by the drive to determine how long to wait (with no disk activity) before turning off the spindle motor to save power. Under such circumstances, the drive may take as long as 30 seconds to respond to a subsequent disk access, though most drives are much quicker. The encoding of the timeout value is somewhat peculiar. A value of zero means "timeouts are disabled": the device will not automatically enter standby mode. Values from 1 to 240 specify multiples of 5 seconds, yielding timeouts from 5 seconds to 20 minutes. Values from 241 to 251 specify from 1 to 11 units of 30 minutes, yielding timeouts from 30 minutes to 5.5 hours. A value of 252 signifies a timeout of 21 minutes. A value of 253 sets a vendor-defined timeout period between 8 and 12 hours, and the value 254 is reserved. 255 is interpreted as 21 minutes plus 15 seconds. Note that some older drives may have very different interpretations of these values. .TP .I -t Perform timings of device reads for benchmark and comparison purposes. For meaningful results, this operation should be repeated 2-3 times on an otherwise inactive system (no other active processes) with at least a couple of megabytes of free memory. This displays the speed of reading through the buffer cache to the disk without any prior caching of data. This measurement is an indication of how fast the drive can sustain sequential data reads under Linux, without any filesystem overhead. To ensure accurate measurements, the buffer cache is flushed during the processing of .I -t using the BLKFLSBUF ioctl. .TP .I -T Perform timings of cache reads for benchmark and comparison purposes. For meaningful results, this operation should be repeated 2-3 times on an otherwise inactive system (no other active processes) with at least a couple of megabytes of free memory. This displays the speed of reading directly from the Linux buffer cache without disk access. This measurement is essentially an indication of the throughput of the processor, cache, and memory of the system under test. .TP .I --trim-sector-ranges For Solid State Drives (SSDs). .B EXCEPTIONALLY DANGEROUS. DO NOT USE THIS OPTION!! Tells the drive firmware to discard unneeded data sectors, destroying any data that may have been present within them. This makes those sectors available for immediate use by the firmware's garbage collection mechanism, to improve scheduling for wear-leveling of the flash media. This option expects one or more sector range pairs immediately after the option: an LBA starting address, a colon, and a sector count (max 65535), with no intervening spaces. .B EXCEPTIONALLY DANGEROUS. DO NOT USE THIS OPTION!! .IP E.g. .B hdparm --trim-sector-ranges 1000:4 7894:16 /dev/sdz .TP .I --trim-sector-ranges-stdin Identical to .B --trim-sector-ranges above, except the list of lba:count pairs is read from stdin rather than being specified on the command line. This can be used to avoid problems with excessively long command lines. It also permits batching of many more sector ranges into single commands to the drive, up to the currently configured transfer limit (max_sectors_kb). .TP .I -u Get/set the interrupt-unmask flag for the drive. A setting of .B 1 permits the driver to unmask other interrupts during processing of a disk interrupt, which greatly improves Linux\'s responsiveness and eliminates "serial port overrun" errors. .B Use this feature with caution: some drive/controller combinations do not tolerate the increased I/O latencies possible when this feature is enabled, resulting in .B massive filesystem corruption. In particular, .B CMD-640B and .B RZ1000 (E)IDE interfaces can be .B unreliable (due to a hardware flaw) when this option is used with kernel versions earlier than 2.0.13. Disabling the .B IDE prefetch feature of these interfaces (usually a BIOS/CMOS setting) provides a safe fix for the problem for use with earlier kernels. .TP .I -v Display some basic settings, similar to \-acdgkmur for IDE. This is also the default behaviour when no options are specified. .TP .I --verbose Display extra diagnostics from some commands. .TP .I -w Perform a device reset .B (DANGEROUS). Do NOT use this option. It exists for unlikely situations where a reboot might otherwise be required to get a confused drive back into a useable state. .TP .I --write-sector Writes zeros to the specified sector number. VERY DANGEROUS. The sector number must be given (base10) after this option. hdparm will issue a low-level write (completely bypassing the usual block layer read/write mechanisms) to the specified sector. This can be used to force a drive to repair a bad sector (media error). .TP .I -W Get/set the IDE/SATA drive\'s write-caching feature. .TP .I -X Set the IDE transfer mode for (E)IDE/ATA drives. This is typically used in combination with .B -d1 when enabling DMA to/from a drive on a supported interface chipset, where .B -X mdma2 is used to select multiword DMA mode2 transfers and .B -X sdma1 is used to select simple mode 1 DMA transfers. With systems which support UltraDMA burst timings, .B -X udma2 is used to select UltraDMA mode2 transfers (you\'ll need to prepare the chipset for UltraDMA beforehand). Apart from that, use of this option is .B seldom necessary since most/all modern IDE drives default to their fastest PIO transfer mode at power-on. Fiddling with this can be both needless and risky. On drives which support alternate transfer modes, .B -X can be used to switch the mode of the drive .B only. Prior to changing the transfer mode, the IDE interface should be jumpered or programmed (see .B -p option) for the new mode setting to prevent loss and/or corruption of data. .I Use this with extreme caution! For the PIO (Programmed Input/Output) transfer modes used by Linux, this value is simply the desired PIO mode number plus 8. Thus, a value of 09 sets PIO mode1, 10 enables PIO mode2, and 11 selects PIO mode3. Setting 00 restores the drive\'s "default" PIO mode, and 01 disables IORDY. For multiword DMA, the value used is the desired DMA mode number plus 32. for UltraDMA, the value is the desired UltraDMA mode number plus 64. .TP .I -y Force an IDE drive to immediately enter the low power consumption .B standby mode, usually causing it to spin down. The current power mode status can be checked using the .B -C option. .TP .I -Y Force an IDE drive to immediately enter the lowest power consumption .B sleep mode, causing it to shut down completely. A hard or soft reset is required before the drive can be accessed again (the Linux IDE driver will automatically handle issuing a reset if/when needed). The current power mode status can be checked using the .B -C option. .TP .I -z Force a kernel re-read of the partition table of the specified device(s). .TP .I -Z Disable the automatic power-saving function of certain Seagate drives (ST3xxx models?), to prevent them from idling/spinning-down at inconvenient times. .TP .SH ATA Security Feature Set .PP These switches are .B DANGEROUS to experiment with, and might not work with some kernels. .B USE AT YOUR OWN RISK. .TP .I --security-help Display terse usage info for all of the \--security-* options. .TP .I --security-freeze Freeze the drive\'s security settings. The drive does not accept any security commands until next power-on reset. Use this function in combination with \--security-unlock to protect drive from any attempt to set a new password. Can be used standalone, too. No other options are permitted on the command line with this one. .TP .I --security-unlock PWD Unlock the drive, using password PWD. Password is given as an ASCII string and is padded with NULs to reach 32 bytes. The applicable drive password is selected with the \--user-master switch (default is "user" password). No other options are permitted on the command line with this one. .TP .I --security-set-pass PWD Lock the drive, using password PWD (Set Password) .B (DANGEROUS). Password is given as an ASCII string and is padded with NULs to reach 32 bytes. Use the special password .B NULL to set an empty password. The applicable drive password is selected with the \--user-master switch (default is "user" password) and the applicable security mode with the \--security-mode switch. No other options are permitted on the command line with this one. .TP .I --security-disable PWD Disable drive locking, using password PWD. Password is given as an ASCII string and is padded with NULs to reach 32 bytes. The applicable drive password is selected with the \--user-master switch (default is "user" password). No other options are permitted on the command line with this one. .TP .I --security-erase PWD Erase (locked) drive, using password PWD .B (DANGEROUS). Password is given as an ASCII string and is padded with NULs to reach 32 bytes. Use the special password .B NULL to represent an empty password. The applicable drive password is selected with the \--user-master switch (default is "user" password). No other options are permitted on the command line with this one. .TP .I --security-erase-enhanced PWD Enhanced erase (locked) drive, using password PWD .B (DANGEROUS). Password is given as an ASCII string and is padded with NULs to reach 32 bytes. The applicable drive password is selected with the \--user-master switch (default is "user" password). No other options are permitted on the command line with this one. .TP .I --user-master USER Specifies which password (user/master) to select. .B Defaults to "user" password. Only useful in combination with \--security-unlock, \--security-set-pass, \--security-disable, \--security-erase or \--security-erase-enhanced. u user password m master password .TP .I --security-mode MODE Specifies which security mode (high/maximum) to set. .B Defaults to high. Only useful in combination with \--security-set-pass. h high security m maximum security .B THIS FEATURE IS EXPERIMENTAL AND NOT WELL TESTED. USE AT YOUR OWN RISK. .SH FILES /etc/hdparm.conf .SH BUGS As noted above, the .B -m sectcount and .B -u 1 options should be used with caution at first, preferably on a read-only filesystem. Most drives work well with these features, but a few drive/controller combinations are not 100% compatible. Filesystem corruption may result. Backup everything before experimenting! .PP Some options (e.g. \-r for SCSI) may not work with old kernels as necessary ioctl()\'s were not supported. .PP Although this utility is intended primarily for use with SATA/IDE hard disk devices, several of the options are also valid (and permitted) for use with SCSI hard disk devices and MFM/RLL hard disks with XT interfaces. .PP The Linux kernel up until 2.6.12 (and probably later) doesn\'t handle the security unlock and disable commands gracefully and will segfault and in some cases even panic. The security commands however might indeed have been executed by the drive. This poor kernel behaviour makes the PIO data security commands rather useless at the moment. .PP Note that the "security erase" and "security disable" commands have been implemented as two consecutive PIO data commands and will not succeed on a locked drive because the second command will not be issued after the segfault. See the code for hints how patch it to work around this problem. Despite the segfault it is often still possible to run two instances of hdparm consecutively and issue the two necessary commands that way. .SH AUTHOR .B hdparm has been written by Mark Lord , the original primary developer and maintainer of the (E)IDE driver for Linux, and current contributer to the libata subsystem, along with suggestions and patches from many netfolk. .PP The disable Seagate auto-powersaving code is courtesy of Tomi Leppikangas(tomilepp@paju.oulu.fi). .PP Security freeze command by Benjamin Benz, 2005. .PP PIO data out security commands by Leonard den Ottolander, 2005. Some other parts by Benjamin Benz and others. .SH SEE ALSO .B http://www.t13.org/ Technical Committee T13 AT Attachment (ATA/ATAPI) Interface. .PP .B http://www.serialata.org/ Serial ATA International Organization. .PP .B http://www.compactflash.org/ CompactFlash Association.