home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / boot / i386 / rescue / bin / rescan-scsi-bus.sh < prev    next >
Linux/UNIX/POSIX Shell Script  |  2006-11-29  |  11KB  |  376 lines

  1. #!/bin/bash
  2. # Skript to rescan SCSI bus, using the 
  3. # scsi add-single-device mechanism
  4. # (w) 1998-03-19 Kurt Garloff <kurt@garloff.de> (c) GNU GPL
  5. # (w) 2003-07-16 Kurt Garloff <garloff@suse.de> (c) GNU GPL
  6. # $Id: rescan-scsi-bus.sh,v 1.22 2006/07/24 11:26:04 garloff Exp $
  7.  
  8. setcolor ()
  9. {
  10.   red="\e[0;31m"
  11.   green="\e[0;32m"
  12.   yellow="\e[0;33m"
  13.   bold="\e[0;1m"
  14.   norm="\e[0;0m"
  15. }
  16.  
  17. unsetcolor () 
  18. {
  19.   red=""; green=""
  20.   yellow=""; norm=""
  21. }
  22.  
  23. # Return hosts. sysfs must be mounted
  24. findhosts_26 ()
  25. {
  26.   hosts=
  27.   if ! ls /sys/class/scsi_host/host* >/dev/null 2>&1; then
  28.     echo "No SCSI host adapters found in sysfs"
  29.     exit 1;
  30.     #hosts=" 0"
  31.     #return
  32.   fi 
  33.   for hostdir in /sys/class/scsi_host/host*; do
  34.     hostno=${hostdir#/sys/class/scsi_host/host}
  35.     hostname=`cat $hostdir/proc_name`
  36.     hosts="$hosts $hostno"
  37.     echo "Host adapter $hostno ($hostname) found."
  38.   done  
  39. }
  40.  
  41. # Return hosts. /proc/scsi/HOSTADAPTER/? must exist
  42. findhosts ()
  43. {
  44.   hosts=
  45.   for driverdir in /proc/scsi/*; do
  46.     driver=${driverdir#/proc/scsi/}
  47.     if test $driver = scsi -o $driver = sg -o $driver = dummy -o $driver = device_info; then continue; fi
  48.     for hostdir in $driverdir/*; do
  49.       name=${hostdir#/proc/scsi/*/}
  50.       if test $name = add_map -o $name = map -o $name = mod_parm; then continue; fi
  51.       num=$name
  52.       driverinfo=$driver
  53.       if test -r $hostdir/status; then
  54.     num=$(printf '%d\n' `sed -n 's/SCSI host number://p' $hostdir/status`)
  55.     driverinfo="$driver:$name"
  56.       fi
  57.       hosts="$hosts $num"
  58.       echo "Host adapter $num ($driverinfo) found."
  59.     done
  60.   done
  61. }
  62.  
  63. # Get /proc/scsi/scsi info for device $host:$channel:$id:$lun
  64. # Optional parameter: Number of lines after first (default = 2), 
  65. # result in SCSISTR, return code 1 means empty.
  66. procscsiscsi ()
  67. {  
  68.   if test -z "$1"; then LN=2; else LN=$1; fi
  69.   CHANNEL=`printf "%02i" $channel`
  70.   ID=`printf "%02i" $id`
  71.   LUN=`printf "%02i" $lun`
  72.   if [ -d /sys/class/scsi_device ]; then
  73.       SCSIPATH="/sys/class/scsi_device/${host}:${channel}:${id}:${lun}"
  74.       if [ -d  "$SCSIPATH" ] ; then
  75.       SCSISTR="Host: scsi${host} Channel: $CHANNEL Id: $ID Lun: $LUN"
  76.       if [ "$LN" -gt 0 ] ; then
  77.           IVEND=$(cat ${SCSIPATH}/device/vendor)
  78.           IPROD=$(cat ${SCSIPATH}/device/model)
  79.           IPREV=$(cat ${SCSIPATH}/device/rev)
  80.           SCSIDEV=$(printf '  Vendor: %-08s Model: %-16s Rev: %-4s' "$IVEND" "$IPROD" "$IPREV")
  81.           SCSISTR="$SCSISTR
  82. $SCSIDEV"
  83.       fi
  84.       if [ "$LN" -gt 1 ] ; then
  85.           ILVL=$(cat ${SCSIPATH}/device/scsi_level)
  86.           type=$(cat ${SCSIPATH}/device/type)
  87.           case "$type" in
  88.           0) ITYPE="Direct-Access    " ;;
  89.           1) ITYPE="Sequential-Access" ;;
  90.           2) ITYPE="Printer          " ;;
  91.           3) ITYPE="Processor        " ;;
  92.           4) ITYPE="WORM             " ;;
  93.           5) ITYPE="CD-ROM           " ;;
  94.           6) ITYPE="Scanner          " ;;
  95.           7) ITYPE="Optical Device   " ;;
  96.           8) ITYPE="Medium Changer   " ;;
  97.           9) ITYPE="Communications   " ;;
  98.           10) ITYPE="Unknown          " ;;
  99.           11) ITYPE="Unknown          " ;;
  100.           12) ITYPE="RAID             " ;;
  101.           13) ITYPE="Enclosure        " ;;
  102.           14) ITYPE="Direct-Access-RBC" ;;
  103.           *) ITYPE="Unknown          " ;;
  104.           esac
  105.           SCSITMP=$(printf '  Type:   %-16s                ANSI SCSI revision: %02d' "$ITYPE" "$((ILVL - 1))")
  106.           SCSISTR="$SCSISTR
  107. $SCSITMP"
  108.       fi
  109.           
  110.       else
  111.       return 1
  112.       fi
  113.   else
  114.       grepstr="scsi$host Channel: $CHANNEL Id: $ID Lun: $LUN"
  115.       SCSISTR=`cat /proc/scsi/scsi | grep -A$LN -e"$grepstr"`
  116.   fi
  117.   if test -z "$SCSISTR"; then return 1; else return 0; fi
  118. }
  119.  
  120. # Find sg device with 2.6 sysfs support
  121. sgdevice26 ()
  122. {
  123.   if test -e /sys/class/scsi_device/$host\:$channel\:$id\:$lun/device/generic; then    
  124.     SGDEV=`readlink /sys/class/scsi_device/$host\:$channel\:$id\:$lun/device/generic`
  125.     SGDEV=`basename $SGDEV`
  126.   else
  127.     for SGDEV in /sys/class/scsi_generic/sg*; do
  128.       DEV=`readlink $SGDEV/device`
  129.       if test "${DEV##*/}" = "$host:$channel:$id:$lun"; then
  130.     SGDEV=`basename $SGDEV`; return
  131.       fi
  132.     done
  133.     SGDEV=""
  134.   fi  
  135. }
  136.  
  137. # Find sg device with 2.4 report-devs extensions
  138. sgdevice24 ()
  139. {
  140.   if procscsiscsi 3; then
  141.     SGDEV=`echo "$SCSISTR" | grep 'Attached drivers:' | sed 's/^ *Attached drivers: \(sg[0-9]*\).*/\1/'`
  142.   fi
  143. }
  144.  
  145. # Find sg device that belongs to SCSI device $host $channel $id $lun
  146. sgdevice ()
  147. {
  148.   SGDEV=
  149.   if test -d /sys/class/scsi_device; then
  150.     sgdevice26
  151.   else  
  152.     DRV=`grep 'Attached drivers:' /proc/scsi/scsi 2>/dev/null`
  153.     repdevstat=$((1-$?))
  154.     if [ $repdevstat = 0 ]; then
  155.       echo "scsi report-devs 1" >/proc/scsi/scsi
  156.       DRV=`grep 'Attached drivers:' /proc/scsi/scsi 2>/dev/null`
  157.       if [ $? = 1 ]; then return; fi
  158.     fi
  159.     if ! `echo $DRV | grep 'drivers: sg' >/dev/null`; then
  160.       modprobe sg
  161.     fi
  162.     sgdevice24
  163.     if [ $repdevstat = 0 ]; then
  164.       echo "scsi report-devs 0" >/proc/scsi/scsi
  165.     fi
  166.   fi
  167. }       
  168.  
  169. # Test if SCSI device is still responding to commands
  170. testonline ()
  171. {
  172.   if test ! -x /usr/bin/sg_turs; then return 0; fi
  173.   sgdevice
  174.   if test -z "$SGDEV"; then return 0; fi
  175.   sg_turs /dev/$SGDEV >/dev/null 2>&1
  176.   RC=$?
  177.   #echo -e "\e[A\e[A\e[A${yellow}Test existence of $SGDEV = $RC ${norm} \n\n\n"
  178.   if test $RC = 1; then return $RC; fi
  179.   # OK, device online, compare INQUIRY string
  180.   INQ=`sg_inq -36 /dev/$SGDEV`
  181.   IVEND=`echo "$INQ" | grep 'Vendor identification:' | sed 's/^[^:]*: \(.*\)$/\1/'`
  182.   IPROD=`echo "$INQ" | grep 'Product identification:' | sed 's/^[^:]*: \(.*\)$/\1/'`
  183.   IPREV=`echo "$INQ" | grep 'Product revision level:' | sed 's/^[^:]*: \(.*\)$/\1/'`
  184.   STR=`printf "  Vendor: %-08s Model: %-16s Rev: %-4s" "$IVEND" "$IPROD" "$IPREV"`
  185.   procscsiscsi
  186.   SCSISTR=`echo "$SCSISTR" | grep 'Vendor:'`
  187.   if [ "$SCSISTR" != "$STR" ]; then
  188.     echo -e "\e[A\e[A\e[A\e[A${red}$SGDEV changed: ${bold}\nfrom:${SCSISTR#* } \nto: $STR ${norm}\n\n\n"
  189.     return 1
  190.   fi
  191.   return $RC
  192. }
  193.  
  194. # Test if SCSI device $host $channen $id $lun exists
  195. # Outputs description from /proc/scsi/scsi, returns SCSISTR 
  196. testexist ()
  197. {
  198.   SCSISTR=
  199.   if procscsiscsi; then
  200.     echo "$SCSISTR" | head -n1
  201.     echo "$SCSISTR" | tail -n2 | pr -o4 -l1
  202.   fi
  203. }
  204.  
  205. # Perform search (scan $host)
  206. dosearch ()
  207. {
  208.   for channel in $channelsearch; do
  209.     for id in $idsearch; do
  210.       for lun in $lunsearch; do
  211.         SCSISTR=
  212.     devnr="$host $channel $id $lun"
  213.     echo "Scanning for device $devnr ..."
  214.     printf "${yellow}OLD: $norm"
  215.     testexist
  216.     if test ! -z "$remove" -a ! -z "$SCSISTR"; then
  217.       # Device exists: Test whether it's still online
  218.       # (testonline returns 1 if it's gone or has changed)
  219.       testonline
  220.       if test $? = 1 -o ! -z "$forceremove"; then
  221.         echo -en "\r\e[A\e[A\e[A${red}REM: "
  222.         echo "$SCSISTR" | head -n1
  223.         echo -e "${norm}\e[B\e[B"
  224.         if test -e /sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device; then
  225.           echo 1 > /sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device/delete
  226.           # Try readding, should fail if device is gone
  227.           echo "$channel $id $lun" > /sys/class/scsi_host/host${host}/scan
  228.         else
  229.           echo "scsi remove-single-device $devnr" > /proc/scsi/scsi
  230.           # Try readding, should fail if device is gone
  231.           echo "scsi add-single-device $devnr" > /proc/scsi/scsi
  232.         fi
  233.           fi
  234.       printf "\r\x1b[A\x1b[A\x1b[A${yellow}OLD: $norm"
  235.       testexist
  236.       if test -z "$SCSISTR"; then
  237.         printf "\r${red}DEL: $norm\r\n\n\n\n"
  238.         let rmvd+=1;
  239.           fi
  240.     fi
  241.     if test -z "$SCSISTR"; then
  242.       # Device does not exist, try to add
  243.       printf "\r${green}NEW: $norm"
  244.       if test -e /sys/class/scsi_host/host${host}/scan; then
  245.         echo "$channel $id $lun" > /sys/class/scsi_host/host${host}/scan 2> /dev/null
  246.       else
  247.         echo "scsi add-single-device $devnr" > /proc/scsi/scsi
  248.       fi
  249.       testexist
  250.       if test -z "$SCSISTR"; then
  251.         # Device not present
  252.         printf "\r\x1b[A";
  253.           # Optimization: if lun==0, stop here (only if in non-remove mode)
  254.         if test $lun = 0 -a -z "$remove" -a $optscan = 1; then 
  255.           break;
  256.         fi  
  257.       else 
  258.         let found+=1; 
  259.       fi
  260.     fi
  261.       done
  262.     done
  263.   done
  264. }
  265.  
  266. # main
  267. if test @$1 = @--help -o @$1 = @-h -o @$1 = @-?; then
  268.     echo "Usage: rescan-scsi-bus.sh [options] [host [host ...]]"
  269.     echo "Options:"
  270.     echo " -l      activates scanning for LUNs 0-7    [default: 0]"
  271.     echo " -L NUM  activates scanning for LUNs 0--NUM [default: 0]"
  272.     echo " -w      scan for target device IDs 0 .. 15 [default: 0-7]"
  273.     echo " -c      enables scanning of channels 0 1   [default: 0]"
  274.     echo " -r      enables removing of devices        [default: disabled]"
  275.     echo "--remove:        same as -r"
  276.     echo "--forceremove:   Remove and readd every device (DANGEROUS)"
  277.     echo "--nooptscan:     don't stop looking for LUNs is 0 is not found"
  278.     echo "--color:         use coloured prefixes OLD/NEW/DEL"
  279.     echo "--hosts=LIST:    Scan only host(s) in LIST"
  280.     echo "--channels=LIST: Scan only channel(s) in LIST"
  281.     echo "--ids=LIST:      Scan only target ID(s) in LIST"
  282.     echo "--luns=LIST:     Scan only lun(s) in LIST"  
  283.     echo " Host numbers may thus be specified either directly on cmd line (deprecated) or"
  284.     echo " or with the --hosts=LIST parameter (recommended)."
  285.     echo "LIST: A[-B][,C[-D]]... is a comma separated list of single values and ranges"
  286.     echo " (No spaces allowed.)"
  287.     exit 0
  288. fi
  289.  
  290. expandlist ()
  291. {
  292.     list=$1
  293.     result=""
  294.     first=${list%%,*}
  295.     rest=${list#*,}
  296.     while test ! -z "$first"; do 
  297.     beg=${first%%-*};
  298.     if test "$beg" = "$first"; then
  299.         result="$result $beg";
  300.         else
  301.             end=${first#*-}
  302.         result="$result `seq $beg $end`"
  303.     fi
  304.     test "$rest" = "$first" && rest=""
  305.     first=${rest%%,*}
  306.     rest=${rest#*,}
  307.     done
  308.     echo $result
  309. }
  310.  
  311. if test ! -d /proc/scsi/; then
  312.   echo "Error: SCSI subsystem not active"
  313.   exit 1
  314. fi    
  315.  
  316. # Make sure sg is there
  317. modprobe sg >/dev/null 2>&1
  318.  
  319. # defaults
  320. unsetcolor
  321. lunsearch="0"
  322. idsearch=`seq 0 7`
  323. channelsearch="0"
  324. remove=
  325. forceremove=
  326. optscan=1
  327. if test -d /sys/class/scsi_host; then 
  328.   findhosts_26
  329. else  
  330.   findhosts
  331. fi  
  332.  
  333. # Scan options
  334. opt="$1"
  335. while test ! -z "$opt" -a -z "${opt##-*}"; do
  336.   opt=${opt#-}
  337.   case "$opt" in
  338.     l) lunsearch=`seq 0 7` ;;
  339.     L) lunsearch=`seq 0 $2`; shift ;;
  340.     w) idsearch=`seq 0 15` ;;
  341.     c) channelsearch="0 1" ;;
  342.     r) remove=1 ;;
  343.     -remove)      remove=1 ;;
  344.     -forceremove) remove=1; forceremove=1 ;;
  345.     -hosts=*)     arg=${opt#-hosts=};   hosts=`expandlist $arg` ;;
  346.     -channels=*)  arg=${opt#-channels=};channelsearch=`expandlist $arg` ;; 
  347.     -ids=*)   arg=${opt#-ids=};         idsearch=`expandlist $arg` ;; 
  348.     -luns=*)  arg=${opt#-luns=};        lunsearch=`expandlist $arg` ;; 
  349.     -color) setcolor ;;
  350.     -nooptscan) optscan=0 ;;
  351.     *) echo "Unknown option -$opt !" ;;
  352.   esac
  353.   shift
  354.   opt="$1"
  355. done    
  356.  
  357. # Hosts given ?
  358. if test "@$1" != "@"; then 
  359.   hosts=$*; 
  360. fi
  361.  
  362. echo "Scanning hosts $hosts channels $channelsearch for "
  363. echo " SCSI target IDs " $idsearch ", LUNs " $lunsearch
  364. test -z "$remove" || echo " and remove devices that have disappeared"
  365. declare -i found=0
  366. declare -i rmvd=0
  367. for host in $hosts; do 
  368.   # YOU MAY NEED TO UNCOMMENT THESE TO ALLOW FOR A RESCAN
  369.   #test -e /sys/class/fc_host/host$host/issue_lip && echo 1 > /sys/class/fc_host/host$host/issue_lip 2> /dev/null;
  370.   #echo "- - -" > /sys/class/scsi_host/host$host/scan 2> /dev/null;
  371.   dosearch; 
  372. done
  373. echo "$found new device(s) found.               "
  374. echo "$rmvd device(s) removed.                 "
  375.  
  376.