1#!/bin/bash 2# Script to rescan SCSI bus, using the scsi add-single-device mechanism. 3# (c) 1998--2010 Kurt Garloff <kurt@garloff.de>, GNU GPL v2 or v3 4# (c) 2006--2022 Hannes Reinecke, GNU GPL v2 or later 5# $Id: rescan-scsi-bus.sh,v 1.57 2012/03/31 14:08:48 garloff Exp $ 6 7VERSION="20220930" 8SCAN_WILD_CARD=4294967295 9 10TMPLUNINFOFILE="/tmp/rescan-scsi-mpath-info.txt" 11 12setcolor () 13{ 14 red="\e[0;31m" 15 green="\e[0;32m" 16 yellow="\e[0;33m" 17 bold="\e[0;1m" 18 norm="\e[0;0m" 19} 20 21unsetcolor () 22{ 23 red=""; green="" 24 yellow=""; norm="" 25} 26 27echo_debug() 28{ 29 if [ "$debug" -eq 1 ] ; then 30 echo "$1" 31 fi 32} 33 34# Output some text and return cursor to previous position 35# (only works for simple strings) 36# Stores length of string in LN and returns it 37print_and_scroll_back () 38{ 39 STRG="$1" 40 LN=${#STRG} 41 BK="" 42 declare -i cntr=0 43 while [ $cntr -lt "$LN" ] ; do BK="$BK\e[D"; let cntr+=1; done 44 echo -en "$STRG$BK" 45 return "$LN" 46} 47 48# Overwrite a text of length $LN with whitespace 49white_out () 50{ 51 BK=""; WH="" 52 declare -i cntr=0 53 while [ $cntr -lt "$LN" ] ; do BK="$BK\e[D"; WH="$WH "; let cntr+=1; done 54 echo -en "$WH$BK" 55} 56 57# Return hosts. sysfs must be mounted 58findhosts_26 () 59{ 60 hosts= 61 for hostdir in /sys/class/scsi_host/host* ; do 62 [ -e "$hostdir" ] || continue 63 hostno=${hostdir#/sys/class/scsi_host/host} 64 if [ -f "$hostdir/isp_name" ] ; then 65 hostname="qla2xxx" 66 elif [ -f "$hostdir/lpfc_drvr_version" ] ; then 67 hostname="lpfc" 68 else 69 hostname=$(cat "$hostdir/proc_name") 70 fi 71 hosts="$hosts $hostno" 72 echo_debug "Host adapter $hostno ($hostname) found." 73 done 74 if [ -z "$hosts" ] ; then 75 echo "No SCSI host adapters found in sysfs" 76 exit 1; 77 fi 78 # ensure numeric ordering. No quotes arount $hosts to skip leading space. 79 hosts=$(echo $hosts | tr ' ' '\n' | sort -n) 80} 81 82# Return hosts. /proc/scsi/HOSTADAPTER/? must exist 83findhosts () 84{ 85 hosts= 86 for driverdir in /proc/scsi/*; do 87 driver=${driverdir#/proc/scsi/} 88 if [ "$driver" = scsi ] || [ "$driver" = sg ] || [ "$driver" = dummy ] || [ "$driver" = device_info ] ; then continue; fi 89 for hostdir in $driverdir/*; do 90 name=${hostdir#/proc/scsi/*/} 91 if [ "$name" = add_map ] || [ "$name" = map ] || [ "$name" = mod_parm ] ; then continue; fi 92 num=$name 93 driverinfo=$driver 94 if [ -r "$hostdir/status" ] ; then 95 num=$(printf '%d\n' "$(sed -n 's/SCSI host number://p' "$hostdir/status")") 96 driverinfo="$driver:$name" 97 fi 98 hosts="$hosts $num" 99 echo "Host adapter $num ($driverinfo) found." 100 done 101 done 102} 103 104printtype () 105{ 106 local type=$1 107 108 case "$type" in 109 0) echo "Direct-Access" ;; 110 1) echo "Sequential-Access" ;; 111 2) echo "Printer" ;; 112 3) echo "Processor" ;; 113 4) echo "WORM" ;; 114 5) echo "CD-ROM" ;; 115 6) echo "Scanner" ;; 116 7) echo "Optical-Device" ;; 117 8) echo "Medium-Changer" ;; 118 9) echo "Communications" ;; 119 10) echo "Unknown" ;; 120 11) echo "Unknown" ;; 121 12) echo "RAID" ;; 122 13) echo "Enclosure" ;; 123 14) echo "Direct-Access-RBC" ;; 124 *) echo "Unknown" ;; 125 esac 126} 127 128print02i() 129{ 130 if [ "$1" = "*" ] ; then 131 echo "00" 132 else 133 printf "%02i" "$1" 134 fi 135} 136 137# Get /proc/scsi/scsi info for device $host:$channel:$id:$lun 138# Optional parameter: Number of lines after first (default = 2), 139# result in SCSISTR, return code 1 means empty. 140procscsiscsi () 141{ 142 if [ -z "$1" ] ; then 143 LN=2 144 else 145 LN=$1 146 fi 147 CHANNEL=$(print02i "$channel") 148 ID=$(print02i "$id") 149 LUN=$(print02i "$lun") 150 if [ -d /sys/class/scsi_device ]; then 151 SCSIPATH="/sys/class/scsi_device/${host}:${channel}:${id}:${lun}" 152 if [ -d "$SCSIPATH" ] ; then 153 SCSISTR="Host: scsi${host} Channel: $CHANNEL Id: $ID Lun: $LUN" 154 if [ "$LN" -gt 0 ] ; then 155 IVEND=$(cat "${SCSIPATH}/device/vendor") 156 IPROD=$(cat "${SCSIPATH}/device/model") 157 IPREV=$(cat "${SCSIPATH}/device/rev") 158 SCSIDEV=$(printf ' Vendor: %-08s Model: %-16s Rev: %-4s' "$IVEND" "$IPROD" "$IPREV") 159 SCSISTR="$SCSISTR 160$SCSIDEV" 161 fi 162 if [ "$LN" -gt 1 ] ; then 163 ILVL=$(cat "${SCSIPATH}/device/scsi_level") 164 type=$(cat "${SCSIPATH}/device/type") 165 ITYPE=$(printtype "$type") 166 SCSITMP=$(printf ' Type: %-17s ANSI SCSI revision: %02d' "$ITYPE" "$((ILVL - 1))") 167 SCSISTR="$SCSISTR 168$SCSITMP" 169 fi 170 else 171 return 1 172 fi 173 else 174 grepstr="scsi$host Channel: $CHANNEL Id: $ID Lun: $LUN" 175 SCSISTR=$(grep -A "$LN" -e "$grepstr" /proc/scsi/scsi) 176 fi 177 if [ -z "$SCSISTR" ] ; then 178 return 1 179 else 180 return 0 181 fi 182} 183 184# Find sg device with 2.6 sysfs support 185sgdevice26 () 186{ 187 local gendev 188 189 # if the scsi device has not been added, then there would not 190 # a related sgdev. So it's pointless to scan all sgs to find 191 # a related sg. 192 scsidev=/sys/class/scsi_device/${host}:${channel}:${id}:${lun} 193 if [ ! -e "$scsidev" ]; then 194 SGDEV="" 195 return 196 fi 197 198 gendev=/sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device/generic 199 if [ -e "$gendev" ] ; then 200 SGDEV=$(basename "$(readlink "$gendev")") 201 return 202 fi 203 SGDEV="" 204} 205 206# Find sg device with 2.4 report-devs extensions 207sgdevice24 () 208{ 209 if procscsiscsi 3; then 210 SGDEV=$(echo "$SCSISTR" | grep 'Attached drivers:' | sed 's/^ *Attached drivers: \(sg[0-9]*\).*/\1/') 211 fi 212} 213 214# Find sg device that belongs to SCSI device $host $channel $id $lun 215# and return in SGDEV 216sgdevice () 217{ 218 SGDEV= 219 if [ -d /sys/class/scsi_device ] ; then 220 sgdevice26 221 else 222 DRV=$(grep 'Attached drivers:' /proc/scsi/scsi 2>/dev/null) 223 repdevstat=$((1-$?)) 224 if [ $repdevstat = 0 ]; then 225 echo "scsi report-devs 1" >/proc/scsi/scsi 226 DRV=$(grep 'Attached drivers:' /proc/scsi/scsi 2>/dev/null) 227 [ $? -eq 1 ] && return 228 fi 229 if ! echo "$DRV" | grep -q 'drivers: sg'; then 230 modprobe sg 231 fi 232 sgdevice24 233 if [ $repdevstat = 0 ]; then 234 echo "scsi report-devs 0" >/proc/scsi/scsi 235 fi 236 fi 237} 238 239# Whether or not the RMB (removable) bit has been set in the INQUIRY response. 240# Uses ${host}, ${channel}, ${id} and ${lun}. Assumes that sg_device() has 241# already been called. How to test this function: copy/paste this function 242# in a shell and run 243# (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) 244is_removable () 245{ 246 local b p 247 248 p=/sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device/inquiry 249 # Extract the second byte of the INQUIRY response and check bit 7 (mask 0x80). 250 b=$(hexdump -n1 -e '/1 "%02X"' "$p" 2>/dev/null) 251 if [ -n "$b" ]; then 252 echo $(((0x$b & 0x80) != 0)) 253 else 254 sg_inq /dev/$SGDEV 2>/dev/null | sed -n 's/^.*RMB=\([0-9]*\).*$/\1/p' 255 fi 256} 257 258# Test if SCSI device is still responding to commands 259# Return values: 260# 0 device is present 261# 1 device has changed 262# 2 device has been removed 263testonline () 264{ 265 local ctr RC RMB 266 267 : testonline 268 ctr=0 269 RC=0 270 # Set default values 271 IPTYPE=31 272 IPQUAL=3 273 [ ! -x /usr/bin/sg_turs ] && return 0 274 sgdevice 275 [ -z "$SGDEV" ] && return 0 276 sg_turs /dev/$SGDEV >/dev/null 2>&1 277 RC=$? 278 279 # Handle in progress of becoming ready and unit attention 280 while [ $RC = 2 -o $RC = 6 ] && [ $ctr -lt $timeout ] ; do 281 if [ $RC = 2 ] && [ "$RMB" != "1" ] && sg_inq /dev/$SGDEV | grep -q -i "PQual=0" ; then 282 echo -n "." 283 let LN+=1 284 sleep 1 285 else 286 sleep 0.02 287 fi 288 let ctr+=1 289 sg_turs /dev/$SGDEV >/dev/null 2>&1 290 RC=$? 291 # Check for removable device; TEST UNIT READY obviously will 292 # fail for a removable device with no medium 293 RMB=$(is_removable) 294 print_and_scroll_back "$host:$channel:$id:$lun $SGDEV ($RMB) " 295 [ $RC = 2 ] && [ "$RMB" = "1" ] && break 296 done 297 if [ $ctr != 0 ] ; then 298 white_out 299 fi 300 # echo -e "\e[A\e[A\e[A${yellow}Test existence of $SGDEV = $RC ${norm} \n\n\n" 301 [ $RC = 1 ] && return $RC 302 # Reset RC (might be !=0 for passive paths) 303 RC=0 304 # OK, device online, compare INQUIRY string 305 INQ=$(sg_inq "$sg_len_arg" /dev/$SGDEV 2>/dev/null) 306 if [ -z "$INQ" ] ; then 307 echo -e "\e[A\e[A\e[A\e[A${red}$SGDEV changed: ${bold}INQUIRY failed${norm} \n\n\n" 308 return 2 309 fi 310 IVEND=$(echo "$INQ" | grep 'Vendor identification:' | sed 's/^[^:]*: \(.*\)$/\1/') 311 IPROD=$(echo "$INQ" | grep 'Product identification:' | sed 's/^[^:]*: \(.*\)$/\1/') 312 IPREV=$(echo "$INQ" | grep 'Product revision level:' | sed 's/^[^:]*: \(.*\)$/\1/') 313 STR=$(printf " Vendor: %-08s Model: %-16s Rev: %-4s" "$IVEND" "$IPROD" "$IPREV") 314 IPTYPE=$(echo "$INQ" | sed -n 's/.* Device_type=\([0-9]*\) .*/\1/p') 315 if [ -z "$IPTYPE" ]; then 316 IPTYPE=$(echo "$INQ" | sed -n 's/.* PDT=\([0-9]*\) .*/\1/p') 317 fi 318 IPQUAL=$(echo "$INQ" | sed -n 's/ *PQual=\([0-9]*\) Device.*/\1/p') 319 if [ -z "$IPQUAL" ] ; then 320 IPQUAL=$(echo "$INQ" | sed -n 's/ *PQual=\([0-9]*\) PDT.*/\1/p') 321 fi 322 if [ "$IPQUAL" != 0 ] ; then 323 [ -z "$IPQUAL" ] && IPQUAL=3 324 [ -z "$IPTYPE" ] && IPTYPE=31 325 echo -e "\e[A\e[A\e[A\e[A${red}$SGDEV changed: ${bold}LU not available (PQual $IPQUAL)${norm} \n\n\n" 326 return 2 327 fi 328 329 TYPE=$(printtype $IPTYPE) 330 if ! procscsiscsi ; then 331 echo -e "\e[A\e[A\e[A\e[A${red}$SGDEV removed. ${norm}\n\n\n" 332 return 2 333 fi 334 TMPSTR=$(echo "$SCSISTR" | grep 'Vendor:') 335 if [ "$ignore_rev" -eq 0 ] ; then 336 if [ "$TMPSTR" != "$STR" ]; then 337 echo -e "\e[A\e[A\e[A\e[A${red}$SGDEV changed: ${bold}\nfrom:${SCSISTR#* } \nto: $STR ${norm} \n\n\n" 338 return 1 339 fi 340 else 341 # Ignore disk revision change 342 local old_str_no_rev= 343 local new_str_no_rev= 344 345 old_str_no_rev=${TMPSTR%Rev:*} 346 new_str_no_rev=${STR%Rev:*} 347 if [ "$old_str_no_rev" != "$new_str_no_rev" ]; then 348 echo -e "\e[A\e[A\e[A\e[A${red}$SGDEV changed: ${bold}\nfrom:${SCSISTR#* } \nto: $STR ${norm} \n\n\n" 349 return 1 350 fi 351 fi 352 TMPSTR=$(echo "$SCSISTR" | sed -n 's/.*Type: *\(.*\) *ANSI.*/\1/p' | sed 's/ *$//g') 353 if [ "$TMPSTR" != "$TYPE" ] ; then 354 echo -e "\e[A\e[A\e[A\e[A${red}$SGDEV changed: ${bold}\nfrom:${TMPSTR} \nto: $TYPE ${norm} \n\n\n" 355 return 1 356 fi 357 return $RC 358} 359 360# Test if SCSI device $host $channel $id $lun exists 361# Outputs description from /proc/scsi/scsi (unless arg passed) 362# Returns SCSISTR (empty if no dev) 363testexist () 364{ 365 : testexist 366 SCSISTR= 367 if procscsiscsi && [ -z "$1" ] ; then 368 echo "$SCSISTR" | head -n1 369 echo "$SCSISTR" | tail -n2 | pr -o4 -l1 370 fi 371} 372 373# Returns the list of existing channels per host 374chanlist () 375{ 376 local hcil 377 local cil 378 local chan 379 local tmpchan 380 381 for dev in /sys/class/scsi_device/${host}:* ; do 382 [ -d "$dev" ] || continue; 383 hcil=${dev##*/} 384 cil=${hcil#*:} 385 chan=${cil%%:*} 386 for tmpchan in $channelsearch ; do 387 if [ "$chan" -eq "$tmpchan" ] ; then 388 chan= 389 fi 390 done 391 if [ -n "$chan" ] ; then 392 channelsearch="$channelsearch $chan" 393 fi 394 done 395 if [ -z "$channelsearch" ] ; then 396 channelsearch="0" 397 fi 398} 399 400# Returns the list of existing targets per host 401idlist () 402{ 403 local tmpid 404 local newid 405 local oldid 406 407 oldlist=$(find /sys/class/scsi_device -name "${host}:${channel}:*" -printf "%f\n") 408 # Rescan LUN 0 to check if we found new targets 409 echo "${channel} - -" > "/sys/class/scsi_host/host${host}/scan" 410 newlist=$(find /sys/class/scsi_device -name "${host}:${channel}:*" -printf "%f\n") 411 for newid in $newlist ; do 412 oldid=$newid 413 for tmpid in $oldlist ; do 414 if [ "$newid" = "$tmpid" ] ; then 415 oldid= 416 break 417 fi 418 done 419 if [ -n "$oldid" ] ; then 420 if [ -d /sys/class/scsi_device/$oldid ] ; then 421 hcil=${oldid} 422 printf "\r${green}NEW: %s ${norm}" 423 testexist 424 if [ "$SCSISTR" ] ; then 425 incrfound "$hcil" 426 fi 427 fi 428 fi 429 done 430 idsearch=$(find /sys/bus/scsi/devices -name "target${host}:${channel}:*" -printf "%f\n" | cut -f 3 -d :) 431} 432 433# Returns the list of existing LUNs from device $host $channel $id $lun 434# and returns list to stdout 435getluns() 436{ 437 sgdevice 438 [ -z "$SGDEV" ] && return 1 439 if [ ! -x /usr/bin/sg_luns ] ; then 440 echo 0 441 return 1 442 fi 443 LLUN=$(sg_luns /dev/$SGDEV 2>/dev/null | sed -n 's/ \(.*\)/\1/p') 444 # Added -z $LLUN condition because $? gets the RC from sed, not sg_luns 445 if [ $? -ne 0 ] || [ -z "$LLUN" ] ; then 446 echo 0 447 return 1 448 fi 449 for lun in $LLUN ; do 450 # Swap LUN number 451 l0=0x$lun 452 l1=$(( (l0 >> 48) & 0xffff )) 453 l2=$(( (l0 >> 32) & 0xffff )) 454 l3=$(( (l0 >> 16) & 0xffff )) 455 l4=$(( l0 & 0xffff )) 456 l0=$(( ( ( (l4 * 0xffff) + l3 ) * 0xffff + l2 ) * 0xffff + l1 )) 457 printf "%u\n" $l0 458 done 459 return 0 460} 461 462# Wait for udev to settle (create device nodes etc.) 463udevadm_settle() 464{ 465 local tmo=60 466 if [ -x /sbin/udevadm ] ; then 467 print_and_scroll_back " Calling udevadm settle (can take a while) " 468 # Loop for up to 60 seconds if sd devices still are settling.. 469 # This allows us to continue if udev events are stuck on multipaths in recovery mode 470 while [ $tmo -gt 0 ] ; do 471 if ! /sbin/udevadm settle --timeout=1 | egrep -q sd[a-z]+ ; then 472 break; 473 fi 474 let tmo=$tmo-1 475 done 476 white_out 477 elif [ -x /sbin/udevsettle ] ; then 478 print_and_scroll_back " Calling udevsettle (can take a while) " 479 /sbin/udevsettle 480 white_out 481 else 482 sleep 0.02 483 fi 484} 485 486# Perform scan on a single lun $host $channel $id $lun 487dolunscan() 488{ 489 local remappedlun0= 490 local devpath 491 SCSISTR= 492 devnr="$host $channel $id $lun" 493 echo -e " Scanning for device $devnr ... " 494 printf "${yellow}OLD: %s ${norm}" 495 testexist 496 # Device exists: Test whether it's still online 497 # (testonline returns 2 if it's gone and 1 if it has changed) 498 devpath="/sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device" 499 if [ "$SCSISTR" ] ; then 500 testonline 501 RC=$? 502 # Well known lun transition case. Only for Direct-Access devs (type 0) 503 # If block directory exists && and PQUAL != 0, we unmapped lun0 and just have a well-known lun 504 # If block directory doesn't exist && PQUAL == 0, we mapped a real lun0 505 if [ "$lun" -eq 0 ] && [ $IPTYPE -eq 0 ] ; then 506 if [ $RC = 2 ] ; then 507 if [ -e "$devpath" ] ; then 508 if [ -d "$devpath/block" ] ; then 509 remappedlun0=2 # Transition from real lun 0 to well-known 510 else 511 RC=0 # Set this so the system leaves the existing well known lun alone. This is a lun 0 with no block directory 512 fi 513 fi 514 elif [ $RC = 0 ] && [ $IPTYPE -eq 0 ] ; then 515 if [ -e "$devpath" ] ; then 516 if [ ! -d "$devpath/block" ] ; then 517 remappedlun0=1 # Transition from well-known to real lun 0 518 fi 519 fi 520 fi 521 fi 522 fi 523 524 # Special case: lun 0 just got added (for reportlunscan), 525 # so make sure we correctly treat it as new 526 if [ "$lun" = "0" ] && [ "$1" = "1" ] && [ -z "$remappedlun0" ] ; then 527 SCSISTR="" 528 printf "\r\e[A\e[A\e[A" 529 fi 530 531 : f "$remove" s $SCSISTR 532 if [ "$remove" ] && [ "$SCSISTR" -o "$remappedlun0" = "1" ] ; then 533 if [ $RC != 0 ] || [ ! -z "$forceremove" ] || [ -n "$remappedlun0" ] ; then 534 if [ "$remappedlun0" != "1" ] ; then 535 echo -en "\r\e[A\e[A\e[A${red}REM: " 536 echo "$SCSISTR" | head -n1 537 echo -e "${norm}\e[B\e[B" 538 fi 539 if [ -e "$devpath" ] ; then 540 # have to preemptively do this so we can figure out the mpath device 541 # Don't do this if we're deleting a well known lun to replace it 542 if [ "$remappedlun0" != "1" ] ; then 543 incrrmvd "$host:$channel:$id:$lun" 544 fi 545 echo 1 > "$devpath/delete" 546 sleep 0.02 547 else 548 echo "scsi remove-single-device $devnr" > /proc/scsi/scsi 549 if [ $RC -eq 1 ] || [ "$lun" -eq 0 ] ; then 550 # Try readding, should fail if device is gone 551 echo "scsi add-single-device $devnr" > /proc/scsi/scsi 552 fi 553 fi 554 fi 555 if [ $RC = 0 ] || [ "$forcerescan" ] ; then 556 if [ -e "$devpath" ] ; then 557 echo 1 > "$devpath/rescan" 558 fi 559 fi 560 printf "\r\e[A\e[A\e[A${yellow}OLD: %s ${norm}" 561 testexist 562 if [ -z "$SCSISTR" ] && [ $RC != 1 ] && [ "$remappedlun0" != "1" ] ; then 563 printf "\r${red}DEL: %s\r\n\n ${norm}" 564 # In the event we're replacing with a well known node, we need to let it continue, to create the replacement node 565 [ "$remappedlun0" != "2" ] && return 2 566 fi 567 fi 568 if [ -z "$SCSISTR" ] || [ -n "$remappedlun0" ] ; then 569 if [ "$remappedlun0" != "2" ] ; then 570 # Device does not exist, try to add 571 printf "\r${green}NEW: %s ${norm}" 572 fi 573 if [ -e "/sys/class/scsi_host/host${host}/scan" ] ; then 574 echo "$channel $id $lun" > "/sys/class/scsi_host/host${host}/scan" 2> /dev/null 575 else 576 echo "scsi add-single-device $devnr" > /proc/scsi/scsi 577 fi 578 testexist 579 if [ -z "$SCSISTR" ] ; then 580 # Device not present 581 printf "\r\e[A"; 582 # Optimization: if lun==0, stop here (only if in non-remove mode) 583 if [ "$lun" = 0 ] && [ -z "$remove" ] && [ "$optscan" = 1 ] ; then 584 return 1; 585 fi 586 else 587 if [ "$remappedlun0" != "2" ] ; then 588 incrfound "$host:$channel:$id:$lun" 589 fi 590 fi 591 fi 592 return 0; 593} 594 595# Perform report lun scan on $host $channel $id using REPORT_LUNS 596doreportlun() 597{ 598 lun=0 599 SCSISTR= 600 devnr="$host $channel $id $lun" 601 echo -en " Scanning for device $devnr ...\r" 602 lun0added= 603 #printf "${yellow}OLD: %s ${norm}" 604 # Phase one: If LUN0 does not exist, try to add 605 testexist -q 606 if [ -z "$SCSISTR" ] ; then 607 # Device does not exist, try to add 608 #printf "\r${green}NEW: %s ${norm}" 609 if [ -e "/sys/class/scsi_host/host${host}/scan" ] ; then 610 echo "$channel $id $lun" > "/sys/class/scsi_host/host${host}/scan" 2> /dev/null 611 udevadm_settle 612 else 613 echo "scsi add-single-device $devnr" > /proc/scsi/scsi 614 fi 615 testexist -q 616 if [ -n "$SCSISTR" ] ; then 617 lun0added=1 618 #testonline 619 else 620 # Device not present 621 # return 622 # Find alternative LUN to send getluns to 623 for dev in /sys/class/scsi_device/${host}:${channel}:${id}:*; do 624 [ -d "$dev" ] || continue 625 lun=${dev##*:} 626 break 627 done 628 fi 629 fi 630 targetluns=$(getluns) 631 REPLUNSTAT=$? 632 lunremove= 633 #echo "getluns reports " $targetluns 634 olddev=$(find /sys/class/scsi_device/ -name "$host:$channel:$id:*" 2>/dev/null | sort -t: -k4 -n) 635 oldtargets="$targetluns" 636 # OK -- if we don't have a LUN to send a REPORT_LUNS to, we could 637 # fall back to wildcard scanning. Same thing if the device does not 638 # support REPORT_LUNS 639 # TODO: We might be better off to ALWAYS use wildcard scanning if 640 # it works 641 if [ "$REPLUNSTAT" = "1" ] ; then 642 if [ -e "/sys/class/scsi_host/host${host}/scan" ] ; then 643 echo "$channel $id -" > "/sys/class/scsi_host/host${host}/scan" 2> /dev/null 644 udevadm_settle 645 else 646 echo "scsi add-single-device $host $channel $id $SCAN_WILD_CARD" > /proc/scsi/scsi 647 fi 648 targetluns=$(find /sys/class/scsi_device/ -name "$host:$channel:$id:*" -printf "%f\n" | cut -d : -f 4) 649 let found+=$(echo "$targetluns" | wc -l) 650 let found-=$(echo "$olddev" | wc -l) 651 fi 652 [ -z "$targetluns" ] && targetluns="$oldtargets" 653 # Check existing luns 654 for dev in $olddev; do 655 [ -d "$dev" ] || continue 656 lun=${dev##*:} 657 newsearch= 658 inlist= 659 # OK, is existing $lun (still) in reported list 660 for tmplun in $targetluns; do 661 if [ "$tmplun" = "$lun" ] ; then 662 inlist=1 663 dolunscan $lun0added 664 [ $? -eq 1 ] && break 665 else 666 newsearch="$newsearch $tmplun" 667 fi 668 done 669 # OK, we have now done a lunscan on $lun and 670 # $newsearch is the old $targetluns without $lun 671 if [ -z "$inlist" ]; then 672 # Stale lun 673 lunremove="$lunremove $lun" 674 fi 675 # $lun removed from $lunsearch 676 targetluns=${newsearch# } 677 done 678 # Add new ones and check stale ones 679 for lun in $targetluns $lunremove; do 680 dolunscan $lun0added 681 [ $? -eq 1 ] && break 682 done 683} 684 685# Perform search (scan $host) 686dosearch () 687{ 688 if [ -z "$channelsearch" ] ; then 689 chanlist 690 fi 691 for channel in $channelsearch; do 692 if [ -z "$idsearch" ] ; then 693 if [ -z "$lunsearch" ] ; then 694 idlist 695 else 696 idsearch=$(find /sys/bus/scsi/devices -name "target${host}:${channel}:*" -printf "%f\n" | cut -f 3 -d :) 697 fi 698 fi 699 for id in $idsearch; do 700 if [ -z "$lunsearch" ] ; then 701 doreportlun 702 else 703 for lun in $lunsearch; do 704 dolunscan 705 [ $? -eq 1 ] && break 706 done 707 fi 708 done 709 done 710} 711 712expandlist () 713{ 714 list=$1 715 result="" 716 first=${list%%,*} 717 rest=${list#*,} 718 while [ ! -z "$first" ] ; do 719 beg=${first%%-*}; 720 if [ "$beg" = "$first" ] ; then 721 result="$result $beg"; 722 else 723 end=${first#*-} 724 result="$result $(seq -s ' ' $beg $end)" 725 fi 726 [ "$rest" = "$first" ] && rest="" 727 first=${rest%%,*} 728 rest=${rest#*,} 729 done 730 echo "$result" 731} 732 733searchexisting() 734{ 735 local tmpch; 736 local tmpid 737 local match=0 738 local targets= 739 740 targets=$(find /sys/bus/scsi/devices -name "target${host}:*" -printf "%f\n" | cut -d : -f 2-3) 741 # Nothing came back on this host, so we should skip it 742 [ -z "$targets" ] && return 743 744 local target=; 745 for target in $targets ; do 746 channel=${target%:*} 747 id=${target#*:} 748 if [ -n "$channelsearch" ] ; then 749 for tmpch in $channelsearch ; do 750 [ $tmpch -eq "$channel" ] && match=1 751 done 752 else 753 match=1 754 fi 755 756 [ $match -eq 0 ] && continue 757 match=0 758 759 if [ "$filter_ids" -eq 1 ] ; then 760 for tmpid in $idsearch ; do 761 if [ "$tmpid" = "$id" ] ; then 762 match=1 763 fi 764 done 765 else 766 match=1 767 fi 768 769 [ $match -eq 0 ] && continue 770 771 if [ -z "$lunsearch" ] ; then 772 doreportlun 773 else 774 for lun in $lunsearch ; do 775 dolunscan 776 [ $? -eq 1 ] && break 777 done 778 fi 779 done 780} 781 782getallmultipathinfo() 783{ 784 local mp= 785 local uuid= 786 local dmtmp= 787 local maj_min= 788 local tmpfile= 789 790 truncate -s 0 $TMPLUNINFOFILE 791 for mp in $($DMSETUP ls --target=multipath | cut -f 1) ; do 792 [ "$mp" = "No" ] && break; 793 maj_min=$($DMSETUP status "$mp" | cut -d " " -f14) 794 if [ ! -L /dev/mapper/${mp} ]; then 795 echo "softlink /dev/mapper/${mp} not available." 796 continue 797 fi 798 local ret=$(readlink /dev/mapper/$mp 2>/dev/null) 799 if [[ $? -ne 0 || -z "$ret" ]]; then 800 echo "readlink /dev/mapper/$mp failed. check multipath status." 801 continue 802 fi 803 dmtmp=$(basename $ret) 804 uuid=$(cut -f2 -d- "/sys/block/$dmtmp/dm/uuid") 805 echo "$mp $maj_min $dmtmp $uuid" >> $TMPLUNINFOFILE 806 done 807} 808 809# Go through all of the existing devices and figure out any that have been remapped 810findremapped() 811{ 812 local hctl=; 813 local devs= 814 local sddev= 815 local id_serial= 816 local id_serial_old= 817 local remapped= 818 mpaths="" 819 local tmpfile= 820 821 tmpfile=$(mktemp /tmp/rescan-scsi-bus.XXXXXXXX 2> /dev/null) 822 if [ -z "$tmpfile" ] ; then 823 tmpfile="/tmp/rescan-scsi-bus.$$" 824 rm -f $tmpfile 825 fi 826 827 # Get all of the ID_SERIAL attributes, after finding their sd node 828 devs=$(ls /sys/class/scsi_device/) 829 for hctl in $devs ; do 830 if [ -d "/sys/class/scsi_device/$hctl/device/block" ] ; then 831 sddev=$(ls "/sys/class/scsi_device/$hctl/device/block") 832 id_serial_old=$(udevadm info -q all -n "$sddev" | grep "ID_SERIAL=" | cut -d"=" -f2) 833 [ -z "$id_serial_old" ] && id_serial_old="none" 834 echo "$hctl $sddev $id_serial_old" >> $tmpfile 835 fi 836 done 837 838 # Trigger udev to update the info 839 echo -n "Triggering udev to update device information... " 840 /sbin/udevadm trigger 841 udevadm_settle 2>&1 /dev/null 842 echo "Done" 843 844 getallmultipathinfo 845 846 # See what changed and reload the respective multipath device if applicable 847 while read -r hctl sddev id_serial_old ; do 848 remapped=0 849 id_serial=$(udevadm info -q all -n "$sddev" | grep "ID_SERIAL=" | cut -d"=" -f2) 850 [ -z "$id_serial" ] && id_serial="none" 851 if [ "$id_serial_old" != "$id_serial" ] ; then 852 remapped=1 853 fi 854 # If udev events updated the disks already, but the multipath device isn't update 855 # check for old devices to make sure we found remapped luns 856 if [ -n "$mp_enable" ] && [ $remapped -eq 0 ]; then 857 findmultipath "$sddev" $id_serial 858 if [ $? -eq 1 ] ; then 859 remapped=1 860 fi 861 fi 862 863 # if uuid is 1, it's unmapped, so we don't want to treat it as a remap 864 # if remapped flag is 0, just skip the rest of the logic 865 if [ "$id_serial" = "1" ] || [ $remapped -eq 0 ] ; then 866 continue 867 fi 868 printf "${yellow}REMAPPED: %s ${norm}" 869 host=$(echo "$hctl" | cut -d":" -f1) 870 channel=$(echo "$hctl" | cut -d":" -f2) 871 id=$(echo "$hctl" | cut -d":" -f3) 872 lun=$(echo "$hctl" | cut -d":" -f4) 873 procscsiscsi 874 echo "$SCSISTR" 875 incrchgd "$hctl" 876 done < $tmpfile 877 rm -f $tmpfile 878 879 if [ -n "$mp_enable" ] && [ -n "$mpaths" ] ; then 880 echo "Updating multipath device mappings" 881 flushmpaths 882 $MULTIPATH | grep "create:" 2> /dev/null 883 fi 884} 885 886incrfound() 887{ 888 local hctl="$1" 889 if [ -n "$hctl" ] ; then 890 let found+=1 891 FOUNDDEVS="$FOUNDDEVS\t[$hctl]\n" 892 else 893 return 894 fi 895} 896 897incrchgd() 898{ 899 local hctl="$1" 900 if [ -n "$hctl" ] ; then 901 if ! echo "$CHGDEVS" | grep -q "\[$hctl\]"; then 902 let updated+=1 903 CHGDEVS="$CHGDEVS\t[$hctl]\n" 904 fi 905 else 906 return 907 fi 908 909 if [ -n "$mp_enable" ] ; then 910 local sdev 911 912 sdev=$(findsddev "$hctl") 913 if [ -n "$sdev" ] ; then 914 findmultipath "$sdev" 915 fi 916 fi 917} 918 919incrrmvd() 920{ 921 local hctl="$1" 922 if [ -n "$hctl" ] ; then 923 let rmvd+=1; 924 RMVDDEVS="$RMVDDEVS\t[$hctl]\n" 925 else 926 return 927 fi 928 929 if [ -n "$mp_enable" ] ; then 930 local sdev 931 932 sdev=$(findsddev "$hctl") 933 if [ -n "$sdev" ] ; then 934 findmultipath "$sdev" 935 fi 936 fi 937} 938 939findsddev() 940{ 941 local hctl="$1" 942 local sddev= 943 local blkpath 944 945 blkpath="/sys/class/scsi_device/$hctl/device/block" 946 if [ -e "$blkpath" ] ; then 947 sddev=$(ls "$blkpath") 948 echo "$sddev" 949 fi 950} 951 952addmpathtolist() 953{ 954 local mp="$1" 955 local mp2= 956 957 for mp2 in $mpaths ; do 958 # The multipath device is already in the list 959 if [ "$mp2" = "$mp" ] ; then 960 return 961 fi 962 done 963 mpaths="$mpaths $mp" 964} 965 966findmultipath() 967{ 968 local dev="$1" 969 local find_mismatch="$2" 970 local mp= 971 local found_dup=0 972 local maj_min= 973 974 # Need a sdev, and executable multipath and dmsetup command here 975 if [ -z "$dev" ] || [ ! -x "$DMSETUP" ] || [ ! -x "$MULTIPATH" ] ; then 976 return 1 977 fi 978 979 maj_min=$(cat "/sys/block/$dev/dev") 980 mp=$(cat $TMPLUNINFOFILE | grep -w "$maj_min" | cut -d " " -f1) 981 if [ -n "$mp" ]; then 982 if [ -n "$find_mismatch" ] ; then 983 uuid=$(cat $TMPLUNINFOFILE | grep -w "$maj_min" | cut -d " " -f4) 984 if [ "$find_mismatch" != "$uuid" ] ; then 985 addmpathtolist "$mp" 986 found_dup=1 987 fi 988 else 989 # Normal mode: Find the first multipath with the sdev 990 # and add it to the list 991 addmpathtolist "$mp" 992 return 993 fi 994 fi 995 996 # Return 1 to signal that a duplicate was found to the calling function 997 if [ $found_dup -eq 1 ] ; then 998 return 1 999 else 1000 return 0 1001 fi 1002} 1003 1004reloadmpaths() 1005{ 1006 local mpath 1007 if [ ! -x "$MULTIPATH" ] ; then 1008 echo "no -x multipath" 1009 return 1010 fi 1011 1012 # Pass 1 as the argument to reload all mpaths 1013 if [ "$1" = "1" ] ; then 1014 echo "Reloading all multipath devices" 1015 $MULTIPATH -r > /dev/null 2>&1 1016 return 1017 fi 1018 1019 # Reload the multipath devices 1020 for mpath in $mpaths ; do 1021 echo -n "Reloading multipath device $mpath... " 1022 if $MULTIPATH -r "$mpath" > /dev/null 2>&1 ; then 1023 echo "Done" 1024 else 1025 echo "Fail" 1026 fi 1027 done 1028} 1029 1030resizempaths() 1031{ 1032 local mpath 1033 1034 for mpath in $mpaths ; do 1035 echo -n "Resizing multipath map $mpath ..." 1036 multipathd -k"resize map $mpath" 1037 let updated+=1 1038 done 1039} 1040 1041flushmpaths() 1042{ 1043 local mpath 1044 local remove="" 1045 local i 1046 local flush_retries=5 1047 1048 if [ -n "$1" ] ; then 1049 for mpath in $($DMSETUP ls --target=multipath | cut -f 1) ; do 1050 [ "$mpath" = "No" ] && break 1051 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 }') 1052 if [ "$num" -eq 0 ] ; then 1053 remove="$remove $mpath" 1054 fi 1055 done 1056 else 1057 remove="$mpaths" 1058 fi 1059 1060 for mpath in $remove ; do 1061 i=0 1062 echo -n "Flushing multipath device $mpath... " 1063 while [ $i -lt $flush_retries ] ; do 1064 $DMSETUP message "$mpath" 0 fail_if_no_path > /dev/null 2>&1 1065 if $MULTIPATH -f "$mpath" > /dev/null 2>&1 ; then 1066 echo "Done ($i retries)" 1067 break 1068 elif [ $i -eq $flush_retries ] ; then 1069 echo "Fail" 1070 fi 1071 sleep 0.02 1072 let i=$i+1 1073 done 1074 done 1075} 1076 1077 1078# Find resized luns 1079findresized() 1080{ 1081 local devs= 1082 local size= 1083 local new_size= 1084 local sysfs_path= 1085 local sddev= 1086 local i= 1087 local m= 1088 local mpathsize= 1089 declare -a mpathsizes 1090 1091 if [ -z "$lunsearch" ] ; then 1092 devs=$(ls /sys/class/scsi_device/) 1093 else 1094 for lun in $lunsearch ; do 1095 devs="$devs $(cd /sys/class/scsi_device/ && ls -d *:${lun})" 1096 done 1097 fi 1098 1099 for hctl in $devs ; do 1100 sysfs_path="/sys/class/scsi_device/$hctl/device" 1101 if [ -d "$sysfs_path/block" ] ; then 1102 sddev=$(ls "$sysfs_path/block") 1103 size=$(cat "$sysfs_path/block/$sddev/size") 1104 1105 echo 1 > "$sysfs_path/rescan" 1106 new_size=$(cat "$sysfs_path/block/$sddev/size") 1107 1108 if [ "$size" != "$new_size" ] && [ "$size" != "0" ] && [ "$new_size" != "0" ] ; then 1109 printf "${yellow}RESIZED: %s ${norm}" 1110 host=$(echo "$hctl" | cut -d":" -f1) 1111 channel=$(echo "$hctl" | cut -d":" -f2) 1112 id=$(echo "$hctl" | cut -d":" -f3) 1113 lun=$(echo "$hctl" | cut -d":" -f4) 1114 1115 procscsiscsi 1116 echo "$SCSISTR" 1117 incrchgd "$hctl" 1118 fi 1119 fi 1120 done 1121 1122 if [ -n "$mp_enable" ] && [ -n "$mpaths" ] ; then 1123 i=0 1124 for m in $mpaths ; do 1125 mpathsizes[$i]="$($MULTIPATH -l "$m" | egrep -o [0-9]+.[0-9]+[KMGT])" 1126 let i=$i+1 1127 done 1128 resizempaths 1129 i=0 1130 for m in $mpaths ; do 1131 mpathsize="$($MULTIPATH -l "$m" | egrep -o [0-9\.]+[KMGT])" 1132 echo "$m ${mpathsizes[$i]} => $mpathsize" 1133 let i=$i+1 1134 done 1135 fi 1136} 1137 1138FOUNDDEVS="" 1139CHGDEVS="" 1140RMVDDEVS="" 1141 1142# main 1143if [ "@$1" = @--help ] || [ "@$1" = @-h ] || [ "@$1" = "@-?" ] ; then 1144 echo "Usage: rescan-scsi-bus.sh [options] [host [host ...]]" 1145 echo "Options:" 1146 echo " -a scan all targets, not just currently existing [default: disabled]" 1147 echo " -c enables scanning of channels 0 1 [default: 0 / all detected ones]" 1148 echo " -d enable debug [default: 0]" 1149 echo " -f flush failed multipath devices [default: disabled]" 1150 echo " -h help: print this usage message then exit" 1151 echo " -i issue a FibreChannel LIP reset [default: disabled]" 1152 echo " -I SECS issue a FibreChannel LIP reset and wait for SECS seconds [default: disabled]" 1153 echo " -l activates scanning for LUNs 0--7 [default: 0]" 1154 echo " -L NUM activates scanning for LUNs 0--NUM [default: 0]" 1155 echo " -m update multipath devices [default: disabled]" 1156 echo " -r enables removing of devices [default: disabled]" 1157 echo " -s look for resized disks and reload associated multipath devices, if applicable" 1158 echo " -t SECS timeout for testing if device is online. Test is skipped if 0 [default: 30]" 1159 echo " -u look for existing disks that have been remapped" 1160 echo " -V print version date then exit" 1161 echo " -w scan for target device IDs 0--15 [default: 0--7]" 1162 echo "--alltargets: same as -a" 1163 echo "--attachpq3: Tell kernel to attach sg to LUN 0 that reports PQ=3" 1164 echo "--channels=LIST: Scan only channel(s) in LIST" 1165 echo "--color: use coloured prefixes OLD/NEW/DEL" 1166 echo "--flush: same as -f" 1167 echo "--forceremove: Remove stale devices (DANGEROUS)" 1168 echo "--forcerescan: Remove and readd existing devices (DANGEROUS)" 1169 echo "--help: print this usage message then exit" 1170 echo "--hosts=LIST: Scan only host(s) in LIST" 1171 echo "--ids=LIST: Scan only target ID(s) in LIST" 1172 echo "--ignore-rev: Ignore the revision change" 1173 echo "--issue-lip: same as -i" 1174 echo "--issue-lip-wait=SECS: same as -I" 1175 echo "--largelun: Tell kernel to support LUNs > 7 even on SCSI2 devs" 1176 echo "--luns=LIST: Scan only lun(s) in LIST" 1177 echo "--multipath: same as -m" 1178 echo "--no-lip-scan: don't scan FC Host with issue-lip" 1179 echo "--nooptscan: don't stop looking for LUNs if 0 is not found" 1180 echo "--remove: same as -r" 1181 echo "--reportlun2: Tell kernel to try REPORT_LUN even on SCSI2 devices" 1182 echo "--resize: same as -s" 1183 echo "--sparselun: Tell kernel to support sparse LUN numbering" 1184 echo "--sync/nosync: Issue a sync / no sync [default: sync if remove]" 1185 echo "--timeout=SECS: same as -t" 1186 echo "--update: same as -u" 1187 echo "--version: same as -V" 1188 echo "--wide: same as -w" 1189 echo "" 1190 echo "Host numbers may thus be specified either directly on cmd line (deprecated)" 1191 echo "or with the --hosts=LIST parameter (recommended)." 1192 echo "LIST: A[-B][,C[-D]]... is a comma separated list of single values and ranges" 1193 echo "(No spaces allowed.)" 1194 exit 0 1195fi 1196 1197if [ "@$1" = @--version ] || [ "@$1" = @-V ] ; then 1198 echo ${VERSION} 1199 exit 0 1200fi 1201 1202if [ ! -d /sys/class/scsi_host/ ] && [ ! -d /proc/scsi/ ] ; then 1203 echo "Error: SCSI subsystem not active" 1204 exit 1 1205fi 1206 1207# Make sure sg is there 1208modprobe sg >/dev/null 2>&1 1209 1210if [ -x /usr/bin/sg_inq ] ; then 1211 sg_version=$(sg_inq -V 2>&1 | cut -d " " -f 3) 1212 if [ -n "$sg_version" ] ; then 1213 sg_ver_maj=${sg_version:0:1} 1214 sg_version=${sg_version##?.} 1215 let sg_version+=$((100 * sg_ver_maj)) 1216 fi 1217 sg_version=${sg_version##0.} 1218 #echo "\"$sg_version\"" 1219 if [ -z "$sg_version" ] || [ "$sg_version" -lt 70 ] ; then 1220 sg_len_arg="-36" 1221 else 1222 sg_len_arg="--len=36" 1223 fi 1224else 1225 echo "WARN: /usr/bin/sg_inq not present -- please install sg3_utils" 1226 echo " or rescan-scsi-bus.sh might not fully work." 1227fi 1228 1229# defaults 1230unsetcolor 1231debug=0 1232lunsearch= 1233opt_idsearch=$(seq -s ' ' 0 7) 1234filter_ids=0 1235opt_channelsearch= 1236remove= 1237updated=0 1238update=0 1239resize=0 1240forceremove= 1241optscan=1 1242sync=1 1243existing_targets=1 1244mp_enable= 1245lipreset=-1 1246timeout=30 1247declare -i scan_flags=0 1248ignore_rev=0 1249no_lip_scan=0 1250 1251# Scan options 1252opt="$1" 1253while [ ! -z "$opt" ] && [ -z "${opt##-*}" ] ; do 1254 opt=${opt#-} 1255 case "$opt" in 1256 a) existing_targets=;; #Scan ALL targets when specified 1257 c) opt_channelsearch="0 1" ;; 1258 d) debug=1 ;; 1259 f) flush=1 ;; 1260 i) lipreset=0 ;; 1261 I) shift; lipreset=$1 ;; 1262 l) lunsearch=$(seq -s ' ' 0 7) ;; 1263 L) lunsearch=$(seq -s ' ' 0 "$2"); shift ;; 1264 m) mp_enable=1 ;; 1265 r) remove=1 ;; 1266 s) resize=1; mp_enable=1 ;; 1267 t) timeout=$2; shift ;; 1268 u) update=1 ;; 1269 w) opt_idsearch=$(seq -s ' ' 0 15) ;; 1270 -alltargets) existing_targets=;; 1271 -attachpq3) scan_flags=$((scan_flags|0x1000000)) ;; 1272 -channels=*) arg=${opt#-channels=};opt_channelsearch=$(expandlist "$arg") ;; 1273 -color) setcolor ;; 1274 -flush) flush=1 ;; 1275 -forceremove) remove=1; forceremove=1 ;; 1276 -forcerescan) remove=1; forcerescan=1 ;; 1277 -hosts=*) arg=${opt#-hosts=}; hosts=$(expandlist "$arg") ;; 1278 -ids=*) arg=${opt#-ids=}; opt_idsearch=$(expandlist "$arg") ; filter_ids=1;; 1279 -ignore-rev) ignore_rev=1;; 1280 -issue-lip) lipreset=0 ;; 1281 -issue-lip-wait=*) lipreset=${opt#-issue-lip-wait=};; 1282 -largelun) scan_flags=$((scan_flags|0x200)) ;; 1283 -luns=*) arg=${opt#-luns=}; lunsearch=$(expandlist "$arg") ;; 1284 -multipath) mp_enable=1 ;; 1285 -no-lip-scan) no_lip_scan=1 ;; 1286 -nooptscan) optscan=0 ;; 1287 -nosync) sync=0 ;; 1288 -remove) remove=1 ;; 1289 -reportlun2) scan_flags=$((scan_flags|0x20000)) ;; 1290 -resize) resize=1;; 1291 -timeout=*) timeout=${opt#-timeout=};; 1292 -sparselun) scan_flags=$((scan_flags|0x40)) ;; 1293 -sync) sync=2 ;; 1294 -update) update=1;; 1295 -wide) opt_idsearch=$(seq -s ' ' 0 15) ;; 1296 *) echo "Unknown option -$opt !" ;; 1297 esac 1298 shift 1299 opt="$1" 1300done 1301 1302if [ -z "$hosts" ] ; then 1303 if [ -d /sys/class/scsi_host ] ; then 1304 findhosts_26 1305 else 1306 findhosts 1307 fi 1308fi 1309 1310if [ -d /sys/class/scsi_host ] && [ ! -w /sys/class/scsi_host ]; then 1311 echo "You need to run scsi-rescan-bus.sh as root" 1312 exit 2 1313fi 1314[ "$sync" = 1 ] && [ "$remove" = 1 ] && sync=2 1315if [ "$sync" = 2 ] ; then 1316 echo "Syncing file systems" 1317 sync 1318fi 1319if [ -w /sys/module/scsi_mod/parameters/default_dev_flags ] && [ $scan_flags != 0 ] ; then 1320 OLD_SCANFLAGS=$(cat /sys/module/scsi_mod/parameters/default_dev_flags) 1321 NEW_SCANFLAGS=$((OLD_SCANFLAGS|scan_flags)) 1322 if [ "$OLD_SCANFLAGS" != "$NEW_SCANFLAGS" ] ; then 1323 echo -n "Temporarily setting kernel scanning flags from " 1324 printf "0x%08x to 0x%08x\n" "$OLD_SCANFLAGS" "$NEW_SCANFLAGS" 1325 echo $NEW_SCANFLAGS > /sys/module/scsi_mod/parameters/default_dev_flags 1326 else 1327 unset OLD_SCANFLAGS 1328 fi 1329fi 1330DMSETUP=$(which dmsetup) 1331[ -z "$DMSETUP" ] && flush= && mp_enable= 1332MULTIPATH=$(which multipath) 1333[ -z "$MULTIPATH" ] && flush= && mp_enable= 1334 1335echo -n "Scanning SCSI subsystem for new devices" 1336[ -z "$flush" ] || echo -n ", flush failed multipath devices," 1337[ -z "$remove" ] || echo -n " and remove devices that have disappeared" 1338echo 1339declare -i found=0 1340declare -i updated=0 1341declare -i rmvd=0 1342 1343if [ -n "$flush" ] ; then 1344 if [ -x "$MULTIPATH" ] ; then 1345 flushmpaths 1 1346 fi 1347fi 1348 1349# Update existing mappings 1350if [ $update -eq 1 ] ; then 1351 echo "Searching for remapped LUNs" 1352 findremapped 1353 # If you've changed the mapping, there's a chance it's a different size 1354 mpaths="" 1355 findresized 1356# Search for resized LUNs 1357elif [ $resize -eq 1 ] ; then 1358 echo "Searching for resized LUNs" 1359 findresized 1360# Normal rescan mode 1361else 1362 for host in $hosts; do 1363 echo -n "Scanning host $host " 1364 if [ $no_lip_scan -eq 0 ] && [ -e "/sys/class/fc_host/host$host" ] ; then 1365 # It's pointless to do a target scan on FC 1366 issue_lip=/sys/class/fc_host/host$host/issue_lip 1367 if [ -e "$issue_lip" ] && [ "$lipreset" -ge 0 ] ; then 1368 echo 1 > "$issue_lip" 2> /dev/null; 1369 udevadm_settle 1370 [ "$lipreset" -gt 0 ] && sleep "$lipreset" 1371 fi 1372 channelsearch= 1373 idsearch= 1374 else 1375 channelsearch=$opt_channelsearch 1376 idsearch=$opt_idsearch 1377 fi 1378 [ -n "$channelsearch" ] && echo -n "channels $channelsearch " 1379 echo -n "for " 1380 if [ -n "$idsearch" ] ; then 1381 echo -n " SCSI target IDs $idsearch" 1382 else 1383 echo -n " all SCSI target IDs" 1384 fi 1385 if [ -n "$lunsearch" ] ; then 1386 echo ", LUNs $lunsearch" 1387 else 1388 echo ", all LUNs" 1389 fi 1390 1391 if [ -n "$existing_targets" ] ; then 1392 searchexisting 1393 else 1394 dosearch 1395 fi 1396 done 1397 if [ -n "$OLD_SCANFLAGS" ] ; then 1398 echo "$OLD_SCANFLAGS" > /sys/module/scsi_mod/parameters/default_dev_flags 1399 fi 1400fi 1401 1402let rmvd_found=$rmvd+$found 1403if [ -n "$mp_enable" ] && [ $rmvd_found -gt 0 ] ; then 1404 echo "Attempting to update multipath devices..." 1405 if [ $rmvd -gt 0 ] ; then 1406 udevadm_settle 1407 echo "Removing multipath mappings for removed devices if all paths are now failed... " 1408 flushmpaths 1 1409 fi 1410 if [ $found -gt 0 ] ; then 1411 /sbin/udevadm trigger --sysname-match=sd* 1412 udevadm_settle 1413 if [ -x "$MULTIPATH" ] ; then 1414 echo "Trying to discover new multipath mappings for newly discovered devices... " 1415 $MULTIPATH | grep "create:" 2> /dev/null 1416 fi 1417 fi 1418fi 1419 1420echo "$found new or changed device(s) found. " 1421if [ ! -z "$FOUNDDEVS" ] ; then 1422 echo -e "$FOUNDDEVS" 1423fi 1424echo "$updated remapped or resized device(s) found." 1425if [ ! -z "$CHGDEVS" ] ; then 1426 echo -e "$CHGDEVS" 1427fi 1428echo "$rmvd device(s) removed. " 1429if [ ! -z "$RMVDDEVS" ] ; then 1430 echo -e "$RMVDDEVS" 1431fi 1432 1433# Local Variables: 1434# sh-basic-offset: 2 1435# End: 1436 1437