#!/bin/bash
#               @(#)probe-luns    2.1    1        4/04/2003
## *****************************************************************
## *                                                               *
## *   Copyright (c) Compaq Computer Corporation, 1996 - 2002      *
## *                                                               *
## *   All Rights Reserved.  Unpublished rights  reserved  under   *
## *   the copyright laws of the United States.                    *
## *                                                               *
## *   The software contained on this media  is  proprietary  to   *
## *   and  embodies  the  confidential  technology  of  Compaq    *
## *   Computer Corporation.  Possession, use,  duplication  or    *
## *   dissemination of the software and media is authorized only  *
## *   pursuant to a valid written license from Compaq Computer    *
## *   Corporation.                                                *
## *                                                               *
## *   RESTRICTED RIGHTS LEGEND   Use, duplication, or disclosure  *
## *   by the U.S. Government is subject to restrictions  as  set  *
## *   forth in Subparagraph (c)(1)(ii)  of  DFARS  252.227-7013,  *
## *   or  in  FAR 52.227-19, as applicable.                       *
## *                                                               *
## *****************************************************************
##
##
## Author:      Andrew Kreitser (AMK), andrew.kreitser@hp.com 
##                                     
##                               
#  HISTORY:
#               AMK 04/04/03 - ver. 2.1
#               AMK 05/14/02 - ver. 1.0

min_ch_range="0"
min_id_range="0"
min_lun_range="0"

max_ch_range="0 1 2 3 4 5 6 7"
max_id_range="0 1 2 3 4 5 6 7"
max_lun_range="0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32"

ch_range=${min_ch_range}
id_range=${min_id_range}
lun_range=${min_lun_range}

obj=""

hba_flag=0;
inst_flag=0;
remove_flag=0;
swsp_ch_flg=0;
swsp_ch_max=0;
swsp_lun_max=256;

help()
{

  echo ""
  cat $0 | grep '^#' | grep '@(#)' | cut -c 3-
  echo "Usage:"
  echo " $0 [-h | -a | [[-r] [-l] [-i] [-c] [[hba [hba]] | -n inst [inst]]]"
  echo "  -h help"
  echo "  -a hba list"
  echo "  -r remove luns"
  echo "  -n use adapter instance number instead of hba name"
  echo "  -c scanning for channels: [${max_ch_range}], default: [${min_ch_range}]"
  echo "  -i scanning for IDs:  [${max_id_range}], default: [${min_id_range}]"
  echo "  -l scanning for LUNs: [${max_lun_range}], default: [${min_lun_range}]"
  echo " If hbas or instances are given, only these are scanned [default: all]"
  echo ""

}

cmd_line()
{
  opt="${1}"
  while [ ! -z "${opt}" ]
  do
    case "$opt" in
     -a) hba_flag=1 ;;
     -r) remove_flag=1 ;;
     -n) inst_flag=1 ;;
     -c) ch_range=${max_ch_range} ;;
     -i) id_range=${max_id_range} ;;
     -l) lun_range=${max_lun_range} ;;
      *) break ;;
    esac
    shift
    opt="${1}"
  done

  opt="${1}"
  while [ ! -z "${opt}" ]
  do
    obj=${obj}' '${opt}
    shift
    opt="${1}"
  done
   
}

hba_by_instance()
{

  if [ $# -eq 0 ]
  then
    find /proc/scsi/ | grep /[0-9] 2>/dev/null | sort -u
  else
    val=`echo ${*} | tr ' ' ','`
    find /proc/scsi/ |grep /[0-9] 2>/dev/null | \
    awk 'BEGIN{n=split("'${val}'",Ar,",");} \
    {for(i=1;i<=n;i++){s=sprintf("/%s",Ar[i]); \
    if((index($0,s)+length(s))>length($0))print index($0,s),length(s),length($0)$0;}}' | sort -u
  fi

}

hba_by_name()
{

  if [ $# -eq 0 ]
  then
    find /proc/scsi/ | grep /[0-9] 2>/dev/null | sort -u
  else
    val=`echo ${*} | tr ' ' ','`
    find /proc/scsi/ |grep /[0-9] 2>/dev/null | \
    awk 'BEGIN{n=split("'${val}'",Ar,",");} {for(i=1;i<=n;i++){s=sprintf("/%s/",Ar[i]);if(index($0,s))print $0;}}' | sort -u
  fi

}

probe_loop()
{

  for inst in ${hbas}
  do
    [ "${1}" = "ADD" ] && adpr=`ls /proc/scsi/*/${inst} | awk -F/ '{print $4}'`
    [ "${1}" = "ADD" ] && printf "\rProbing ${inst} ${adpr} ...                         \n"
    [ "${1}" = "DEL" ] && printf "\rRemoving ${inst} ${adpr} ...                        \n"
    for ch in ${cur_ch_range}
    do
      for id in ${cur_id_range}
      do
        for lun in ${cur_lun_range}
        do
          [ "${1}" = "ADD" ] && printf "\rProbing ${adpr} ${inst} ${ch} ${id} ${lun} ...           "
          [ "${1}" = "ADD" ] && echo "scsi add-single-device ${inst} ${ch} ${id} ${lun}" > /proc/scsi/scsi
          [ "${1}" = "DEL" ] && echo "scsi remove-single-device ${inst} ${ch} ${id} ${lun}" > /proc/scsi/scsi
        done
        [ "${1}" = "ADD" ] && sleep 1
      done  
    done
  done

}

resume()
{
  printf "\r                                                      \n\n"
  for inst in ${hbas}
  do
    cat /proc/scsi/scsi | tr -d '\n'| 
    awk '{ for(i=1;i<=NF;i++) if(index($i,"scsi")!=0)printf("\n%s ",$i); else printf("%s ",$i)}' | \
    awk 'BEGIN{n=split("scsi|Channel|Id|Lun|Vendor|Model|Rev|Type",ar,"|");} \
         {for(i=1;i<NF;i++)for(j=1;j<=n;j++) \
          if(index($i,ar[j])){printf(" %s",index($i,"scsi")?$i:$(i+1));break}print "";}' | \
    awk '{if(index($0,"scsi'${inst}'")) \
          printf("%-6.6s %2.2s %2.2s %2.2s %-10.10s %-10.10s %-10.10s %s\n", $1,$2,$3,$4,$5,$6,$7,index($8,"known")?"":$8);}'
  done
  echo

}

main()
{

  if [ $# -eq 0 -o "_${1}" = "_--help" -o "_${1}" = "_-h" ]
  then
    help;
    exit 0;
  else
    cmd_line ${*};
  fi

  if [ "${hba_flag}" = "1" ] # Get list of HBAs
  then
    hba_by_name | awk -F/ '{printf("%s %s\n",$NF,$(NF-1));}' | sort -k 1,1 -n
    exit 0;
  fi

  if [ "${inst_flag}" = "1" ]
  then
    hbas=`hba_by_instance ${obj} | awk -F/ '{printf(" %s",$NF);}'`
  else
    hbas=`hba_by_name ${obj} | awk -F/ '{printf(" %s",$NF);}'`  
  fi

  for inst in ${hbas}
  do
    [ ! -f /proc/scsi/swsp/${inst} ] && continue;
    n=`grep -ic "Array WWID" /proc/scsi/swsp/${inst}`
    [ ${n} -le ${swsp_ch_max} ] && continue;
    swsp_ch_max=${n}
    swsp_ch_flg=1;
  done
  
  cur_ch_range=${max_ch_range}
  cur_id_range=${max_id_range}
  cur_lun_range=${max_lun_range}
  [ ${swsp_ch_flg} -eq 0 ] && probe_loop DEL;

  if [ "${remove_flag}" = "1" ]
  then
    exit 0;
  fi
  
  cur_ch_range=${ch_range}
  cur_id_range=${id_range}
  cur_lun_range=${lun_range}

  if [ "${swsp_ch_flg}" = "1" ]
  then
    cur_id_range=0;
    cur_ch_range=`echo ${swsp_ch_max} | awk '{for(i=0;i<$0;i++) printf("%d ",i);}'`
    cur_lun_range=`echo ${swsp_lun_max} | awk '{for(i=0;i<$0;i++) printf("%d ",i);}'`
  fi

#echo cur_id_range=${cur_id_range}
#echo cur_ch_range=${cur_ch_range}
#echo cur_lun_range=${cur_lun_range}

  probe_loop ADD;

  resume;
  exit 0;
    
}

main ${*};
