#!/bin/sh
#
# sas_switch_id
#
# Callout script for multipathd to obtain disk UUIDs.  Combine the UUID
# from the scsi_id program with the SAS switch port number and enclosure
# bay number, if available.  This naming convention enables easier
# identification of the physical drive location when multiple disk
# enclosures are accessed via a SAS switch.  For other storage
# topologies just return the undecorated UUID of the drive.

PHYS_PER_PORT=4
DEV=

usage() {
        cat << EOF
Usage: sas_switch_id [-d disk] [-p phys_per_port]
  -d    Basename of the disk device [default=none]
  -p    Number of PHYs per switch port [default=${PHYS_PER_PORT}]
  -h    Show this message
EOF
        exit 0
}

while getopts 'd:p:h' OPTION; do
        case ${OPTION} in
        d)
                DEV=${OPTARG}
                ;;
        p)
                PHYS_PER_PORT=${OPTARG}
                ;;
        h)
                usage
                ;;
        esac
done

if [ -z "$DEV" ] ; then
	echo "Error: missing required option -d"
	exit 1
fi

UUID=`/lib/udev/scsi_id --whitelisted --device=/dev/$DEV`
if [ $? != 0 -o -z "$UUID" ] ; then
	exit 1
fi
sys_path=`udevadm info -q path -p /sys/block/$DEV`
dirs=(`echo "$sys_path" | tr / ' '`)
switch_port_dir="/sys"

# Get path up to /sys/.../hostX
for (( i=0; i<${#dirs[*]}; i++ )); do
	d=${dirs[$i]}
	switch_port_dir=$switch_port_dir/$d
	echo $d | egrep -q -e '^host[0-9]+$' && break
done

if [ $i = ${#dirs[*]} ] ; then
	echo $UUID
	exit 0
fi

# The directory three levels beneath /sys/.../hostX contains
# symlinks to phy devices that reveal the switch port number.
# Lowest phy number is $PHYS_PER_PORT*switch_port_number.
for (( j=(($i+1)) ; j<(($i+4)); j++ )); do
	switch_port_dir=$switch_port_dir/${dirs[$j]}
done
pushd $switch_port_dir > /dev/null
PHY=`ls -d phy* 2>/dev/null | head -1 | awk -F: '{print $NF}'`
PORT=$(( $PHY / $PHYS_PER_PORT ))
popd > /dev/null
if [ -z "$PHY" ] ; then
	echo $UUID
	exit 0
fi

# Look in /sys/.../sas_device/end_device-X for the bay_identifier
# attribute.
end_device_dir=$switch_port_dir
for (( k=$j ; k<${#dirs[*]} ; k++ )); do
	d=${dirs[$k]}
	end_device_dir=$end_device_dir/$d
	if echo $d | egrep -q -e '^end_device' ; then
		end_device_dir=$end_device_dir/sas_device/$d
		break
	fi
done
SLOT=`cat $end_device_dir/bay_identifier 2>/dev/null`
if [ -z "$SLOT" ] ; then
	echo $UUID
	exit 0
fi

echo "$UUID-switch-port:$PORT-slot:$SLOT"
