#!/bin/sh

# Name: adapter_info
# Copyright: (C)2003 Hewlett-Packard
#
# Description: lists all the qla* adapters in a system,
#              their state, WWNN, and WWPN, and other
#	       info
#
# Modification History
#
# Chad Dupuis	03/14/03	Initial Development
# Chad Dupuis   09/17/03        Added target listing option;
#                               display login retry count in
#                               some instances; Allow just the
#                               instance number to specified
#                               with the -d option
# Chad Dupuis   04/21/04	Look for SCSI targets searching
#                               for the "target" string only
# Chad Dupuis   06/11/04	Updates for SLES 9 (2.6 kernel)
# Chad Dupuis   08/03/04	Added -m switch to list adapter models
# Chad Dupuis	01/04/06	Added support for Emulex adapters
# Chad Dupuis	01/23/06	Add '2>/dev/null' to the end of find
#                               commands in get_adapters
# Chad Dupuis	03/27/06	Fixed HBA model output with the Emulex
#                               7.x driver; Fixed driver version output
#                               for QLogic 4Gb adapters on 2.6 kernels
# Chad Dupuis	05/22/06	Call sysfs_scandisk for Emulex adapters
#                               to list LUNs
# Chad Dupuis	08/28/06	Changes for SLES 10
# Chad Dupuis	09/15/06	Put quotes around grep statment when 
#                               searching for adapters

#
# Defines
#

SYSFSSCANDISK=/opt/hp/hp_fibreutils/sysfs_scandisk
SYSFSSCANRPORT=/opt/hp/hp_fibreutils/sysfs_scan_rport

# Get the minor revision number of the 2.6 kernel

if [ "`uname -r | cut -c 1-3`" = "2.6" ]
then
	KERNMINORREV=`uname -r | awk 'BEGIN {FS="."} {print $3}' | awk 'BEGIN {FS="-"} {print $1}'`
fi

#
# Function defs
#

# Name: sysfs_elx_list
# Description: Returns a list of numbers that corrospond to Emulex adapters in
#              sysfs
# In: none
# Out: List of sysfs Emulex adapters
# Returns: none

sysfs_elx_list () {
	# Directory of SCSI hosts
	SCSIHOSTDIR=/sys/class/scsi_host

	# List of hosts in scsi host directory
	HOSTLIST=`ls $SCSIHOSTDIR 2>/dev/null`

	# List of emulex adapters to return
	SYSFS_ELX_LIST=""

	# Look for lpfc host adapters.  These will be the ones with the lpfc_log_verbose
	# file

	for i in $HOSTLIST
	do
        	if test -f ${SCSIHOSTDIR}/${i}/lpfc_log_verbose
        	then
                	SYSFS_ELX_LIST=$SYSFS_ELX_LIST" `echo ${i} | sed 's/host//g'`"
        	fi
	done
}

# Get a list of QLogic and Emulex adapters in the system.  The QLogic adapters
# are listed in the variable QADAPTERS and the Emulex adapters are listed in the 
# variable EADAPTERS

get_adapters () {
 # The location where adapter listings can be found are different for each kernel type

 if [ "$KERNVER" = "2.4" ]
 then
 	QADAPTERS=`find /proc/scsi/qla2300 2>/dev/null | grep "/[0-9]" 2>/dev/null`
	EADAPTERS=`find /proc/scsi/lpfc 2>/dev/null | grep "/[0-9]" 2>/dev/null`
 elif [ "$KERNVER" = "2.6" ]
 then
	QADAPTERS=`find /proc/scsi/qla2xxx 2>/dev/null | grep "/[0-9]" 2>/dev/null`
	sysfs_elx_list
	EADAPTERS=$SYSFS_ELX_LIST
 fi
}

# Prints out a list of QLogic and Emulex adapters

list_adapters () {
 for i in $QADAPTERS
 do
	echo $i
 done
 for i in $EADAPTERS
 do
	if [ "$KERNVER" = "2.4" ]
	then
		echo $i
	else
		echo "/sys/class/scsi_host/host${i}"
	fi
 done
}

# Lists useful information for each adapter.  The non-verbose mode lists
# just the name, state, WWPN and WWNN.  The verbose modes lists a little 
# more adapter specific information.

normal_output () {

 if [ $VERBOSEFLAG -eq 0 ]
 then
	# normal output

	# List QLogic adapters

	for i in $QADAPTERS
  	do
   		if [ "$KERNVER" = "2.4" ]
                then
                        STATE=`cat $i | grep "state=" | awk '{print $4}' | sed -e 's/,//' -e 's/<//' -e 's/>//'`
                elif [ "$KERNVER" = "2.6" ]
                then
                        STATE=`cat $i | grep "loop state" | awk '{print $5}' | sed -e 's/,//' -e 's/<//' -e 's/>//'`
                fi

		WWNN=`cat $i | grep "adapter-node=" | cut -c 24-39`
   		WWPN=`cat $i | grep "adapter-port=" | cut -c 24-39`

   		echo "${i}: STATE=${STATE} WWNN=${WWNN} WWPN=${WWPN}"
  	done

	# List Emulex adapters

	for i in $EADAPTERS
	do
		if [ "$KERNVER" = "2.4" ]
		then
			STATE=`cat $i | grep Link | awk '{print $1""$2}' | tr "[a-z]" "[A-Z]"`
			WWNN=`cat $i | grep "Nodename" | awk '{print $2}' | sed 's/://g'`
			WWPN=`cat $i | grep "Portname" | awk '{print $4}' | sed 's/://g'`
		elif [ "$KERNVER" = "2.6" ]
		then
			# We need the scsi host adapter instance to access to correct directory
			# in the /sys directory

			INST=`echo $i | awk 'BEGIN {FS="/"} {print $NF}'`
			
			STATE=`cat /sys/class/scsi_host/host${INST}/state | grep Link | awk '{print $1$2}' | tr "[a-z]" "[A-Z]"`
			if [ $KERNMINORREV -gt 15 ]
			then
				SYSADAPTERDIR=fc_host
			else
				SYSADAPTERDIR=scsi_host
			fi
		
			WWNN=`cat /sys/class/${SYSADAPTERDIR}/host${INST}/node_name | cut -c 3-`
			WWPN=`cat /sys/class/${SYSADAPTERDIR}/host${INST}/port_name | cut -c 3-`
		fi

		if [ "$KERNVER" = "2.4" ]
		then
			echo -n "${i}: "
		else
			echo -n "/sys/class/scsi_host/${i}: "
		fi
		echo "STATE=${STATE} WWNN=${WWNN} WWPN=${WWPN}"
	done

 else
 	# verbose output
  	
	# List QLogic adapters

  	for i in $QADAPTERS
  	do
   		if [ "$KERNVER" = "2.4" ]
   		then
			STATE=`cat $i | grep "state=" | awk '{print $4}' | sed -e 's/,//' -e 's/<//' -e 's/>//'`
   		elif [ "$KERNVER" = "2.6" ]
   		then
			STATE=`cat $i | grep "loop state" | awk '{print $5}' | sed -e 's/,//' -e 's/<//' -e 's/>//'`
   		fi

   		WWNN=`cat $i | grep "adapter-node=" | cut -c 24-39`
   		WWPN=`cat $i | grep "adapter-port=" | cut -c 24-39`
   		QDEPTH=`cat $i | grep "Device queue depth" | awk '{print $5}'`

   		if [ "$KERNVER" = "2.4" ]
   		then
   			VERSION=`cat $i | grep "Driver version" | awk '{print $6}'`
   		elif [ "$KERNVER" = "2.6" ]
   		then
                        if [ "`cat $i | grep "Driver version" | grep "\[IP\]"`" = "" ]
                        then
                                VERSION=`cat $i | grep "Driver version" | awk '{print $7}'`
                        else
                                VERSION=`cat $i | grep "Driver version" | awk '{print $8}'`
                        fi
		fi

   		PDRC=`cat $i | grep "Port down retry" | awk '{print $5}'`
   		LRC=`cat $i | grep "Login retry count" | awk '{print $5}'`

		ATYPE=`cat $i | grep "QLogic PCI to Fibre Channel Host Adapter" | awk '{print $9}' | sed 's/://g'`

       		if [ "$ATYPE" = "HP" ]
        	then
                	ATYPE=`cat $i | grep "QLogic PCI to Fibre Channel Host Adapter" | awk '{print $10}' | sed 's/://g'`
        	fi

   		echo "${i}:"
   		echo "	Driver version = $VERSION"
   		echo "	Adapter state = $STATE"
   		echo "	Adapter model = $ATYPE"
		echo "	WWNN = $WWNN"
   		echo "	WWPN = $WWPN"
   		echo "	Queue depth = `printf "%d" $QDEPTH`"
   		echo "	Port down retry count = $PDRC"
   		echo "        Login retry count = $LRC"
  	done

	# List Emulex adapters

	for i in $EADAPTERS
	do
		if [ "$KERNVER" = "2.4" ]
		then
			VERSION=`cat $i | grep "FC SCSI" | awk '{print $5}'`
			ATYPE=`cat $i | grep "LP" | awk '{print $2}'`
			STATE=`cat $i | grep Link | awk '{print $1""$2}' | tr "[a-z]" "[A-Z]"`
			WWNN=`cat $i | grep Nodename | awk '{print $2}' | sed 's/://g'`
			WWPN=`cat $i | grep Portname | awk '{print $4}' | sed 's/://g'`
			FIRMWARE=`cat $i | grep Firmware | awk '{print $3}'`
		elif [ "$KERNVER" = "2.6" ]
		then
			# We need the scsi host adapter instance to access to correct directory
                        # in the /sys directory

			INST=`echo $i | awk 'BEGIN {FS="/"} {print $NF}'`
                        
			VERSION=`cat /sys/class/scsi_host/host${INST}/lpfc_drvr_version | awk '{print $7}'`
			ATYPE=`cat /sys/class/scsi_host/host${INST}/modelname`
			STATE=`cat /sys/class/scsi_host/host${INST}/state | grep Link | awk '{print $1$2}' | tr "[a-z]" "[A-Z]"`
			if [ $KERNMINORREV -gt 15 ]
                        then
                                SYSADAPTERDIR=fc_host
                        else
                                SYSADAPTERDIR=scsi_host
                        fi

                        WWNN=`cat /sys/class/${SYSADAPTERDIR}/host${INST}/node_name | cut -c 3-`
                        WWPN=`cat /sys/class/${SYSADAPTERDIR}/host${INST}/port_name | cut -c 3-`
			FIRMWARE=`cat /sys/class/scsi_host/host${INST}/fwrev`
			QDEPTH=`cat /sys/class/scsi_host/host${INST}/lpfc_lun_queue_depth`
			NODEVTMO=`cat /sys/class/scsi_host/host${INST}/lpfc_nodev_tmo`
		fi

		if [ "$KERNVER" = "2.4" ]
		then
			echo "${i}:"
		else
			echo "/sys/class/scsi_host/host${i}:"
		fi
   		echo "	Driver version = $VERSION"
   		echo "	Adapter state = $STATE"
   		echo "	Adapter model = $ATYPE"
		echo "	WWNN = $WWNN"
   		echo "	WWPN = $WWPN"
   		echo "	Firmware version = $FIRMWARE"
		if [ "$KERNVER" = "2.6" ]
		then
			echo "	Queue depth = $QDEPTH"
			echo "	NODEV timeout = $NODEVTMO"
		fi
	done
 fi


}

# Produce a list of LUNs for each adapter.  Only QLogic gives this listing
# so we do not print anything out for Emulex.

lun_output () {

 for i in $QADAPTERS
 do
  	echo ${i}":"
  	echo ""
  	cat $i | grep Pending
  	echo ""
 done
 for i in $EADAPTERS
 do
	if [ "$KERNVER" = "2.4" ]
        then
                echo $i
        else
                echo "/sys/class/scsi_host/host${i}"
        fi
	echo ""
	$SYSFSSCANDISK `basename $i`
	echo ""
 done
}


# Print out all the targets that each adapter sees

target_output () {

 # List targets for QLogic adapters

 for i in $QADAPTERS
 do
  	echo ${i}":"
  	echo ""
  	cat $i | grep target
  	echo ""
 done

 # List targets for Emulex adapters

 for i in $EADAPTERS
 do
	if [ "$KERNVER" = "2.6" ]
	then
		if [ $KERNMINORREV -lt 16 ]
		then
			# Get the targets from /proc

			PROCNAME="/proc/scsi/lpfc/$i"
			echo $PROCNAME":"
			echo ""
			cat $PROCNAME | grep DID
			echo ""
		else
			# Get the targets from /sys
			echo "/sys/class/scsi_host/host${i}:"
			echo ""
			$SYSFSSCANRPORT $i
			echo ""
		fi

	else
		echo ""
		echo "Use lssd or lssg to get a listing of SCSI devices attached to this adapter."
		echo ""
	fi
 done
}


# Prints out the model of each adapter.

adapter_types () {

 # List QLogic adapter models

 for i in $QADAPTERS
 do
 	ATYPE=`cat $i | grep "QLogic PCI to Fibre Channel Host Adapter" | awk '{print $9}' | sed 's/://g'`

	if [ "$ATYPE" = "HP" ]
	then
		ATYPE=`cat $i | grep "QLogic PCI to Fibre Channel Host Adapter" | awk '{print $10}' | sed 's/://g'`
	fi
	
	echo "${i} - $ATYPE"
 done

 # List Emulex adapter models

 for i in $EADAPTERS
 do
	if [ "$KERNVER" = "2.4" ]
	then
		ATYPE=`cat $i | grep "LP" | awk '{print $2}'`
	elif [ "$KERNVER" = "2.6" ]
	then
		INST=`echo $i | awk 'BEGIN {FS="/"} {print $NF}'`
		ATYPE=`cat /sys/class/scsi_host/host${INST}/modelname`
	fi

	if [ "$KERNVER" = "2.4" ]
        then
                echo -n "${i} - "
        else
                echo -n "/sys/class/scsi_host/host${i} - "
        fi

	echo "$ATYPE"
 done
}


# List the output that can be produced by other options, but for just a
# single SCSI host instance.

device_output () {

 # from adapter instance, get actual full path

 i=`find /proc/scsi 2>/dev/null | grep /$1`

 if [ ! "$i" ]
 then
 	# Try to find the instance in /sys first before we exit out

	if test ! -d /sys/class/scsi_host/host${1} 
	then
		echo "$1 is not a valid SCSI instance"
		exit 1
	else
		i=$1
	fi
 fi

 # are we a QLogic adapter or an Emulex adapter?

 if [ "`echo $i | grep qla`" != "" ]
 then
	#
	# we're a QLogic adapter

	if [ "`uname -r | cut -c 1-3`" = "2.4" ]
 	then
 		STATE=`cat $i | grep "state=" | awk '{print $4}' | sed -e 's/,//' -e 's/<//' -e 's/>//'`
 	elif [ "`uname -r | cut -c 1-3`" = "2.6" ]
 	then
		STATE=`cat $i | grep "loop state" | awk '{print $5}' | sed -e 's/,//' -e 's/<//' -e 's/>//'`
 	fi

 	WWNN=`cat $i | grep "adapter-node=" | cut -c 24-39`
 	WWPN=`cat $i | grep "adapter-port=" | cut -c 24-39`
 	QDEPTH=`cat $i | grep "Device queue depth" | awk '{print $5}'`

 	if [ "`uname -r | cut -c 1-3`" = "2.4" ]
 	then
		VERSION=`cat $i | grep "Driver version" | awk '{print $6}'`
 	elif [ "`uname -r | cut -c 1-3`" = "2.6" ]
 	then
                        if [ "`cat $i | grep "Driver version" | grep "\[IP\]"`" = "" ]
                        then
                                VERSION=`cat $i | grep "Driver version" | awk '{print $7}'`
                        else
                                VERSION=`cat $i | grep "Driver version" | awk '{print $8}'`
                        fi
	fi

 	PDRC=`cat $i | grep "Port down retry" | awk '{print $5}'`
 	LRC=`cat $i | grep "Login retry count" | awk '{print $5}'`

 	ATYPE=`cat $i | grep "QLogic PCI to Fibre Channel Host Adapter" | awk '{print $9}' | sed 's/://g'`

 	if [ "$ATYPE" = "HP" ]
 	then
 		ATYPE=`cat $i | grep "QLogic PCI to Fibre Channel Host Adapter" | awk '{print $10}' | sed 's/://g'`
 	fi

 	echo "General Info"
 	echo "------------------"
 	echo "Driver version = $VERSION"
 	echo "Adapter state = $STATE"
 	echo "Adapter model = $ATYPE"
 	echo "WWNN = $WWNN"
 	echo "WWPN = $WWPN"
 	echo "Queue depth = `printf "%d" $QDEPTH`"
 	echo "Port down retry count = $PDRC"
 	echo "Login retry count = $LRC"
 	echo ""
 	echo "LUNs"
 	echo "----------"
 	cat $i | grep Pending
 	echo ""
 	echo "Targets"
 	echo "-------------"
 	cat $i | grep target
 elif [ "`echo $i | grep lpfc`" != "" ] || test -f /sys/class/scsi_host/host${i}/lpfc_log_verbose
 then
 	#
	# we're an Emulex adapter

	
        if [ "$KERNVER" = "2.4" ]
        then
		VERSION=`cat $i | grep "FC SCSI" | awk '{print $5}'`
		ATYPE=`cat $i | grep "LP" | awk '{print $2}'`
	STATE=`cat $i | grep Link | awk '{print $1""$2}' | tr "[a-z]" "[A-Z]"`
		WWNN=`cat $i | grep Nodename | awk '{print $2}' | sed 's/://g'`
		WWPN=`cat $i | grep Portname | awk '{print $4}' | sed 's/://g'`
		FIRMWARE=`cat $i | grep Firmware | awk '{print $3}'`
	elif [ "$KERNVER" = "2.6" ]
	then
		 # We need the scsi host adapter instance to access to correct directory
		 # in the /sys directory

		INST=`echo $i | awk 'BEGIN {FS="/"} {print $NF}'`

		VERSION=`cat /sys/class/scsi_host/host${INST}/lpfc_drvr_version | awk '{print $7}'`
		ATYPE=`cat /sys/class/scsi_host/host${INST}/modelname`
		STATE=`cat /sys/class/scsi_host/host${INST}/state | grep Link | awk '{print $1$2}' | tr "[a-z]" "[A-Z]"`
		if [ $KERNMINORREV -gt 15 ]
                then
                	SYSADAPTERDIR=fc_host
                else
                	SYSADAPTERDIR=scsi_host
                fi

                WWNN=`cat /sys/class/${SYSADAPTERDIR}/host${INST}/node_name | cut -c 3-`
                WWPN=`cat /sys/class/${SYSADAPTERDIR}/host${INST}/port_name | cut -c 3-`
		FIRMWARE=`cat /sys/class/scsi_host/host${INST}/fwrev`
		QDEPTH=`cat /sys/class/scsi_host/host${INST}/lpfc_lun_queue_depth`
		NODEVTMO=`cat /sys/class/scsi_host/host${INST}/lpfc_nodev_tmo`
	fi

	echo "General Info"
 	echo "------------------"
	echo "Driver version = $VERSION"
	echo "Adapter state = $STATE"
	echo "Adapter model = $ATYPE"
	echo "WWNN = $WWNN"
	echo "WWPN = $WWPN"
	echo "Firmware version = $FIRMWARE"
	if [ "$KERNVER" = "2.6" ]
	then
		echo "Queue depth = $QDEPTH"
		echo "NODEV timeout = $NODEVTMO"
	fi
   	echo ""
 	echo "LUNs"
 	echo "----------"
 	echo ""
	if [ "$KERNVER" = "2.6" ]
	then
		$SYSFSSCANDISK `basename $i`
	else 
		echo "Use lssd or lssg to get a listing of SCSI devices attached to this adapter."
	fi
	echo ""
 	echo "Targets"
 	echo "-------------"
 	echo ""
	if [ "$KERNVER" = "2.6" ]
        then
                if [ $KERNMINORREV -lt 16 ]
                then
                        # Get the targets from /proc

                        PROCNAME="/proc/scsi/lpfc/$i"
                        echo ""
                        cat $PROCNAME | grep DID
                else
                        # Get the targets from /sys
                        $SYSFSSCANRPORT $i
                        echo ""
                fi

        else
                echo ""
                echo "Use lssd or lssg to get a listing of SCSI devices attached to this adapter."
                echo ""
        fi

 fi
}

# prints out a help message

help_message () {
 echo "Usage: adapter_info [ -lLtmvhd device instance ]"
 echo "adapter_info: lists useful information for HP supported"
 echo "              FC adapters on this system"
 echo ""
 echo "-l: lists all FC adapters in this system"
 echo "-L: lists all LUN's for each adapter"
 echo "-t: lists all targets seen by each adapter"
 echo "-m: lists each adapter\'s model"
 echo "-v: verbose"
 echo "-h: prints this help menu"
 echo "-d: prints LUN and verbose information for a specific device"
}

#
# Script Main
#

# get the kernel major and minor version

KERNVER=`uname -r | cut -c 1-3`

# get a list of adapters on the system

get_adapters

# set default values for output flags

LISTFLAG=0
LUNFLAG=0
VERBOSEFLAG=0
DEVICEFLAG=0
HELPFLAG=0
TARGETFLAG=0
TYPEFLAG=0

# parse command line into arguments

getopt lLtvhd:m $* 1>/dev/null 2>/dev/null

# check result of parsing

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

set -- `getopt lLtvhd:m $*`

while [ $1 != -- ]
do
 case $1 in
 	-l) LISTFLAG=1;;
  	-L) LUNFLAG=1;;
  	-t) TARGETFLAG=1;;
  	-v) VERBOSEFLAG=1;;
	-m) TYPEFLAG=1;;
  	-h) HELPFLAG=1;;
  	-d) DEVICEFLAG=1
      	    DEVICE=$2
            shift;;
 esac
 shift   # next flag
done

shift   # skip --

if [ $HELPFLAG -eq 1 ]
then
 help_message
 exit 0
elif [ $DEVICEFLAG -eq 1 ]
then
 # list output for a specific adapter

 device_output $DEVICE
 exit 0
elif [ $LISTFLAG -eq 1 ]
then
 # list adapters, then exit

 list_adapters
 exit 0
elif [ $LUNFLAG -eq 1 ] || [ $TARGETFLAG -eq 1 ] || [ $TYPEFLAG -eq 1 ]
then
 # list LUNs for each adapter

 if [ $LUNFLAG -eq 1 ]
 then
 	echo "LUNs..."
	echo ""
 	lun_output
 fi

 # list targets for all devices

 if [ $TARGETFLAG -eq 1 ]
 then
  	echo "Targets..."
  	echo ""
  	target_output
 fi

 # list each adapter's model type

 if [ $TYPEFLAG -eq 1 ]
 then
	echo "Adapter Models..."
	echo ""
	adapter_types
 fi

 exit 0
fi

normal_output

