From: Tejun Heo <teheo@suse.de>
To: "Ivan N. Zlatev" <contact@i-nz.net>
Cc: linux-ide@vger.kernel.org
Subject: Re: Seagate HDD Frequent Head Unload - hdparm/dmidecode/smartctl output
Date: Sun, 03 Aug 2008 17:23:40 +0900 [thread overview]
Message-ID: <48956B0C.3030406@suse.de> (raw)
In-Reply-To: <3db1ec7f0808020601h20b2282ch51e6d93a484ac61c@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 479 bytes --]
Ivan N. Zlatev wrote:
> Hi again,
>
> It appears that the storage-fixup rule [1] doesn't work. Verbose
> output below[2]. Also I saw that you use hdparm -i and sg_inq so
> output from those for the HDD too. I badly failed to understand this
> brainf*** called bash :-), so may be you can advice what's going
> wrong? Thanks in advance.
Can you please the attached updated script? The previous version failed
match if dmi string contains leading or trailing blanks.
--
tejun
[-- Attachment #2: storage-fixup --]
[-- Type: text/plain, Size: 8555 bytes --]
#! /bin/bash
#
# storage-fixup - Tejun Heo <teheo@suse.de>
#
# Script to issue fix up commands for weird disks. This is primarily
# to adjust ATA APM setting. Some laptop BIOSen set this value too
# aggressively causing frequent head unloads which can kill the drive
# quickly. This script should be called during boot and resume. It
# examines rules from /etc/stroage-fixup.conf and executes matching
# commands.
#
# In stroage-fixup.conf, empty lines and lines starting w/ # are
# ignored. Each line starts with rule, dmi, ata or act.
#
# rule RULENAME
# Starts a rule. $RULENAME can't contain whitespaces.
#
# dmi KEY PATTERN
# Checks whether DMI value for KEY matches PATTERN. If not, the
# rule is skipped.
#
# ata KEY PATTERN
# Checks whether ATA value for KEY matches PATTERN. If not, the
# rule is skipped. KEY can be one of model, rev and serial.
#
# act ACTION
# Executes ACTION on matched devices. ACTION can contain $DEV
# which will be substituted with device file of matching device.
#
# sact ACTION
# Silent version of "act". Useful when the action to take is
# printing out a warning message.
#
# PATTERN is bash extglob pattern.
#
# For example, the following (useless) rule disables APM on the first
# harddrive of my machine.
#
# rule p5w64
# dmi baseboard-product-name P5W64 WS Pro
# dmi baseboard-manufacturer ASUSTeK Computer INC.
# ata model WDC WD5000YS-01M
# ata serial *WMANU1217262
# act hdparm -B 255 $DEV
#
# Release under BSD license. See LICENSE.
#
declare usage="
Usage: storage-fixup [-h] [-V] [-v] [-b] [-c config_file] [-m max_devs]
-h Print this help message and exit
-V Print version and exit
-v Verbose
-d Dry run, don't actually execute action
-c Use config_file instead of /etc/storage-fixup.conf
-m Maximum number of allowed devices (default=64, 0 for unlimited)
"
declare dmidecode=${DMIDECODE:-dmidecode}
declare hdparm=${HDPARM:-hdparm}
declare sg_inq=${HDPARM:-sg_inq}
declare sed=${SED:-sed}
declare version=0.2
declare conf_file=/etc/storage-fixup.conf
declare max_devs=64
declare newline=$'\n'
declare dry_run=0 verbose=0 lineno=0 skip=0 rule_name="" reply
declare -a storage_devs
declare -a match_cache
declare -a matches
log() {
echo "storage-fixup: $@"
}
warn() {
log "$@" 1>&2
}
debug() {
if [ $verbose -ne 0 ]; then
warn "$@"
fi
}
trim() {
local str="$1"
str="${str##*([[:blank:]])}"
str="${str%%*([[:blank:]])}"
echo -n "$str"
}
#
# search_match_cache - search match cache
# @type: type of match
# @key: key of property to search
# @idx: index of device to search for
#
# Searches match cache and returns 0 if found, 1 if @type:@key
# properties are cached but matching entry is not found, 2 if
# @type:@key properties are not cached yet. On success, the matched
# property is returned in $reply.
#
search_match_cache() {
local type="$1" key=$(trim "$2") idx="$3"
local i key_found=0 cache len match
reply=
for ((i=0;i<${#match_cache[@]};i++)); do
cache=${match_cache[i]}
len=${#cache}
match="${cache#$type:$key:?(-)+([0-9]) }"
if [ ${#match} -ne $len ]; then
key_found=1
fi
match="${cache#$type:$key:$idx }"
if [ ${#match} -ne $len ]; then
reply="$match"
return 0
fi
done
if [ $key_found -eq 1 ]; then
return 1
else
return 2
fi
}
#
# add_to_match_cache - add entry to match cache
# @type: type of match
# @key: key of the entry to be added
# @idx: index of device to add entry for
# @property: property of the entry to be added
#
# Add $property for $type:$key:$idx.
#
add_to_match_cache() {
local type="$1" key=$(trim "$2") idx="$3" property=$(trim "$4")
match_cache+=("$type:$key:$idx $property")
debug "C $type:$key:$idx $property"
reply="$property"
return 0
}
#
# do_dmi - perform DMI match
# @key: DMI key to be passed as --string argument to dmidecode
# @pattern: glob pattern to match
#
# Returns 0 on match, 1 on mismatch, 2 on invalid match (triggers
# warning).
#
do_dmi() {
local key="$1" pattern="$2"
local ret val
if [ -z "$key" -o -z "$pattern" ]; then
return 1
fi
search_match_cache dmi "$key" 0
ret=$?
if [ $ret -eq 2 ]; then
val=$($dmidecode --string "$key")
if [ "$?" -ne 0 ]; then
add_to_match_cache dmi "$key" -1
return 2
fi
add_to_match_cache dmi "$key" 0 "$val"
elif [ $ret -eq 1 ]; then
return 2
fi
if [ -z "${reply##$pattern}" ]; then
debug "Y $lineno $rule_name dmi $key=$pattern"
return 0
fi
debug "N $lineno $rule_name dmi $key=$pattern"
return 1
}
#
# do_storage - perform storage match
# @type: ata or scsi
# @key: ata key - model, rev or serial for both ata and scsi or vendor for scsi
# @pattern: glob pattern to match
#
# Returns 0 on match, 1 on mismatch, 2 on invalid match (triggers
# warning).
#
do_storage() {
local type="$1" key="$2" pattern="$3" idx
local -a old_matches=("${matches[@]}")
if [ -z "$key" -o -z "$pattern" ]; then
return 1
fi
matches=()
for idx in ${old_matches[@]}; do
if search_match_cache $type "$key" $idx; then
if [ $? -eq 0 -a -z "${reply##$pattern}" ]; then
matches+=($idx)
fi
fi
done
if [ ${#matches[@]} -eq 0 ]; then
debug "N $lineno $rule_name $type:$key=$pattern"
return 1
fi
debug "Y $lineno $rule_name $type nr_devs=${#matches[@]} $type:$key"
return 0
}
#
# do_act - execute action
# @act: action to execute
#
# Execute @act for each device in $matches. "$DEV" in @act is
# substituted with the /dev node of each match. If $dry_run is set,
# the action is logged but not actually executed.
#
# Returns 0.
#
do_act() {
local act="$1" verbose="$2"
local id dev
for idx in ${matches[@]}; do
DEV=${storage_devs[idx]}
if [ $dry_run -eq 0 ]; then
if [ $verbose -ne 0 ]; then
eval log "$rule_name: executing \"$act\""
fi
eval "$act"
else
eval log "$rule_name: dry-run \"$act\""
fi
done
return 0
}
#
# Execution starts here
#
shopt -s extglob
while getopts "dvVc:m:h" option; do
case $option in
d)
dry_run=1;;
v)
verbose=1;;
V)
echo "$version"
exit 0;;
c)
conf_file=$OPTARG;;
m)
max_devs=$((OPTARG+0));;
*)
echo "$usage" 2>&1
exit 1;;
esac
done
# what storage devices do we have?
storage_devs=($(ls /dev/[sh]d+([a-z]) /dev/sr+([0-9]) 2> /dev/null))
debug "I ${#storage_devs[@]} storage devices"
if [ $max_devs -ne 0 -a ${#storage_devs[@]} -gt $max_devs ]; then
warn "nr_storage_devs=${#storage_devs[@]} > limit=$max_devs, skipping"
exit 1
fi
# populate storage info
for ((i=0;i<${#storage_devs};i++)); do
output=$($hdparm -i ${storage_devs[i]} 2> /dev/null)
if [ $? -eq 0 ]; then
MODEL=
REV=
SERIAL=
eval $(echo "$output" | $sed -nr 's/^\s*Model=\s*(.*\S|\s*)\s*,\s*FwRev=\s*(.*\S|\s*)\s*,\s*SerialNo=\s*(.*\S|\s*)\s*$/MODEL=\"\1\"\nREV=\"\2\"\nSERIAL=\"\3\"/p')
add_to_match_cache ata model $i "$MODEL"
add_to_match_cache ata rev $i "$REV"
add_to_match_cache ata serial $i "$SERIAL"
fi
output=$($sg_inq ${storage_devs[i]} 2> /dev/null)
if [ $? -eq 0 ]; then
VENDOR=
MODEL=
REV=
SERIAL=
eval $(echo "$output" | $sed -nr 's/^\s*Vendor identification:\s*(.*\S|\s*)\s*$/VENDOR=\"\1\"/p')
eval $(echo "$output" | $sed -nr 's/^\s*Product identification:\s*(.*\S|\s*)\s*$/MODEL=\"\1\"/p')
eval $(echo "$output" | $sed -nr 's/^\s*Product revision level:\s*(.*\S|\s*)\s*$/REV=\"\1\"/p')
eval $(echo "$output" | $sed -nr 's/^\s*Unit serial number:\s*(.*\S|\s*)\s*$/SERIAL=\"\1\"/p')
add_to_match_cache scsi vendor $i "$VENDOR"
add_to_match_cache scsi model $i "$MODEL"
add_to_match_cache scsi rev $i "$REV"
add_to_match_cache scsi serial $i "$SERIAL"
fi
done
while read f0 f1 f2; do
true $((lineno++))
if [ -z ${f0###*} ]; then
continue
fi
if [ "$f0" = rule ]; then
rule_name=$f1
skip=0
matches=($(seq 0 $((${#storage_devs[@]}-1))))
continue
fi
if [ $skip -ne 0 ]; then
continue
fi
case "$f0" in
dmi)
do_dmi "$f1" "$f2"
;;
ata)
do_storage ata "$f1" "$f2"
;;
scsi)
do_storage scsi "$f1" "$f2"
;;
act)
do_act "$f1 $f2" 1
;;
sact)
do_act "$f1 $f2" 0
;;
*)
false
;;
esac
ret=$?
if [ $ret -ne 0 ]; then
if [ $ret -eq 2 ]; then
warn "malformed line $lineno \"$f0 $f1 $f2\","\
"skipping rule $rule_name" 2>&1
fi
skip=1
fi
done < $conf_file
next prev parent reply other threads:[~2008-08-03 8:24 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-07-26 13:34 Seagate HDD Frequent Head Unload - hdparm/dmidecode/smartctl output Ivan N. Zlatev
2008-07-28 7:28 ` Tejun Heo
2008-07-28 9:04 ` Ivan N. Zlatev
2008-07-28 9:18 ` Tejun Heo
2008-08-02 13:01 ` Ivan N. Zlatev
2008-08-03 8:23 ` Tejun Heo [this message]
2008-08-03 15:29 ` Ivan N. Zlatev
2008-08-03 22:42 ` Tejun Heo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=48956B0C.3030406@suse.de \
--to=teheo@suse.de \
--cc=contact@i-nz.net \
--cc=linux-ide@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).