# -*-Shell-script-*-
# 
# disk-functions: This file contains functions used xrnginstall  
#                 and panini/spirit to configure and access
#                 the 2nd pci block device/partition on a VM
#
# Copyright (c) 2014-2018 by Cisco Systems, Inc.
# All rights reserved.
#

/usr/bin/logger -p 0 -t udev  "(source: calvados/hostos_pkg/boot/scripts/Disk-functions) "

#Source function library
. /etc/init.d/spirit-functions

if [ -f /etc/init.d/spirit_pd.sh -a "$spirit_pd_sourced" != "true" ]; then
   . /etc/init.d/spirit_pd.sh
   spirit_pd_sourced=true
fi

readonly fs_sb_output=/tmp/fs_sb_output
readonly EXT2_FS_MAGIC_NUMBER=0xEF53

cmdline=$(cat /proc/cmdline)

PLATFORM=`echo $cmdline | sed 's/^.*platform=//' | cut -d" " -f1`
PLATFORM=$(override_platform_type ${PLATFORM}  $SIMULATION)
if [ "$PLATFORM" == "scapa" ]; then
    readonly DISK1_PV=ecu_disk1
else
    readonly DISK1_PV=pci_disk1
fi
readonly DISK1_LV=ssd_disk1_
readonly DISK1_LABEL=DISK_ONE

# Default size set for debug partition, 10M
readonly DEBUG_PART_SIZE_DEFAULT=10

# 5 sub-partitions: 1 for hostOS, 2 for Calvados VMs, 2 for XR VMs
# Note: The maximum length of a mkfs.ext4 volume label is 16 bytes.
#       When used (e.g., asr9k) Ensure "D1_XXXX_LV[X]_DISK1_LABEL" < 16
readonly D1_HOST_LV=hostos

D1_CVDS_LABEL_LV1=cd_1
D1_CVDS_LV1=calvados_1

D1_CVDS_LABEL_LV2=cd_2
D1_CVDS_LV2=calvados_2

readonly D1_XR_LV1=xr_1
readonly D1_XR_LV2=xr_2

declare -F pd_create_dummy_volumes >& /dev/null
  if [ $? -eq 0 ]; then
     readonly D1_NUM_LV=5
  else
     readonly D1_NUM_LV=3
  fi

function DFLOG {
    local msg=$1
    echo "$(date -R): $msg" >> /var/log/disk-functions.log
}
readonly -f DFLOG

#get_disk_by_ata_port returns sd[a|b] for the given ata port.
function get_disk_by_ata_port {
   local -a ata_path=($(find /sys/devices -name ata5))
   for i in ${ata_path[@]}; do
       local block=`find $i -name block`
       if [ -n "$block" ]; then
          local device=`ls $block`
          echo "${device}"
          return
       fi
   done
}

#get_disk_model returns device model code for given disk ($1)
function get_disk_model {
    local model=`smartctl -i /dev/$1 | grep "Device Model:" |sed -e 's/Device Model://' -e 's/^[ |\t]*//'`
    echo "${model}"
}

#Get the attribute id for attribute SSD Life Left for the given ssd model.
function get_ssd_life_left_id 
{
    local model="${1}"
    local id
    case "${model}" in
    "Micron P400m-MTFDDAK200MAN"|"Micron_M550_MTFDDAT256MAY")
       id=202
       ;; 
    "SMART SATA SHSLM32G3BCCTHD22"|"SMART iSATA SHSLM32GEBCITHD02")
       id=231
       ;;
    "KINGSTON SKC380S3120G")
       id=231
       ;;
    "UGBA1TPH32H0S2-PNN-CTF")
       id=231
       ;;
    *)
    #The following SSDs used in xr platforms does not support SSD Life Left:
    #ST96023AS(Seagate),STM00017A892(STEC)
       id=""
       ;;
    esac
    echo "${id}"
}

#First honor smartctl -H check result. If passed, further apply specific
#checks. List of such specific checks being conducted:
# - SSD Life Left 
#   If attribute SSD Life Left is supported, ensure its reading stands 
#   1% above vendor suggested threshold.
function check_disk_health
{
    local disk=/dev/$1
    local model="${2}"

    #smartctl return code with bit 3(1<<3), bit 2(1<<2) and bit1(1<<1)
    #corresponding to internal FAILSTATUS, FAILSMART and FAILDEV defs.
    #smartctl -H check fail in ata/scsi-smart aspects sets FAILSTATUS,
    #FAILSMART or FAILDEV respectively. For use case of smartctl -H in
    #our scripts check those three bits are good enough.
    local FAILURE_DEF=14

    smartctl -H ${disk} >/dev/null 2>&1
    rc=$?
    if (($rc & $FAILURE_DEF)); then         
       #Health check failed
       return 1
    else
       #Further check attribute SSD Life Left, if supported, to ensure
       #its reading stands 1% above the vendor suggested threshold. If
       #SSD Life Left by name exists in the attrbute list of smartctl,
       #take it. Otherwise, get it by its attr id per vendor's def.
       
       local attr
       attr=`smartctl -A ${disk} | grep  ".*SSD_Life_Left.*Pre-fail"`
       if [ -z "${attr}" ]; then
          local attr_id=$(get_ssd_life_left_id "${model}")
          if [ -n "$attr_id" ]; then
             attr=`smartctl -A ${disk} | grep  "${attr_id}.*Pre-fail"`
          fi
       fi
       if [ -n "${attr}" ]; then
          local result=`echo "${attr}" |awk '{print $4}'`
          local thresh=`echo "${attr}" |awk '{print $6}'`
          thresh=$(($thresh + 1))
          if [ -n "${result}" -a "${thresh}" -a $result -le $thresh ]; then
             return 1
          fi
       fi
       #If needed, apply other specific checks here
    fi
    return 0
}

#Check disks and call PD functions to report failures.
#Failures are classified as follows:
#Primary disk:
#   - Missing: fatal event
#   - Health check failure: h/w error event
#   - ATA failed: fatal event
#Other disks:
#   - All failures: h/w error event
#
#A disk which did not pass health check may still fully functional at 
#that moment but it can fail soon. No guarantee how long it can last. 
#Because of that, a health check failure will be reported as h/w err
#event, too.
#
#Upon reciving of a fatal event, PD usually does a reload to the card
#while an error event does not reload the card,thus keeping it in the 
#failed state for diagnosis.
function check_disks
{
    local disk_faiulre_reported

    # Make primary disk still available
    if [ ! -b /dev/$disk ]; then
        step_log_console "Primary disk /dev/$disk is missing."
        echo "$(date):Primary disk /dev/$disk is missing\n" >&107
        disk_faiulre_reported=true
        declare -F pd_notify_hw_fatal_event >/dev/null 2>&107 && \
                pd_notify_hw_fatal_event "Primary disk is missing."
    else
        # Further check its health
        check_disk_health $disk "$disk_model"
        if [ $? -ne 0 ]; then
            step_log_console "Primary disk /dev/$disk health check failed"
            echo "$(date):Primary disk /dev/$disk health check failed.\n" >&107
            disk_faiulre_reported=true
            smartctl -a /dev/$disk >&107 2>&1
            declare -F pd_notify_hw_error_event >/dev/null 2>&107 && \
                pd_notify_hw_error_event "Primary disk health check failed, impending drive failure expected. SAVE ALL DATA."
        fi
    fi
    # Make sure secondary disk exists if it is supposed to be
    if [ ! -b /dev/$second_disk ]; then
        declare -F pd_platform_has_second_disk >/dev/null 2>&107 && \
                pd_platform_has_second_disk
        if [ $? -eq 0 ]; then
            step_log_console "Secondary disk /dev/$second_disk is missing."
            echo "$(date):Secondary disk /dev/$second_disk is missing.\n" >&107
            disk_faiulre_reported=true
            declare -F pd_notify_hw_error_event >/dev/null 2>&107 && \
                    pd_notify_hw_error_event "Secondary disk is missing."
        fi
    else
        # Further check its health
        check_disk_health $second_disk "$second_disk_model"
        if [ $? -ne 0 ]; then
            step_log_console "Secondary disk /dev/$seond_disk health check failed"
            echo "$(date):Secondary disk /dev/$second_disk health check failed.\n" >&107
            disk_faiulre_reported=true
            smartctl -a /dev/$second_disk >&107 2>&1
            declare -F pd_notify_hw_error_event >/dev/null 2>&107 && \
                pd_notify_hw_error_event "Secondary disk health check failed, impending drive failure expected. SAVE ALL DATA."
        fi
    fi

    #Report and log ata errors if observed. Considering same messages can
    #be repeatedly observed in dmesg buffer, log them only ONCE and limit
    #report to 3 times.
    local error=$(dmesg | grep ".* ata.*reset failed, giving up")
    if [ -n "${error}" ]; then
       if [ $ata_error_report_count -lt 3 -a "$disk_failure_reported" != "true" ]; then
          local ata_port=`echo "${error}"|sed -e "s/^.*\(ata[0-9]*\).*$/\1/"`
          local ata_disk=$(get_disk_by_ata_port "${ata_port}")
          if [ "$ata_disk" == "$disk" ]; then
               ata_disk="Primary"
          elif [ "${ata_disk}" == "${second_disk}" ]; then
               ata_disk="Secondary"
          else 
               #if not sda/sdb
               ata_disk="Tertiary"
          fi
          step_log_console "${ata_disk} disk ATA failed"
          echo "$(date):${ata_disk} disk ATA failed." >&107
          if [ "${ata_disk}" == "Primary" ]; then
             declare -F pd_notify_hw_fatal_event >/dev/null 2>&107 && \
                pd_notify_hw_fatal_event "${ata_disk} disk failed."
          else
             declare -F pd_notify_hw_error_event >/dev/null 2>&107 && \
                pd_notify_hw_error_event "${ata_disk} disk failed."
          fi
          ata_error_report_count=$(($ata_error_report_count + 1))
       fi
 
       if [ "$ata_error_logged" != "true" ]; then
          echo "$(date):logging ata messages:" >&107
          dmesg|grep " ata" >&107
          ata_error_logged=true
       fi
    fi

    sync
}

# Check/repair filesystem.
# Args: $1-storage device name, $2-mount point
# Return: (error code returned by fsck)
function check_repair_fs {
    local dev=$1
    local mnt=$2
    local status=0

    echo "$FUNCNAME $dev $mnt called at $(date)" >&107

    DFLOG "Checking filesystem in $dev $mnt ..."
    #abort check if partition is already mounted
    local mount=`mount | grep "$dev"`
    if [ ! -z "$mount" ]; then
        DFLOG "Aborting fs check. Device $dev is mounted."
        # equivalent to fsck error code (8) for operational error
        return 8
    fi
    #only perform fsck on partition that is not clean
    local state=`dumpe2fs $dev 2>&107 | grep "Filesystem state" | cut -d ':' -f 2 | tr -d ' '`
    if [ "$state" != "clean" ]; then
        DFLOG "Filesystem is not clean trying to repair ..."
        fsck -y $dev
        status=$?
        if [ $status -eq 0 ]; then
            DFLOG "No errors found"
        fi
        if [ $status -eq 1 ]; then
            DFLOG "Errors were found and corrected"
        fi
        if [ $status -gt 1 ]; then
            DFLOG "Error encountered"
        fi
    else
        DFLOG "Filesystem is clean"
    fi
    return $status
}
readonly -f check_repair_fs

function check_fs_sb {
    local return_code=0
    local fs_mn=0
    local part=${1}

    dumpe2fs -h ${part}  > $fs_sb_output 2>&1
    if (( $? == 1 )); then
        return_code=1
    else
        fs_mn=$(grep "magic number" $fs_sb_output | awk '{print $4}')
        if (( $fs_mn != $EXT2_FS_MAGIC_NUMBER )); then
            return_code=2
        fi
    fi

    return $return_code
}
readonly -f check_fs_sb

function format_partition {
    local dev_name=${1} label=${2}
    local caller="$(ps -o comm= $PPID)"

    DFLOG "$FUNCNAME:format partition dev [$dev_name] label [$label] requested by $caller"
    DFLOG "$FUNCNAME:$(file $dev_name)"

    # Reformat partition with an ext4 file system
    if [ "$PLATFORM" == "ncs1001" ]; then
        /sbin/mkfs.ext4 -L ${label} -b 4096 -O ^huge_file -vv ${dev_name}
        /sbin/tune2fs -c 0 -i 0 ${dev_name} 
    else
        /sbin/mkfs.ext4 -L ${label} -b 4096 -O ^huge_file -vv ${dev_name} >&107 2>&1
        /sbin/tune2fs -c 0 -i 0 ${dev_name} >&107 2>&1
    fi
    sync
}
readonly -f format_partition

# Format disk1 of calvados
function format_calvados_partition {
    local dev_name=/dev/mapper/${DISK1_PV}-${DISK1_LV}${D1_CVDS_LV1}
    local label=${DISK1_LABEL}

    # PI team to review and enable
    # if [[ $VIRT_METHOD == "lxc" ]]; then
    #    label = "${D1_CVDS_LABEL_LV1}_${DISK1_LABEL}"
    # fi
    # Reformat partition with an ext4 file system
    /sbin/mkfs.ext4 -L ${label} -b 4096 -O ^huge_file -vv ${dev_name} >&107 2>&1
    /sbin/tune2fs -c 0 -i 0 ${dev_name} >&107 2>&1
    sync
}
readonly -f format_calvados_partition

function check_fs_partition {
    local dev_name=${1} label=${2}

    check_fs_sb ${dev_name}
    # Even though super block is EXT4, redo mkfs.
    # The Partition label may have changed
    format_partition ${dev_name} ${label}
}

# Get size of the disk, in MB
# Parameter: disk (ex: /dev/sda)
# Return: $DISK_SIZE
function get_disk_size {
    local dev=${1}

    #
    # Handle optional disks
    #
    if [ ! -b $dev ]
    then
        let "DISK_SIZE=0"
        return
    fi

    max=$(fdisk -l ${dev} 2>&107 | grep "Disk ${dev}:"  | cut -d ',' -f2)
    max=${max%bytes}
    let "DISK_SIZE=$max/1000000"
}

function provision_disk_one {
  local args=$1
  local logvol_size
  local total_disk_size
  declare -a pdisks=($@)
  static_part=${STATIC_SEC_DISK_PARTITION[@]}
  # check for multiple disks
  local gotone

  for i in "${pdisks[@]}"
  do
      gotone=1

      secondary_disks="${secondary_disks} /dev/$i"
      dev=/dev/$i

      if [ ! -b "${dev}" ]; then
        return
      fi
      step_log_console "Partitioning PCI block device $dev"

      # Check if it is a PCI device
      local pci_disk_check=$(udevadm info -q path -n ${dev} 2>&107 \
                             | grep pci | grep -v usb)

      if [ -z "$pci_disk_check" ]; then
         echo "Not a pci/usb block device ${dev}"
         return
      fi

      #Is volume group name same as desired
      OLD_DISK1_PV=$(pvdisplay ${dev} 2>&107 | grep "VG Name" | awk '{print $3}')
      if [[ "${OLD_DISK1_PV}" == "${DISK1_PV}" ]]; then
          # If volume group name is as expected, check the number of 
          # LVs in this VG. And check if the name of the calvados
          # volume matches the expected name (calvados_1). 

          cnt=$(lvscan 2>&107 | grep -c ${DISK1_PV}\/${DISK1_LV})
          if [[ ${cnt} == ${D1_NUM_LV} ]]; then
               #Volume count matches remove any stale xr_data_lv in pci_disk
               lvremove -f /dev/pci_disk1/xr_data_lv* >> /tmp/log 2>&1 
              # Volume count matches, check if the volume name matches 
              cnt=$(lvscan 2>&107 | grep ${D1_CVDS_LV1} | wc -l)
              if [[ ${cnt} == 1 ]]; then
                check_fs_secondary_vols "${DISK1_PV}" "${dev}"
                ret=$?

                if [ "${ret}" == 0 ]; then
                    step_log_console "Retaining Volume Group ${DISK1_PV}"
                    return
                else
                    step_log_console "Removing Volume Group ${DISK1_PV}"
                fi
              fi
          fi
          declare -F pd_remove_tpa_volume >& /dev/null
          if [ $? -eq 0 ]; then
            # PD remove app hosting lv
            pd_remove_tpa_volume ${DISK1_PV}
          fi
          LOG_PV1=$(pvdisplay ${dev} 2>&107 )
          step_log_console "PV display : ${LOG_PV1}"
          LOG_LV1=$(lvscan 2>&107 )
          step_log_console "LV scan : ${LOG_LV1}"
          step_log_console "Removing Volume Group ${DISK1_PV}"
          vgremove -f ${DISK1_PV}  >&107 2>&1
          pvremove -ff -y ${dev} >&107 2>&1
      else
          if [ "$PLATFORM" == "scapa" -a \
                "${OLD_DISK1_PV}" == "pci_disk1" ]; then
              #Do we have same number of logical volumes
              cnt=$(lvscan 2>&107 | grep ${DISK1_LV} | wc -l)
              if [[ ${cnt} == ${D1_NUM_LV} ]]; then
                  #Rename the volumes group name ! need active here ?
                  vgrename -v /dev/pci_disk1 /dev/ecu_disk1
                  return
              fi
	      /usr/bin/logger -p 0 -t udev "ecu : mismatch in number of logical volumes: ${cnt} to ${D1_NUM_LV}"
          fi
          LOG_PV1=$(pvdisplay ${dev} 2>&107 )
          step_log_console "PV display: ${LOG_PV1}"
          LOG_LV1=$(lvscan 2>&107 )
          step_log_console "LV scan: ${LOG_LV1}"

          #Remove the physical volume on the device
          step_log_console "Removing Volume Group ${DISK1_PV} due to mis-match"
          vgremove -f ${OLD_DISK1_PV} >&107 2>&1
          pvremove -ff -y ${dev} >&107 2>&1
      fi
      get_disk_size ${dev}
      let total_disk_size=$total_disk_size+DISK_SIZE
  done

  if [ "$gotone" = "" ]
  then
    return
  fi

  # Remove any stale disk one volume groups on devices
  # other than secondary disk for Compute cards on NCS6k
  declare -F pd_remove_stale_disk_one_vg >/dev/null 2>&1
  if [ $? -eq 0 ]; then
     pd_remove_stale_disk_one_vg ${BOARDTYPE} ${DISK1_PV} ${secondary_disks} 
  fi

  #Remove recovery related leftover volumes
  declare -F pd_remove_recovery_disk_loop_volumes >/dev/null 2>&1
  if [ $? -eq 0 ]; then
     step_log_console "Removing recovery disk loop volumes"
     pd_remove_recovery_disk_loop_volumes "/dev/${SECONDARY_DISK}" 
  fi

  if [[ "$PLATFORM" == "asr9k" ]]; then
  /bin/dd if=/dev/zero of=${dev} bs=1024 count=10000 >&107 2>&1
  else
  secondary_disks=$(echo "${secondary_disks}" | sed -e 's/^[ \t]*//')
  /bin/dd if=/dev/zero of=${secondary_disks[0]} bs=1024 count=10000 >&107 2>&1
  fi
  pvcreate -ff -y ${secondary_disks} >&107 2>&1
  vgcreate -f -y ${DISK1_PV} ${secondary_disks} >&107 2>&1

  #Logical volume for Host
  let logvol_size=$total_disk_size*${DISK_SSD_HOST_SIZE}/100
  lvcreate -L ${logvol_size} -n ${DISK1_LV}${D1_HOST_LV} ${DISK1_PV} >&107 2>&1
  check_fs_partition "/dev/mapper/${DISK1_PV}-${DISK1_LV}${D1_HOST_LV}" \
                     "${D1_HOST_LV}_${DISK1_LABEL}"

  let cal_logvol_size=$total_disk_size*${DISK_SSD_CALVADOS_SIZE}/100
  let xr_logvol_size=$total_disk_size*${DISK_SSD_XR_SIZE}/100

  if [[ $VIRT_METHOD == "lxc" ]] || [[ $PLATFORM == "asr9k" ]]; then
    #Logical volume for Calvados VM1/2
    lvcreate -L ${cal_logvol_size} -n ${DISK1_LV}${D1_CVDS_LV1} ${DISK1_PV} >&107 2>&1 
    check_fs_partition "/dev/mapper/${DISK1_PV}-${DISK1_LV}${D1_CVDS_LV1}" \
                       "${D1_CVDS_LABEL_LV1}_${DISK1_LABEL}"
  
  
   # lvcreate -L ${cal_logvol_size} -n ${DISK1_LV}${D1_CVDS_LV2} ${DISK1_PV} >&107 2>&1
    #check_fs_partition "/dev/mapper/${DISK1_PV}-${DISK1_LV}${D1_CVDS_LV2}" \
     #                  "${D1_CVDS_LABEL_LV2}_${DISK1_LABEL}"

    #Logical volume for XR VM1/2
    if [ ! -z "$static_part" ]; then
    lvcreate -L ${xr_logvol_size} -n ${DISK1_LV}${D1_XR_LV1} ${DISK1_PV} >&107 2>&1
    check_fs_partition "/dev/mapper/${DISK1_PV}-${DISK1_LV}${D1_XR_LV1}" \
                       "${D1_XR_LV1}_${DISK1_LABEL}"

    #lvcreate -L ${xr_logvol_size} -n ${DISK1_LV}${D1_XR_LV2} ${DISK1_PV} >&107 2>&1
    #check_fs_partition "/dev/mapper/${DISK1_PV}-${DISK1_LV}${D1_XR_LV2}" \
     #                  "${D1_XR_LV2}_${DISK1_LABEL}"
    fi
    declare -F pd_create_tpa_volume >& /dev/null
    if [ $? -eq 0 ]; then
        # asr9k creates app hosting lv
        pd_create_tpa_volume ${DISK1_PV}
    fi
  else
    #Logical volume for Calvados VM1/2
    lvcreate -L ${cal_logvol_size} -n ${DISK1_LV}${D1_CVDS_LV1} ${DISK1_PV} >&107 2>&1

    check_fs_partition "/dev/mapper/${DISK1_PV}-${DISK1_LV}${D1_CVDS_LV1}" \
                       "${DISK1_LABEL}"

  declare -F pd_create_dummy_volumes >& /dev/null
  if [ $? -eq 0 ]; then
    #creating two dummy volumes for ncs6k and ncs4k to make vol count to 5 to support 61x to 524 downgrade 
    pd_create_dummy_volumes ${DISK1_PV}
  fi
    
    #lvcreate -L ${cal_logvol_size} -n ${DISK1_LV}${D1_CVDS_LV2} ${DISK1_PV} >&107 2>&1
    #check_fs_partition "/dev/mapper/${DISK1_PV}-${DISK1_LV}${D1_CVDS_LV2}" \
     #                  "${DISK1_LABEL}"

    #Logical volume for XR VM1/2
    if [ ! -z "$static_part" ]; then
    lvcreate -L ${xr_logvol_size} -n ${DISK1_LV}${D1_XR_LV1} ${DISK1_PV} >&107 2>&1

    check_fs_partition "/dev/mapper/${DISK1_PV}-${DISK1_LV}${D1_XR_LV1}" \
                       "${DISK1_LABEL}"

   # lvcreate -L ${xr_logvol_size} -n ${DISK1_LV}${D1_XR_LV2} ${DISK1_PV} >&107 2>&1
   # check_fs_partition "/dev/mapper/${DISK1_PV}-${DISK1_LV}${D1_XR_LV2}" \
    #                   "${DISK1_LABEL}"
    fi

    # Create 18+ GB Install repository in disk1 as LV for panini platform
    if [ "$BOARDTYPE" == "RP" -o "$BOARDTYPE" == "CC" ] && [[ "$SIMULATION" == 0 ]]; then
        declare -F pd_create_install_repo_in_disk >&107 2>&1
        if [ $? -eq 0 ]
        then
            pd_create_install_repo_in_disk
        fi
    fi

  fi
}

# Run a soft filesystem check on each of the secondary disk volumes to check for
# filesystem corruption through bad sectors, superblocks etc.
# Failing this check, these volumes will need to be re-partitioned and re-formatted.
function check_fs_secondary_vols {
    local disk1_pv=${1}
    local dev=${2}
    local retval=0
    local is_ssd_local=0

    declare -F pd_check_fs_secondary_vols >&107 2>&1
    if [ $? -eq 0 ]; then
        # filesystem check DISK1_LV LVs
        pd_check_fs_secondary_vols ${1} ${DISK1_LV}
        return $?
    fi

    declare -F pd_check_for_secondary_vols_resize >&107 2>&1
    if [ $? -eq 0 ]; then
        # Check for DISK1_LV change in sizes
        pd_check_for_secondary_vols_resize ${dev}
        if [ $? -ne 0 ]; then
            step_log_console "Secondary volumes need to be resized"
            return 1
        fi
    fi

    # Currently this check is in place only for platforms that have their main disk
    # hosting secondary disk volumes since recovering such a partition on a live
    # system is non-trivial.
    for _pv in `pvdisplay | awk '/PV Name.*dev.sda/{print $3}'`; do
        # If there is an existing PV on disk(sda) hosting secondary disk volumes,
        local vg_name=`pvdisplay $_pv | awk '/VG Name/{print $3}' | grep $disk1_pv`
        if [ -n "${vg_name}" ]; then
           is_ssd_local=1 
           break
        fi
    done

    if [ "${is_ssd_local}" == 0 ]; then
        step_log_file "Secondary disk fs check is only for platforms that host secondary disk volumes on the main disk"
        return $retval
    fi
    
    lvchange -a y /dev/${disk1_pv} >&107 2>&1
    ssd_lvnames=`lvdisplay ${disk1_pv} | grep "LV Path" | awk '{print $3}'`
    for lv in ${ssd_lvnames[@]}; do
        check_fs_sb $lv
        retval=$?
        if [ "${retval}" != 0 ]; then
            step_log_console "Filesystem for $lv is corrupt!!"
            step_log_console "Need to re-format ${DISK1_PV} volumes"
            break
        fi
    done
    lvchange -a n /dev/${disk1_pv} >&107 2>&1 
    step_log_console "Final return val $retval  ...."
    return $retval
}

function activate_disk_one_vg {
    modprobe dm-mod
    disk1_pv=($(pvscan | grep ${DISK1_PV} | awk '{print $4}'))
    if [ "${disk1_pv}" == "${DISK1_PV}" ]; then
        lvchange -a y /dev/${DISK1_PV} >&107 2>&1
    fi
}

# Mount a filesystem by label. Before its mounting, run fsck to fix corrutpion
# if found.
function mount_fs_label {
    local label=${1}
    local dir=${2}
    local journalled=${3}
    local dev="$(blkid -L $label)"
    local caller="$(ps -o comm= $PPID)"

    DFLOG "mounting fs label $label on $dir requested by $caller"
    if [ -b "$dev" ]; then
       DFLOG "$(blkid $dev)"
    else
       DFLOG "No filesystem labeled $label is present"
    fi
    echo "$(date) mount ${label} ${dir}" >&107 2>&1
    check_repair_fs ${dev} ${dir}
    if [ ! -d ${dir} ]; then
       mkdir -p ${dir}
    fi
    if [ ${journalled} = "true" ]; then
        mount -o discard,data=journal -L ${label} ${dir} >&107 2>&1
    else
        mount -L ${label} ${dir} >&107 2>&1
    fi
    if [ $? -ne 0 ]; then
        DFLOG "Mounting failed"
    fi
}                                    

function mount_disk_one {
    local mount_dir=${1}
    local label=${DISK1_LABEL}
    local install=$(cat /proc/cmdline | grep install=)
   
    if [ -n "${install}" ]; then
        return
    fi

    # Activate volume group on disk1
    activate_disk_one_vg >&107 2>&1 

    local vm_type=`cat /proc/cmdline | grep vmtype=`
    if [ -z "${vm_type}" ] || [[ "${vm_type}" =~ "hostos" ]]; then
        label=${D1_HOST_LV}_${DISK1_LABEL}
    fi
    if [[ $VIRT_METHOD == "lxc" ]] || [[ $PLATFORM == "asr9k" ]]; then
        if [ -z "${vm_type}" ] || [[ "${vm_type}" =~ "sysadmin-vm" ]]; then
            label=${D1_CVDS_LABEL_LV1}_${DISK1_LABEL}
        fi
        if [ -z "${vm_type}" ] || [[ "${vm_type}" =~ "xr-vm" ]]; then
            label=${D1_XR_LV1}_${DISK1_LABEL}
        fi
        # TBD: When are V2 labels to be used?
    fi

    # Loop through each of the block-device and mount the filesystem
    # that was labeled "DISK_ONE" during install.

    for device in `find /dev/ -xdev -type b`; do
        out=$(dumpe2fs -h ${device} 2>&107 | grep "Filesystem volume name:" | \
              awk '{print $4}')
        if [ "${out}" == "${label}" ]; then
            mkdir -p ${mount_dir} >&107 2>&1
            fsck -y ${device} >&107 2>&1
            /sbin/tune2fs -c 0 -i 0 ${device} >&107 2>&1
            mount -o discard ${device} ${mount_dir} >&107 2>&1
            # somewhere may have mounted the device to RDONLY 
            # mount the device to RDONLY, then remount path to RW
            if [ $? -ne 0 ]; then
                mount -o ro,discard ${device} ${mount_dir} >&107 2>&1
                if [ $? -ne 0 ]; then
                    echo "Mount ${device} at ${mount_dir} as RDONLY failed"
                    return
                fi
                mount -o remount,rw,discard ${mount_dir} >&107 2>&1
                if [ $? -ne 0 ]; then
                    echo "Re-mount ${mount_dir} as Read/Write failed"
                    return
                fi
            fi
            echo "Mount ${device} at ${mount_dir}"
            return
        fi
    done
}


function remove_old_volumes {

  # function copied from http://grox.net/sysadm/unix/nuke.lvm
  # adapted for spirit
  # Remove volumes on /dev/sda and /dev/sdb with the name panini*
  # of pci*

  declare -F pd_remove_old_volumes >&107 2>&1
  if [ $? -eq 0 ]; then
    # Remove non-DISK1_LV LVs
    pd_remove_old_volumes ${DISK1_LV} ${DISK1_PV}
    return
  fi

  step_log_console "Inside Volume-Cleaning Function"
  /usr/bin/logger -p 0 -t udev "ecu : Inside Volume-Cleaning Function"
  # remove existings lvm configs for for panini_vol_grp
  for _vol in `lvdisplay | awk '/LV Name/{print $3}' | awk '/panini_vol_grp/{print $1}'`; do
    umount -f $_vol >> /tmp/log 2>&1
    lvchange -an $_vol >&107 2>&1
    yes | lvremove -f $_vol >&107 2>&1
    step_log_console "Removed LVM ${_vol} for Panini"
  done

 # remove existings lvm configs for for app_vol_grp
  for _vol in `lvdisplay | awk '/LV Name/{print $3}' | awk '/app_vol_grp/{print $1}'`; do
    umount -f $_vol >> /tmp/log 2>&1
    lvchange -an $_vol >&107 2>&1
    yes | lvremove -f $_vol >&107 2>&1
    step_log_console "Removed LVM ${_vol} for App-Host"
  done

 # removing app-vol-groups
  for _vol in `vgdisplay | awk '/VG Name/{print $3}' | awk '/app_vol_grp/{print $1}'`; do
    vgchange -an $_vol >&107 2>&1
    yes | vgremove -f $_vol >&107 2>&1
    step_log_console "Removed App-Vol Grp ${_vol}"
  done

  for _vol in `vgdisplay | awk '/VG Name/{print $3}' | awk '/panini_vol_grp/{print $1}'`; do
    vgchange -an $_vol >&107 2>&1
    yes | vgremove -f $_vol >&107 2>&1
    step_log_console "Removed Panini Vol-Grp ${_vol}"
  done

  # last step didn't get 'em all...
  for _vol in /dev/mapper/panini*; do
    if [ -b "$_vol" ]; then
      dd if=/dev/zero of=$_vol bs=512 count=12 >&107 2>&1
      step_log_console "Formatted Panini volume ${_vol}"
    fi
  done


  # Formatting App-Volume Groups
  # last step didn't get 'em all...
  for _vol in /dev/mapper/app* ; do
    if [ -b "$_vol" ]; then
        dd if=/dev/zero of=$_vol bs=512 count=12 >&107 2>&1
        step_log_console "Formatted App-Volume ${_vol}"
    fi
  done

  for _pv in `pvdisplay | awk '/PV Name.*dev.sda/{print $3}'`; do
    # If there is an existing PV on disk(sda) hosting secondary disk volumes,
    # delete ONLY non disk1 volumes under it.
    local vg_name=`pvdisplay $_pv | awk '/VG Name/{print $3}' | grep $DISK1_PV`
    if [ -z $vg_name ] || [ "${BOARDTYPE}" != "RP" -a "${BOARDTYPE}" != "CC" ]; then
        yes | pvremove -ff -y $_pv >&107 2>&1
    else
        for _vol in `lvdisplay ${vg_name} | awk '/LV Path/{print $3}' | grep -v ${DISK1_LV}`; do
            umount -f $_vol >> /tmp/log 2>&1
            lvchange -an $_vol >&107 2>&1
            yes | lvremove -f $_vol >&107 2>&1
        done
    fi
  done

  # just in case some were missed... (some always are)
  for _pv in $disks; do
    yes | pvremove -ff -y $_pv >&107 2>&1
    dd if=/dev/zero of=$_pv bs=512 count=255 >&107 2>&1
  done

  step_log_console "Removed PV"

  # see what else the system still knows about
  # and get rid of them, too.
  # note that we ignore 'sd*' partitions and that this
  # assumes that we don't need dm-? for the system
  # that we're running on. i know, big assumption.
  #
  for _part in `awk '/dm-/{print $4}' /proc/partitions`; do
    yes | pvremove -ff -y $_part >&107 2>&1
    dd if=/dev/zero of=$_part bs=512 count=255 >&107 2>&1
  done
  step_log_console "Exiting from the Volume Cleaning Section"

}

function check_disk_one_space {
  local dev=/dev/${1}
  local dsize=0

  if [ ! -b "${dev}" ]; then
    return 0
  fi
  echo "Checking PCI block device $dev disk space"

  # Check if it is a PCI device
  local pci_disk_check=$(udevadm info -q path -n ${dev} 2>&107 \
                         | grep pci | grep -v usb)

  if [ ! -z "${pci_disk_check}" ]; then
    # find disk one volume group name
    DISK1PV=$(pvdisplay ${dev} 2>&107 | grep "VG Name" | awk '{print $3}')

    if [[ "${DISK1PV}"="ecu_disk1" || "${DISK1PV}"="pci_disk1" ]]; then
      local label=${DISK1PV}-${DISK1_LV}${D1_CVDS_LV1}
      local device=/dev/mapper/$label

      #Do we have same number of logical volumes
      cnt=$(lvscan 2>&107 | grep ${DISK1_LV} | wc -l)
      if [[ ${cnt} == "${D1_NUM_LV}" ]]; then
        # Activate volume group on disk1
        activate_disk_one_vg

        # mount calvados-1 partition to check disk space
        DISK1MNT=$(mktemp -d /tmp/disk1dev.XXXXXX)
        mount -o ro,noload ${device} ${DISK1MNT} 2>&107 || return 1

        dsize=$(df -Pk ${DISK1MNT} | tail -1 | awk {'print $4'})
        echo "PCI block device ${dev} free space: ${dsize}K"

        # unmount ISO, we no longer need it
        [ -d "${DISK1MNT}" ] && umount ${DISK1MNT} && rmdir ${DISK1MNT}
        if [ "${dsize}" -gt 2000000 ]; then
          return 0
        else
          return 1
        fi
      fi
    fi
  fi
  /usr/bin/logger -p 0 -t udev "ecu : disk-functions : check_disk_one_space - this disk need partition properly, continue install"
  # this disk need partition properly, continue install.
  return 0
}

function pxe_install_second_disk_pre_check {
    # check disk space, need at least 2G disk space for install image for pxe boot
    if [ ! -z ${SIMULATION} ]; then
      check_disk_one_space "${second_disk}${1}"
      if [ $? -eq 1 ]; then
        pxeflag=1
	/usr/bin/logger -p 0 -t udev "ecu : disk-functions : pxe_install_second_disk_pre_check - There is not enough disk space in /misc/disk1 to copy internal PXE boot image"
        echo "There is not enough disk space in /misc/disk1 to copy internal PXE boot image."
      fi

      while [ -n "${pxeflag}" ]; do
        echo "Choose an option :"
        echo "1). Format /misc/disk1, and continue install"
        echo "2). Abort install"
        printf "option [1/2]? "
        read answers123

        if [ "${answers123}" = "1" -o "${answers123}" = "2" ]; then
          if [ "${answers123}" = "1" ]; then
            printf "Option 1 is selected. Existing files on /misc/disk1 will be lost.  Continue? [y/n] "
          elif [ "${answers123}" = "2" ]; then
            printf "Option 2 is selected. Installation will be terminated.  Confirm? [y/n] "
          fi

          read answers

          if [ "${answers}" = "y" ]; then
            if [ "${answers123}" -eq 1 ]; then
              format_calvados_partition
              echo "format disk1 passed to sysadmin VM"
            /usr/bin/logger -p 0 -t udev "ecu : disk-functions : pxe_install_second_disk_pre_check - format disk1 passed to sysadmin VM"  
	    break
            elif [ "${answers123}" -eq 2 ]; then
              echo "Installation terminated.  Please clean up /misc/disk1 and rerun install."
	      /usr/bin/logger -p 0 -t udev "ecu : disk-functions : pxe_install_second_disk_pre_check - Installation terminated.  Please clean up /misc/disk1 and rerun install."
              call_reboot
              exit
            fi
          fi
        fi
      done
    fi
}


function reformat_partition {
    local dev_name=${1}

    # Reformat partition with an ext4 file system
    if [ "$PLATFORM" == "ncs1001" ]; then
        /sbin/mkfs.ext4 -b 4096 -O ^huge_file -vv ${dev_name}
        /sbin/tune2fs -c 0 -i 0 ${dev_name}
    else
        /sbin/mkfs.ext4 -b 4096 -O ^huge_file -vv ${dev_name} >&107 2>&1
        /sbin/tune2fs -c 0 -i 0 ${dev_name} >&107 2>&1
    fi
    sync
}
readonly -f reformat_partition

# Get debug partition (dp) offset and size
function get_dp_offset {
    local dev=${1}
    max=$(fdisk -l ${dev} 2>/dev/null | grep "Disk /dev"  | cut -d ',' -f2)
    max=${max%bytes}
    max=$(($max / 1000000))
    startm=$(($max - 10))
    startb=$(($startm * 1000000))
    dpstarts=$(($startb / 512))
    endb=$(($max * 1000000))
    dpends=$(($endb / 512))
    if [ $(($startm % 512)) -ne 0 ]; then
       dpstarts=$(($dpstarts + 1))
    fi
    dpdiffs=$(($dpends - $dpstarts + 1))
    dpoffset=$(($dpstarts * 512))
    dpsizeb=$(($dpdiffs * 512))
}
# Mount dp to /tmp/bakelog. If dp does not exist, create dp.
function prepare_dploop {
    local dev=${1}
    local src=${2}
    mkdir -p ${LOGFLOWDIR}.sav
    rm -rf ${LOGFLOWDIR}.sav/*
    cp -rf ${LOGFLOWDIR}/* ${LOGFLOWDIR}.sav/ >&107 2>&1
    cp -f ${LOGDIR}/${LOGFILE0} ${LOGFLOWDIR}.sav/ >&107 2>&1
    cp -f ${LOGDIR2}/${LOGFILE} ${LOGFLOWDIR}.sav/ >&107 2>&1
    rm -rf ${LOGFLOWDIR}/*
    dploop=$(losetup --find)
    losetup --offset $dpoffset --sizelimit $dpsizeb ${dploop} ${dev}
    local label=`blkid ${dploop} | grep "debug" | grep "ext4"`
    if [ -z "$label" ]; then
       if [ -z "$src" ]; then
          check_fs_partition ${dploop} "debug"
       else
          losetup -d ${dploop} >&107 2>&1
          return 1 
       fi
    fi
    mount ${dploop} ${LOGFLOWDIR} >&107 2>&1
    if [ $? -eq 0 -a -z "$src" ]; then
       avail=$(df -k | grep ${dploop} |awk '{print $4}')
       if [ "$avail" -lt 1536 ]; then
          umount ${LOGFLOWDIR} >/dev/null 2>&1
          check_fs_partition ${dploop} "debug"
          mount ${dploop} ${LOGFLOWDIR} >&107 2>&1
       fi
    fi
    if [ $? -ne 0 ]; then
       umount ${LOGFLOWDIR} >/dev/null 2>&1
       losetup -d ${dploop} >&107 2>&1
       cp -rf ${LOGFLOWDIR}.sav/* ${LOGFLOWDIR}/ >&107 2>&1 
       rm -rf ${LOGFLOWDIR}.sav 
       return 1
    fi
    if [ -z "$src" ]; then
       avail=$(df -k | grep ${dploop} |awk '{print $4}')
       if [ "$avail" -lt 1536 ]; then
          umount ${LOGFLOWDIR} >/dev/null 2>&1
          losetup -d ${dploop} >&107 2>&1
          cp -rf ${LOGFLOWDIR}.sav/* ${LOGFLOWDIR}/ >&107 2>&1
          rm -rf ${LOGFLOWDIR}.sav
          return 1
       fi
    fi

    cp -rf ${LOGFLOWDIR}.sav/* ${LOGFLOWDIR}/ >&107 2>&1 
    rm -rf ${LOGFLOWDIR}.sav 
    sync
    return 0
}

# Fix ported from CSCvi96682
function mount_install_repo {
    local label=$1
    local dir=$2

    local dev=$(blkid -L $label)

    # Check if journaling is present. if not, create it
    tune2fs -l ${dev} | grep -q "has_journal"
    if [ $? -ne 0 ]; then
        tune2fs -j ${dev}
    fi

    # Mount the repo
    mount_fs_label ${label} ${dir}

    # Clean un-mount to finalize the FS
    umount ${dir}

    # Disable journaling to delete Journal entries
    tune2fs -O ^has_journal ${dev}

    check_repair_fs ${dev} ${dir}

    # Enable journaling
    tune2fs -j ${dev}

    # Mount the repo
    mount_fs_label ${label} ${dir}
}
