diff options
author | Douglas Gilbert <dgilbert@interlog.com> | 2015-04-01 21:45:22 +0000 |
---|---|---|
committer | Douglas Gilbert <dgilbert@interlog.com> | 2015-04-01 21:45:22 +0000 |
commit | baa91c3f8356cf0b5ff94a778070c3c6714ac5f9 (patch) | |
tree | 826c695e97adaba3d4cd421a4fb115014f516b87 /scripts/rescan-scsi-bus.sh | |
parent | e65afc2448aee567499271a1a0c904be67f797d4 (diff) | |
download | sg3_utils-baa91c3f8356cf0b5ff94a778070c3c6714ac5f9.tar.gz |
rescan-scsi-bus.sh+sg_rdac+sg_inq+sg_vpd: updates from Sean Stewart, NetApp
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@640 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'scripts/rescan-scsi-bus.sh')
-rwxr-xr-x | scripts/rescan-scsi-bus.sh | 250 |
1 files changed, 165 insertions, 85 deletions
diff --git a/scripts/rescan-scsi-bus.sh b/scripts/rescan-scsi-bus.sh index 51fdfd99..96c06890 100755 --- a/scripts/rescan-scsi-bus.sh +++ b/scripts/rescan-scsi-bus.sh @@ -91,8 +91,8 @@ findhosts () num=$name driverinfo=$driver if test -r $hostdir/status; then - num=$(printf '%d\n' `sed -n 's/SCSI host number://p' $hostdir/status`) - driverinfo="$driver:$name" + num=$(printf '%d\n' `sed -n 's/SCSI host number://p' $hostdir/status`) + driverinfo="$driver:$name" fi hosts="$hosts $num" echo "Host adapter $num ($driverinfo) found." @@ -147,19 +147,19 @@ procscsiscsi () if [ -d "$SCSIPATH" ] ; then SCSISTR="Host: scsi${host} Channel: $CHANNEL Id: $ID Lun: $LUN" if [ "$LN" -gt 0 ] ; then - IVEND=$(cat ${SCSIPATH}/device/vendor) - IPROD=$(cat ${SCSIPATH}/device/model) - IPREV=$(cat ${SCSIPATH}/device/rev) - SCSIDEV=$(printf ' Vendor: %-08s Model: %-16s Rev: %-4s' "$IVEND" "$IPROD" "$IPREV") - SCSISTR="$SCSISTR + IVEND=$(cat ${SCSIPATH}/device/vendor) + IPROD=$(cat ${SCSIPATH}/device/model) + IPREV=$(cat ${SCSIPATH}/device/rev) + SCSIDEV=$(printf ' Vendor: %-08s Model: %-16s Rev: %-4s' "$IVEND" "$IPROD" "$IPREV") + SCSISTR="$SCSISTR $SCSIDEV" fi if [ "$LN" -gt 1 ] ; then - ILVL=$(cat ${SCSIPATH}/device/scsi_level) - type=$(cat ${SCSIPATH}/device/type) - ITYPE=$(printtype $type) - SCSITMP=$(printf ' Type: %-17s ANSI SCSI revision: %02d' "$ITYPE" "$((ILVL - 1))") - SCSISTR="$SCSISTR + ILVL=$(cat ${SCSIPATH}/device/scsi_level) + type=$(cat ${SCSIPATH}/device/type) + ITYPE=$(printtype $type) + SCSITMP=$(printf ' Type: %-17s ANSI SCSI revision: %02d' "$ITYPE" "$((ILVL - 1))") + SCSISTR="$SCSISTR $SCSITMP" fi else @@ -175,14 +175,14 @@ $SCSITMP" # Find sg device with 2.6 sysfs support sgdevice26 () { - if test -e /sys/class/scsi_device/$host\:$channel\:$id\:$lun/device/generic; then + if test -e /sys/class/scsi_device/$host\:$channel\:$id\:$lun/device/generic; then SGDEV=`readlink /sys/class/scsi_device/$host\:$channel\:$id\:$lun/device/generic` SGDEV=`basename $SGDEV` else for SGDEV in /sys/class/scsi_generic/sg*; do DEV=`readlink $SGDEV/device` if test "${DEV##*/}" = "$host:$channel:$id:$lun"; then - SGDEV=`basename $SGDEV`; return + SGDEV=`basename $SGDEV`; return fi done SGDEV="" @@ -286,7 +286,7 @@ testonline () echo -e "\e[A\e[A\e[A\e[A${red}$SGDEV changed: ${bold}\nfrom:${SCSISTR#* } \nto: $STR ${norm} \n\n\n" return 1 fi - TMPSTR=`echo "$SCSISTR" | sed -n 's/.*Type: *\(.*\) *ANSI.*/\1/p'` + TMPSTR=`echo "$SCSISTR" | sed -n 's/.*Type: *\(.*\) *ANSI.*/\1/p' | sed 's/ *$//g'` if [ "$TMPSTR" != "$TYPE" ] ; then echo -e "\e[A\e[A\e[A\e[A${red}$SGDEV changed: ${bold}\nfrom:${TMPSTR} \nto: $TYPE ${norm} \n\n\n" return 1 @@ -322,7 +322,7 @@ chanlist () chan=${cil%%:*} for tmpchan in $channelsearch ; do if test "$chan" -eq $tmpchan ; then - chan= + chan= fi done if test -n "$chan" ; then @@ -348,8 +348,8 @@ idlist () newid=$id for tmpid in $idsearch ; do if test $id -eq $tmpid ; then - newid= - break + newid= + break fi done if test -n "$newid" ; then @@ -394,9 +394,17 @@ getluns() # Wait for udev to settle (create device nodes etc.) udevadm_settle() { + local tmo=60 if test -x /sbin/udevadm; then print_and_scroll_back " Calling udevadm settle (can take a while) " - /sbin/udevadm settle + # Loop for up to 60 seconds if sd devices still are settling.. + # This allows us to continue if udev events are stuck on multipaths in recovery mode + while [ $tmo -gt 0 ] ; do + if ! /sbin/udevadm settle --timeout=1 | egrep -q sd[a-z]+ ; then + break; + fi + let tmo=$tmo-1 + done white_out elif test -x /sbin/udevsettle; then print_and_scroll_back " Calling udevsettle (can take a while) " @@ -465,13 +473,13 @@ dolunscan() incrrmvd "$host:$channel:$id:$lun" fi echo 1 > /sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device/delete - usleep 20000 + usleep 20000 else echo "scsi remove-single-device $devnr" > /proc/scsi/scsi - if test $RC -eq 1 -o $lun -eq 0 ; then + if test $RC -eq 1 -o $lun -eq 0 ; then # Try readding, should fail if device is gone echo "scsi add-single-device $devnr" > /proc/scsi/scsi - fi + fi fi fi if test $RC = 0 -o "$forcerescan" ; then @@ -543,7 +551,7 @@ doreportlun() # Find alternative LUN to send getluns to for dev in /sys/class/scsi_device/${host}:${channel}:${id}:*; do [ -d "$dev" ] || continue - lun=${dev##*:} + lun=${dev##*:} break done fi @@ -581,10 +589,10 @@ doreportlun() # OK, is existing $lun (still) in reported list for tmplun in $targetluns; do if test $tmplun -eq $lun ; then - inlist=1 - dolunscan $lun0added + inlist=1 + dolunscan $lun0added else - newsearch="$newsearch $tmplun" + newsearch="$newsearch $tmplun" fi done # OK, we have now done a lunscan on $lun and @@ -614,9 +622,9 @@ dosearch () fi for id in $idsearch; do if test -z "$lunsearch" ; then - doreportlun + doreportlun else - for lun in $lunsearch; do + for lun in $lunsearch; do dolunscan done fi @@ -661,12 +669,12 @@ searchexisting() id=`echo $target | cut -d":" -f 3` if [ -n "$channelsearch" ] ; then for tmpch in $channelsearch ; do - test $tmpch -eq $channel && match=1 + test $tmpch -eq $channel && match=1 done else match=1 fi - + test $match -eq 0 && continue match=0 @@ -692,6 +700,8 @@ findremapped() local id_serial= local id_serial_old= local sysfs_devpath= + local mpath_uuid= + local remapped= mpaths="" local tmpfile="/tmp/rescan-scsi-bus-`date +s`" @@ -700,7 +710,7 @@ findremapped() # Get all of the ID_SERIAL attributes, after finding their sd node for hctl in $devs ; do if [ -d /sys/class/scsi_device/$hctl/device/block ] ; then - sddev=`ls /sys/class/scsi_device/$hctl/device/block` + sddev=`ls /sys/class/scsi_device/$hctl/device/block` id_serial_old=`udevadm info -q all -n $sddev | grep "ID_SERIAL=" | cut -d"=" -f2` [ -z "$id_serial_old" ] && id_serial_old="none" echo "$hctl $sddev $id_serial_old" >> $tmpfile @@ -710,33 +720,46 @@ findremapped() # Trigger udev to update the info echo -n "Triggering udev to update device information... " /sbin/udevadm trigger - udevadm_settle 2&>1 /dev/null + udevadm_settle 2>&1 /dev/null echo "Done" # See what changed and reload the respective multipath device if applicable while read hctl sddev id_serial_old ; do + remapped=0 id_serial=`udevadm info -q all -n $sddev | grep "ID_SERIAL=" | cut -d"=" -f2` [ -z "$id_serial" ] && id_serial="none" if [ "$id_serial_old" != "$id_serial" ] ; then - if [ "$id_serial" = "1" ] ; then - continue # the lun was unmapped and is getting the blank scsi id (1) + remapped=1 + fi + # If udev events updated the disks already, but the multipath device isn't update + # check for old devices to make sure we found remapped luns + if [ -n "$mp_enable" ] && [ $remapped -eq 0 ]; then + findmultipath $sddev $id_serial + if [ $? -eq 1 ] ; then + remapped=1 fi - printf "${yellow}REMAPPED: $norm" - host=`echo $hctl | cut -d":" -f1` - channel=`echo $hctl | cut -d":" -f2` - id=`echo $hctl | cut -d":" -f3` - lun=`echo $hctl | cut -d":" -f4` - procscsiscsi - echo "$SCSISTR" - incrchgd "$hctl" fi + + # if uuid is 1, it's unmapped, so we don't want to treat it as a remap + # if remapped flag is 0, just skip the rest of the logic + if [ "$id_serial" = "1" ] || [ $remapped -eq 0 ] ; then + continue + fi + printf "${yellow}REMAPPED: $norm" + host=`echo $hctl | cut -d":" -f1` + channel=`echo $hctl | cut -d":" -f2` + id=`echo $hctl | cut -d":" -f3` + lun=`echo $hctl | cut -d":" -f4` + procscsiscsi + echo "$SCSISTR" + incrchgd "$hctl" done < $tmpfile - rm $tmpfile 2&>1 /dev/null + rm $tmpfile 2>&1 /dev/null if test -n "$mp_enable" -a -n "$mpaths" ; then echo "Updating multipath device mappings" flushmpaths - $MULTIPATH | grep "create:" 2> /dev/null #2&>1 /dev/null + $MULTIPATH | grep "create:" 2> /dev/null fi } @@ -755,8 +778,10 @@ incrchgd() { local hctl="$1" if test -n "$hctl" ; then - let updated+=1 - CHGDEVS="$CHGDEVS\t[$hctl]\n" + if ! echo $CHGDEVS | grep -q "\[$hctl\]"; then + let updated+=1 + CHGDEVS="$CHGDEVS\t[$hctl]\n" + fi else return fi @@ -802,30 +827,61 @@ findsddev() return 0 } +addmpathtolist() +{ + local mp="$1" + local mp2= + + for mp2 in $mpaths ; do + # The multipath device is already in the list + if [ "$mp2" = "$mp" ] ; then + return + fi + done + mpaths="$mpaths $mp" +} + findmultipath() { local dev="$1" + local find_mismatch="$2" local mp= local mp2= + local found_dup=0 # Need a sdev, and executable multipath and dmsetup command here - if [ -z "$dev" ] || [ ! -x $DMSETUP ] ; then + if [ -z "$dev" ] || [ ! -x $DMSETUP ] || [ ! -x $MULTIPATH ] ; then return 1 fi local maj_min=`cat /sys/block/$dev/dev` for mp in $($DMSETUP ls --target=multipath | cut -f 1) ; do if $($DMSETUP status $mp | grep -q " $maj_min ") ; then - for mp2 in $mpaths ; do - # mp device is already there, return - if [ "$mp2" = "$mp" ] ; then - return + # With two arguments, look up current uuid from sysfs + # if it doesn't match what was passed, this multipath + # device is not updated, so this is a remapped LUN + if [ -n "$find_mismatch" ] ; then + mp2=`$MULTIPATH -l $mp | egrep -o dm-[0-9]+` + mp2=`cat /sys/block/$mp2/dm/uuid | cut -f2 -d-` + if [ "$find_mismatch" != "$mp2" ] ; then + addmpathtolist $mp + found_dup=1 fi - done - mpaths="$mpaths $mp" + continue + fi + # Normal mode: Find the first multipath with the sdev + # and add it to the list + addmpathtolist $mp return fi done + + # Return 1 to signal that a duplicate was found to the calling function + if [ $found_dup -eq 1 ] ; then + return 1 + else + return 0 + fi } reloadmpaths() @@ -836,51 +892,58 @@ reloadmpaths() return fi + # Pass 1 as the argument to reload all mpaths if [ "$1" = "1" ] ; then echo "Reloading all multipath devices" - $MULTIPATH -r 2&>1 /dev/null + $MULTIPATH -r > /dev/null 2>&1 return fi # Reload the multipath devices for mpath in $mpaths ; do - echo "Reloading multipath device $mpath" - $MULTIPATH -r $mpath 2&>1 /dev/null + echo -n "Reloading multipath device $mpath... " + $MULTIPATH -r $mpath > /dev/null 2>&1 + if test "$?" = "0" ; then + echo "Done" + else + echo "Fail" + fi done } flushmpaths() { local mpath - # Mode: flush only failed + local remove="" + local i + local flush_retries=5 + if test -n "$1" ; then for mpath in $($DMSETUP ls --target=multipath | cut -f 1) ; do num=$($DMSETUP status $mpath | awk 'BEGIN{RS=" ";active=0}/[0-9]+:[0-9]+/{dev=1}/A/{if (dev == 1) active++; dev=0} END{ print active }') if [ $num -eq 0 ] ; then - echo -n "Flushing multipath device $mpath... " - $DMSETUP message $mpath 0 fail_if_no_path 2&>1 /dev/null - $MULTIPATH -f $mpath 2&>1 /dev/null - $DMSETUP status $mpath 2&>1 /dev/null - if test "$?" = "1" ; then - echo "Done" - else - echo "Fail" - fi + remove="$remove $mpath" fi done - return + else + remove="$mpaths" fi - # Flush all the devs specified in $mpaths - for mpath in $mpaths ; do - echo -n "Flushing multipath device $mpath... " - $DMSETUP message $mpath 0 fail_if_no_path 2&>1 /dev/null - $MULTIPATH -f $mpath 2&>1 /dev/null - $DMSETUP status $mpath 2&>1 /dev/null - if test "$?" = "1" ; then - echo "Done" - else - echo "Fail" - fi + + for mpath in $remove ; do + i=0 + echo -n "Flushing multipath device $mpath... " + while [ $i -lt $flush_retries ] ; do + $DMSETUP message $mpath 0 fail_if_no_path > /dev/null 2>&1 + $MULTIPATH -f $mpath > /dev/null 2>&1 + if test "$?" = "0" ; then + echo "Done ($i retries)" + break + elif test $i -eq $flush_retries ; then + echo "Fail" + fi + usleep 20000 + let i=$i+1 + done done } @@ -893,16 +956,20 @@ findresized() local new_size= local sysfs_path= local sddev= + local i= + local m= + local mpathsize= + declare -a mpathsizes for hctl in $devs ; do sysfs_path="/sys/class/scsi_device/$hctl/device" if [ -d "$sysfs_path/block" ] ; then sddev=`ls $sysfs_path/block` size=`cat $sysfs_path/block/$sddev/size` - + echo 1 > $sysfs_path/rescan - new_size=`cat $sysfs_path/block/$sddev/size` - + new_size=`cat $sysfs_path/block/$sddev/size` + if [ "$size" != "$new_size" ] && [ "$size" != "0" ] && [ "$new_size" != "0" ] ; then printf "${yellow}RESIZED: $norm" host=`echo $hctl | cut -d":" -f1` @@ -918,7 +985,18 @@ findresized() done if test -n "$mp_enable" -a -n "$mpaths" ; then + i=0 + for m in $mpaths ; do + mpathsizes[$i]="`$MULTIPATH -l $m | egrep -o [0-9]+.[0-9]+[KMGT]`" + let i=$i+1 + done reloadmpaths + i=0 + for m in $mpaths ; do + mpathsize="`$MULTIPATH -l $m | egrep -o [0-9\.]+[KMGT]`" + echo "$m ${mpathsizes[$i]} => $mpathsize" + let i=$i+1 + done fi } @@ -976,7 +1054,7 @@ fi if test ! -d /sys/class/scsi_host/ -a ! -d /proc/scsi/; then echo "Error: SCSI subsystem not active" exit 1 -fi +fi # Make sure sg is there modprobe sg >/dev/null 2>&1 @@ -1114,6 +1192,9 @@ fi if [ $update -eq 1 ] ; then echo "Searching for remapped LUNs" findremapped + # If you've changed the mapping, there's a chance it's a different size + mpaths="" + findresized # Search for resized LUNs elif [ $resize -eq 1 ] ; then echo "Searching for resized LUNs" @@ -1164,13 +1245,12 @@ let rmvd_found=$rmvd+$found if test -n "$mp_enable" -a $rmvd_found -gt 0 ; then echo "Attempting to update multipath devices..." if test $rmvd -gt 0 ; then - /sbin/udevadm trigger udevadm_settle echo "Removing multipath mappings for removed devices if all paths are now failed... " flushmpaths 1 fi if test $found -gt 0 ; then - /sbin/udevadm trigger + /sbin/udevadm trigger --sysname-match=sd* udevadm_settle echo "Trying to discover new multipath mappings for newly discovered devices... " $MULTIPATH | grep "create:" 2> /dev/null @@ -1181,7 +1261,7 @@ echo "$found new or changed device(s) found. " if test ! -z "$FOUNDDEVS" ; then printf "$FOUNDDEVS" fi -echo "$updated remapped or resized device(s) found. " +echo "$updated remapped or resized device(s) found." if test ! -z "$CHGDEVS" ; then printf "$CHGDEVS" fi |