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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.