#!/bin/sh # #/******************************************************************* # * This file is part of the Emulex Linux Device Driver for * # * Fibre Channel Host Bus Adapters. * # * Copyright (C) 2003-2010 Emulex. All rights reserved. * # * EMULEX and SLI are trademarks of Emulex. * # * www.emulex.com * # * * # * This program is free software; you can redistribute it and/or * # * modify it under the terms of version 2 of the GNU General * # * Public License as published by the Free Software Foundation. * # * This program is distributed in the hope that it will be useful. * # * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * # * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * # * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * # * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * # * TO BE LEGALLY INVALID. See the GNU General Public License for * # * more details, a copy of which can be found in the file COPYING * # * included with this package. * # *******************************************************************/ # # scripts/lun_scan (VERSION variable below) # This script is provided by Emulex to use with its 7.x and 8.x linux device # drivers for Light Pulse Fibre Channel adapters. # # This script allows a user to peform one of more of the following actions, # for specified SCSI Hosts/LPFC HBAs: # - Scan for new devices # - Resize existing LUNs # - Delete LUNs that are offline/deleted. # # Usage: # # lun_scan.sh [-h|--help] [SCAN_OPTIONS] [ <#> [<#>] | all ]" # # where: # -h, --help : Prints this usage message # <#> : Scsi host number of a specific LPFC HBA for which an # operation is to be applied. # # All : Indicates that operation should be applied to all hosts. # # [SCAN_OPTIONS] could be one or more of: # -l, --lip : Reinitialize Fibre Channel link before scanning # # -s, --scan : Scan for new devices # # -r, --resize : Resize LUNs # # -d, --delete : Delete LUNs that are offline/deleted # # Note: If no [SCAN_OPTIONS] are specified, the default options are # --delete, --resize followed by --scan. # If one or more [SCAN_OPTIONS] are specified only those options # will be performed. # # Warning: Scanning an adapter while performing a tape backup should # be avoided. # # Examples: # # lun_scan.sh all : Scans all LPFC HBAs." # lun_scan.sh 2 4 : Scans the LPFC HBAs with scsi host number 2 and 4. # lun_scan.sh -s 2 : Scans only for new LUNs the LPFC HBA with scsi # host number 2." # lun_scan.sh -s -d 2 : Scans for new LUNs and remove LUNS that have # been deleted in the LPFC HBA with scsi host number 2. # lun_scan.sh -l 1 : Reinitialize FC link before scanning the LPFC # HBA with scsi host number 1. # lun_scan.sh -s -d 2 : Scans for new LUNs and remove LUNS that have been # deleted in the LPFC HBA with scsi host number 2. # ############################################################################# VERSION="1.3" OS_REV=`uname -r | cut -c1-3` ELX_SCAN=$(basename $0) err_msg () { msg_line="$1" cat< [<#>] | all ]" echo "" echo " where:" echo "" echo " -h, --help : Prints this usage message" echo " <#> : Scsi host number of a specific LPFC HBA that is to be" echo " scanned. More than one host number can be specified." echo " all : Indicates that all LPFC HBAs are to be scanned." echo "" echo " [SCAN_OPTIONS] is one or more of:" echo " -l, --lip : Reinitialize Fibre Channel link before scanning" echo " -s, --scan : Scan for new devices" echo " -r, --resize : Resize LUNs" echo " -d, --delete : Delete LUNs that are offline/deleted" echo "" echo " Note: If no [SCAN_OPTIONS] are specified, the default options are" echo " --delete, --resize followed by --scan." echo " If one or more [SCAN_OPTIONS] are specified only those options" echo " will be performed." echo "" echo " Warning: Scanning an adapter while performing a tape backup should" echo " be avoided." echo "" } input_is_valid () { INPUT=$* GOOD=0 BAD=1 DETERMINATION=$GOOD ALL_TEST=$(echo $INPUT| tr 'a-z' 'A-Z') if [ "${ALL_TEST}" == "ALL" ] ; then ALL_HOSTS=1 else check=$(echo ${INPUT} | grep ^[0-9' '] ) if [ "$?" -ne 0 ] ; then DETERMINATION=$BAD else check=$(echo $INPUT|grep [a-zA-Z]) if [ "$?" -ne 1 ] ; then DETERMINATION=$BAD fi fi fi return $DETERMINATION } usage_exit () { echo "Invalid argument $1" usage exit 1 } ALL_HOSTS=0 OPTIONS_USED=0 DELETE_SPECIFIED=0 RESIZE_SPECIFIED=0 SCAN_SPECIFIED=0 LIP_SPECIFIED=0 HELP_ONLY=0 hostslist= while [ $# -gt 0 ]; do case $1 in -d|--delete) OPTIONS_USED=1 DELETE_SPECIFIED=1 shift ;; -r|--resize) OPTIONS_USED=1 RESIZE_SPECIFIED=1 shift ;; -s|--scan) OPTIONS_USED=1 SCAN_SPECIFIED=1 shift ;; -l|--lip) OPTIONS_USED=1 LIP_SPECIFIED=1 shift ;; -h|--help) OPTIONS_USED=1 HELP_ONLY=1 shift ;; all) ALL_HOSTS=1 shift ;; [0-9]*) hostslist="$hostslist $1" shift ;; *) hostslist="$hostslist $1" input_is_valid $hostslist if [ $? -ne 0 ] ; then echo "Please specify a valid host number" usage_exit $1 else shift fi ;; esac done if [ ${HELP_ONLY} -eq 1 ] ; then usage exit 0 fi # if no options were specified then enable all operations except LIP. if [ ${OPTIONS_USED} -eq 0 ] ; then DELETE_SPECIFIED=1 RESIZE_SPECIFIED=1 SCAN_SPECIFIED=1 LIP_SPECIFIED=0 fi if [ -n "${hostslist}" ] ; then input_is_valid $hostslist ||\ err_msg "Please specify a valid host number" hosts=($hostslist) else ALL_HOSTS=1 fi abort_exit() { echo "" echo "Error: Cannot find an lpfc HBA instance with scsi host number : $host" echo "... Aborting lun_scan." echo "" exit 2 } get_hosts_list () { if [ ${OS_REV} = 2.4 ]; then lowhost=0 ha=`ls /proc/scsi/lpfc/? 2> /dev/null | cut -f5 -d'/'` hb=`ls /proc/scsi/lpfc/?? 2> /dev/null | cut -f5 -d'/'` hc=`ls /proc/scsi/lpfc/??? 2> /dev/null | cut -f5 -d'/'` all_hosts="$ha $hb $hc" lowhost=`echo $all_hosts | sed "s/ .*//"` else ha=`ls -1 -d /sys/bus/pci/drivers/lpfc/*/host* 2>/dev/null | sed -e "s/.*host//"` hb=`ls -1 -d /sys/bus/pci/drivers/lpfc/*/host*/host* 2>/dev/null | sed -e "s/.*host//"` hc=`ls -1 -d /sys/bus/pci/drivers/lpfc/*/host*/vport*/host* 2>/dev/null | sed -e "s/.*host//"` all_hosts="$ha $hb $hc" fi } send_lip_command() { cat< /sys/class/fc_host/host$host/issue_lip elif [ -e /sys/class/scsi_host/host$host/issue_lip ] ; then echo 1 > /sys/class/scsi_host/host$host/issue_lip fi #Do nothing if issue_lip doesn't exist, i.e. host is a vport return $? } scan_hosts() { if [ ${OS_REV} = 2.4 ]; then for host in $hosts ; do # Convert host number to lpfc instance number. instance=`expr $host - $lowhost` if [ ! -e /proc/scsi/lpfc/$host ] ; then abort_exit fi echo Scanning lpfc$instance, scsi host number : $host; max_lun=256 targets=`cat /proc/scsi/lpfc/$host | grep 'lpfc*t*' | cut -f2 -d't' | cut -f1 -d' '` for target in $targets ; do # Convert target ID to decimal from Hex format let "dec_target = 0x$target" echo " Scanning Target Id $dec_target..." for ((lun=0; lun<$max_lun; lun++)) ; do echo "scsi add-single-device $host 0 $dec_target $lun" >/proc/scsi/scsi done done done else for host in ${hosts[@]} ; do let item=0 if [ ! -e /sys/bus/pci/drivers/lpfc/*/host$host ] && [ ! -e /sys/bus/pci/drivers/lpfc/*/host*/host$host ] && [ ! -e /sys/bus/pci/drivers/lpfc/*/host*/vport*/host$host ] ; then abort_exit fi if [ "${LIP_SPECIFIED}" -eq 1 ] ; then send_lip_command fi if [ "${DELETE_SPECIFIED}" -eq 1 ] || [ "${RESIZE_SPECIFIED}" -eq 1 ] ; then which sg_turs > /dev/null 2>&1 if [ $? -ne 0 ] ; then echo "Missing sg3_utils - unable to detect removed target LUNs" else # Determine if sg_turs accepts -v switch sg_turs -v 2>&1 | grep -q "Unrecognized switch" if [ $? -eq 0 ] ; then # grep found the "Unrecognized switch" error message SG_TURS="sg_turs" else SG_TURS="sg_turs -v" fi echo "Searching for :" if [ "${DELETE_SPECIFIED}" -eq 1 ] ; then let item+=1 echo -e "\t $item. Target LUNs to remove on scsi host number : $host" fi if [ "${RESIZE_SPECIFIED}" -eq 1 ] ; then let item+=1 echo -e " \t $item. Target LUNs to resize on scsi host number : $host" fi # send SCSI TUR to each device on this host cd /sys/class/scsi_host/host$host # device paths for RHEL 5 and SLES 10 device_dirs="device/rport-*/target*/$host:0:*" # device paths for RHEL 4 device_dirs="${device_dirs} device/target*/$host:0:*" # device paths for SLES 9 device_dirs="${device_dirs} device/$host:0:*" for id in $device_dirs ; do if [ -e $id/generic ] ; then # number of retries for Unit Attention ua_retries_left=3 sg_link=$(ls -d $id/generic) sg_device=$(readlink $sg_link) sg_device=${sg_device##*/} block_link=$(ls -d $id/block*) block_link=$(readlink $block_link) sd_device=${block_link##*/} while [ $ua_retries_left -gt 0 ] ; do tur_output=$($SG_TURS /dev/$sg_device 2>&1) case $tur_output in *Unit\ Attention*) let ua_retries_left=(ua_retries_left - 1) if [ $ua_retries_left -gt 0 ] ; then echo -n "Device $sd_device returned Unit Attention" echo ", retrying $ua_retries_left more times" # delay for target sleep 1 else # that was the last retry echo -n "Device $sd_device unresolved Unit Attention" echo ", skipping" fi ;; *Illegal\ Request*) # only retry if we get Unit Attention back ua_retries_left=0 if [ "${DELETE_SPECIFIED}" -eq 1 ] ; then echo "removing $sd_device (no longer available)" echo 1 > $id/generic/device/delete fi ;; *DID_NO_CONNECT*) # only retry if we get Unit Attention back ua_retries_left=0 # Temporary path down - leave it alone ;; *) # only retry if we get Unit Attention back ua_retries_left=0 # Check if this LUN has been resized if [ "${RESIZE_SPECIFIED}" -eq 1 ] ; then if [ -n "$sd_device" ]; then echo 1 > /sys/block/$sd_device/device/rescan fi fi ;; esac done fi done fi fi # Perform SCAN Operation only if it is allowable if [ "${SCAN_SPECIFIED}" -eq 1 ] ; then echo Scanning lpfc HBA instance with scsi host number : $host echo '- - -' > /sys/class/scsi_host/host$host/scan || \ err_msg "Unable to scan for host $host" fi done echo " " fi } if [ ${ALL_HOSTS} -eq 1 ] ; then get_hosts_list hosts=($all_hosts) else hosts=($hostslist) fi scan_hosts