#!/bin/bash
#
# Name: lssd
# Copyright: (c)Copyright 2003-2008 Hewlett-Packard Development Company, L.P.
#
# Description: lists all sd devies and a description
#              of each device
#
# Modification History
#
# Chad Dupuis	04/11/03 Initial Development
# Chad Dupuis   06/11/04 Added code to get the wwid of the
#                        FC target that a particular sd
#                        device is attached to
# Chad Dupuis	08/23/05 Added command line options to determine whether to print
#                        the world wide name and UUID of each device; Use
#                        /sys/block to get a listing of sd devices
#                        on the system
# Chad Dupuis	06/19/07 With 2.6 kernels, do not stop when scsi_info doesn't work
# Chad Dupuis	07/31/07 Add -c option to allow device data to be printed from
#                        a cache instead of scanning
# Chad Dupuis	08/11/08 Change scsi_info.26 to scsi_info
# Chad Dupuis	09/22/08 Fix grep statement that parses /sys/block for sd devices
#                        to only look for files that begin with sd
# Chad Dupuis	10/30/08 Add support for device files that are five characters
# Chad Dupuis	11/24/08 Fixed problem printing sdsd* devices

#
# Functions
#

# This function prints a help message

print_help () {
 echo "Usage: $0 [-w|l|c|h]"
 echo ""
 echo "Prints all bound /dev/sd* devices"
 echo ""
 echo "-w: print world wide node name of devices"
 echo "-l: print inquiry page 0x83 UUID of devices"
 echo "-c: print cached data instead of scanning"
 echo "-h: print help message"
 exit 0
}

# gets a list of devices
# The device list check ahs been modified to get the list from 
#Rhel5.3 and Sles10Sp3 OS onwards
device_list () {
MAJVER=0
MINVER=0

if test -f /etc/redhat-release
then
        #
        # RHEL case
        if [ `grep -c "Red Hat Enterprise Linux" /etc/redhat-release` -gt 0 ]
        then
                VERSTR="`grep "Red Hat Enterprise Linux" /etc/redhat-release | awk '{print $7}'`"

                if [ "$VERSTR" != "" ]
                then
                        MAJVER="`echo $VERSTR | awk 'BEGIN {FS="."} {print $1}'`"
                        MINVER="`echo $VERSTR | awk 'BEGIN {FS="."} {print $2}'`"
                fi
        fi

        #
        # OEL case
        if [ `grep -c "Enterprise Linux Enterprise Linux" /etc/redhat-release` -gt 0 ]
        then
                VERSTR="`grep "Enterprise Linux Enterprise Linux" /etc/redhat-release | awk '{print $7}'`"

                if [ "$VERSTR" != "" ]
                then
                        MAJVER="`echo $VERSTR | awk 'BEGIN {FS="."} {print $1}'`"
                        MINVER="`echo $VERSTR | awk 'BEGIN {FS="."} {print $2}'`"
                fi
        fi

        # Now check to see if we're an update of RHEL 5
        if [ "$MAJVER" = "5" ]
        then
                if [ $MINVER -lt 3 ]
                then
		    LETT_LIST=""
		    exit 1
                fi
        fi
fi

# Check to see if we're greater than SLES 10 SP 2

if test -f /etc/SuSE-release
then
        SLESREV="`grep VERSION /etc/SuSE-release | awk '{print $3}'`"
        UPDATE="`grep PATCHLEVEL /etc/SuSE-release | awk '{print $3}'`"	

        if [ "$SLESREV" = "10" ]
        then
                if [ $UPDATE -lt 3 ]
                then
		    LETT_LIST=""
		    exit 1
                fi
        fi
fi
LETT_LIST="`ls /sys/block | grep ^sd | sed 's/sd//'`"
}
 	
space_str () {
 STRINGSIZE=$1
 STR=$2 
 SPACESTR=""
 
 SIZE=`echo $STR | wc -c`
 NUM_OF_SPACES=`expr $STRINGSIZE - $SIZE`

 COUNT=$NUM_OF_SPACES

 while [ $COUNT -ge 0 ]
 do
  SPACESTR=$SPACESTR" "
  COUNT=`expr $COUNT - 1`
 done
}

# Name: print_device_data
# Description: Print the data for the current device
# In: None
# Out: None
# Returns: None

print_device_data () {
	echo -n "${DEVICE}${DEVICESPACE} ${CONN}${CONNSPACE} $VENDOR $MODEL $FWREV"
	
	if [ $WWIDFLAG -eq 1 ]
	then
	 	echo -n "  $WWID"
	fi
	
	if [ $LUNIDFLAG -eq 1 ]
 	then
 		echo -n "  $LUNID"
 	fi
 	echo ""
}

# Name: format_device_data
# Description: Formats the various variables that are used to print the device
#              data
# In: None
# Out: None
# Returns: None

format_device_data () {
	CONN=`echo $OUTPUT | awk 'BEGIN {FS=":"} {print $1}' | awk 'BEGIN {FS="="} {print $2}' | sed 's/"//g'`
 	VENDOR=`echo $OUTPUT | awk 'BEGIN {FS=":"} {print $2}' | awk 'BEGIN {FS="="} {print $2}' | sed 's/"//g'`
 	MODEL=`echo $OUTPUT | awk 'BEGIN {FS=":"} {print $3}' | awk 'BEGIN {FS="="} {print $2}' | sed 's/"//g'`
 	FWREV=`echo $OUTPUT | awk 'BEGIN {FS=":"} {print $4}' | awk 'BEGIN {FS="="} {print $2}' | sed 's/"//g'`
 	WWID=`echo $OUTPUT | awk 'BEGIN {FS=":"} {print $5}' | awk 'BEGIN {FS="="} {print $2}' | sed 's/"//g'`
 	LUNID=`echo $OUTPUT | awk 'BEGIN {FS=":"} {print $6}' | awk 'BEGIN {FS="="} {print $2}' | sed 's/"//g'`
	
	# get the number of spaces to pad after the connection address

 	space_str 6 "${DEVICE}"
 	DEVICESPACE=$SPACESTR 
 	space_str 16 $CONN
 	CONNSPACE=$SPACESTR
 
 	# format world wide ID string

 	if [ "$WWID" != "" ]
 	then
  		WWID="`echo $WWID | cut -c 1-4`"-"`echo $WWID | cut -c 5-8`"-"`echo $WWID | cut -c 9-12`"-"`echo $WWID | cut -c 13-16`"
	fi 
}

# Name: print_scan_data
# Description: Actually send INQUIRY commands to the devices to get the device
#              data
# In: None
# Out: None
# Returns: None

print_scan_data () {
	# If we've made it this far, delete easier cached data
	rm -f $CACHEFILE
	
	# get list of device suffixes
	device_list

	# loop through devices and query the devices directly
	# to obtain information 

	for i in $LETT_LIST
	do
 		DEVICE="sd${i}"

		# check to see if device is bound 
 		$SCSI_INFO /dev/$DEVICE 1>/dev/null 2>/dev/null

 		if [ $? -ne 0 ]
 		then
			# The behavior when scsi_info fails is slightly different depending on the 
			# kernel version.  With 2.4 kernels we want to exit because we can assume
			# consecutive device lettering.  With 2.6, we have an exact listing of all
			# devices from the /sys/block directory so simply skip to the next device

			if [ "$KERNELVERSION" = "2.4" ]
			then	
				exit 0
			else
				echo -n ""
				#continue
			fi
 		fi

 		# get device info from scsi_info
 		OUTPUT=`$SCSI_INFO /dev/$DEVICE` 
		
		# Save device information in cache file
		echo "DEVICE=$DEVICE:$OUTPUT" >> $CACHEFILE

		# Format the device data
		format_device_data

		# Actually print out the data for this device
		print_device_data
	done
}

# Name: print_cache_data
# Description: Prints sd device data from the last scan instead
#              of doing a fresh scan
# In: None
# Out: None
# Returns: None
print_cache_data () {
	if test ! -f $CACHEFILE
	then
		return
	fi

	while read line
	do
		DEVICE="`echo $line | awk 'BEGIN {FS=":"} {print $1}' | awk 'BEGIN {FS="="} {print $2}'`"
		OUTPUT="`echo $line | sed 's/DEVICE=[a-z]*://'`"
		
		# Format the device data
                format_device_data

                # Actually print out the data for this device
                print_device_data
			
	done < $CACHEFILE

}
 
# This function parses parameters passed in from the command line

read_args () {

 WWIDFLAG=0
 LUNIDFLAG=0
 HELPFLAG=0
 CACHEFLAG=0

 if [ $# -gt 0 ]
 then
        # parse command line into arguments

        getopt wlch $* 1>/dev/null 2>/dev/null

        # check result of parsing

        if [ $? != 0 ]
        then
                echo "Bad argument or missing argument"
                exit 1
        fi

        set -- `getopt wlch $*`

        while [ $1 != -- ]
        do
                case $1 in
                        -w) WWIDFLAG=1;;
                        -h) HELPFLAG=1;;
			-l) LUNIDFLAG=1;;
			-c) CACHEFLAG=1;;
                        *) echo "$1 is an illegal argument"
                           exit 1;;
                esac
                shift   # next flag
        done

        shift   # skip --

        if [ $HELPFLAG -eq 1 ]
        then
                print_help
                exit 0
        fi

	if [ $CACHEFLAG -eq 1 ] && test -f $CACHEFILE
	then
		print_cache_data
		exit 0
	fi
 fi
}



# 
# defines
#

KERNELVERSION="`uname -r | cut -c 1-3`"
CACHEFILE="/opt/hp/hp_fibreutils/lssd.cache"

# determine scsi_info executable to use

SCSI_INFO="/opt/hp/hp_fibreutils/scsi_info"

# check to make sure that scsi_info exists

ls $SCSI_INFO 1>/dev/null 2>/dev/null

if [ $? -ne 0 ]
then
 echo "$SCSI_INFO does not exist"
 exit 1
fi

# parse argument list

read_args $*

if [ $CACHEFLAG -eq 1 ] && test -f $CAHCEFILE
then
	print_cache_data
else
	print_scan_data	
fi

