Advertisement
Guest User

Untitled

a guest
Aug 20th, 2017
493
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.55 KB | None | 0 0
  1. #!/bin/bash
  2. # Skript to rescan SCSI bus, using the
  3. # scsi add-single-device mechanism
  4. # (c) 1998--2008 Kurt Garloff <kurt@garloff.de>, GNU GPL v2 or later
  5. # (c) 2006--2008 Hannes Reinecke, GNU GPL v2 or later
  6. # $Id: rescan-scsi-bus.sh-1.29,v 1.1 2009/03/12 11:03:19 dhorak 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. for hostdir in /sys/class/scsi_host/host*; do
  28. hostno=${hostdir#/sys/class/scsi_host/host}
  29. if [ -f $hostdir/isp_name ] ; then
  30. hostname="qla2xxx"
  31. elif [ -f $hostdir/lpfc_drvr_version ] ; then
  32. hostname="lpfc"
  33. else
  34. hostname=`cat $hostdir/proc_name`
  35. fi
  36. hosts="$hosts $hostno"
  37. echo "Host adapter $hostno ($hostname) found."
  38. done
  39. if [ -z "$hosts" ] ; then
  40. echo "No SCSI host adapters found in sysfs"
  41. exit 1;
  42. fi
  43. }
  44.  
  45. # Return hosts. /proc/scsi/HOSTADAPTER/? must exist
  46. findhosts ()
  47. {
  48. hosts=
  49. for driverdir in /proc/scsi/*; do
  50. driver=${driverdir#/proc/scsi/}
  51. if test $driver = scsi -o $driver = sg -o $driver = dummy -o $driver = device_info; then continue; fi
  52. for hostdir in $driverdir/*; do
  53. name=${hostdir#/proc/scsi/*/}
  54. if test $name = add_map -o $name = map -o $name = mod_parm; then continue; fi
  55. num=$name
  56. driverinfo=$driver
  57. if test -r $hostdir/status; then
  58. num=$(printf '%d\n' `sed -n 's/SCSI host number://p' $hostdir/status`)
  59. driverinfo="$driver:$name"
  60. fi
  61. hosts="$hosts $num"
  62. echo "Host adapter $num ($driverinfo) found."
  63. done
  64. done
  65. }
  66.  
  67. printtype ()
  68. {
  69. local type=$1
  70.  
  71. case "$type" in
  72. 0) echo "Direct-Access " ;;
  73. 1) echo "Sequential-Access" ;;
  74. 2) echo "Printer " ;;
  75. 3) echo "Processor " ;;
  76. 4) echo "WORM " ;;
  77. 5) echo "CD-ROM " ;;
  78. 6) echo "Scanner " ;;
  79. 7) echo "Optical Device " ;;
  80. 8) echo "Medium Changer " ;;
  81. 9) echo "Communications " ;;
  82. 10) echo "Unknown " ;;
  83. 11) echo "Unknown " ;;
  84. 12) echo "RAID " ;;
  85. 13) echo "Enclosure " ;;
  86. 14) echo "Direct-Access-RBC" ;;
  87. *) echo "Unknown " ;;
  88. esac
  89. }
  90. # Get /proc/scsi/scsi info for device $host:$channel:$id:$lun
  91. # Optional parameter: Number of lines after first (default = 2),
  92. # result in SCSISTR, return code 1 means empty.
  93. procscsiscsi ()
  94. {
  95. if test -z "$1"; then LN=2; else LN=$1; fi
  96. CHANNEL=`printf "%02i" $channel`
  97. ID=`printf "%02i" $id`
  98. LUN=`printf "%02i" $lun`
  99. if [ -d /sys/class/scsi_device ]; then
  100. SCSIPATH="/sys/class/scsi_device/${host}:${channel}:${id}:${lun}"
  101. if [ -d "$SCSIPATH" ] ; then
  102. SCSISTR="Host: scsi${host} Channel: $CHANNEL Id: $ID Lun: $LUN"
  103. if [ "$LN" -gt 0 ] ; then
  104. IVEND=$(cat ${SCSIPATH}/device/vendor)
  105. IPROD=$(cat ${SCSIPATH}/device/model)
  106. IPREV=$(cat ${SCSIPATH}/device/rev)
  107. SCSIDEV=$(printf ' Vendor: %-08s Model: %-16s Rev: %-4s' "$IVEND" "$IPROD" "$IPREV")
  108. SCSISTR="$SCSISTR
  109. $SCSIDEV"
  110. fi
  111. if [ "$LN" -gt 1 ] ; then
  112. ILVL=$(cat ${SCSIPATH}/device/scsi_level)
  113. type=$(cat ${SCSIPATH}/device/type)
  114. ITYPE=$(printtype $type)
  115. SCSITMP=$(printf ' Type: %-16s ANSI SCSI revision: %02d' "$ITYPE" "$((ILVL - 1))")
  116. SCSISTR="$SCSISTR
  117. $SCSITMP"
  118. fi
  119.  
  120. else
  121. return 1
  122. fi
  123. else
  124. grepstr="scsi$host Channel: $CHANNEL Id: $ID Lun: $LUN"
  125. SCSISTR=`cat /proc/scsi/scsi | grep -A$LN -e"$grepstr"`
  126. fi
  127. if test -z "$SCSISTR"; then return 1; else return 0; fi
  128. }
  129.  
  130. # Find sg device with 2.6 sysfs support
  131. sgdevice26 ()
  132. {
  133. if test -e /sys/class/scsi_device/$host\:$channel\:$id\:$lun/device/generic; then
  134. SGDEV=`readlink /sys/class/scsi_device/$host\:$channel\:$id\:$lun/device/generic`
  135. SGDEV=`basename $SGDEV`
  136. else
  137. for SGDEV in /sys/class/scsi_generic/sg*; do
  138. DEV=`readlink $SGDEV/device`
  139. if test "${DEV##*/}" = "$host:$channel:$id:$lun"; then
  140. SGDEV=`basename $SGDEV`; return
  141. fi
  142. done
  143. SGDEV=""
  144. fi
  145. }
  146.  
  147. # Find sg device with 2.4 report-devs extensions
  148. sgdevice24 ()
  149. {
  150. if procscsiscsi 3; then
  151. SGDEV=`echo "$SCSISTR" | grep 'Attached drivers:' | sed 's/^ *Attached drivers: \(sg[0-9]*\).*/\1/'`
  152. fi
  153. }
  154.  
  155. # Find sg device that belongs to SCSI device $host $channel $id $lun
  156. sgdevice ()
  157. {
  158. SGDEV=
  159. if test -d /sys/class/scsi_device; then
  160. sgdevice26
  161. else
  162. DRV=`grep 'Attached drivers:' /proc/scsi/scsi 2>/dev/null`
  163. repdevstat=$((1-$?))
  164. if [ $repdevstat = 0 ]; then
  165. echo "scsi report-devs 1" >/proc/scsi/scsi
  166. DRV=`grep 'Attached drivers:' /proc/scsi/scsi 2>/dev/null`
  167. if [ $? = 1 ]; then return; fi
  168. fi
  169. if ! `echo $DRV | grep 'drivers: sg' >/dev/null`; then
  170. modprobe sg
  171. fi
  172. sgdevice24
  173. if [ $repdevstat = 0 ]; then
  174. echo "scsi report-devs 0" >/proc/scsi/scsi
  175. fi
  176. fi
  177. }
  178.  
  179. # Test if SCSI device is still responding to commands
  180. testonline ()
  181. {
  182. : testonline
  183. if test ! -x /usr/bin/sg_turs; then return 0; fi
  184. sgdevice
  185. if test -z "$SGDEV"; then return 0; fi
  186. sg_turs /dev/$SGDEV >/dev/null 2>&1
  187. RC=$?
  188. # echo -e "\e[A\e[A\e[A${yellow}Test existence of $SGDEV = $RC ${norm} \n\n\n"
  189. if test $RC = 1; then return $RC; fi
  190. # OK, device online, compare INQUIRY string
  191. INQ=`sg_inq $sg_len_arg /dev/$SGDEV`
  192. IVEND=`echo "$INQ" | grep 'Vendor identification:' | sed 's/^[^:]*: \(.*\)$/\1/'`
  193. IPROD=`echo "$INQ" | grep 'Product identification:' | sed 's/^[^:]*: \(.*\)$/\1/'`
  194. IPREV=`echo "$INQ" | grep 'Product revision level:' | sed 's/^[^:]*: \(.*\)$/\1/'`
  195. STR=`printf " Vendor: %-08s Model: %-16s Rev: %-4s" "$IVEND" "$IPROD" "$IPREV"`
  196. IPTYPE=`echo "$INQ" | sed -n 's/.* Device_type=\([0-9]*\) .*/\1/p'`
  197. IPQUAL=`echo "$INQ" | sed -n 's/ *PQual=\([0-9]*\) Device.*/\1/p'`
  198. if [ "$IPQUAL" != 0 ] ; then
  199. echo -e "\e[A\e[A\e[A\e[A${red}$SGDEV changed: ${bold}\nLU not available (PQual $IPQUAL)${norm}\n\n\n"
  200. return 2
  201. fi
  202.  
  203. TYPE=$(printtype $IPTYPE)
  204. procscsiscsi
  205. TMPSTR=`echo "$SCSISTR" | grep 'Vendor:'`
  206. if [ "$TMPSTR" != "$STR" ]; then
  207. echo -e "\e[A\e[A\e[A\e[A${red}$SGDEV changed: ${bold}\nfrom:${SCSISTR#* } \nto: $STR ${norm}\n\n\n"
  208. return 1
  209. fi
  210. TMPSTR=`echo "$SCSISTR" | sed -n 's/.*Type: *\(.*\) *ANSI.*/\1/p'`
  211. if [ $TMPSTR != $TYPE ] ; then
  212. echo -e "\e[A\e[A\e[A\e[A${red}$SGDEV changed: ${bold}\nfrom:${TMPSTR} \nto: $TYPE ${norm}\n\n\n"
  213. return 1
  214. fi
  215. return $RC
  216. }
  217.  
  218. # Test if SCSI device $host $channen $id $lun exists
  219. # Outputs description from /proc/scsi/scsi, returns SCSISTR
  220. testexist ()
  221. {
  222. : testexist
  223. SCSISTR=
  224. if procscsiscsi; then
  225. echo "$SCSISTR" | head -n1
  226. echo "$SCSISTR" | tail -n2 | pr -o4 -l1
  227. fi
  228. }
  229.  
  230. # Returns the list of existing channels per host
  231. chanlist ()
  232. {
  233. local hcil
  234. local cil
  235. local chan
  236. local tmpchan
  237.  
  238. for dev in /sys/class/scsi_device/${host}:* ; do
  239. [ -d $dev ] || continue;
  240. hcil=${dev##*/}
  241. cil=${hcil#*:}
  242. chan=${cil%%:*}
  243. for tmpchan in $channelsearch ; do
  244. if test "$chan" -eq $tmpchan ; then
  245. chan=
  246. fi
  247. done
  248. if test -n "$chan" ; then
  249. channelsearch="$channelsearch $chan"
  250. fi
  251. done
  252. }
  253.  
  254. # Returns the list of existing targets per host
  255. idlist ()
  256. {
  257. local hcil
  258. local cil
  259. local il
  260. local target
  261. local tmpid
  262.  
  263. for dev in /sys/class/scsi_device/${host}:${channel}:* ; do
  264. [ -d $dev ] || continue;
  265. hcil=${dev##*/}
  266. cil=${hcil#*:}
  267. il=${cil#*:}
  268. target=${il%%:*}
  269. for tmpid in $idsearch ; do
  270. if test "$target" -eq $tmpid ; then
  271. target=
  272. break
  273. fi
  274. done
  275. if test -n "$target" ; then
  276. idsearch="$idsearch $target"
  277. fi
  278. done
  279. }
  280.  
  281. # Returns the list of existing LUNs
  282. getluns ()
  283. {
  284. if test ! -x /usr/bin/sg_luns; then return ""; fi
  285. sgdevice
  286. if test -z "$SGDEV"; then return ""; fi
  287. sg_luns -d /dev/$SGDEV | sed -n 's/.*lun=\(.*\)/\1/p'
  288. }
  289.  
  290. # Perform scan on a single lun
  291. dolunscan()
  292. {
  293. SCSISTR=
  294. devnr="$host $channel $id $lun"
  295. echo "Scanning for device $devnr ..."
  296. printf "${yellow}OLD: $norm"
  297. testexist
  298. : f $remove s $SCSISTR
  299. if test "$remove" -a "$SCSISTR"; then
  300. # Device exists: Test whether it's still online
  301. # (testonline returns 1 if it's gone or has changed)
  302. testonline
  303. RC=$?
  304. if test $RC != 0 -o ! -z "$forceremove"; then
  305. echo -en "\r\e[A\e[A\e[A${red}REM: "
  306. echo "$SCSISTR" | head -n1
  307. echo -e "${norm}\e[B\e[B"
  308. if test -e /sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device; then
  309. echo 1 > /sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device/delete
  310. if test $RC -eq 1 -o $lun -eq 0 ; then
  311. # Try readding, should fail if device is gone
  312. echo "$channel $id $lun" > /sys/class/scsi_host/host${host}/scan
  313. fi
  314. else
  315. echo "scsi remove-single-device $devnr" > /proc/scsi/scsi
  316. if test $RC -eq 1 -o $lun -eq 0 ; then
  317. # Try readding, should fail if device is gone
  318. echo "scsi add-single-device $devnr" > /proc/scsi/scsi
  319. fi
  320. fi
  321. fi
  322. if test $RC = 0 -o "$forcerescan" ; then
  323. if test -e /sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device; then
  324. echo 1 > /sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device/rescan
  325. fi
  326. fi
  327. printf "\r\x1b[A\x1b[A\x1b[A${yellow}OLD: $norm"
  328. testexist
  329. if test -z "$SCSISTR"; then
  330. printf "\r${red}DEL: $norm\r\n\n"
  331. let rmvd+=1;
  332. return 1
  333. fi
  334. fi
  335. if test -z "$SCSISTR"; then
  336. # Device does not exist, try to add
  337. printf "\r${green}NEW: $norm"
  338. if test -e /sys/class/scsi_host/host${host}/scan; then
  339. echo "$channel $id $lun" > /sys/class/scsi_host/host${host}/scan 2> /dev/null
  340. else
  341. echo "scsi add-single-device $devnr" > /proc/scsi/scsi
  342. fi
  343. testexist
  344. if test -z "$SCSISTR"; then
  345. # Device not present
  346. printf "\r\x1b[A";
  347. # Optimization: if lun==0, stop here (only if in non-remove mode)
  348. if test $lun = 0 -a -z "$remove" -a $optscan = 1; then
  349. break;
  350. fi
  351. else
  352. let found+=1;
  353. fi
  354. fi
  355. }
  356.  
  357. # Perform report lun scan
  358. doreportlun()
  359. {
  360. lun=
  361. SCSISTR=
  362. for dev in /sys/class/scsi_device/${host}:${channel}:${id}:*; do
  363. if [ -d "$dev" ]; then
  364. lun=${dev##*:}
  365. break
  366. else
  367. continue
  368. fi
  369. done
  370. #If not a single LUN is present then assign lun=0
  371. if [ -z $lun ]; then
  372. lun=0
  373. devnr="$host $channel $id $lun"
  374. echo "Scanning for device $devnr ..."
  375. printf "${yellow}OLD: $norm"
  376. testexist
  377. if test -z "$SCSISTR"; then
  378. # Device does not exist, try to add
  379. printf "\r${green}NEW: $norm"
  380. if test -e /sys/class/scsi_host/host${host}/scan; then
  381. echo "$channel $id $lun" > /sys/class/scsi_host/host${host}/scan 2> /dev/null
  382. else
  383. echo "scsi add-single-device $devnr" > /proc/scsi/scsi
  384. fi
  385. testexist
  386. if test -z "$SCSISTR"; then
  387. # Device not present
  388. printf "\r\x1b[A";
  389. lunsearch=
  390. return
  391. fi
  392. fi
  393. fi
  394. flag=0
  395. lun_search=" `getluns`"
  396. # Set flag=1 if all the LUNs are removed
  397. if [ "${#lun_search}" = "1" ]; then
  398. flag=1
  399. fi
  400. lunremove=
  401. # Check existing luns
  402. for dev in /sys/class/scsi_device/${host}:${channel}:${id}:*; do
  403. [ -d "$dev" ] || continue
  404. lun=${dev##*:}
  405. if [ "$flag" = "1" ]; then
  406. lunremove="$lunremove $lun"
  407. fi
  408. newsearch=
  409. oldsearch="$lun_search"
  410. for tmplun in $lun_search; do
  411. if test $tmplun -eq $lun ; then
  412. dolunscan
  413. else
  414. newsearch="$newsearch $tmplun"
  415. fi
  416. done
  417. if [ "${#oldsearch}" = "${#newsearch}" ] ; then
  418. # Stale lun
  419. lunremove="$lunremove $lun"
  420. fi
  421. lun_search="$newsearch"
  422. done
  423. # Add new ones and check stale ones
  424. for lun in $lun_search $lunremove; do
  425. dolunscan
  426. done
  427. }
  428.  
  429. # Perform search (scan $host)
  430. dosearch ()
  431. {
  432. if test -z "$channelsearch" ; then
  433. chanlist
  434. fi
  435. for channel in $channelsearch; do
  436. if test -z "$idsearch" ; then
  437. idlist
  438. fi
  439. for id in $idsearch; do
  440. if test -z "$lunsearch" ; then
  441. doreportlun
  442. else
  443. for lun in $lunsearch; do
  444. dolunscan
  445. done
  446. fi
  447. done
  448. done
  449. }
  450.  
  451. # main
  452. if test @$1 = @--help -o @$1 = @-h -o @$1 = @-?; then
  453. echo "Usage: rescan-scsi-bus.sh [options] [host [host ...]]"
  454. echo "Options:"
  455. echo " -l activates scanning for LUNs 0-7 [default: 0]"
  456. echo " -L NUM activates scanning for LUNs 0--NUM [default: 0]"
  457. echo " -w scan for target device IDs 0 .. 15 [default: 0-7]"
  458. echo " -c enables scanning of channels 0 1 [default: 0]"
  459. echo " -r enables removing of devices [default: disabled]"
  460. echo " -i issue a FibreChannel LIP reset [default: disabled]"
  461. echo "--remove: same as -r"
  462. echo "--issue-lip: same as -i"
  463. echo "--forcerescan: Rescan existing devices"
  464. echo "--forceremove: Remove and readd every device (DANGEROUS)"
  465. echo "--nooptscan: don't stop looking for LUNs is 0 is not found"
  466. echo "--color: use coloured prefixes OLD/NEW/DEL"
  467. echo "--hosts=LIST: Scan only host(s) in LIST"
  468. echo "--channels=LIST: Scan only channel(s) in LIST"
  469. echo "--ids=LIST: Scan only target ID(s) in LIST"
  470. echo "--luns=LIST: Scan only lun(s) in LIST"
  471. echo " Host numbers may thus be specified either directly on cmd line (deprecated) or"
  472. echo " or with the --hosts=LIST parameter (recommended)."
  473. echo "LIST: A[-B][,C[-D]]... is a comma separated list of single values and ranges"
  474. echo " (No spaces allowed.)"
  475. exit 0
  476. fi
  477.  
  478. expandlist ()
  479. {
  480. list=$1
  481. result=""
  482. first=${list%%,*}
  483. rest=${list#*,}
  484. while test ! -z "$first"; do
  485. beg=${first%%-*};
  486. if test "$beg" = "$first"; then
  487. result="$result $beg";
  488. else
  489. end=${first#*-}
  490. result="$result `seq $beg $end`"
  491. fi
  492. test "$rest" = "$first" && rest=""
  493. first=${rest%%,*}
  494. rest=${rest#*,}
  495. done
  496. echo $result
  497. }
  498.  
  499. if test ! -d /sys/class/scsi_host/ -a ! -d /proc/scsi/; then
  500. echo "Error: SCSI subsystem not active"
  501. exit 1
  502. fi
  503.  
  504. # Make sure sg is there
  505. modprobe sg >/dev/null 2>&1
  506.  
  507. sg_version=$(sg_inq -V 2>&1 | cut -d " " -f 3)
  508. sg_version=${sg_version##0.}
  509. if [ "$sg_version" -lt 70 ] ; then
  510. sg_len_arg="-36"
  511. else
  512. sg_len_arg="--len=36"
  513. fi
  514.  
  515. # defaults
  516. unsetcolor
  517. lunsearch=""
  518. idsearch=`seq 0 7`
  519. channelsearch=""
  520. remove=
  521. forceremove=
  522. optscan=1
  523. if test -d /sys/class/scsi_host; then
  524. findhosts_26
  525. else
  526. findhosts
  527. fi
  528.  
  529. # Scan options
  530. opt="$1"
  531. while test ! -z "$opt" -a -z "${opt##-*}"; do
  532. opt=${opt#-}
  533. case "$opt" in
  534. l) lunsearch=`seq 0 7` ;;
  535. L) lunsearch=`seq 0 $2`; shift ;;
  536. w) idsearch=`seq 0 15` ;;
  537. c) channelsearch="0 1" ;;
  538. r) remove=1 ;;
  539. i) lipreset=1 ;;
  540. -remove) remove=1 ;;
  541. -forcerescan) remove=1; forcerescan=1 ;;
  542. -forceremove) remove=1; forceremove=1 ;;
  543. -hosts=*) arg=${opt#-hosts=}; hosts=`expandlist $arg` ;;
  544. -channels=*) arg=${opt#-channels=};channelsearch=`expandlist $arg` ;;
  545. -ids=*) arg=${opt#-ids=}; idsearch=`expandlist $arg` ;;
  546. -luns=*) arg=${opt#-luns=}; lunsearch=`expandlist $arg` ;;
  547. -color) setcolor ;;
  548. -nooptscan) optscan=0 ;;
  549. -issue-lip) lipreset=1 ;;
  550. *) echo "Unknown option -$opt !" ;;
  551. esac
  552. shift
  553. opt="$1"
  554. done
  555.  
  556. # Hosts given ?
  557. if test "@$1" != "@"; then
  558. hosts=$*;
  559. fi
  560.  
  561. echo "Scanning SCSI subsystem for new devices"
  562. test -z "$remove" || echo " and remove devices that have disappeared"
  563. declare -i found=0
  564. declare -i rmvd=0
  565. for host in $hosts; do
  566. echo -n "Scanning host $host "
  567. if test -e /sys/class/fc_host/host$host ; then
  568. if test -n "$lipreset" ; then
  569. echo 1 > /sys/class/fc_host/host$host/issue_lip 2> /dev/null;
  570. fi
  571. echo "- - -" > /sys/class/scsi_host/host$host/scan 2> /dev/null;
  572. channelsearch=""
  573. idsearch=""
  574. fi
  575. [ -n "$channelsearch" ] && echo -n "channels $channelsearch "
  576. echo -n "for "
  577. if [ -n "$idsearch" ] ; then
  578. echo -n " SCSI target IDs " $idsearch
  579. else
  580. echo -n " all SCSI target IDs"
  581. fi
  582. if [ -n "$lunsearch" ] ; then
  583. echo ", LUNs " $lunsearch
  584. else
  585. echo ", all LUNs"
  586. fi
  587. dosearch;
  588. done
  589. echo "$found new device(s) found. "
  590. echo "$rmvd device(s) removed. "
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement