11#! /bin/bash
2- # Skript to rescan SCSI bus, using the
3- # scsi add-single-device mechanism
2+ # Script to rescan SCSI bus, using the scsi add-single-device mechanism.
43# (c) 1998--2010 Kurt Garloff <[email protected] >, GNU GPL v2 or v354# (c) 2006--2015 Hannes Reinecke, GNU GPL v2 or later
65# $Id: rescan-scsi-bus.sh,v 1.57 2012/03/31 14:08:48 garloff Exp $
76
8- VERSION=" 20160201 "
7+ VERSION=" 20160228 "
98SCAN_WILD_CARD=4294967295
109
1110setcolor ()
@@ -44,11 +43,10 @@ print_and_scroll_back ()
4443 return $LN
4544}
4645
47- # Overwrite a text of length $1 (fallback to $LN) with whitespace
46+ # Overwrite a text of length $LN with whitespace
4847white_out ()
4948{
5049 BK=" " ; WH=" "
51- if test -n " $1 " ; then LN=$1 ; fi
5250 declare -i cntr=0
5351 while test $cntr -lt $LN ; do BK=" $BK \e[D" ; WH=" $WH " ; let cntr+=1; done
5452 echo -en " $WH$BK "
@@ -91,8 +89,8 @@ findhosts ()
9189 if test $name = add_map -o $name = map -o $name = mod_parm; then continue ; fi
9290 num=$name
9391 driverinfo=$driver
94- if test -r $hostdir /status; then
95- num=$( printf ' %d\n' ` sed -n ' s/SCSI host number://p' $hostdir /status` )
92+ if test -r " $hostdir /status" ; then
93+ num=$( printf ' %d\n' " $( sed -n ' s/SCSI host number://p' " $hostdir /status" ) " )
9694 driverinfo=" $driver :$name "
9795 fi
9896 hosts=" $hosts $num "
@@ -168,17 +166,19 @@ $SCSITMP"
168166 fi
169167 else
170168 grepstr=" scsi$host Channel: $CHANNEL Id: $ID Lun: $LUN "
171- SCSISTR=` cat /proc/scsi/scsi | grep -A$LN -e" $grepstr " `
169+ SCSISTR=$( grep -A " $LN " -e " $grepstr " /proc/scsi/scsi )
172170 fi
173171 if test -z " $SCSISTR " ; then return 1; else return 0; fi
174172}
175173
176174# Find sg device with 2.6 sysfs support
177175sgdevice26 ()
178176{
179- if test -e /sys/class/scsi_device/$host \: $channel \: $id \: $lun /device/generic; then
180- SGDEV=` readlink /sys/class/scsi_device/$host \: $channel \: $id \: $lun /device/generic`
181- SGDEV=` basename $SGDEV `
177+ local gendev
178+
179+ gendev=/sys/class/scsi_device/${host} :${channel} :${id} :${lun} /device/generic
180+ if test -e " $gendev " ; then
181+ SGDEV=$( basename " $( readlink " $gendev " ) " )
182182 else
183183 for SGDEV in /sys/class/scsi_generic/sg* ; do
184184 DEV=` readlink $SGDEV /device`
@@ -213,7 +213,7 @@ sgdevice ()
213213 DRV=` grep ' Attached drivers:' /proc/scsi/scsi 2> /dev/null`
214214 if [ $? = 1 ]; then return ; fi
215215 fi
216- if ! ` echo $DRV | grep ' drivers: sg' > /dev/null ` ; then
216+ if ! echo " $DRV " | grep -q ' drivers: sg' ; then
217217 modprobe sg
218218 fi
219219 sgdevice24
@@ -223,14 +223,37 @@ sgdevice ()
223223 fi
224224}
225225
226+ # Whether or not the RMB (removable) bit has been set in the INQUIRY response.
227+ # Uses ${host}, ${channel}, ${id} and ${lun}. Assumes that sg_device() has
228+ # already been called. How to test this function: copy/paste this function
229+ # in a shell and run
230+ # (cd /sys/class/scsi_device && for d in *; do set ${d//:/ }; echo -n "$d $(</sys/class/scsi_device/${d}/device/block/*/removable) <> "; SGDEV=bsg/$d host=$1 channel=$2 id=$3 lun=$4 is_removable; done)
231+ is_removable ()
232+ {
233+ local b p
234+
235+ p=/sys/class/scsi_device/${host} :${channel} :${id} :${lun} /device/inquiry
236+ # Extract the second byte of the INQUIRY response and check bit 7 (mask 0x80).
237+ b=$( od -tx1 -j1 -N1 " $p " 2> /dev/null |
238+ { read -r offset byte rest; echo -n " $byte " ; })
239+ if [ -n " $b " ]; then
240+ echo $(( (0 x$b & 0x80 ) != 0 ))
241+ else
242+ sg_inq /dev/$SGDEV 2> /dev/null | sed -n ' s/^.*RMB=\([0-9]*\).*$/\1/p'
243+ fi
244+ }
245+
226246# Test if SCSI device is still responding to commands
227247# Return values:
228248# 0 device is present
229249# 1 device has changed
230250# 2 device has been removed
231251testonline ()
232252{
253+ local ctr RC RMB
254+
233255 : testonline
256+ ctr=0
234257 RC=0
235258 # Set default values
236259 IPTYPE=31
@@ -250,7 +273,7 @@ testonline ()
250273 RC=$?
251274 # Check for removable device; TEST UNIT READY obviously will
252275 # fail for a removable device with no medium
253- RMB=` sg_inq /dev/ $SGDEV 2> /dev/null | grep ' RMB= ' | sed ' s/^.*RMB=\(.\).*$/\1/ ' `
276+ RMB=$( is_removable )
254277 print_and_scroll_back " $host :$channel :$id :$lun $SGDEV ($RMB ) "
255278 test $RC = 2 -a " $RMB " = " 1" && break
256279 done
@@ -296,7 +319,7 @@ testonline ()
296319 return $RC
297320}
298321
299- # Test if SCSI device $host $channen $id $lun exists
322+ # Test if SCSI device $host $channel $id $lun exists
300323# Outputs description from /proc/scsi/scsi (unless arg passed)
301324# Returns SCSISTR (empty if no dev)
302325testexist ()
@@ -382,7 +405,7 @@ getluns()
382405 if test $? ! = 0 -o -z " $LLUN " ; then echo 0; return 1; fi
383406 for lun in $LLUN ; do
384407 # Swap LUN number
385- l0=$( printf ' %u ' 0x$lun )
408+ l0=0x$lun
386409 l1=$(( ($l0 >> 48 ) & 0xffff ))
387410 l2=$(( ($l0 >> 32 ) & 0xffff ))
388411 l3=$(( ($l0 >> 16 ) & 0xffff ))
@@ -562,8 +585,7 @@ doreportlun()
562585 REPLUNSTAT=$?
563586 lunremove=
564587 # echo "getluns reports " $targetluns
565- olddev=` find /sys/class/scsi_device/ -name $host :$channel :$id :* 2> /dev/null | sort -t: -k4 -n`
566- oldluns=` echo " $olddev " | awk -F' /' ' {print $5}' | awk -F' :' ' {print $4}' `
588+ olddev=` find /sys/class/scsi_device/ -name " $host :$channel :$id :*" 2> /dev/null | sort -t: -k4 -n`
567589 oldtargets=" $targetluns "
568590 # OK -- if we don't have a LUN to send a REPORT_LUNS to, we could
569591 # fall back to wildcard scanning. Same thing if the device does not
@@ -577,7 +599,7 @@ doreportlun()
577599 else
578600 echo " scsi add-single-device $host $channel $id $SCAN_WILD_CARD " > /proc/scsi/scsi
579601 fi
580- targetluns=` find /sys/class/scsi_device/ -name $host :$channel :$id :* 2> /dev/null | awk -F' /' ' {print $5}' | awk -F' :' ' {print $4}' | sort -n`
602+ targetluns=` find /sys/class/scsi_device/ -name " $host :$channel :$id :*" 2> /dev/null | awk -F' /' ' {print $5}' | awk -F' :' ' {print $4}' | sort -n`
581603 let found+=` echo " $targetluns " | wc -l`
582604 let found-=` echo " $olddev " | wc -l`
583605 fi
@@ -701,8 +723,6 @@ findremapped()
701723 local sddev=
702724 local id_serial=
703725 local id_serial_old=
704- local sysfs_devpath=
705- local mpath_uuid=
706726 local remapped=
707727 mpaths=" "
708728 local tmpfile=$( mktemp /tmp/rescan-scsi-bus.XXXXXXXX 2> /dev/null)
@@ -862,13 +882,13 @@ findmultipath()
862882 local maj_min=` cat /sys/block/$dev /dev`
863883 for mp in $( $DMSETUP ls --target=multipath | cut -f 1) ; do
864884 [ " $mp " = " No" ] && break ;
865- if $( $ DMSETUP status $mp | grep -q " $maj_min " ) ; then
885+ if $DMSETUP status $mp | grep -q " $maj_min " ; then
866886 # With two arguments, look up current uuid from sysfs
867887 # if it doesn't match what was passed, this multipath
868888 # device is not updated, so this is a remapped LUN
869889 if [ -n " $find_mismatch " ] ; then
870- mp2=` $ MULTIPATH -l $mp | egrep -o dm-[0-9]+`
871- mp2=` cat /sys/block/$mp2 /dm/uuid | cut -f2 -d- `
890+ mp2=$( $ MULTIPATH -l " $mp " | egrep -o " dm-[0-9]+" )
891+ mp2=$( cut -f2 -d- " /sys/block/$mp2 /dm/uuid" )
872892 if [ " $find_mismatch " != " $mp2 " ] ; then
873893 addmpathtolist $mp
874894 found_dup=1
0 commit comments