ecaabc0285eb41f187420a874fa35476288656d3
[zfs.git] / cmd / sas_switch_id / sas_switch_id
1 #!/bin/sh
2 #
3 # sas_switch_id
4 #
5 # Callout script for multipathd to obtain disk UUIDs.  Combine the UUID
6 # from the scsi_id program with the SAS switch port number and enclosure
7 # bay number, if available.  This naming convention enables easier
8 # identification of the physical drive location when multiple disk
9 # enclosures are accessed via a SAS switch.  For other storage
10 # topologies just return the undecorated UUID of the drive.
11
12 PHYS_PER_PORT=4
13 DEV=
14
15 usage() {
16         cat << EOF
17 Usage: sas_switch_id [-d disk] [-p phys_per_port]
18   -d    Basename of the disk device [default=none]
19   -p    Number of PHYs per switch port [default=${PHYS_PER_PORT}]
20   -h    Show this message
21 EOF
22         exit 0
23 }
24
25 while getopts 'd:p:h' OPTION; do
26         case ${OPTION} in
27         d)
28                 DEV=${OPTARG}
29                 ;;
30         p)
31                 PHYS_PER_PORT=${OPTARG}
32                 ;;
33         h)
34                 usage
35                 ;;
36         esac
37 done
38
39 if [ -z "$DEV" ] ; then
40         echo "Error: missing required option -d"
41         exit 1
42 fi
43
44 UUID=`/lib/udev/scsi_id --whitelisted --device=/dev/$DEV`
45 if [ $? != 0 -o -z "$UUID" ] ; then
46         exit 1
47 fi
48 sys_path=`udevadm info -q path -p /sys/block/$DEV`
49 dirs=(`echo "$sys_path" | tr / ' '`)
50 switch_port_dir="/sys"
51
52 # Get path up to /sys/.../hostX
53 for (( i=0; i<${#dirs[*]}; i++ )); do
54         d=${dirs[$i]}
55         switch_port_dir=$switch_port_dir/$d
56         echo $d | egrep -q -e '^host[0-9]+$' && break
57 done
58
59 if [ $i = ${#dirs[*]} ] ; then
60         echo $UUID
61         exit 0
62 fi
63
64 # The directory three levels beneath /sys/.../hostX contains
65 # symlinks to phy devices that reveal the switch port number.
66 # Lowest phy number is $PHYS_PER_PORT*switch_port_number.
67 for (( j=(($i+1)) ; j<(($i+4)); j++ )); do
68         switch_port_dir=$switch_port_dir/${dirs[$j]}
69 done
70 pushd $switch_port_dir > /dev/null
71 PHY=`ls -d phy* 2>/dev/null | head -1 | awk -F: '{print $NF}'`
72 PORT=$(( $PHY / $PHYS_PER_PORT ))
73 popd > /dev/null
74 if [ -z "$PHY" ] ; then
75         echo $UUID
76         exit 0
77 fi
78
79 # Look in /sys/.../sas_device/end_device-X for the bay_identifier
80 # attribute.
81 end_device_dir=$switch_port_dir
82 for (( k=$j ; k<${#dirs[*]} ; k++ )); do
83         d=${dirs[$k]}
84         end_device_dir=$end_device_dir/$d
85         if echo $d | egrep -q -e '^end_device' ; then
86                 end_device_dir=$end_device_dir/sas_device/$d
87                 break
88         fi
89 done
90 SLOT=`cat $end_device_dir/bay_identifier 2>/dev/null`
91 if [ -z "$SLOT" ] ; then
92         echo $UUID
93         exit 0
94 fi
95
96 echo "$UUID-switch-port:$PORT-slot:$SLOT"