Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2020940
  • 博文数量: 593
  • 博客积分: 20034
  • 博客等级: 上将
  • 技术积分: 6779
  • 用 户 组: 普通用户
  • 注册时间: 2006-02-06 14:07
文章分类

全部博文(593)

文章存档

2016年(1)

2011年(101)

2010年(80)

2009年(10)

2008年(102)

2007年(16)

2006年(283)

我的朋友

分类:

2006-10-28 22:38:48

#!/bin/ksh93
# IBM_PROLOG_BEGIN_TAG
# This is an automatically generated prolog.



# Licensed Materials - Property of IBM

# (C) COPYRIGHT International Business Machines Corp. 1990,2006
# All Rights Reserved

# US Government Users Restricted Rights - Use, duplication or
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp.

# IBM_PROLOG_END_TAG
# @(#)13 1.2.5.51  src/43haes/usr/sbin/cluster/events/utils/cl_disk_available.sh, hacmp.events, 51haes_r520, r520s008a 4/7/06 17:06:35
#
#   COMPONENT_NAME: hacmp.events
#
#   FUNCTION: Given a list of disks, make sure that they are in the
#         'available' state.  If necessary, break reserves, and remove any
#         ghost disks.
#
#   ORIGINS: 27
#
###############################################################################
#
# Name: cl_disk_available
# Returns:
#  0 Success
#  1 Failure - Can't make it Available
#  2 Failure - Bad args
#
# Check to see if a disk is available to the system, if not try to
# make it available.
#
# Arguments: [ -s ] [ hdiskname .... ]
#
#   If called with '-s' flag the script implies that it is called not from the
#   event script context, so skip resource manager updates
#
#   If called with a list of hdisks, make those disks available
#
#   If called with no list of hdisks, then process by resource group, based on
#   environment variables set by process_resources:
#    RESOURCE_GROUPS - space separated list of resource groups
#    HDISKS - list of disks for a resource group
#    - comma separated list of disks within a resource group
#    - colon separated lists of disks for each resource group
#    VOLUME_GROUPS - list of owning volume group (if any) for each
#      hdisk.  Same pattern of comma and colon separated
#      lists as for HDISKS
#    e.g. -
# RESOURCE_GROUPS="curley larry moe shemp"
# HDISKS="hdisk11,hdisk22:hdisk21,hdisk31:hdisk99:hdisk101,hdisk1"
# VOLUME_GROUPS="vg01,vg01:vg02,vg02,::vg03,vg0"
#
# Environment: VERBOSE_LOGGING - "high" => set -x
#
# Questions? Comments? Expressions of Astonishment?  
#
###############################################################################
#
#   Name: make_disktypes_available
#
#   Input: 1) owning adapter for list of disks
#  2) disk type - FSCSI or SCSIDISK
#  3) list of disks
#
#   Function: This routine is passed a list of disks, all on a common
#  adapter.
#  * The names of any ghost disks are collected for later removal
#  * Any that are not available are added to the list of disks to
#    be made available later
#  * The adapter and disk names are passed to a routine that will
#    open the adapter and use ioctls to break any reserves
#
#   Output: None
#
#   Environment:    VERBOSE_LOGGING, PATH, disklist, ghostlist, fscarray,
#      pscarray
#
###############################################################################
function make_disktypes_available
{
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x 
    typeset parent=$1
    typeset disktype=$2
    shift 2
    typeset disks=$*
    #
    # Scan through the list of given disks, checking each one
    # for possible ghost disks, which must be later removed
    #
    for disk in $disks      # Check to see if each disk is in an
    do        # available state
 #
 #   The disk is not available
 #
 if [[ -z $(lsdev -Cc disk -l $disk -S A -F 'status') ]]
 then
     # It is possible for the original disk device to become
     # "Defined" while a new disk device becomes "Available".
     # Go find all those new disks, which have the same parent
     # and address, but different name.  Add them to the global
     # list of ghost disks to be removed.
     case $disktype in
  FSCSI)
      ghostlist=${ghostlist:+"$ghostlist "}$(cl_fscsighost $disk)
    ;;
  
  SCSIDISK)
      ghostlist=${ghostlist:+"$ghostlist "}$(odmget -q "parent = $parent AND \
   name != $disk AND \
   location = $(lsdev -Cc disk -l $disk -F 'location')" CuDv | \
   sed -n 's/^.*name ="\(.*\)".*/\1/p')
    ;;
     esac 
    
     #
     # Add this disk to the list of those that must be made
     # available, after reserves are broken and ghosts
     # removed.
     #
     disklist=${disklist:+"$disklist "}"MKDEV.${disk}"
 fi       # End if disk not available
    done       # End loop through all given disks
    #
    # Break the reserve - pass the given list of disks having the given parent
    #
    case $disktype in
 FSCSI )
     #
     # Perform a LUN reset on a SCSI-3 device
     #
     cl_fscsilunreset $parent $disks
   ;;
 SCSIDISK)
     #
     # Perform a LUN reset on a SCSI-2 device, if the device supports
     # it.  Otherwise, do a target reset.
     #
     cl_pscsilunreset $parent $disks
   ;;
 ISCSI )
     #
     # Perform a LUN reset on an iSCSI device
     #
     cl_iscsilunreset $parent $disks
   ;;
 SCSIRAID )
     #
     # Tell the SCSI RAID adapter that this node is going to be
     # primary
     #
     if [[ -x /usr/bin/sisraidmgr ]] ; then
  #
  #   Talk to the right ioa
  #
  SISIOA=$(lsdev -C -l $parent -F parent)
  #
  #   Make this adapter primary
  #
  if ! /usr/bin/sisraidmgr -X -l $SISIOA -o '1'
  then
      #
      # Log any failure, but keep going
      #
      cl_log 999 "$PROGNAME: sisraidmgr failed for $SISIOA" $PROGNAME $SISIOA
  fi
     fi
     #
     # Perform a LUN reset for each disk on the adapter
     #
     for disk in $disks ; do
  cl_flutereset $disk
     done
   ;;
    
    esac
}
 
###############################################################################
#
# Name: is_disk_reserved
#    Returns:
#       0 If disk does NOT have reservation against it
#       1 If disk has reservation against it
#       2 If scdiskutil failed for some other reason
#
# Check to see if a disk is reserved by a system through use of the SCIOTUR
# (Test Unit Ready) ioctl.
#
# Arguments: diskname
#
# Environment: None
#
###############################################################################
function is_disk_reserved
{
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x 
    typeset disk
    disk=$1
    #
    # scdiskutil retries 6 times, if necessary.
    # Call it only once.
    #
    scdiskutil -t /dev/$disk
    TUR_RC=$?
    if (( $TUR_RC == 0 ))
    then
        return 0
 
    elif (( $TUR_RC == 24 ))
    then
        # 24 is SC_RESERVATION_CONFLICT - disk has a reserve on it
        return 1
    else
        # scdiskutil -t failed for some other reason
        return 2
    fi
}

###############################################################################
#
# Name: breakres
# Returns:
#  0 If reservation has been broken
#  -1 If anything goes wrong
#
# Break and, if appropriate, re-establish the reservation on a disk
#
# Arguments:    1. Owning adapter - e.g., "scsi0"
#               2. disk type - e.g., "SCSIDISK"
#               3. disk name - e.g., "hdisk333"
#
# Environment: None
#
###############################################################################
function breakres
{
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x
    # Pick up the passed disk name
    typeset parent disktype disk
    parent=$1
    disktype=$2
    disk=$3
    # Process by disk type
    case $disktype in
 SSA | FCPARRAY )
     #   Perform a target reset, using openx(hdisk, ,SC_FORCED_OPEN)
     #  Check to see if the disk is currently reserved
     is_disk_reserved $disk
     isdr_rc=$?
           
     if (( $isdr_rc == 0 )) ; then
      # If no reserve is in place,
  # claim the reset worked
      rsrv_rc=0
     elif (( $isdr_rc == 1 )) ; then
  # There is a reserve in place.  Break it and establish
  # our own reserve.
  # Note: cl_scdiskrsrv resets AND reserves device
  cl_scdiskrsrv /dev/$disk
  rsrv_rc=$?
     elif (( $isdr_rc == 2 )) ; then
         # Test unit ready failed for unknown reason, let's
         # try a reset to ready the disk
  cl_scdiskreset /dev/$disk
  rsrv_rc=$?
     fi
     if (( $rsrv_rc == 255 )) ; then
         cl_log 205 "$PROGNAME: Failed reset/reserve for device: $disk." $PROGNAME $disk
     fi
   ;;
 DPO )
            #
            #   Special processing for vpath disks, which may have a
            #   persistent reserve in place.
            #
            if [[ -x /usr/sbin/lquerypr ]] ; then
                #
                #       If support is available to directly query the
                #       persistent reserve, do so.
                #
                [[ "$VERBOSE_LOGGING" == "high" ]] && Vflags='-v -V'
                lquerypr $Vflags -h /dev/$disk
                query_rc=$?
                case $query_rc in
                    0 | 3 )
                        #       Either this node has a persistent reserve on
                        #       this device, or the device is already open
                        #       (and need not be further checked)
                        rsrv_rc=0
                    ;;
                    1 )
                        #       This device has a persistent reserve put in
                        #       place by another node.  Pre-empt that with our
                        #       key.
                        lquerypr $Vflags -p -h /dev/$disk
                        rsrv_rc=$?
                        if (( $rsrv_rc == 2 )) ; then
                            #   pre-empt can fail if the ESS is sufficiently
                            #   dazed and confused, or is being pounded on by
                            #   the malicious, or generally having problems
                            #   with its queues.  Use a bigger hammer.
                            cl_vpathreset /dev/$disk
                            rsrv_rc=$?
                        fi
                    ;;
                    * )
                        #       For some reason, the query persistent reserve
                        #       function isn't working.  Resort to cruder
                        #       methods.
                        cl_vpathreset /dev/$disk
                        rsrv_rc=$?
                    ;;
                esac
               
            else
                #   Check to see if we can read the disk directly.  If so,
                #   there's nothing more to do.  Otherwise, attempt to break
                #   the reserve and re-establish the reservation.
                #
                cl_vpathreset /dev/$disk
                rsrv_rc=$?
            fi
   ;;
        FLUTE )
            #
            #   For Flute, check to see if the device can be read; and if not
            #   break the reserve
            #
            cl_flutereset /dev/$disk
            rsrv_rc=$?
          ;;
 ARRAY )
     #   7135
     is_disk_reserved $disk
     isdr_rc=$?
     if (( $isdr_rc == 0 )) ; then
  # If there is no reserve, we should be able to read the disk
  # directly and we're done.
  if cl_querypv -q /dev/$disk ; then
      rsrv_rc=0
  else
      # It was not possible to read the disk.  The most likely
      # cause is that a persistent reserve is held by another
      # node.  An SC_FORCED_OPEN will take care of that.
      cl_scdiskreset /dev/$disk
      rsrv_rc=$?
  fi
     elif (( $isdr_rc == 1 )) ; then
  # There is a reserve in place.  Break it and establish
  # our own reserve.
  # Note: cl_scdiskrsrv resets AND reserves device
  cl_scdiskrsrv /dev/$disk
  rsrv_rc=$?
  
     elif (( $isdr_rc == 2 )) ; then
  # Test unit ready failed for unknown reason, let's
  # try a reset to ready the disk
  cl_scdiskreset /dev/$disk
  rsrv_rc=$?
     fi
     if (( $rsrv_rc == 255 )) ; then
  cl_log 205 "$PROGNAME: Failed reset/reserve for device: $disk." $PROGNAME $disk
     fi
   ;;
 SCSIDISK | FSCSI | ISCSI )
     # Processing for this disk type is done in the function
     # 'make_disktypes_available'.  This routine should not be called
     # for these cases.
     :
   ;;
 * )
     #  Anything else, we don't have special support for
     #  So, try the straight forward approach.  This will
     #  work if the disk device driver supports openx(SC_FORCED_OPEN)
     #  and ioctl(SCIOTUR)
     is_disk_reserved $disk
     isdr_rc=$?
     if (( $isdr_rc == 0 )) ; then
      # If no reserve is in place,
  # claim the reset worked
      rsrv_rc=0
     elif (( $isdr_rc == 1 )) ; then
  # There is a reserve in place.  Break it and establish
  # our own reserve.
  # Note: cl_scdiskrsrv resets AND reserves device
  cl_scdiskrsrv /dev/$disk
  rsrv_rc=$?
     elif (( $isdr_rc == 2 )) ; then
         # Test unit ready failed for unknown reason, let's
         # try a reset to ready the disk
  cl_scdiskreset /dev/$disk
  rsrv_rc=$?
     fi
     if (( $rsrv_rc == 255 )) ; then
         cl_log 205 "$PROGNAME: Failed reset/reserve for device: $disk." $PROGNAME $disk
     fi
   ;;
    esac
    return $rsrv_rc
}

###############################################################################
#
# Name:  vpath_dup
#
# Function: Given a vpath, look at the underlying hdisks
#  * collect any ghost disks for later removal
#  * if any underlying hdisks are not 'Available', save their
#    names for later processing by make_disktypes_available
#
# Arguments: vpath
#
# Environment: VERBOSE_LOGGING, PATH, fscarray, pscarray
#
###############################################################################
function vpath_dup
{
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x
    typeset vpath v_disklist hdiskvalue u_disk u_parent
    vpath=$1
    #
    #   For vpath there should be multiple available hdisks for each vpath.
    #   Pick up the disk names from ODM.
    #
    v_disklist=$(odmget -q "name = $vpath AND attribute = active_hdisk" CuAt |
  sed -n 's/^.*value = "\(.*\)".*/\1/p')
    for hdiskvalue in $v_disklist ; do
 #
 #       For each of the hdisks underlying the vpath disk, make sure
 #       that there are no ghost disks.  First, extract the hdisk name.
 #
 u_disk=${hdiskvalue%%/*}
 #
 #  Check to see if the underlying disk is available.  If not, it
 #  will be made so. If the underlying disk is available, do not
        #  add it to the array which will be passed to the 'make_disktypes_available'
        #  function.
 #
 if [[ -n $(lsdev -Cc disk -l $u_disk -S A -F 'status') ]]
        then
            continue
 else
     # 
     # We have determined that the underlying disk is not available.
     # Vpath disks can be built on top of either parallel or fibre
     # SCSI.  Figure out which disk is this, and add it to the
     # appropriate list of disks to be processed.
     #
     u_parent=$(lsdev -Cl $u_disk -F parent)
     if [[ ${u_parent} == fscsi* ]] ; then
  fscarray[${u_parent}]=${fscarray[${u_parent}]:+"${fscarray[${u_parent}]} "}${u_disk}
     else  # Assume it's a scsi* parent
  pscarray[${u_parent}]=${pscarray[${u_parent}]:+"${pscarray[${u_parent}]} "}${u_disk}
     fi
        fi
    done   #   all hdisks in this vpath
}

###############################################################################
#
#  Name: makedev
#
#  Run the mkdev command on a given disk, up to four times, to make it
#  available
#
#  Returns: return code from mkdev command
#
#  Arguments: disk name - e.g., 'hdisk108'
#
#  Environment: None
#
###############################################################################
function makedev {
    typeset disk
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x
    disk=$1
    # Try up to four times to make the disk available by running the appropriate
    # config method
    [[ $VERBOSE_LOGGING != high ]] &&
 cl_echo 641 "$PROGNAME: Attempting to make disk device: $disk." $PROGNAME $disk
    for ((i=0 ; i<4 ; i++)) ; do
 if mkdev -l $disk ; then     # if it worked
     break       # can quit now
 fi
    done
}

###############################################################################
#
#  Name: oemghostdisks
#
#  Invoke the OEM supplied method - or the specified internal built in method
#  to find all the ghost disks for a given disk
#
#  Returns; A list of hdisk names that are ghosts for the given disk,
#               written to standard out
#
#  Arguements:  Method name - this is either the path name for the OEM
#         supplied method, or the identifier for an
#         internal build in method
#
#  disk name - e.g., hdisk43
#
###############################################################################
function oemghostdisks {
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x
    typeset findghost disk msg
    findghost=$1
    disk=$2
    msg=$(dspmsg scripts.cat 6581 "Custom method %s invoked for disk %s to perform %s" $findghost $disk "ghostbusting")
    logger -t "HACMP for AIX" $msg
    case $findghost in
 SCSI2 )
     loc=$(lsdev -Cc disk -l $disk -F 'location')
     odmget -q "parent = $parent AND \
         name != $disk AND \
         location = $loc" CuDv | sed -n 's/^.*name = "\(.*\)".*/\1/p'
 ;;
 SCSI3 )
     cl_fscsighost $disk
 ;;
 * )
     $findghost $disk
 ;;
    esac
}

###############################################################################
#
#  Name: oemcheckres
#
#  Invoke the OEM supplied method - or the specified internal built in method
#  to check if a reserve is held on a disk (and hence must be broken)
#
#  Returns: 0 If disk does NOT have reservation against it
#  1 If disk has reservation against it
#
#  Arguements:  Method name - this is either the path name for the OEM
#         supplied method, or the identifier for an
#         internal build in method
#
#  disk name - e.g., hdisk43
#
###############################################################################
function oemcheckres {
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x
    typeset checkres disk msg
    checkres=$1
    disk=$2
    msg=$(dspmsg scripts.cat 6581 "Custom method %s invoked for disk %s to perform %s " $checkres $disk "checkreserves")
    logger -t "HACMP for AIX" $msg
    case $checkres in
 SCSI_TUR )
     is_disk_reserved $disk
 ;; 
 * )
     $checkres $disk
 ;;
    esac
}

###############################################################################
#
#  Name: oembreakres
#
#  Invoke the OEM supplied methods - or the specified internal built in
#  methods - to check for a reserve on a disk, and break it if its there.
#
#  Returns: any return code from the method
#
#  Arguements:  Break Reserve Method name - this is either the path name for
#                             the OEM supplied method, or the identifier for an
#         internal build in method
#
#   Check Reserve Method Name
#
#  parent - name of the adapter owning the disk - e.g., scsi3
#
#  disk name - e.g., hdisk43
#
###############################################################################
function oembreakres {
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x
    typeset breakres checkres parent disk msg
    breakres=$1
    checkres=$2
    parent=$3
    disk=$4
    msg=$(dspmsg scripts.cat 6581 "Custom method %s invoked for disk %s to perform %s" $breakres $disk "breakres")
    logger -t "HACMP for AIX" $msg
    oemcheckres ${checkres} $disk
    ckres_rc=$?
    if (( $ckres_rc != 0 )) ; then
 case $breakres in
     TARGET )
  cl_scdiskrsrv /dev/$disk
     ;;
     PSCSI )
                oem_disktype=SCSIDISK
                pscarray[${parent}]=${pscarray[${parent}]:+"${pscarray[${parent}]} "}${disk}
     ;;
     FSCSI )
                oem_disktype=FSCSI
                fscarray[${parent}]=${fscarray[${parent}]:+"${fscarray[${parent}]} "}${disk}
     ;;
    
     * )
      $breakres $parent $disk
     ;;
 esac
    else
 return $ckres_rc
    fi
}

###############################################################################
#
#  Name: oemmakedev
#
#  Invoke the OEM supplied method - or the specified internal built in method
#  to make a disk available
#
#  Returns: any return code from the method
#
#  Arguements:  Method name - this is either the path name for the OEM
#         supplied method, or the identifier for an
#         internal build in method
#
#  disk name - e.g., hdisk43
#
###############################################################################
function oemmakedev {
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x
    typeset makedev disk msg
    makedev=$1
    disk=$2
    msg=$(dspmsg scripts.cat 6581 "Custom method %s invoked for disk %s to perform %s" $makedev $disk "makdev")
    logger -t "HACMP for AIX" $msg
    case $makedev in
 MKDEV )
     makedev $disk
 ;; 
 * )
     $makedev $disk
 ;;
    esac
}

###############################################################################
#
#   Name: make_disk_available
#
#   Function: Given a disk name, determine its type and state, and invoke
#     the appropriate routines to
#   * break any reserves
#   * remove any ghost disks
#   * make it 'Available'
#
#   Input: disk name - e.g., hdisk43
#
#   Output: None
#
###############################################################################
function make_disk_available
{
   [[ "$VERBOSE_LOGGING" == "high" ]] && set -x
   disk=$1
    # Determine the owning adapter.  This will be used to determine the
    # disk type.
    parent=$(lsdev -Cc disk -l $disk -F parent)
    PdDvLn=$(lsdev -Cc disk -l $disk -F PdDvLn)
    #
    # Do not check Remote Physical Volume Client disk.
    # If PdDvLn=disk/remote_disk/rpvclient there is no parent.
    #
    if [[ ${PdDvLn} != 'disk/remote_disk/rpvclient' ]]
    then
       if [[ -z "$parent" || -z "$PdDvLn" ]] ; then
          cl_log 35 "$PROGNAME: Undefined disk device $disk. (May have been duplicate)." $PROGNAME $disk
          # update resource manager with the status
          cl_RMupdate resource_error $disk $PROGNAME
          continue
       fi
    fi
    # Determine the disk type.  The mechanism used to break the reserves is
    # dependent on the type.
    disktype="UNKNOWN"
    # First, check to see if this disk should be treated as equivalent to
    # one of the known types.  This check is done first, because it is more
    # specific than the "known types" checking below, which is primarily
    # based on owning adapter type.
    OEMDISKTYPES="/etc/cluster/disktype.lst"
    #   The format of this file is
    #  
    #   E.g.,
    #   disk/fcal/HAL9000       FSCSI
    #
    #   will cause this routine to treat such as device as 'fibre SCSI'
    if [[ -r $OEMDISKTYPES && -s $OEMDISKTYPES ]] ; then
        PdDvLn=$(odmget -q "name = $disk" CuDv | sed -n 's/^.*PdDvLn = "\(.*\)".*/\1/p')
        if oemdisktype=$(grep -w "^${PdDvLn}" $OEMDISKTYPES | cut -f2) ; then
           if [[ ${oemdisktype} == @(SCSIDISK|SSA|FCPARRAY|ARRAY|FSCSI|FLUTE) ]] ; then
                disktype=$oemdisktype
           fi
        fi
    fi
    #
    #   Check to see if the disk has custom methods.
    #
    parallel='false'
    makedev='MKDEV'
    checkres='SCSI_TUR'
    breakres=''
    if [[ ${disktype} == 'UNKNOWN' ]] ; then
        #    Read the custom methods from the HACMPdisktype ODM class. This
        #    will instatiate the following variables:
        #       ghostdisks - routine to find ghost disks
        #       checkres   - routine to check is a reserve is held
        #       breakres   - routine to break reserves
        #       parallel   - 'true' => can break reserves in parallel
        #       makedev    - routine to make device available
        eval $(odmget -q "PdDvLn = $PdDvLn" HACMPdisktype | sed -n 's/ = /=/p')
        if [[ -n $breakres ]] ; then
            disktype="OEM"
        fi
    fi
    #
    # Check for disk type Remote Physical Volume Client
    #
    if [[ ${disktype} == 'UNKNOWN' ]]
    then
       if [[ ${PdDvLn} == 'disk/remote_disk/rpvclient' ]]
       then
          disktype="RPV_CLIENT"
       fi
    fi
    if [[ ${disktype} == 'UNKNOWN' ]] ; then
     #
 # Normal disk type checking, in lieu of any overrides or added
 # customizations
 #
 case $parent in
     scsi* | vscsi* )
  disktype="SCSIDISK"     # parallel SCSI - SCSI-2
       ;;
     ssar )
  disktype="SSA"
       ;;
     dar* )
  if [[ -n $(odmget -q "name = $disk AND PdDvLn = disk/fdar/array" CuDv) ]] ; then
      #   Either Dolphin or Flute.  They behave differently, but have
      #   nearly identical ODM entries.
      daclist=$(odmget -q "name = $parent AND attribute = all_controller" CuAt | grep 'value =' | cut -f2 -d'"')
      if [[ -z $daclist ]] ; then
   disktype="FCPARRAY"
      else
   #       Check for IBM microcode, necessary to work with reset
   #       logic later
   firstdac=${daclist%%,*}
   if LANG=C lscfg -vl $firstdac | grep -q 'Manufacturer\.*\.IBM' ; then
       disktype="FLUTE"
   fi
      fi
  else
      disktype="ARRAY"
  fi
       ;;
     dpo )
  disktype="DPO"      # SDD vpath disks
       ;;
     fscsi* )
  disktype="FSCSI"     # fibre SCSI - SCSI-3
       ;;
     isc* )
  disktype="ISCSI"     # iSCSI
       ;;
     sisraid* )
  disktype="SCSIRAID"     # SCSI RAID adapters
       ;;
     * )
  # The following code has been duplicated above under parent of
  # dar as it was apparent from the field that the parent in the
  # case of FLUTE at least, is a dar.  Since we were unable to
  # determine for sure if the parent of a Dolphin is also a dar
  # or possibly something else, the code has been left here as
  # well to be on the safe side.
  if [[ -n $(odmget -q "name = $disk AND PdDvLn = disk/fdar/array" CuDv) ]] ; then
      #   Either Dolphin or Flute.  They behave differently, but have
      #   nearly identical ODM entries.
      daclist=$(odmget -q "name = $parent AND attribute = all_controller" CuAt | grep 'value =' | cut -f2 -d'"')
      if [[ -z $daclist ]] ; then
   disktype="FCPARRAY"
      else
   # Check for IBM microcode, necessary to work with reset
   # logic later
   firstdac=${daclist%%,*}
   if LANG=C lscfg -vl $firstdac | grep -q 'Manufacturer\.*\.IBM' ; then
       disktype="FLUTE"
   fi
      fi
  fi
       ;;
 esac
    fi
    # Check to see if the device is available. We can tell this by
    # calling lsdev with the logical name of the device (-l) and
    # asking to see the devices that have a status of Available (-S A)
    # we limit the output to the status field (-F "status).
    if [[ -n $(lsdev -Cc disk -l $disk -S A -F 'status') ]] ; then
 #   Break the reserve on an "available" disk.  Where supported, do so in
        #   a background task that will run asynchronously to this one.
        case $disktype in
            SSA )
                #
                #   SSA and vpath can run in parallel
                #
  parallel='true'
                breakres $parent $disktype $disk &
            ;;
           DPO ) 
  #
                #   Clean up any ghost disks for underlying hdisks,
  #   and note the vpath disk for processing later
  #
  vpath_dup $disk
  dpolist=${dpolist:+"$dpolist "}${disk}
            ;;
            OEM )
                #
                #   For OEM methods, the method provider indicates whether
                #   parallel processing is possible.
                #
                if [[ $parallel == 'true' ]] ; then
                    oembreakres $breakres $checkres $parent $disk &
                else
                    oembreakres $breakres $checkres $parent $disk
                fi
            ;;
            FSCSI )
  #
  #   Collect the fibre SCSI disks by owning adapter, for
  #   later processing in parallel.
  #
                fscarray[${parent}]=${fscarray[${parent}]:+"${fscarray[${parent}]} "}${disk}  
            ;;
     ISCSI )
  #
  #   Collect the ISCSI disks by owning adapter, for
  #   later processing in parallel. 
  #
                iscarray[${parent}]=${iscarray[${parent}]:+"${iscarray[${parent}]} "}${disk}  
            ;;
     SCSIDISK ) 
  #
  #   Collect the parallel SCSI disks by owning adapter, for
  #   later processing in parallel
  #
                pscarray[${parent}]=${pscarray[${parent}]:+"${pscarray[${parent}]} "}${disk}  
            ;;
            RPV_CLIENT )
                #
                # Do nothing if Remote Physical Volume Client disk is available.
                #
              ;;
     SCSIRAID )
  #
  #   Collect the RAID scsi disks by owning adapter, for later
  #   processing by adapter
  #
                rscarray[${parent}]=${rscarray[${parent}]:+"${rscarray[${parent}]} "}${disk}  
              ;;
            * )
                #
                #   Everything else has to be serial
                #
                breakres $parent $disktype $disk
            ;;
        esac
    else
 # If the disk is not available, determine if disk is defined.
 # If it is not then there is nothing we can do since we
 # don't have any information on the disk.
 if [[ -z $(lsdev -Cc disk -l $disk -S D -F 'status') ]]
 then
     # If the disk is not even defined then we can't recover
     cl_log 35 "$PROGNAME: Undefined disk device $disk. (May have been duplicate)." $PROGNAME $disk
     continue
 fi
 # At this point we know the disk is Defined
 # Process by disk type
 case $disktype in
     SSA )
  # Reconfigure the defined disk, and make it available
  makedev $disk
  #  Check to see if it worked
  if [[ -n $(lsdev -Cc disk -l $disk -S A -F 'status') ]] ; then
     #  Disk is now available; go break reserves
     breakres $parent "SSA" $disk &
  fi
       ;;
         
     DPO )
  #
  #   Clean up any ghost disks for underlying disks, and add
  #   this vpath device to the list to be made available and
  #   have reserves broken.
  # 
  vpath_dup $disk
  disklist=${disklist:+"$disklist "}"MKDEV.${disk}"
  dpolist=${dpolist:+"$dpolist "}${disk}
       ;;
     SCSIDISK )
  #
  #   Collect the parallel SCSI disks by owning adapter, for
  #   later processing in parallel
  #
  pscarray[${parent}]=${pscarray[${parent}]:+"${pscarray[${parent}]} "}${disk}
             ;;
        
            FSCSI )
  #
  #   Collect the fibre SCSI disks by owning adapter, for
  #   later processing in parallel. 
  #
  fscarray[${parent}]=${fscarray[${parent}]:+"${fscarray[${parent}]} "}${disk}
             ;;
     ISCSI )
  #
  #   Collect the ISCSI disks by owning adapter, for
  #   later processing in parallel. 
  #
                iscarray[${parent}]=${iscarray[${parent}]:+"${iscarray[${parent}]} "}${disk}  
            ;;
     SCSIRAID )
  #
  #   Collect the RAID scsi disks by owning adapter, for later
  #   processing by adapter
  #
                rscarray[${parent}]=${rscarray[${parent}]:+"${rscarray[${parent}]} "}${disk}  
              ;;
     ARRAY )
        # It is possible for the original disk device to become
  # "Defined" while the new disk device becomes "Available".
  # This needs to be corrected. Get the connection address for
  # the device and check to see if there is another device
  # available at this address. If there is then delete it.
  loc=$(lsdev -Cc disk -l $disk -F 'location')
  duplist=$(odmget -q "parent = $parent AND \
     name != $disk AND \
     location = $loc" CuDv | \
        sed -n 's/^.*name = "\(.*\)".*/\1/p')
  brokeres='false'
         for ghostdisk in $duplist ; do
     # The reason we reserve rather than simply reset is
     # because a device must be reserved by another node
     # during boot of this node for the disk to be unavailable.
     if [[ $brokeres == 'false' && \
           -n $(lsdev -Cc disk -l $ghostdisk -S A -F 'status') ]] ; then
         breakres $parent $disktype $ghostdisk
         if (( $? == 0 || $? == 1 )) ; then
            brokeres='true'
         fi
     fi
     
     [[ $VERBOSE_LOGGING != high ]] &&
         cl_echo 640 "$PROGNAME: Removing duplicate disk device: $ghostdisk." $PROGNAME $ghostdisk
     rmdev -l "$ghostdisk" '-d'
  done
  # Reconfigure the defined disk, and make it available
  makedev $disk
  if [[ $brokeres == 'false' && \
        -n $(lsdev -Cc disk -l $disk -S A -F 'status') ]] ; then
      #   If the reserve was not broken using the available
      #   duplicate above, break it here
      breakres $parent $disktype $disk
  fi
       ;;
     FCPARRAY | FLUTE )
  # FCPARRAY and Flute disks aren't supposed to get ghost disks,
                # so let's just make it available, and then break any
  # reservations.
  makedev $disk
  # Break the reserve on an "available" disk, this is a special
  # case for fcparray only.
  if [[ -n $(lsdev -Cc disk -l $disk -S A -F 'status') ]] ; then
     breakres $parent $disktype $disk
  fi
           ;;  
     OEM )
                #    Find the ghost disks for the given disk
                duplist=$(oemghostdisks ${ghostdisks} $disk)
                if (( $? != 0 )) ; then
                    #   If something goes wrong with finding ghost disks, skip
                    #   this disk and go on to the next
                    continue
                fi
                brokeres='false'
                for ghostdisk in $duplist ; do
                   #    Break the reserve using this available ghost disk, so
                   #    that when we go to make the real disk available, the
                   #    PVID can be read.
                   if [[ $brokeres == 'false' && \
                         -n $(lsdev -Cc disk -l $ghostdisk -S A -F 'status') ]] ; then
                         if [[ $parallel == 'true' ]] ; then      
                            oembreakres $breakres $checkres $parent $ghostdisk &
                         else                                    
                            oembreakres $breakres $checkres $parent $ghostdisk
                            if (( $? != 0 )) ; then              
                                #    If for some reason, breaking the reserve
                                #    failed, skip this disk and go on to the
                                #    next                        
                                continue                         
                            fi                                   
                         fi                                      
                         brokeres='true'                         
                         #      Because we may have back grounded the process
                         #      of breaking the reserve, the remaining steps
                         #      of deleting the ghost disk profile and making
                         #      the real disk available have to be queued up,
                         #      and done when that finishes.     
                         disklist="$disklist ${makedev}.${disk}" 
                   fi                                            
     ghostlist=${ghostlist:+"$ghostlist "}${ghostdisk}
                done                                             
                                                                 
                if [[ $brokeres == 'false' ]] ; then              
                    #   If we've not queued up this processing above, now try
                    #   and make the real disk available.        
                    oemmakedev $makedev $disk                    
                    if [[ -n $(lsdev -Cc disk -l $disk -S A -F 'status') ]] ; then
                        if [[ $parallel == 'true' ]] ; then       
                            oembreakres $breakres $checkres $parent $disk &
                        else                                     
                            oembreakres $breakres $checkres $parent $disk
                        fi                                       
                    else                                         
                        # We had a problem, exit failure         
                                                                 
                        cl_log 31 "$PROGNAME: Unable to make device $disk available.  Check hardware connections." $PROGNAME $disk
                    fi                                           
                fi                                               
            ;;                                                   
            RPV_CLIENT )
                #
                #  Do not do makedev for a Remote Physical Volume Client disk.
                #  The makedev for a Remote Physical Volume Client disk is
                #  done in the predisk_available Replicated Resource Method.
                #
              ;;
   * )
         #   Whatever this kind of disk is, there is no special support
  #   for it.  So, treat it similar to a generic SCSI-2 disk
  #   and hope for the best.
  loc=$(lsdev -Cc disk -l $disk -F 'location')
  #   First, look for obvious duplicates
  duplist=$(odmget -q "parent = $parent AND \
     name != $disk AND \
     location = $loc" CuDv | \
        sed -n 's/^.*name = "\(.*\)".*/\1/p')
  brokeres='false'
         for ghostdisk in $duplist; do
     #   Attempt to break any outstanding reserve on this device
     #   because a device must be reserved by another node
     #   during boot of this node for the disk to be unavailable
     if [[ $brokeres == 'false' && \
           -n $(lsdev -Cc disk -l $ghostdisk -S A -F 'status') ]] ; then
         breakres $parent $disktype $ghostdisk
         if (( $? == 0 || $? == 1 )) ; then
            brokeres='true'
         fi
     fi
      ghostlist=${ghostlist:+"$ghostlist "}${ghostdisk}
  done
  # Reconfigure the defined disk, and make it available
  makedev $disk
  if [[ $brokeres == 'false' && \
        -n $(lsdev -Cc disk -l $disk -S A -F 'status') ]] ; then
      #   If the reserve was not broken using the available
      #   duplicate above, break it here
      breakres $parent $disktype $disk
  fi
     ;;
 esac
    fi
}

###############################################################################
#
#  Name:        verify_disk_availability
#
#  This function verifies whether the disk came up.  If not, an appropriate
#  error message is written.
#
#  Returns:
#
#  Arguments:
#               disk name - e.g., hdisk43
#
###############################################################################
function verify_disk_availability
{
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x
    typeset disk=$1
    #
    # Do not do this check for a Remote Physical Volume Client
    # disk.  The makedev for a Remote Physical Volume Client disk
    # is done in the predisk_available Replicated Resource Method.
    #
    PdDvLn=$(lsdev -Cc disk -l $disk -F PdDvLn)
    if [[ ${PdDvLn} == 'disk/remote_disk/rpvclient' ]]
    then
       return 0
    fi
    if [[ -z $(LANG=C lsdev -Cc disk -l $disk -S A -F 'status') ]] ; then
 #   We were unable to bring this disk on line.  Note the problem,
 #   and the non-functional state of the disk
 cl_log 31 "$PROGNAME: Unable to make device $disk available.  Check hardware connections." $PROGNAME $disk
    fi
    #
    # Note that the resource manager is not updated with the status of the
    # individual disks.  This is because loss of a disk is not necessarily
    # severe enough to stop the event - varyonvg may still work.
    #
}

###############################################################################
#
#  Main routine
#
###############################################################################
PROGNAME=${0##*/}
export PATH="$(/usr/es/sbin/cluster/utilities/cl_get_path all)"
[[ "$VERBOSE_LOGGING" == "high" ]] && set -x
[[ "$VERBOSE_LOGGING" == "high" ]] && version="1.2.5.51"
[[ "$VERBOSE_LOGGING" != "high" ]] && cl_echo 33 "Starting execution of $0 with parameters: $*\n" $0 "$*"
HA_DIR="es"
#
#   This routine can be invoked from various C-SPOC flows, in which its
#   inappropriate to do cl_RMupdate.  Such processing is skipped if '-s' is
#   specified.
#
if [[ "$1" == "-s" ]]
then
    shift
    JUST_DISKS=true      # No resource manager updates needed
else
    JUST_DISKS=false      # Normal event processing
fi
ghostlist=''       # Ghost disks to be deleted
disklist=''       # Disks to be made available
#
#   Global variables to define associative arrays for types FSCSI SCSIDISK
#   ISCSI: This will be used to collect the disks by owning adapter, to handle
#   in parallel.  The index is the adapter name, the element is a list of
#   disks on that adapter.  E.g.,
#  
# fscarray[fscsi0]="hdisk11 hdisk22 hdisk33"
#
typeset -A fscarray      # Array for type FSCSI
typeset -A pscarray      # Array for type SCSIDISK
typeset -A iscarray      # Array for type ISCSI
typeset -A rscarray      # Array for type SCSIRAID
#
#   List of vpath devices to be processed after the underlying hdisks are
#   cleaned up
#
typeset dpolist       # Array for type dpo
#
#   This routine can be invoked in two different fashions:
# - resource groups processed serially
#     A list of disks are passed as arguments
# - resource groups are processed in parallel
#     Resource groups, their disks, and owning
#     volume groups are passed as environment
#     variables
#
if [[ $JUST_DISKS == false && -n $JOB_TYPE && $JOB_TYPE != "GROUP" ]] ; then
    #   
    # Resource groups processed in parallel
    #
    PROC_RES=true      # implies JUST_DISKS is false
    ON_LIST=$(print $(lsvg -L -o 2>/var/hacmp/log/lsvg.err))
    #
    # Get a sorted list of the volume groups, and add any that are vary'd on
    # in passive mode to the list of volume groups that are on line.  The
    # disks for such volume groups are already locally accessable, so do not
    # need to have reserves broken.
    #
    SORTED_VGS=$(
      IFS=:,  set -- $VOLUME_GROUPS ; print $* | \
      tr ' ' '\n' | sort -u
  )
    # If a volume group is vary'd off, lsvg -L produces no output
    PASSIVE_VGS=$(
      # If a volume group is vary'd off, lsvg -L produces no output
      LANG=C lsvg -L $SORTED_VGS 2>/dev/null | \
      sed -n 's/VOLUME GROUP: *\([^ ]*\).*/\1/p'
  )
    ON_LIST="$ON_LIST $PASSIVE_VGS"
    #
    # Process by resource group
    #     RESOURCE_GROUPS - space separated list of resource groups
    #     HDISKS - list of disks for a resource group
    #     - comma separated list of disks within a resource group
    #     - colon separated lists of disks for each resource group
    #     VOLUME_GROUPS - list of owning volume group (if any) for each
    #       hdisk.  Same pattern of comma and colon separated
    #       lists as for HDISKS
    #     e.g. -
    #  RESOURCE_GROUPS="curley larry moe shemp"
    #  HDISKS="hdisk11,hdisk22:hdisk21,hdisk31:hdisk99:hdisk101,hdisk1"
    #  VOLUME_GROUPS="vg01,vg01:vg02,vg02,::vg03,vg0"
    #
    _HDISKS=$HDISKS
    _VOLUME_GROUPS=$VOLUME_GROUPS
    for GROUPNAME in $RESOURCE_GROUPS ; do
 
 #
 #   Tell the resource manager we're about to bring these disks online
 #
 export GROUPNAME
 ALLDISKS="All_disks"
 cl_RMupdate resource_acquiring $ALLDISKS $PROGNAME
 #
 #   Extract the disk list and corresponding volume group list for
 #   the disks for this resource group
 #
 print $HDISKS | IFS=':' read LIST_OF_HDISKS_FOR_RG HDISKS
 print $VOLUME_GROUPS | IFS=':' read LIST_OF_VOLUME_GROUPS_FOR_RG VOLUME_GROUPS
 for disk in $(IFS=', ' set -- $LIST_OF_HDISKS_FOR_RG ; print $*)
 do
     #
     # Extract the name of the volume group that owns this disk
     #
     print $LIST_OF_VOLUME_GROUPS_FOR_RG | IFS=', ' read vg LIST_OF_VOLUME_GROUPS_FOR_RG
     #
     # If the disk is in a volume group that is already vary'd on, or
     # vary'd on in passive mode, the disks are aleady locally
     # accessable, so there is nothing to do.
     #
            if  [[ -n $vg && $ON_LIST == ?(* )$vg?( *) ]]
            then
                continue
     #
     # Otherwise, go make sure the disk is accessable and available
     #
            else
  make_disk_available $disk
     fi
 done
    done
   
    #
    # Restore resource group list
    #
    HDISKS=$_HDISKS
    VOLUME_GROUPS=$_VOLUME_GROUPS
    export GROUPNAME=$RESOURCE_GROUPS
else
    #
    # If not called from process_resources, arguments are needed on
    # the command line
    #
    PROC_RES=false
   
    if (( $# == 0 )) ; then  # no disks passed
 cl_echo 34 "$PROGNAME usage: cl_disk_available hdisk ...\n" $PROGNAME
 exit 2
    fi
    if [[ $JUST_DISKS == true ]] ; then
 #
 #   If not called during event processing, skip the resource manager
 #   update.
 #
 ALLDISKS="All_disks"
 cl_RMupdate resource_acquiring $ALLDISKS $PROGNAME
    fi
    #
    # Requests from serially processed resource groups
    #
    for disk in $*
    do
 make_disk_available $disk
    done
fi
#
#   Take care of all the fibre scsi disks, doing all those associated
#   with a specific adapter at one time
#
for parent in ${!fscarray[@]} ; do
    make_disktypes_available $parent FSCSI ${fscarray[$parent]}
done
#
#   Take care of all the parallel scsi disks, doing all those associated
#   with a specific adapter at one time
#
for parent in ${!pscarray[@]} ; do
    make_disktypes_available $parent SCSIDISK ${pscarray[$parent]}
done
#
#   Take care of all the iscsi disks, doing all those associated
#   with a specific adapter at one time
#
for parent in ${!iscarray[@]} ; do
    make_disktypes_available $parent ISCSI ${iscarray[$parent]}
done
#
#   Take care of all the RAID scsi disks, doing all those associated
#   with a specific adapter at one time
#
for parent in ${!rscarray[@]} ; do
    make_disktypes_available $parent SCSIRAID ${rscarray[$parent]}
done
#   wait to sync any background processes still breaking reserves
wait
#
#   If there were ghost disk profiles queued up to be removed, do so now.
#
for ghostdisk in $ghostlist ; do
    [[ $VERBOSE_LOGGING != high ]] &&
 cl_echo 640 "$PROGNAME: Removing duplicate disk device: $ghostdisk." $PROGNAME $ghostdisk
    rmdev -l "$ghostdisk" '-d'
done
#
#   If there were disks to make available, do so now
#
for diskspec in $disklist ; do
    #    Limitations on ksh processing are worked around by saving in the
    #    elements of 'disklist' the makedev method name catenated with the
    #    hdisk name with a '.'.  The next two statements pull the two
    #    apart.
    makedev=${diskspec%.*}
    disk=${diskspec#*.}
    oemmakedev $makedev $disk
done
#  
#   Having finally cleaned up any reserves or ghost disks on the underlying
#   hdisks, break any persistent reserve on vpath devices.
#
for vpath in $dpolist ; do
    breakres DPO DPO $vpath
done
#
#    Go back and check to see if the various disks came on line, and update
#    the cluster manager's status as appropriate
#
if [[ $PROC_RES == true ]]; then
    for GROUPNAME in $RESOURCE_GROUPS ; do
 export GROUPNAME
 #
 #   Extract the disk list and the corresponding volume group list
 #   for the disks in this resource group
 #
 print $HDISKS | IFS=':' read LIST_OF_HDISKS_FOR_RG HDISKS
 print $VOLUME_GROUPS | IFS=':' read LIST_OF_VOLUME_GROUPS_FOR_RG VOLUME_GROUPS
 #
 #   Do each of the disks in the list for this resource group
 #
 for disk in $(IFS=', ' set -- $LIST_OF_HDISKS_FOR_RG ; print $*)
 do
     #
     # Extract the name of the volume group that owns this disk
     #
     print $LIST_OF_VOLUME_GROUPS_FOR_RG | IFS=', ' read vg LIST_OF_VOLUME_GROUPS_FOR_RG
     #
     # Those disks which are in a volume group which is already vary'd on
     # do not need to be checked
     #
     if [[ -z $vg || $ON_LIST != ?(* )$vg?( *) ]] ; then
  verify_disk_availability $disk
     fi
 done
    done
else
    #
    # Resource groups processed serially: check all the disks passed on the command line
    #
    for disk in $*
    do
 verify_disk_availability $disk
    done
fi
#
#   Update the resource manager with the disks that came on line
#
ALLNOERR="All_nonerror_disks"
if [[ $PROC_RES == true ]]; then
    for GROUPNAME in $RESOURCE_GROUPS ; do
 cl_RMupdate resource_up $ALLNOERR $PROGNAME
    done
elif [[ $JUST_DISKS == false ]] ; then
    cl_RMupdate resource_up $ALLNOERR $PROGNAME
fi
exit 0
阅读(2784) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~