Shell script to rescan Linux SCSI bus using the scsi add-single-device mechanism

by on April 9, 2008 · 10 comments

  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.15 2004/05/08 14:47:13 garloff Exp $
  7.  
  8. setcolor ()
  9. {
  10. red="\e[0;31m"
  11. green="\e[0;32m"
  12. yellow="\e[0;33m"
  13. norm="\e[0;0m"
  14. }
  15.  
  16. unsetcolor ()
  17. {
  18. red=""; green=""
  19. yellow=""; norm=""
  20. }
  21.  
  22. # Return hosts. sysfs must be mounted
  23. findhosts_26 ()
  24. {
  25. hosts=
  26. if ! ls /sys/class/scsi_host/host* >/dev/null 2>&1; then
  27. echo "No SCSI host adapters found in sysfs"
  28. exit 1;
  29. #hosts=" 0"
  30. #return
  31. fi
  32. for hostdir in /sys/class/scsi_host/host*; do
  33. hostno=${hostdir#/sys/class/scsi_host/host}
  34. hostname=`cat $hostdir/proc_name`
  35. hosts="$hosts $hostno"
  36. echo "Host adapter $hostno ($hostname) found."
  37. done
  38. }
  39.  
  40. # Return hosts. /proc/scsi/HOSTADAPTER/? must exist
  41. findhosts ()
  42. {
  43. hosts=
  44. for driverdir in /proc/scsi/*; do
  45. driver=${driverdir#/proc/scsi/}
  46. if test $driver = scsi -o $driver = sg -o $driver = dummy -o $driver = device_info; then continue; fi
  47. for hostdir in $driverdir/*; do
  48. name=${hostdir#/proc/scsi/*/}
  49. if test $name = add_map -o $name = map -o $name = mod_parm; then continue; fi
  50. num=$name
  51. driverinfo=$driver
  52. if test -r $hostdir/status; then
  53. num=$(printf '%d\n' `sed -n 's/SCSI host number://p' $hostdir/status`)
  54. driverinfo="$driver:$name"
  55. fi
  56. hosts="$hosts $num"
  57. echo "Host adapter $num ($driverinfo) found."
  58. done
  59. done
  60. }
  61.  
  62. # Test if SCSI device $host $channen $id $lun exists
  63. # Outputs description from /proc/scsi/scsi, returns new
  64. testexist ()
  65. {
  66. grepstr="scsi$host Channel: 0*$channel Id: 0*$id Lun: 0*$lun"
  67. new=`cat /proc/scsi/scsi | grep -e"$grepstr"`
  68. if test ! -z "$new"; then
  69. cat /proc/scsi/scsi | grep -e"$grepstr"
  70. cat /proc/scsi/scsi | grep -A2 -e"$grepstr" | tail -n2 | pr -o4 -l1
  71. fi
  72. }
  73.  
  74. # Perform search (scan $host)
  75. dosearch ()
  76. {
  77. for channel in $channelsearch; do
  78. for id in $idsearch; do
  79. for lun in $lunsearch; do
  80. new=
  81. devnr="$host $channel $id $lun"
  82. echo "Scanning for device $devnr ..."
  83. printf "${yellow}OLD: $norm"
  84. testexist
  85. if test ! -z "$remove" -a ! -z "$new"; then
  86. # Device exists and we're in remove mode, so remove and readd
  87. echo "scsi remove-single-device $devnr" >/proc/scsi/scsi
  88. echo "scsi add-single-device $devnr" >/proc/scsi/scsi
  89. printf "\r\x1b[A\x1b[A\x1b[A${yellow}OLD: $norm"
  90. testexist
  91. if test -z "$new"; then
  92. printf "\r${red}DEL: $norm\r\n\n\n\n"; let rmvd+=1;
  93. fi
  94. fi
  95. if test -z "$new"; then
  96. # Device does not exist, try to add
  97. printf "\r${green}NEW: $norm"
  98. echo "scsi add-single-device $devnr" >/proc/scsi/scsi
  99. testexist
  100. if test -z "$new"; then
  101. # Device not present
  102. printf "\r\x1b[A";
  103. # Optimization: if lun==0, stop here (only if in non-remove mode)
  104. if test $lun = 0 -a -z "$remove" -a $optscan = 1; then
  105. break;
  106. fi
  107. else
  108. let found+=1;
  109. fi
  110. fi
  111. done
  112. done
  113. done
  114. }
  115.  
  116. # main
  117. if test @$1 = @--help -o @$1 = @-h -o @$1 = @-?; then
  118. echo "Usage: rescan-scsi-bus.sh [options] [host [host ...]]"
  119. echo "Options:"
  120. echo " -l activates scanning for LUNs 0-7 [default: 0]"
  121. echo " -w scan for target device IDs 0 .. 15 [default: 0-7]"
  122. echo " -c enables scanning of channels 0 1 [default: 0]"
  123. echo " -r enables removing of devices [default: disabled]"
  124. echo "--remove: same as -r"
  125. echo "--nooptscan: don't stop looking for LUNs is 0 is not found"
  126. echo "--color: use coloured prefixes OLD/NEW/DEL"
  127. echo "--hosts=LIST: Scan only host(s) in LIST"
  128. echo "--channels=LIST: Scan only channel(s) in LIST"
  129. echo "--ids=LIST: Scan only target ID(s) in LIST"
  130. echo "--luns=LIST: Scan only lun(s) in LIST"
  131. echo " Host numbers may thus be specified either directly on cmd line (deprecated) or"
  132. echo " or with the --hosts=LIST parameter (recommended)."
  133. echo "LIST: A[-B][,C[-D]]... is a comma separated list of single values and ranges"
  134. echo " (No spaces allowed.)"
  135. exit 0
  136. fi
  137.  
  138. expandlist ()
  139. {
  140. list=$1
  141. result=""
  142. first=${list%%,*}
  143. rest=${list#*,}
  144. while test ! -z "$first"; do
  145. beg=${first%%-*};
  146. if test "$beg" = "$first"; then
  147. result="$result $beg";
  148. else
  149. end=${first#*-}
  150. result="$result `seq $beg $end`"
  151. fi
  152. test "$rest" = "$first" && rest=""
  153. first=${rest%%,*}
  154. rest=${rest#*,}
  155. done
  156. echo $result
  157. }
  158.  
  159. if test ! -d /proc/scsi/; then
  160. echo "Error: SCSI subsystem not active"
  161. exit 1
  162. fi
  163.  
  164. # defaults
  165. unsetcolor
  166. lunsearch="0"
  167. idsearch=`seq 0 7`
  168. channelsearch="0"
  169. remove=""
  170. optscan=1
  171. if test -d /sys/class/scsi_host; then
  172. findhosts_26
  173. else
  174. findhosts
  175. fi
  176.  
  177. # Scan options
  178. opt="$1"
  179. while test ! -z "$opt" -a -z "${opt##-*}"; do
  180. opt=${opt#-}
  181. case "$opt" in
  182. l) lunsearch=`seq 0 7` ;;
  183. w) idsearch=`seq 0 15` ;;
  184. c) channelsearch="0 1" ;;
  185. r) remove=1 ;;
  186. -remove) remove=1 ;;
  187. -hosts=*) arg=${opt#-hosts=}; hosts=`expandlist $arg` ;;
  188. -channels=*) arg=${opt#-channels=};channelsearch=`expandlist $arg` ;;
  189. -ids=*) arg=${opt#-ids=}; idsearch=`expandlist $arg` ;;
  190. -luns=*) arg=${opt#-luns=}; lunsearch=`expandlist $arg` ;;
  191. -color) setcolor ;;
  192. -nooptscan) optscan=0 ;;
  193. *) echo "Unknown option -$opt !" ;;
  194. esac
  195. shift
  196. opt="$1"
  197. done
  198.  
  199. # Hosts given ?
  200. if test "@$1" != "@"; then
  201. hosts=$*;
  202. fi
  203.  
  204. echo "Scanning hosts $hosts channels $channelsearch for "
  205. echo " SCSI target IDs " $idsearch ", LUNs " $lunsearch
  206. test -z "$remove" || echo " and remove devices that have disappeared"
  207. declare -i found=0
  208. declare -i rmvd=0
  209. for host in $hosts; do
  210. dosearch;
  211. done
  212. echo "$found new device(s) found. "
  213. echo "$rmvd device(s) removed. "


4000+ howtos and counting! If you enjoyed this article, join 45000+ others and get free email updates!

Click here to subscribe via email.

  • Don Gilbert

    This saved me so much time. Thanks.

  • Philippe Borel

    Excellent work !

    Thanks

  • everton

    super stuff – absolutely super!…well done

  • Augusto Fontes

    Congratulations! Very good job.

  • Mark Beierl

    Excellent! I can add hard disks to VMware images and activate them in the OS all without a reboot!

  • vikas aggarwal

    thankyou much for sharing this. it helped me in development effort.

  • Ng Siew Hong

    Error: SCSI subsystem not active

  • Sridhar

    Super Job.
    Thanks for your innovative mind.

  • spiralofhope

    Very nice! I don’t have to rely on the scsiadd tool anymore.

    … which is handy, since the website was down at a critical moment for me.

  • Sundar

    I hope this script is from SUSE LINUX which has its own command to Re-scan the SCSI Subsystem

Previous Script:

Next Script: