#!/bin/sh
# Copyright 2004  VMware, Inc. All rights reserved. 
# Script to rescan a vmkernel SCSI adapter and reflect LUN changes in COS. 

usage()
{
   echo "Usage: $0 <vmkernel SCSI adapter name>"
}

scantools=/usr/sbin/scantools
fstools=/usr/sbin/vmkfstools
vmklist=
coslist=
cosonly=
addonly=
delonly=
updateonly=
visorscan=
scan_all=

main()
{
   # Validate args.
   while getopts "caduhw?" arg
   do
      case $arg in
      c) cosonly=1 ;;
      a) addonly=1 ;;
      d) delonly=1 ;;
      u) updateonly=1 ;;
      w) scan_all=1 ;;
      h) usage && exit 1 ;;
      /?) usage && exit 1 ;;
      ?) usage && exit 1 ;;
      esac
   done
   shift `expr $OPTIND - 1`

   if [ ! "$scan_all" -a "$#" -lt 1 ]; then 
      echo "Incorrect number of arguments."
      usage
      exit 1
   fi
   if [ ! $cosonly ]; then
      if [ ! -x $scantools ]; then 
         echo "$scantools doesn't exist or is not executable."
         exit 1
      fi
      if [ ! -x $fstools ]; then
	 echo "$fstools doesn't exist or is not executable."
	 exit 1
      fi
   fi

   iscos=`uname | grep Linux`
   if [ $? -ne 0 ]; then
      visorscan=1
      if [ $cosonly ]; then
         echo "No COS in VMvisor."
         usage
         exit 1
      fi
   fi

   if [ ! "$scan_all" ]; then
       vmhba_list=$*
   else
      if [ ! $visorscan ]; then
         vmhba_list=`grep "vmhba" /proc/vmware/vmkstor | awk '{print $2}'`
      else
         tmpfile=/tmp/vmware_vmhba_list$$
         esxcfg-info -w | grep vmhba | awk '{ x = $0; gsub ( "^.*\\.", "", x ); \
            print x }' > $tmpfile
         vmhba_list=`cat $tmpfile`
         rm $tmpfile
      fi
   fi

   #
   # * fstool needed if any successful adapter rescan
   # * Exit 1 if either any unsupported adapter to rescan
   #    or any failure from scantools on the adapters
   #
   retval=0
   fstool_needed=0
   for vmhba in $vmhba_list; do
      case $vmhba in
         vmhba*)
            run_scan $vmhba
            if [ $? -ne 0 ]; then
               retval=1;
            else
               fstool_needed=1
            fi
         ;;
         *) echo "'$1' not a valid vmkernel adapter name."
            retval=1;
            usage
         ;;
      esac
   done
   
   if [ $fstool_needed -eq 1 ]; then
      $fstools -V
      echo "Done."
   fi

   if [ $retval -ne 0 ]; then 
       exit 1
   fi
}

run_scan()
{
   local vmhba=$1
   local shnum=
   local failed=
   if [ ! $visorscan ]; then
      if ! grep -q -w $vmhba /proc/vmware/vmkstor; then
         echo "'$vmhba' is not a valid vmkernel adapter name."
         usage
         return 1;
      fi

      # Map vmhba name to COS scsi name.
      coshba=`grep -w "$vmhba" /proc/vmware/vmkstor | awk '{print $1}'`
      mode=`grep -w "$vmhba" /proc/vmware/vmkstor | awk '{print $3}'`
      case $coshba in
         scsi*) 
            shnum=`echo $coshba | sed "s/scsi//"` 
         ;;
         block*)  
            echo "$vmhba does not support rescanning."
            usage 
            return 1;
         ;;
         *) echo "Couldn't find valid console adapter for $vmhba." 
            usage 
            return 1;
         ;;
      esac
      # echo $vmhba -> $coshba
   fi
   
   # Rescan in vmkernel.
   if [ ! $cosonly ]; then
      if [ $visorscan ]; then
         for i in `find /proc/scsi -type f`; do
            cat $i|grep "$vmhba$";
            if [ $? -eq 0 ]; then
               shnum=`basename $i`
	       break;
            fi
         done

         # Could be an ide device, so wont show up in /proc/scsi
         # Rescans are not supported on these device types
         if [ -z "$shnum" ]; then
            echo "$vmhba does not support rescanning."
            usage
            return 1;
         fi
      fi


      qlnode=`find /proc/scsi -type f -name $shnum | grep "qla"`
      hwiscsi=`echo $qlnode | grep -e qla4010 -e qla4022`
      swiscsinode=`find /proc/scsi -type f -name $shnum | grep "vmkiscsi"`

      if [ "$hwiscsi" ]; then
           echo "Doing iSCSI discovery.  This can take a few seconds ..."
           echo "scsi-qlascan" > $qlnode
           vmkiscsi-tool -R $vmhba >/dev/null 2>&1
      elif [ -f "$swiscsinode" ]; then
           echo "Doing iSCSI discovery.  This can take a few seconds ..."
           kill -SIGHUP $(cat /var/run/vmkiscsid.pid)
           sleep 5
           vmkiscsi-tool -R $vmhba >/dev/null 2>&1
      elif [ -f "$qlnode" ]; then
           echo "scsi-qlascan" > $qlnode
	   sleep 5
      fi

      # now do the actual vmkernel rescan
      echo "Rescanning $vmhba ..."

      if [ $addonly ]; then
         echo -n "add operation on $vmhba"
         $scantools -a $vmhba
	 if [ $? -ne 0 ]; then
	    failed=1
	 fi
      elif [ $delonly ]; then
         echo -n "delete operation on $vmhba"
	 $scantools -d $vmhba
         if [ $? -ne 0 ]; then
            failed=1
         fi
      elif [ $updateonly ]; then
         echo -n "update operation on $vmhba"
         $scantools -u $vmhba
         if [ $? -ne 0 ]; then
            failed=1
         fi
      else
         $scantools -d $vmhba
         if [ $? -ne 0 ]; then
            failed=1
         fi
         $scantools -a $vmhba
         if [ $? -ne 0 ]; then
            failed=1
         fi
         $scantools -u $vmhba
         if [ $? -ne 0 ]; then
	    failed=1
         fi
      fi
      if [ "$failed" ]; then 
         echo "failed."
         echo "Warning: Vmkernel adapter $vmhba rescan did not complete successfully."
         return 1;
      fi
   fi

   if [ ! $visorscan ]; then
      # Build a list of vmkernel luns the COS currently knows.
      coslist=`grep -w "$coshba" /proc/scsi/scsi | awk '{print $6+0 ":" $8+0}' | xargs`
      # echo coslist=$coslist

      vmklist=`esxcfg-vmhbadevs -a | sed -n -e "s/$vmhba:\([0-9]*:[0-9]*\).*/\1/gp"`
      # Build a list of luns the vmkernel has after rescan.
      # echo vmklist=$vmklist
      
      # Remove all vmkernel luns from the COS.
      echo -n "On scsi$shnum, removing:"
      for lun in $coslist; do
         tgtlun=`echo $lun | sed "s/:/ /"`
         # Assumes channel 0 for now.
         echo "scsi remove-single-device $shnum 0 $tgtlun" > /proc/scsi/scsi
         if [ $mode = "Shared" ]; then
            echo "shrdev remove $shnum:$lun" > /proc/vmware/vmkstor
         fi
         echo -n " $lun"
      done
      echo "."
   
      # Add in all luns detected by vmkernel.
      echo -n "On scsi$shnum, adding:"
      for lun in $vmklist; do
         tgtlun=`echo $lun | sed "s/:/ /"`
         # Assumes channel 0 for now.
         if [ $mode = "Shared" ]; then
            echo "shrdev add $shnum:$lun" > /proc/vmware/vmkstor
         fi
         echo "scsi add-single-device $shnum 0 $tgtlun" > /proc/scsi/scsi
         echo -n " $lun"
      done
      echo "."
   fi
   return 0;
}

main $*
